Documentaciónde la clave al primer clip
Todo lo que necesitas para una primera generación: una clave, una solicitud, la tarea y el webhook.
El acceso a la API para desarrolladores requiere aprobación previa.
Descripción general
REST sobre HTTPS, con JSON de entrada y de salida. Cada generación es asíncrona.
- URL base
https://api.pershot.app/v1- Autenticación
- Authorization: Bearer seguido de tu clave. Las claves empiezan por sk_test_ o sk_live_ y se muestran una sola vez; solo guardamos un hash.
- Permisos de las claves
- Cada clave tiene permisos y, si configuras una en el estudio, una lista de modelos y herramientas permitidos. Una clave con lista de permitidos solo puede usar lo que está en ella, incluidas las herramientas: ampliación de imágenes, eliminación de fondo, Mejorar, sincronización labial, expansión de imagen y el editor de imágenes. Todo lo demás responde 403 forbidden_model. 1080p o 4K con Mejorar necesita tanto el modelo de video como Mejorar.
- Forma de los errores
{ "error": { "code", "message", "param", "request_id" } }- Identificadores
- Con prefijo según el tipo: job_, qt_, key_, up_.
- OpenAPI
- /api/v1/openapi.json
- Para agentes de IA
- Texto plano para agentes de IA: entradas, valores admitidos, cada precio y un ejemplo de solicitud
seedance-2.0-fastseedance-2.0-miniqwen-image-2512-lightningqwen-image-2512qwen-image-edit-2511-lightningqwen-image-edit-2511
Las generaciones reales aún no están habilitadas. Deja tu correo en la página de un modelo y te escribiremos una sola vez, cuando se habiliten.
Inicio rápido
Cuatro pasos, cada uno con la respuesta que deberías ver.
- 01
Consigue una clave
El acceso a la API para desarrolladores requiere aprobación previa: pídelo en el estudio, en Claves de API. Cuando te lo aprueben, crea ahí una clave y cópiala: la clave completa se muestra una sola vez.
export API_KEY="sk_test_…" - 02
Envía una solicitud
Envía la toma por POST con un Idempotency-Key y un límite max_credits. Recibes un 202 y una tarea en cola de inmediato, y los créditos se retienen.
curl https://api.pershot.app/v1/videos/generations \ -H "Authorization: Bearer $API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "model": "seedance-2.0-fast", "prompt": "Perfume mist in hard side light. Slow push-in, black background, grain.", "duration": 5, "resolution": "720p", "aspect_ratio": "16:9", "generate_audio": true, "max_credits": 34 }'{ "id": "job_01J9ZK4T8W", "object": "job", "kind": "video", "status": "queued", "money_status": "reserved", "queue_position": 2, "requested_model": "seedance-2.0-fast", "credits_quoted": 34, "credits_charged": null } - 03
Revisa la tarea
Haz GET de la tarea hasta que su estado sea succeeded. La URL de salida está firmada y caduca; descarga lo que quieras conservar.
curl https://api.pershot.app/v1/jobs/job_01J9ZK4T8W \ -H "Authorization: Bearer $API_KEY"{ "id": "job_01J9ZK4T8W", "object": "job", "kind": "video", "status": "succeeded", "money_status": "settled", "requested_model": "seedance-2.0-fast", "resolved_model": "seedance-2.0-fast", "credits_quoted": 34, "credits_charged": 34, "outputs": [ { "kind": "video", "url": "https://…/job_01J9ZK4T8W.mp4?sig=…", "width": 1280, "height": 720, "duration_s": 5 } ], "error": null } - 04
Recibe el webhook
Pasa webhook_url y te enviaremos por POST cada cambio de estado, firmado con una marca de tiempo. Responde con 2xx; las entregas fallidas se reintentan con espera progresiva.
{ "id": "evt_01J9ZKB1QX", "type": "job.succeeded", "created_at": "2026-09-29T14:02:31Z", "data": { "job": { "id": "job_01J9ZK4T8W", "object": "job", "status": "succeeded", "money_status": "settled", "credits_charged": 34, "outputs": [ { "kind": "video", "url": "https://…/job_01J9ZK4T8W.mp4?sig=…", "width": 1280, "height": 720, "duration_s": 5 } ] } } }
Endpoints
Todas las rutas son relativas a la URL base.
| Método | Ruta | Qué hace |
|---|---|---|
| GET | /v1/models | Modelos, capacidades y estado disponibles para tu cuenta |
| GET | /v1/pricing | Precios públicos; con sesión iniciada, los precios de tu cuenta |
| POST | /v1/quotes | Plan, partidas, cargo máximo y vencimiento (10 minutos) |
| POST | /v1/videos/generations | Generar un video; 202 y una tarea |
| POST | /v1/images/generations | Generar o editar una imagen; 202 y una tarea |
| GET | /v1/jobs/{id} | Estado, resultados como enlaces firmados, costo real |
| GET | /v1/jobs | Tus tareas, de la más reciente a la más antigua |
| POST | /v1/jobs/{id}/cancel | Solicitar la cancelación; los créditos retenidos se reembolsan salvo que el modelo ya haya aceptado la tarea |
| GET | /v1/balance | Créditos disponibles y retenidos, por tipo |
| GET | /v1/usage | Uso por día o por modelo, en JSON o CSV |
| POST | /v1/uploads | Subir un JPEG, PNG o WebP de hasta 10 MB |
Cotizaciones y límites de precio
Cada generación necesita un quote_id o un límite max_credits, nunca ambos. Con un quote_id, la tarea se ejecuta con esa cotización; con max_credits, se ejecuta solo si el precio es igual o menor que el límite.
model: "auto" siempre necesita max_credits. Una cotización es válida durante 10 minutos; después recibes quote_expired.
Idempotencia
Envía un encabezado Idempotency-Key (de 1 a 255 caracteres ASCII visibles) en cada solicitud de generación.
La misma clave dentro de 24 horas devuelve la misma tarea con HTTP 200 en lugar de 202, así que reintentar después de un tiempo de espera agotado nunca crea ni cobra una segunda tarea.
Webhooks
Pasa webhook_url en una generación (o en un lote) para recibir sus cambios de estado. Cada evento es un POST cuyo cuerpo JSON tiene id, type, created_at y data: data.job para los eventos de tarea, data.batch para batch.completed.
Eventos
job.queuedjob.processingjob.succeededjob.failedjob.cancelledbatch.completed
- Cada entrega tiene un id de evento, una marca de tiempo y una firma. Verifícala antes de confiar en el cuerpo.
- Una entrega cuenta cuando tu endpoint responde 2xx en 10 segundos. Si no, se reintenta después de 1 min, 5 min, 30 min, 2 h y 6 h, y luego se marca como fallida; soporte puede reenviarla. No se siguen las redirecciones.
- Las URL de webhook deben ser https. Se rechazan los hosts con direcciones privadas, de loopback o reservadas, tanto al enviar como al conectarnos.
Encabezados
X-Signaturet=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")>X-Event-Id- El id del evento, también en el cuerpo. Los reintentos y reenvíos lo conservan, así que guárdalo y omite un id que ya hayas procesado.
- Secreto de firma
- Un secreto whsec_… por cuenta, en el estudio, en Claves de API. La clave HMAC es el secreto completo, incluido el prefijo.
- Rotación
- Después de rotarlo, el secreto anterior sigue firmando durante 24 horas como una segunda entrada v1. Acepta una entrega si alguna v1 coincide.
Calcula el HMAC sobre el cuerpo sin procesar, no sobre una copia vuelta a serializar, compara en tiempo constante y rechaza las marcas de tiempo de más de cinco minutos.
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody: the request body exactly as received, before any JSON parsing.
export function verifyWebhook(header, rawBody, secret, toleranceSec = 300) {
let t = null;
const signatures = [];
for (const item of (header ?? "").split(",")) {
const [key, value] = item.split("=", 2);
if (key === "t") t = Number(value);
if (key === "v1") signatures.push(Buffer.from(value, "hex"));
}
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
return signatures.some((s) => s.length === expected.length && timingSafeEqual(s, expected));
}
// verifyWebhook(req.headers["x-signature"], rawBody, process.env.WEBHOOK_SECRET)
// Answer 2xx quickly, and skip an X-Event-Id you have already handled.Errores
Los códigos y los estados HTTP son fijos; el mensaje es para las personas.
| Código | HTTP | Cuándo |
|---|---|---|
invalid_request | 400 | Falta un campo o está fuera de rango |
unauthorized | 401 | Sin clave, una clave revocada o una firma incorrecta |
insufficient_credits | 402 | El saldo no cubre la retención |
forbidden_model | 403 | La lista de permitidos de la clave no incluye este modelo o herramienta |
region_not_supported | 403 | El modelo no se ofrece en tu región |
developer_api_closed | 403 | Una clave de desarrollador mientras la API para desarrolladores está cerrada; el acceso requiere aprobación previa |
member_connections_paused | 403 | Un inicio de sesión de miembro (MCP, código de conexión o línea de comandos) mientras la conexión de tu propio agente de IA está en pausa |
not_found | 404 | No existe esa tarea, cotización o archivo subido en tu cuenta |
quote_expired | 409 | La cotización tiene más de 10 minutos |
price_changed | 409 | El precio subió por encima de tu límite |
content_rejected | 422 | El contenido se rechazó; no se cobra nada |
rate_limited | 429 | Demasiadas solicitudes para esta clave |
concurrency_limited | 429 | Demasiadas tareas en curso para esta cuenta |
internal_error | 500 | Algo falló de nuestro lado |
upstream_unavailable | 503 | El modelo no está disponible; vuelve a intentarlo más tarde |
Un resultado incierto del modelo no es un error: la tarea informa el estado unknown y se verifica antes de reenviar nada.
Límites
- Solicitudes
- 60 por minuto por clave de forma predeterminada.
- Concurrencia
- 3 tareas a la vez por cuenta de forma predeterminada; puedes pedir que se aumente.
- Tope
- La capacidad del modelo es un tope estricto. Más claves no agregan concurrencia.
Imágenes
POST /v1/images/generations acepta los mismos encabezados. Elige un id de modelo según el nivel y la operación; los modelos de edición también necesitan image_url, y los de generación lo rechazan.
| Nivel | generar | editar |
|---|---|---|
| Image MiniEconómico · borrador | qwen-image-2512-lightning | qwen-image-edit-2511-lightning |
| Image FastRecomendado | qwen-image-2512 | qwen-image-edit-2511 |
Límites por modelo
La página de la API de cada modelo tiene la tabla completa: el valor, la unidad, quién lo verifica y qué pasa si se supera. GET /v1/models devuelve los mismos límites como JSON.
- AplicadoLo verificamos nosotros y respondemos 400 antes de cotizar o retener nada.
- ProveedorLo verifica el proveedor. Una tarea que rechaza falla y no se cobra nada.
- RecomendadoNadie lo verifica. Mantenerse dentro de él da mejores resultados.
| Modelo | Límites principales | Tabla completa |
|---|---|---|
seedance-2.0-fastSeedance 2.0 Fast | Prompt de 2 a 2000 caracteres · 4 a 15 s · hasta 9 imágenes de referencia · imágenes de 300 a 6000 px por lado | Abrir la tabla |
seedance-2.0-miniSeedance 2.0 Mini | Prompt de 2 a 2000 caracteres · 4 a 15 s · hasta 9 imágenes de referencia · imágenes de 300 a 6000 px por lado | Abrir la tabla |
qwen-image-2512Qwen-Image-2512 | Prompt de 2 a 2000 caracteres · 1K o 2K · sin imagen de origen | Abrir la tabla |
qwen-image-2512-lightningQwen-Image-2512 · Lightning 4-step | Prompt de 2 a 2000 caracteres · 1K o 2K · sin imagen de origen | Abrir la tabla |
qwen-image-edit-2511Qwen-Image-Edit-2511 | Prompt de 2 a 2000 caracteres · 1K o 2K · una imagen de origen, JPEG, PNG o WebP de hasta 10 MB | Abrir la tabla |
qwen-image-edit-2511-lightningQwen-Image-Edit-2511 · Lightning | Prompt de 2 a 2000 caracteres · 1K o 2K · una imagen de origen, JPEG, PNG o WebP de hasta 10 MB | Abrir la tabla |
Archivos subidos
POST /v1/uploads lee el tipo del propio archivo. Los enlaces de subida duran 7 días.
| Archivo | Formatos | Archivo más grande | Duración máxima |
|---|---|---|---|
| Imagen: primer fotograma, referencia u origen de edición | JPEG, PNG, WebP | 10 MB | – |
| Video: sincronización labial | MP4 | 50 MB | 60 s |
| Audio: sincronización labial | MP3, WAV, M4A | 10 MB | 60 s |
Nunca descargamos imágenes de otros servidores, así que para esos enlaces el proveedor verifica el tamaño, y una tarea que rechaza no se cobra. Los mismos límites se devuelven como JSON: GET /v1/models devuelve un objeto limits para cada modelo.
Si vienes de fal, Replicate o WaveSpeed
No basta con cambiar la URL base y la clave: cada solicitud también necesita el id del modelo en el cuerpo, un encabezado Idempotency-Key y un límite de precio (max_credits o un quote_id). La guía de migración relaciona cada campo de Seedance 2.0 y Qwen-Image y enumera lo que no se traslada.