Plataforma
Callbacks (webhooks)
Em vez de fazer polling, inclua um callback_url na requisição de imagem ou vídeo. Quando a geração terminar ou falhar, a Zurelay envia o resultado via POST para essa URL, com uma assinatura para você confirmar que veio de nós.
Solicite um callback
Adicione callback_url a qualquer uma destas requisições. Deve ser uma URL https acessível na 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" }'Requisições de imagem com callback
Sem callback_url, a requisição de imagem espera e responde com as imagens, como faz a API da OpenAI. Com ele, a requisição é aceita imediatamente e a resposta traz a tarefa. Só há cobrança se as imagens forem geradas:
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}Você também pode fazer polling: GET /v1/images/{id} retorna o mesmo objeto, com links atualizados em data quando o status for completed. Os callbacks sempre trazem links, nunca base64, independentemente do valor de response_format.
O que enviamos
Um POST por evento, com um corpo JSON: type, timestamp e data, a tarefa exatamente como a API a retorna (o objeto de vídeo ou a requisição de imagem acima), com links de download válidos por 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" }}Verifique a assinatura
Os callbacks seguem o formato Standard Webhooks, o mesmo usado pelos webhooks da OpenAI. A assinatura é um HMAC-SHA256 de <webhook-id>.<webhook-timestamp>.<body>, calculado com o segredo de assinatura do seu workspace e codificado em base64. Encontre o segredo (que começa com whsec_) na página API Chaves de do painel e mantenha-o apenas no seu 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}- Verifique o corpo bruto: fazer o parsing e serializar o JSON novamente altera os bytes e, com eles, a assinatura.
- Rejeite um
webhook-timestampcom mais de cinco minutos: isso impede que alguém reenvie um callback interceptado. As bibliotecas fazem isso por você. - A troca do segredo (por proprietários e administradores, na página Chaves de API) gera um novo imediatamente. O antigo continua assinando junto com o novo por 24 horas, então atualize seu servidor dentro desse prazo.
Responda antes de processar
Responda com qualquer 2xx em até 15 segundos para que o callback seja considerado entregue. Salve o evento e responda primeiro; baixe o vídeo ou as imagens depois. Um callback pode chegar mais de uma vez (se a sua resposta se perder no caminho, por exemplo), então use webhook-id para processar cada um apenas uma vez.
Novas tentativas
Em qualquer outro caso (status de erro, redirecionamento, ausência de resposta em 15 segundos ou servidor inacessível), tentamos novamente, até um total de seis tentativas:
Cada callback aparece junto da sua requisição em Requisições no painel: para onde foi enviado, a resposta de cada tentativa e quando será a próxima. A opção Reenviar callback envia o callback de novo na hora, tenha ele sido entregue ou não. Os links incluídos são renovados a cada tentativa.
Tem dúvidas ou falta algo? Fale com nossa equipe de suporte e responderemos por e-mail, geralmente em até um minuto.