Guides essentiels
API de gestion des webhooks
Configurez les notifications de tâches via le Dashboard, l'API ou MCP, vérifiez les signatures et dépannez la livraison.
Les webhooks notifient votre application lorsqu'une tâche asynchrone se termine, échoue ou expire. Configurez-les dans Dashboard → API → Webhooks, via l'API de gestion (Management API) ou via le profil full de TokenLab MCP. Ils partagent les mêmes endpoints d'espace de travail et le même historique de livraison.
Quel identifiant utiliser
| Identifiant | Objectif | Où l'utiliser |
|---|---|---|
Management Token mt-… | Créer, lister, mettre à jour, supprimer, tester et renouveler les webhooks | Authorization: Bearer mt-… sur /v1/management/webhooks* |
Clé API sk-… | Soumettre des requêtes de modèle et interroger le statut des tâches | API de modèles et /v1/tasks/{id} |
Secret de signature whsec_… | Vérifier qu'une notification reçue est authentique | Votre récepteur ; ne jamais l'utiliser comme jeton Bearer API |
Créez un Management Token sur Dashboard → API → Management Tokens. Les jetons sont limités à l'espace de travail : choisissez le même espace de travail que la clé API utilisée pour soumettre les tâches. Un jeton ne peut pas lire ou modifier les endpoints d'un autre espace de travail. Les clés API et les secrets de signature sont rejetés par l'API de gestion. La configuration du Dashboard utilise votre session administrateur de l'espace de travail connecté.
Stockez mt-… et whsec_… sur votre backend. Ne les intégrez pas dans le code du navigateur, les prompts, les fichiers de dépôt ou les URLs. Les Management Tokens autorisent également d'autres opérations de gestion de l'espace de travail ; ce ne sont pas des identifiants réservés uniquement aux webhooks.
Configurer un endpoint
export TOKENLAB_MANAGEMENT_TOKEN="mt-your-management-token"
curl https://api.tokenlab.sh/v1/management/webhooks \
-H "Authorization: Bearer $TOKENLAB_MANAGEMENT_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"url":"https://your-app.example/webhooks/tokenlab","events":["task.completed","task.failed","task.timeout"],"description":"Production task results"}'La réponse 201 inclut un id et un secret à usage unique commençant par whsec_. Stockez le secret avant de quitter cette étape. Les réponses de liste/get/update ne l'exposent jamais. Jusqu'à 10 endpoints peuvent être configurés par espace de travail. Les URLs doivent utiliser le protocole HTTPS public et ne peuvent pas contenir d'identifiants, de chaînes de requête ou de fragments. Les redirections ne sont pas suivies.
| Opération | Endpoint |
|---|---|
| Lister / Créer | GET / POST /v1/management/webhooks |
| Obtenir / Mettre à jour / Supprimer | GET / PATCH / DELETE /v1/management/webhooks/{webhookId} |
| Renouveler le secret de signature | POST /v1/management/webhooks/{webhookId}/rotate-secret |
| Envoyer un test | POST /v1/management/webhooks/{webhookId}/test |
| Historique de livraison | GET /v1/management/webhooks/{webhookId}/deliveries?page=1&limit=50 |
Mettez en pause avec PATCH {"is_active":false} ; reprenez avec PATCH {"is_active":true}. La reprise réinitialise le compteur d'échecs consécutifs. Le renouvellement (rotation) renvoie un nouveau secret une seule fois ; configurez-le immédiatement sur votre récepteur. Les requêtes déjà en cours peuvent encore porter l'ancienne signature, acceptez donc brièvement les deux secrets pendant la rotation. La rotation n'est pas réversible.
Événements et charges utiles (payloads)
Les abonnements couvrent les futurs événements de tâches asynchrones terminées ; les résultats synchrones et les tâches historiques ne sont pas rejoués. Recevez toutes les tâches de l'espace de travail pour les types d'événements sélectionnés et faites correspondre data.taskId à l'ID renvoyé lors de la création de la tâche. Les champs de rappel utilisent le format camelCase ; les champs de réponse de gestion utilisent le format snake_case.
{
"id": "event-unique-id",
"type": "task.completed",
"created": 1790000000,
"data": {
"taskType": "video",
"taskId": "ldtask_0123456789abcdef0123456789abcdef",
"model": "your-selected-model",
"durationMs": 42000,
"resultUrls": ["https://api.tokenlab.sh/v1/media-results/7c9e6679-7425-40de-944b-e07fc1f90ae7.mp4?token=…"],
"settledCost": 0.12
}
}| Événement | Données |
|---|---|
task.completed | taskType, taskId, model optionnel, durationMs, resultUrls, settledCost |
task.failed | taskType, taskId, error, errorCode, retryable, refundOutcome |
task.timeout | taskType, taskId, expectedTimeoutMs, actualWaitMs, refundIssued, resolutionSource, refundOutcome |
webhook.test | Message de test et abonnements configurés ; envoyé uniquement par l'opération de test |
Chaque entrée de resultUrls est une URL de résultat multimédia TokenLab valide pendant 30 jours. Voir Conservation des données.
Pour task.timeout, expectedTimeoutMs est le seuil de délai d'attente configuré et actualWaitMs est l'attente écoulée, tous deux en millisecondes. refundIssued: true signifie que le remboursement a réussi ou avait déjà été émis ; false n'exclut pas un remboursement ultérieur. refundOutcome décrit le résultat du traitement du remboursement. Les événements de timeout ne contiennent pas durationMs.
Les champs dépendent de la tâche et peuvent être absents. Utilisez GET /v1/tasks/{id} avec la clé sk-… de l'espace de travail d'origine pour obtenir le résultat faisant autorité et le statut de facturation. Le champ retryable d'un événement décrit l'échec de la génération ; ce n'est pas une instruction pour interroger indéfiniment une tâche terminée ou soumettre automatiquement une nouvelle tâche facturable. Dans task.failed, error, errorCode et retryable sont les valeurs publiques error_details.message, code et retryable de la tâche, les mêmes valeurs qu'un retour de lecture de statut.
Vérifier avant le traitement
Chaque POST inclut X-Webhook-ID, X-Webhook-Timestamp (secondes Unix) et X-Webhook-Signature (sha256=<hex>). Calculez le HMAC-SHA256 sur la chaîne de timestamp exacte, un point, et les octets bruts du corps de la requête, en utilisant le secret whsec_… complet. Ne pas analyser et resérialiser le JSON avant la vérification.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyWebhook(rawBody, headers, secrets) {
const timestamp = headers['x-webhook-timestamp'];
const signature = headers['x-webhook-signature'];
if (typeof timestamp !== 'string' || !/^\d+$/.test(timestamp)) return false;
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
if (typeof signature !== 'string' || !/^sha256=[a-f0-9]{64}$/.test(signature)) return false;
const received = Buffer.from(signature.slice(7), 'hex');
return secrets.some(secret => {
const expected = createHmac('sha256', secret).update(timestamp + '.').update(rawBody).digest();
return timingSafeEqual(expected, received);
});
}Après vérification, vérifiez que le id du corps correspond à X-Webhook-ID, persistez l'ID de l'événement avec votre élément de travail de manière atomique, et renvoyez rapidement 2xx. Traitez les tâches lourdes depuis votre propre file d'attente. Dédupliquez par ID d'événement au sein de l'endpoint de réception : les livraisons peuvent se répéter et l'ordre n'est pas garanti. Une tolérance de timestamp de cinq minutes limite l'âge de rejeu ; la déduplication par ID empêche le traitement répété dans cette fenêtre.
Tentatives et récupération
Chaque cycle de livraison effectue jusqu'à trois tentatives, en attendant 1 seconde puis 4 secondes. Chaque tentative HTTP a un timeout de 10 secondes et un timestamp/signature frais. Les échecs réseau, 429 et 5xx sont réessayables. Les autres 4xx, les redirections et les cibles réseau invalides arrêtent ce cycle sans réessayer. Les échecs transitoires peuvent déclencher des tentatives d'événement ultérieures avec le même ID de livraison. Dix cycles échoués consécutifs mettent automatiquement l'endpoint en pause.
Utilisez l'opération de test et l'historique de livraison pour voir outcome, http_status, attempts et delivered_at. Une réponse API de test réussie (200) signifie seulement que la tentative a été enregistrée : vérifiez outcome == "delivered". Corrigez le récepteur, reprenez l'endpoint, puis envoyez un autre test. L'historique contient les métadonnées de livraison, pas les charges utiles ; le rejeu manuel d'anciens événements n'est pas disponible. Conservez les IDs de tâche et réconciliez-les avec le statut de la tâche si votre récepteur était en pause ou indisponible.
Configuration MCP
Les outils de gestion des webhooks sont disponibles dans le profil full. L'identifiant de gestion est distinct de la clé d'inférence ; le catalogue et la gestion des webhooks peuvent fonctionner sans clé d'inférence.
{
"mcpServers": {
"tokenlab": {
"command": "npx",
"args": ["-y", "@tokenlabai/mcp-server@latest"],
"env": {
"TOKENLAB_MCP_TOOL_PROFILE": "full",
"TOKENLAB_MANAGEMENT_TOKEN": "mt-your-management-token",
"TOKENLAB_API_KEY": "sk-your-inference-key"
}
}
}
}Outils : list_webhooks, create_webhook, get_webhook, update_webhook, delete_webhook, rotate_webhook_secret, test_webhook, list_webhook_deliveries. Ne collez jamais d'identifiants dans un argument d'outil. Accordez l'accès de gestion uniquement aux clients MCP de confiance.
Alternative par polling
Les webhooks ne suppriment pas l'accès à l'interrogation de statut (polling) et n'imposent pas de nouvelle limite de polling. Si vous utilisez le polling, utilisez le poll_url de la réponse de création, attendez pendant que la tâche est en attente, et arrêtez-vous sur les états terminaux. Arrêtez-vous sur 401, 403, 404 ou error.retryable == false ; réessayez les erreurs transitoires 503 async_task_owner_unavailable avec un backoff. Une tâche manquante ou expirée renvoie 404 async_task_not_found. Interroger à plusieurs reprises une tâche manquante ne peut pas la recréer.
Le callback_url de l'API de compatibilité Seedance (Seedance compatibility API) est un contrat de rappel distinct par requête. Il peut être défini lors de la création de cette tâche ; il n'utilise pas ces charges utiles d'événement d'espace de travail ou ces en-têtes HMAC.