APIMaster Webhooks pour Tâches Asynchrones
Recevez des notifications signées de réussite et d'échec pour Seedance, les vidéos et les tâches d'images asynchrones, avec des nouvelles tentatives, un historique de livraison et un repli sur le polling.
Webhooks APIMaster pour tâches asynchrones
Utilisez les webhooks comme mécanisme de notification principal pour la génération asynchrone, et gardez le polling comme solution de repli. APIMaster envoie une requête HTTPS POST signée lorsqu'une tâche suivie se termine ou échoue. Les notifications sont indépendantes du fournisseur de génération et utilisent votre identifiant de tâche APIMaster.
Modèles et points de terminaison pris en charge
Seedance inclut les quatre modèles : seedance-2.0, seedance-2.5, seedance-2.0-fast et seedance-2.0-mini. Utilisez POST /v1/videos/generations ou le POST /v1/video/generations compatible.
Les notifications pour les tâches vidéo prennent également en charge MiniMax-H3, Kling Omni / Motion Control, Grok Imagine Video et Sora. Les flux de travail d'images GPT Image 2 / 2.5 et Gemini pris en charge utilisent /v1/images/generations/async ou le /v1/images/edits/async pris en charge ; Midjourney v8.2 / Niji 7 utilisent /v1/midjourney/generations. La disponibilité des routes et les paramètres de génération suivent toujours le guide de chaque modèle. La génération d'images Seedream et Grok synchrone, le streaming de chat et la révision des assets Seedance ne font pas partie de ce contrat de webhook de génération.
Consultez GET /v1/webhook-capabilities?model=seedance-2.0-fast pour l'éligibilité des modèles. Utilisez un point de terminaison de soumission asynchrone pris en charge ; l'éligibilité ne signifie pas que chaque opération d'image ou chaque alias de modèle prend en charge la génération asynchrone.
Enregistrer et vérifier un point de terminaison
Utilisez votre clé API dans Authorization: Bearer YOUR_API_KEY. Une clé API peut gérer les points de terminaison et les événements appartenant à son compte. Gardez-la sur votre serveur.
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 réponse contient endpoint.id, endpoint.key_id et signing_secret. Conservez le secret de signature en sécurité : il n'est renvoyé qu'une seule fois. Il est séparé de votre clé API et ne peut pas autoriser la génération ou les téléchargements. L'URL doit être un point de terminaison HTTPS accessible publiquement sur le port 443. Les adresses privées et les redirections sont rejetées. Jusqu'à 20 points de terminaison sont autorisés par compte ; les URL sont immuables, créez donc et vérifiez un nouveau point de terminaison lorsque vous changez de destination.
Après avoir configuré votre récepteur, vérifiez la propriété :
curl --fail-with-body -X POST "https://apimaster.ai/v1/webhook-endpoints/whep_example/verify" \
-H "Authorization: Bearer YOUR_API_KEY"
APIMaster envoie un événement signé webhook.endpoint_verification contenant data.challenge. Renvoyez HTTP 200 avec {"challenge":"THE_RECEIVED_CHALLENGE"} dans les 10 secondes. Une requête de génération référençant un point de terminaison non vérifié, en pause ou appartenant à un autre compte est rejetée avant soumission.
Le délai total de la requête HTTP est de 10 secondes, y compris DNS, connexion et TLS. Les en-têtes de réponse doivent arriver dans les 8 secondes suivant l’envoi. Enregistrez durablement l’événement et accusez réception immédiatement.
Soumettre une tâche avec notifications
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"
}'
Remplacez l'identifiant du modèle par l'un des quatre identifiants Seedance tout en conservant ses propres paramètres pris en charge. Enregistrez l'identifiant de la tâche à partir de la réponse normale de création. client_reference_id est une référence métier facultative d'au plus 128 octets ; ce n'est pas une clé d'idempotence de soumission. Ne combinez pas notifications avec les anciens paramètres de fournisseur webhook ou callback_url.
Pour les modifications d'images multipart prises en charge, envoyez notifications comme champ de formulaire de chaîne JSON et client_reference_id comme champ de formulaire séparé :
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"
Il n'y a pas de point de terminaison par défaut à l'échelle du compte dans cette version : référencez un point de terminaison dans chaque requête de tâche. Les webhooks peuvent arriver avant votre réponse de soumission. Persistez-les même si votre application n'a pas encore enregistré l'identifiant de tâche renvoyé. Certains flux de travail d'images asynchrones encapsulent une génération synchrone en amont, donc la soumission elle-même peut encore prendre du temps.
Charges utiles de réussite et d'échec
Une notification de réussite contient l'identifiant public de la tâche et un lien vidéo authentifié :
{
"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
}
}
L'échec utilise la même enveloppe avec type: "task.failed", data.status: "failed", data.result: null et un objet d'erreur :
{
"code":"generation_failed",
"message":"The generation task failed. Query the task for details."
}
Les échecs confirmés par le fournisseur et les délais d'attente de tâche de la passerelle peuvent tous deux générer des événements d'échec. Une requête de création rejetée avant qu'une tâche ne soit acceptée ne génère pas d'événement de tâche. L'échec de livraison d'une notification ne change pas le statut de génération ni ne relance la génération. Les événements ne confirment pas que la réconciliation de facturation est terminée.
Pour les images, kind est image et outputs contient toutes les sorties d'images disponibles. Les événements de tâches enfants Midjourney incluent batch_id ; vous pouvez également vous abonner à batch.completed pour recevoir un résumé de lot après la fin de tous les enfants. Son statut est completed, partial_failure ou failed, avec des comptes dans data.summary. L'achèvement d'un lot ne signifie pas toujours que chaque enfant a réussi.
Téléchargez les URL de sortie avec une clé API appartenant au compte de la tâche. Sauvegardez les médias générés rapidement. expires_at: null signifie qu'aucun délai d'expiration garanti n'est fourni, pas un stockage permanent ; un téléchargement ultérieur peut renvoyer HTTP 410. Rejouer un événement n'étend pas la disponibilité des médias.
Authentifier les callbacks et les accuser réception rapidement
Chaque POST contient :
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>
Vérifiez HMAC-SHA256 sur l'horodatage, un point littéral et les octets bruts du corps de la requête en utilisant le secret de signature du point de terminaison. Utilisez une comparaison à temps constant, autorisez un décalage d'horloge d'au plus cinq minutes, et vérifiez que l'en-tête Event-ID correspond à l'ID du corps. Les nouvelles tentatives conservent le même ID d'événement et le même corps mais reçoivent un nouvel ID de livraison, un nouvel horodatage et une nouvelle signature.
Le récepteur Python suivant utilise Flask et SQLite. Il persiste un événement de manière atomique avant de l'accuser réception. Votre worker d'application doit consommer les lignes sauvegardées, télécharger les fichiers et exécuter la logique métier séparément.
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
Retournez n'importe quel statut 2xx dans les 10 secondes pour les événements de génération. Accusez réception après un stockage durable, sans attendre les téléchargements de médias. La livraison est au moins une fois : des événements en double sont possibles, surtout si un accusé de réception est perdu, donc dédupliquez par id. Il n'y a aucune garantie d'ordre entre les tâches.
Nouvelles tentatives, historique de livraison et rejeu
APIMaster retente les échecs réseau, les délais d'accusé de réception et les réponses non-2xx pendant jusqu'à 72 heures à partir de la création de l'événement. Les délais initiaux sont de 1, 2, 5, 15 et 30 minutes, puis 1, 2, 4 et 8 heures, suivis d'intervalles de 12 heures, avec jusqu'à 20 % de jitter. Un Retry-After valide sur 429/503 est respecté dans la fenêtre de nouvelle tentative. Les redirections ne sont pas suivies. Un HTTP 410 met en pause le point de terminaison ; les autres réponses 4xx sont retentées pour permettre des corrections de configuration.
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"
Les statuts incluent pending, in_flight, retrying, delivered, paused et exhausted. Les enregistrements d'événements et de tentatives sont conservés pendant 30 jours. Le rejeu conserve l'ID d'événement et la charge utile d'origine et ouvre une nouvelle fenêtre de livraison de 72 heures ; il ne régénère pas les médias ni ne facture à nouveau. Jusqu'à cinq rejeux manuels par événement par jour UTC sont autorisés. Un événement actuellement loué pour livraison ne peut pas être rejoué avant que cette tentative se termine ou que son bail expire.
Mettez en pause ou reprenez un point de terminaison avec PATCH /v1/webhook-endpoints/{id} et {"enabled":false} ou {"enabled":true}. La reprise continue les événements en pause dont la date limite d'origine n'est pas passée. Faites tourner les secrets avec POST /v1/webhook-endpoints/{id}/rotate-secret ; sauvegardez le nouveau secret et kid, et conservez la paire précédente pour la période de transition de 24 heures retournée.
Solution de repli par polling
Pour les tâches sans événement terminal reçu, interrogez /v1/videos/{task_id} ou la requête image-task documentée du modèle toutes les 60 à 120 secondes. Utilisez l'API de tâche comme source de vérité et vérifiez l'historique de livraison si la génération est terminée mais que la notification est manquante. Un webhook manquant n'est pas une raison pour resoumettre une requête de génération facturable. Une indisponibilité persistante du point de terminaison peut épuiser les nouvelles tentatives automatiques ; restaurez le récepteur et rejouez les événements conservés.
