Plateforme
Callbacks (webhooks)
Au lieu d’interroger régulièrement l’API, ajoutez un callback_url à votre requête d’image ou de vidéo. Une fois le résultat prêt, ou en cas d’échec, Zurelay l’envoie à cette URL par POST, avec une signature qui vous permet de vérifier qu’il vient bien de nous.
Demander un callback
Ajoutez callback_url à l’une de ces requêtes. Il doit s’agir d’une URL https accessible sur Internet.
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" }'Requêtes d’image avec callback
Sans callback_url, une requête d’image attend la fin de la génération pour renvoyer les images, comme l’API d’OpenAI. Avec ce paramètre, la requête est acceptée immédiatement et renvoie la tâche. Elle n’est facturée que si des images sont générées :
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}Vous pouvez aussi consulter son état : GET /v1/images/{id} renvoie le même objet, avec de nouveaux liens dans data une fois que son status vaut completed. Les callbacks contiennent toujours des liens, jamais de base64, quelle que soit la valeur de response_format.
Ce que nous envoyons
Un POST par événement, avec un corps JSON : type, timestamp et data, la tâche telle que l’API la renvoie (l’objet vidéo, ou la requête d’image ci-dessus), avec des liens de téléchargement valables 24 heures.
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" }}Vérifier la signature
Les callbacks suivent le format Standard Webhooks, également utilisé par les webhooks d’OpenAI. La signature est un HMAC-SHA256 de <webhook-id>.<webhook-timestamp>.<body>, calculé avec le secret de signature de votre espace de travail et encodé en base64. Vous trouverez ce secret (qui commence par whsec_) sur la page API Clés du tableau de bord. Conservez-le uniquement sur votre serveur.
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}- Vérifiez le corps brut : analyser puis sérialiser à nouveau le JSON modifie les octets, et donc la signature.
- Refusez tout
webhook-timestampdatant de plus de cinq minutes : cela empêche de rejouer un callback intercepté. Les bibliothèques le font pour vous. - Le renouvellement du secret (par les propriétaires et administrateurs, sur la page Clés API) vous en fournit immédiatement un nouveau. L’ancien continue de signer en parallèle pendant 24 heures : mettez donc votre serveur à jour dans ce délai.
Répondez, puis traitez
Renvoyez un code 2xx sous 15 secondes pour que le callback soit considéré comme livré. Enregistrez l’événement et répondez d’abord ; téléchargez ensuite la vidéo ou les images. Un callback peut arriver plusieurs fois (si votre réponse s’est perdue en chemin, par exemple) : utilisez donc webhook-id pour ne le traiter qu’une seule fois.
Nouvelles tentatives
Dans tous les autres cas (code d’erreur, redirection, absence de réponse sous 15 secondes ou serveur inaccessible), l’envoi est réessayé, pour un total de six tentatives :
Chaque callback apparaît avec sa requête dans la section Requêtes du tableau de bord : sa destination, la réponse à chaque tentative et la date du prochain essai. Le bouton Réessayer le callback le renvoie immédiatement, qu’il ait déjà été reçu ou non. Les liens qu’il contient sont renouvelés à chaque tentative.
Une question ou un élément manquant ? Contactez notre équipe d’assistance et nous vous répondrons par e-mail, généralement en moins d’une minute.