APIMaster Webhooks para Tareas Asíncronas
Recibe notificaciones firmadas de finalización y fallo para tareas de Seedance, video e imágenes asíncronas, con reintentos, historial de entrega y sondeo como respaldo.
Webhooks de tareas asíncronas de APIMaster
Utiliza webhooks como mecanismo principal de notificación para la generación asíncrona, manteniendo el sondeo como respaldo. APIMaster envía una solicitud HTTPS POST firmada cuando una tarea rastreada se completa o falla. Las notificaciones son independientes del proveedor de generación y utilizan tu ID de tarea de APIMaster.
Modelos y endpoints compatibles
Seedance incluye los cuatro modelos: seedance-2.0, seedance-2.5, seedance-2.0-fast y seedance-2.0-mini. Usa POST /v1/videos/generations o el compatible POST /v1/video/generations.
Las notificaciones de tareas de video también admiten MiniMax-H3, Kling Omni / Motion Control, Grok Imagine Video y Sora. Los flujos de trabajo de imágenes compatibles de GPT Image 2 / 2.5 y Gemini usan /v1/images/generations/async o los compatibles /v1/images/edits/async; Midjourney v8.2 / Niji 7 usan /v1/midjourney/generations. La disponibilidad de rutas y los parámetros de generación siguen aún la guía de cada modelo. La generación síncrona de Seedream y Grok para imágenes, el streaming de chat y la revisión de activos de Seedance no forman parte de este contrato de webhooks de generación.
Consulta GET /v1/webhook-capabilities?model=seedance-2.0-fast para la elegibilidad del modelo. Usa un endpoint de envío asíncrono compatible; la elegibilidad no significa que cada operación de imagen o cada alias de modelo admita la generación asíncrona.
Registrar y verificar un endpoint
Usa tu clave API en Authorization: Bearer YOUR_API_KEY. Una clave API puede gestionar endpoints y eventos pertenecientes a su cuenta. Mantenla en tu servidor.
curl --fail-with-body "https://apimaster.ai/v1/webhook-endpoints" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://your-server.example/webhooks/apimaster"}'
La respuesta contiene endpoint.id, endpoint.key_id y signing_secret. Guarda el secreto de firma de forma segura: solo se devuelve una vez. Es independiente de tu clave API y no puede autorizar generación o descargas. La URL debe ser un endpoint HTTPS públicamente accesible en el puerto 443. Las direcciones privadas y las redirecciones son rechazadas. Se permiten hasta 20 endpoints por cuenta; las URL son inmutables, así que crea y verifica un nuevo endpoint al cambiar el destino.
Después de configurar tu receptor, verifica la propiedad:
curl --fail-with-body -X POST "https://apimaster.ai/v1/webhook-endpoints/whep_example/verify" \
-H "Authorization: Bearer YOUR_API_KEY"
APIMaster envía un evento firmado webhook.endpoint_verification que contiene data.challenge. Devuelve HTTP 200 con {"challenge":"THE_RECEIVED_CHALLENGE"} dentro de 10 segundos. Una solicitud de generación que hace referencia a un endpoint no verificado, en pausa o de otra cuenta es rechazada antes del envío.
El tiempo de espera total de la solicitud HTTP es de 10 segundos, incluidos DNS, conexión y TLS. Las cabeceras de respuesta deben llegar en los 8 segundos posteriores al envío. Guarde el evento de forma persistente y confirme de inmediato.
Enviar una tarea con notificaciones
curl --fail-with-body "https://apimaster.ai/v1/videos/generations" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model":"seedance-2.5",
"prompt":"A paper boat floating on a calm pond, slow camera movement.",
"duration":4,
"resolution":"480p",
"aspect_ratio":"16:9",
"notifications":{
"webhook":{
"endpoint_id":"whep_example",
"events":["task.completed","task.failed"]
}
},
"client_reference_id":"order_123"
}'
Reemplaza el ID del modelo con cualquiera de los cuatro IDs de Seedance manteniendo sus propios parámetros compatibles. Guarda el ID de la tarea de la respuesta normal de creación. client_reference_id es una referencia comercial opcional de como máximo 128 bytes; no es una clave de idempotencia de envío. No combines notifications con los parámetros de proveedor heredados webhook o callback_url.
Para las ediciones de imágenes multiparte compatibles, envía notifications como un campo de formulario de cadena JSON y client_reference_id como un campo de formulario separado:
curl --fail-with-body "https://apimaster.ai/v1/images/edits/async" \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "model=gpt-image-2" \
-F "prompt=Turn the reference into a watercolor illustration" \
-F "image=@reference.png" \
-F 'notifications={"webhook":{"endpoint_id":"whep_example","events":["task.completed","task.failed"]}}' \
-F "client_reference_id=image_order_123"
No hay un endpoint predeterminado para toda la cuenta en esta versión: referencia un endpoint en cada solicitud de tarea. Los webhooks pueden llegar antes de la respuesta de tu envío. Persístelos incluso si tu aplicación aún no ha guardado el ID de tarea devuelto. Algunos flujos de trabajo asíncronos de imágenes encapsulan generación síncrona ascendente, por lo que el envío en sí aún puede tomar tiempo.
Cargas útiles de éxito y fallo
Una notificación de éxito contiene el ID público de la tarea y un enlace de video autenticado:
{
"id":"evt_example",
"type":"task.completed",
"api_version":"2026-10-03",
"created_at":1791014400,
"data":{
"task_id":"task_example",
"model":"seedance-2.5",
"kind":"video",
"status":"completed",
"client_reference_id":"order_123",
"completed_at":1791014400,
"task_url":"https://apimaster.ai/v1/videos/task_example",
"result":{
"outputs":[{
"output_id":"0",
"type":"video",
"url":"https://apimaster.ai/v1/videos/task_example/content",
"authentication":"bearer",
"expires_at":null
}]
},
"error":null
}
}
El fallo usa el mismo sobre con type: "task.failed", data.status: "failed", data.result: null y un objeto de error:
{
"code":"generation_failed",
"message":"The generation task failed. Query the task for details."
}
Tanto los fallos confirmados por el proveedor como los tiempos de espera de tareas en la puerta de enlace pueden generar eventos de fallo. Una solicitud de creación rechazada antes de que se acepte una tarea no genera un evento de tarea. El fallo en la entrega de la notificación no cambia el estado de generación ni vuelve a ejecutar la generación. Los eventos no confirman que la reconciliación de facturación haya finalizado.
Para imágenes, kind es image y outputs contiene todas las salidas de imagen disponibles. Los eventos de tareas secundarias de Midjourney incluyen batch_id; puedes además suscribirte a batch.completed para recibir un resumen del lote después de que todos los hijos finalicen. Su estado es completed, partial_failure o failed, con conteos en data.summary. La finalización del lote no siempre significa que cada hijo tuvo éxito.
Descarga las URL de salida con una clave API perteneciente a la cuenta de la tarea. Guarda los medios generados prontamente. expires_at: null significa que no se proporciona un tiempo de expiración garantizado, no almacenamiento permanente; una descarga posterior puede devolver HTTP 410. Reproducir un evento no extiende la disponibilidad del medio.
Autenticar callbacks y reconocerlos con prontitud
Cada POST lleva:
X-APIMaster-Event-ID: evt_example
X-APIMaster-Delivery-ID: dlv_example
X-APIMaster-Timestamp: 1791014400
X-APIMaster-Signature: v1=<hex-hmac>,kid=<key-id>
Verifica HMAC-SHA256 sobre la marca de tiempo, un punto literal y los bytes del cuerpo de la solicitud en bruto usando el secreto de firma del endpoint. Usa comparación de tiempo constante, permite un desfase de reloj de como máximo cinco minutos, y verifica que el encabezado Event-ID coincida con el ID del cuerpo. Los reintentos conservan el mismo ID de evento y cuerpo pero reciben un nuevo ID de entrega, marca de tiempo y firma.
El siguiente receptor en Python usa Flask y SQLite. Persiste un evento de forma atómica antes de reconocerlo. Tu worker de aplicación debe consumir las filas guardadas, descargar archivos y ejecutar la lógica de negocio por separado.
import hashlib, hmac, json, os, sqlite3, time
from flask import Flask, request, jsonify, abort
app = Flask(__name__)
# During key rotation, configure both active and previous kid/secret pairs.
SECRETS = json.loads(os.environ["APIMASTER_WEBHOOK_SECRETS_JSON"])
DB_PATH = os.environ.get("WEBHOOK_DB_PATH", "webhook-events.sqlite3")
with sqlite3.connect(DB_PATH) as db:
db.execute("CREATE TABLE IF NOT EXISTS events (id TEXT PRIMARY KEY, body BLOB NOT NULL)")
@app.post("/webhooks/apimaster")
def receive():
raw = request.get_data()
try:
timestamp = request.headers["X-APIMaster-Timestamp"]
if abs(time.time() - int(timestamp)) > 300:
abort(401)
fields = dict(part.split("=", 1) for part in
request.headers["X-APIMaster-Signature"].split(","))
secret = SECRETS[fields["kid"]]
expected = hmac.new(secret.encode(), timestamp.encode() + b"." + raw,
hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, fields["v1"]):
abort(401)
event = json.loads(raw)
if event["id"] != request.headers["X-APIMaster-Event-ID"]:
abort(401)
except (KeyError, ValueError, TypeError):
abort(401)
if event["type"] == "webhook.endpoint_verification":
return jsonify(challenge=event["data"]["challenge"])
with sqlite3.connect(DB_PATH) as db:
db.execute("INSERT OR IGNORE INTO events(id, body) VALUES (?, ?)",
(event["id"], raw))
return "", 204
Devuelve cualquier estado 2xx dentro de 10 segundos para eventos de generación. Reconoce después del almacenamiento duradero, sin esperar las descargas de medios. La entrega es al menos una vez: los eventos duplicados son posibles, especialmente si se pierde un reconocimiento, así que elimina duplicados por id. No hay garantía de orden entre tareas.
Reintentos, historial de entrega y repetición
APIMaster reintenta fallos de red, tiempos de espera de reconocimiento y respuestas no 2xx por hasta 72 horas desde la creación del evento. Los retrasos iniciales son 1, 2, 5, 15 y 30 minutos, luego 1, 2, 4 y 8 horas, seguidos de intervalos de 12 horas, con hasta un 20% de variación aleatoria. Se respeta un Retry-After válido en 429/503 dentro de la ventana de reintento. No se siguen redirecciones. HTTP 410 pausa el endpoint; otras respuestas 4xx se reintentan para permitir correcciones de configuración.
curl --fail-with-body "https://apimaster.ai/v1/webhook-events?task_id=task_example" \
-H "Authorization: Bearer YOUR_API_KEY"
curl --fail-with-body "https://apimaster.ai/v1/webhook-events/evt_example/deliveries" \
-H "Authorization: Bearer YOUR_API_KEY"
curl --fail-with-body -X POST "https://apimaster.ai/v1/webhook-events/evt_example/redeliver" \
-H "Authorization: Bearer YOUR_API_KEY"
Los estados incluyen pending, in_flight, retrying, delivered, paused y exhausted. Los registros de eventos e intentos se conservan durante 30 días. La repetición preserva el ID de evento original y la carga útil y abre una nueva ventana de entrega de 72 horas; no regenera medios ni cobra nuevamente. Se permiten hasta cinco repeticiones manuales por evento por día UTC. Un evento actualmente arrendado para entrega no se puede repetir hasta que ese intento termine o su arrendamiento expire.
Pausa o reanuda un endpoint con PATCH /v1/webhook-endpoints/{id} y {"enabled":false} o {"enabled":true}. Reanudar continúa los eventos pausados cuyo plazo original no ha pasado. Rota secretos con POST /v1/webhook-endpoints/{id}/rotate-secret; guarda el nuevo secreto y kid, y conserva el par anterior durante el período de transición de 24 horas devuelto.
Polling de respaldo
Para tareas sin un evento terminal recibido, consulta /v1/videos/{task_id} o la consulta de tarea de imagen documentada del modelo cada 60–120 segundos. Usa la API de tareas como fuente de verdad y verifica el historial de entrega si la generación ha terminado pero falta la notificación. La falta de un webhook no es motivo para reenviar una solicitud de generación facturable. Un tiempo de inactividad persistente del endpoint puede agotar los reintentos automáticos; restaura el receptor y repite los eventos retenidos.
