Plataforma
Callbacks (webhooks)
En lugar de hacer polling, pásale un callback_url a cada solicitud de imagen o video. Cuando esté lista, o si falla, Zurelay envía el resultado por POST a esa URL, firmado para que puedas comprobar que viene de nosotros.
Solicita un callback
Añade callback_url a cualquiera de estas solicitudes. Debe ser una URL https accesible desde la internet pública.
curl https://api.zurelay.com/v1/videos \ -H "Authorization: Bearer $ZURELAY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "seedance-2.0", "prompt": "A fox running through fresh snow at dawn", "seconds": 5, "callback_url": "https://example.com/hooks/zurelay" }'Solicitudes de imagen con callback
Sin callback_url, una solicitud de imagen espera y devuelve las imágenes, como la API de OpenAI. Con él, la solicitud se acepta de inmediato y responde con el trabajo. Solo se cobra si se generan imágenes:
HTTP/1.1 202 Acceptedx-request-id: req_6fJd0kQ3pW9xT2mB7cZ1hR4u{ "id": "req_6fJd0kQ3pW9xT2mB7cZ1hR4u", "object": "image.generation", "model": "nano-banana-pro", "status": "in_progress", "created_at": 1791000000, "completed_at": null, "data": [], "url_expires_at": null, "cost": null, "error": null, "callback_url": "https://example.com/hooks/zurelay"}/v1/images/{id}También puedes consultarlo por polling: GET /v1/images/{id} devuelve el mismo objeto, con enlaces nuevos en data en cuanto su status esté completed. Las devoluciones de llamada siempre incluyen enlaces, nunca base64, diga lo que diga response_format.
Qué enviamos
Un POST por evento, con un cuerpo JSON: type, timestamp y data, el trabajo exactamente como lo devuelve la API (el objeto de vídeo, o la solicitud de imagen de arriba), con enlaces de descarga válidos durante 24 horas.
POST /hooks/zurelay HTTP/1.1content-type: application/jsonuser-agent: Zurelay-Webhooks/1.0 (+https://zurelay.com/docs/webhooks)webhook-id: msg_2c1f9e0b7a4d4f6e8b3a91c05d7e6f42webhook-timestamp: 1791000094webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4={ "type": "video.completed", "timestamp": "2026-10-03T03:21:34.000Z", "data": { "id": "video_Qm3v8Rk2Lx7Pa1Zt9Ws4Yn6B", "object": "video", "model": "seedance-2.0", "status": "completed", "progress": 100, "created_at": 1791000000, "completed_at": 1791000093, "expires_at": 1793592000, "seconds": 5, "resolution": "720p", "aspect_ratio": "16:9", "size": "1280x720", "generate_audio": true, "url": "https://…/video_Qm3v8Rk2Lx7Pa1Zt9Ws4Yn6B.mp4?token=…", "url_expires_at": 1791086494, "cost": 0.45, "error": null, "callback_url": "https://example.com/hooks/zurelay" }}{ "type": "image.completed", "timestamp": "2026-10-03T03:20:41.000Z", "data": { "id": "req_6fJd0kQ3pW9xT2mB7cZ1hR4u", "object": "image.generation", "model": "nano-banana-pro", "status": "completed", "created_at": 1791000000, "completed_at": 1791000041, "data": [{ "url": "https://…/req_6fJd0kQ3pW9xT2mB7cZ1hR4u-1.png?token=…" }], "url_expires_at": 1791086441, "cost": 0.07, "error": null, "callback_url": "https://example.com/hooks/zurelay" }}Verifica la firma
Las devoluciones de llamada siguen el formato Standard Webhooks, el mismo que usan los webhooks de OpenAI. La firma es un HMAC-SHA256 de <webhook-id>.<webhook-timestamp>.<body>, con clave el secreto de firma de tu espacio de trabajo, en base64. Encontrarás el secreto (empieza por whsec_) en la página Claves de API del panel, y guárdalo solo en tu servidor.
import osfrom fastapi import FastAPI, HTTPException, Requestfrom standardwebhooks.webhooks import Webhook # pip install standardwebhookswebhook = Webhook(os.environ["ZURELAY_WEBHOOK_SECRET"]) # whsec_…app = FastAPI()@app.post("/hooks/zurelay")async def zurelay_hook(request: Request): body = await request.body() # the raw bytes: the signature covers exactly these try: event = webhook.verify(body, dict(request.headers)) except Exception: raise HTTPException(status_code=400) handle(event) # event["type"], event["data"]; keep it quick, or queue it return {"ok": True}- Comprueba el cuerpo sin procesar: analizar y volver a serializar el JSON cambia los bytes, y la firma con ellos.
- Rechaza un
webhook-timestampcon más de cinco minutos de antigüedad: así nadie puede reenviar una devolución de llamada que haya interceptado. Las librerías lo hacen por ti. - Rotar el secreto (propietarios y administradores, en la página API keys) te da uno nuevo al instante. El antiguo sigue firmando junto a él durante 24 horas, así que cambia tu servidor en el plazo de un día.
Responde y luego trabaja
Responde con cualquier 2xx en menos de 15 segundos y la devolución de llamada cuenta como entregada. Guarda el evento y responde primero; descarga el vídeo o las imágenes después. Una devolución de llamada puede llegar más de una vez (por ejemplo, si tu respuesta se perdió por el camino), así que usa webhook-id para hacer cada una solo una vez.
Reintentos
Cualquier otra cosa (un estado de error, una redirección, ninguna respuesta en 15 segundos o un servidor al que no podemos llegar) se reintenta, seis intentos en total:
Cada callback aparece junto a su solicitud en Solicitudes del panel: a dónde fue, la respuesta de cada intento y cuándo es el próximo reintento. Ahí, Retry callback lo envía de nuevo al instante, se entregue o no. Los enlaces que contiene se renuevan en cada intento.
¿Tienes dudas o falta algo? Escribe a nuestro equipo de soporte y te responderemos por email, normalmente en menos de un minuto.