Vous avez créé une tâche de provisioning et reçu un 202 en retour : un ID de moteur, et status: "in_progress". L’agent IA parcourt maintenant vos sources et applique des voix de marque, des éléments de glossaire et des instructions à ce moteur en arrière-plan. Cela peut prendre quelques instants… ou plus longtemps, selon le nombre de liens à explorer. Vous pourriez garder un WebSocket en direct ouvert pour le voir travailler – mais vous n’avez probablement pas envie de maintenir une connexion juste pour savoir quand l’agent a terminé et ce qu’il a produit.
C’est exactement à cela que sert le webhook. Lorsque vous fournissez un callbackUrl au moment de créer la tâche, Lingo envoie le résultat final en POST à cette URL dès que la tâche se termine – vous êtes averti dès que le moteur est prêt, avec l’inventaire de ce qui a été créé. Une tâche menée à bien arrive sous la forme provisioning.completed avec le récapitulatif de chaque enregistrement créé par l’IA. Une tâche en échec arrive sous la forme provisioning.failed avec la raison. Dans les deux cas, votre flux de configuration est informé sans avoir à interroger quoi que ce soit.
Cette page présente les deux payloads et la façon de les traiter. L’envoi est signé et retenté – ce mécanisme est partagé avec la localisation et est documenté sur la page vérification de la signature des webhooks, vers laquelle vous trouverez un lien à chaque étape utile.
Sur cette page
- Fonctionnement de l’envoi
- Le payload completed
- Le payload failed
- Traiter un webhook
- Quand l’envoi n’est pas le bon outil
Fonctionnement de l’envoi#
Une tâche de provisioning ne se termine qu’une seule fois. Dès qu’elle atteint un état terminal – toutes les sources ont été explorées et analysées, ou bien l’exécution a été abandonnée – son résultat est envoyé à votre callbackUrl sous la forme d’un unique POST. Un groupe de localisation se répartit en une tâche par langue cible, chacune avec son propre callback ; une tâche de provisioning reste une seule tâche, donc un seul envoi.
Définissez la destination avec callbackUrl lorsque vous créez la tâche. Deux formats de payload transitent, distingués par leur champ type : provisioning.completed et provisioning.failed. Tous deux indiquent le jobId et le engineId auxquels ils appartiennent, afin qu’un seul handler puisse router selon type et mettre à jour le bon enregistrement.
HTTPS uniquement
callbackUrl doit utiliser HTTPS. Une URL HTTP est rejetée lorsque vous créez la tâche – le webhook est signé, et faire transiter une charge utile signée en clair annule tout l’intérêt du mécanisme.
Gérez proprement les types d’événements inconnus
Aujourd’hui, le flux transporte provisioning.completed et provisioning.failed. Considérez cet ensemble comme ouvert – gérez les types que vous connaissez et ignorez les autres, afin qu’un futur type d’événement ne casse pas un handler déjà déployé.
Le payload completed#
Lorsque la tâche se termine, le payload contient le summary – le même inventaire que vous obtiendriez en consultant la tâche, mais poussé vers vous au lieu d’être récupéré par polling. Il répertorie chaque voix de marque, élément de glossaire et instruction créés par l’IA sur votre moteur, et liste les éventuels échecs par élément rencontrés en cours de route.
{
"type": "provisioning.completed",
"jobId": "pjb_A1b2C3d4E5f6G7h8",
"engineId": "eng_X1y2Z3a4B5c6D7e8",
"summary": {
"brandVoices": { "count": 3, "ids": ["bv_A1b2C3d4", "bv_B2c3D4e5", "bv_C3d4E5f6"] },
"glossaryItems": { "count": 12, "ids": ["gi_A1b2C3d4", "..."] },
"instructions": { "count": 5, "ids": ["ins_A1b2C3d4", "..."] },
"errors": []
}
}| Champ | Description |
|---|---|
type | provisioning.completed |
jobId | La tâche de provisioning terminée (préfixe pjb_) |
engineId | Le moteur qu’elle a configuré (préfixe eng_) |
summary | Ce que l’IA a créé sur le moteur – volumes et ID par composant, ainsi que les échecs par élément dans errors |
Le summary est le même objet que celui porté par la tâche, et sa signification champ par champ – ce qu’est chaque composant, comment les éléments correspondent aux langues, ce qui se retrouve dans errors – est documentée une seule fois dans Ce que l’IA extrait. Ici, il suffit de savoir que le payload completed vous donne les ID de tout ce que l’agent a créé, afin que votre handler puisse les enregistrer ou les afficher dans votre tableau de bord sans relire la tâche.
Un tableau errors non vide arrive quand même en completed.
Les échecs par élément ne font pas échouer la tâche. Si une source n’a pas pu être explorée ou si un enregistrement n’a pas pu être créé, cela apparaît dans summary.errors et le reste est quand même appliqué au moteur – le payload reste donc provisioning.completed, pas provisioning.failed. L’événement completed signifie que la tâche est allée jusqu’au bout ; consultez errors pour voir ce qu’il faut corriger. Un payload provisioning.failed est envoyé lorsque l’exécution n’a produit aucun moteur exploitable.
Le payload failed#
Une tâche de provisioning échoue lorsque l’exécution ne produit rien d’exploitable – par exemple, si toutes les sources échouent à être explorées et que l’agent n’a donc aucun contenu à analyser. Quand cela arrive, vous en êtes tout de même informé. Le type de payload est provisioning.failed, et il contient une chaîne error à la place du récapitulatif :
{
"type": "provisioning.failed",
"jobId": "pjb_A1b2C3d4E5f6G7h8",
"engineId": "eng_X1y2Z3a4B5c6D7e8",
"error": "All sources failed to crawl. No content available for analysis."
}| Champ | Description |
|---|---|
type | provisioning.failed |
jobId | La tâche de provisioning qui a échoué |
engineId | Le moteur qui a été créé mais laissé sans configuration |
error | Raison lisible expliquant pourquoi la tâche n’a pas pu aboutir |
Voici la question qu’un lecteur sceptique a raison de poser : si la tâche a échoué, ai-je aussi perdu le moteur ? Non. Le engineId de ce payload est le même moteur que celui que vous avez reçu dans le 202 – il existe toujours, créé au moment de l’appel, simplement sans la configuration que l’exécution en échec aurait ajoutée. Un échec vous coûte l’extraction, jamais le moteur. Ajustez ce que vous avez soumis et réessayez, ou configurez le moteur manuellement depuis le tableau de bord. Lorsqu’une tâche échoue au moment de l’exploration, les sources en sont généralement la cause – Types de sources explique ce qui fait d’une source un bon point de départ.
Traiter un webhook#
La première réaction d’un lecteur sceptique ici est la bonne : mon handler effectue un vrai travail – une écriture en base de données, une notification, une actualisation du tableau de bord – est-ce que cela ne va pas garder la connexion ouverte assez longtemps pour faire expirer le webhook ?
Oui, donc ne faites pas attendre Lingo. Renvoyez 200 d’abord, puis traitez. Accusez réception, puis effectuez le vrai travail une fois la réponse envoyée. Le contrat complet d’envoi – pourquoi il faut d’abord accuser réception, et le calendrier de nouvelles tentatives qui s’applique sinon – figure sur la page signature et livraison ; l’exemple de handler ci-dessous montre la forme que cela prend pour un payload de provisioning.
app.post("/webhooks/provisioning", verifyWebhook, async (req, res) => {
// Acknowledge first - the job ends once, so this fires once.
res.status(200).send("ok");
const { type, jobId, engineId } = req.body;
if (type === "provisioning.completed") {
const { summary } = req.body;
await db.engines.update({
where: { engineId },
data: {
status: "ready",
brandVoiceCount: summary.brandVoices.count,
glossaryCount: summary.glossaryItems.count,
instructionCount: summary.instructions.count,
},
});
}
if (type === "provisioning.failed") {
console.error(`Provisioning failed: ${jobId} (${engineId})`, req.body.error);
await db.engines.update({
where: { engineId },
data: { status: "needs_configuration" },
});
}
});Le middleware verifyWebhook est la seule pièce que cette page ne définit pas. Chaque envoi est signé selon la spécification Standard Webhooks – trois en-têtes, un HMAC sur le corps brut, un secret whsec_ généré la première fois que vous soumettez une tâche avec un callback. Les callbacks de provisioning et de localisation utilisent ce schéma tel quel ; il n’est donc documenté qu’une seule fois sur vérification de la signature des webhooks. Intégrez ce middleware avant de faire confiance à un payload – un corps non vérifié est un corps non authentifié.
Vérifiez la signature avant de faire confiance au corps
Votre endpoint est une URL publique ; n’importe qui peut lui envoyer un POST. Vérifiez la signature par rapport au corps brut de la requête avant d’agir sur un payload – avant de marquer un moteur comme prêt ou d’enregistrer les ID qu’il prétend avoir créés. La marche à suivre – les en-têtes, le HMAC, le secret whsec_ – est décrite sur la page vérification de la signature.
Quand l’envoi n’est pas le bon outil#
Le webhook est une commodité en mode push, pas le système de référence. Dans deux cas, mieux vaut utiliser autre chose – et les deux sont à un clic.
Si votre endpoint était indisponible lorsque le résultat a été envoyé, la plateforme retente selon le même calendrier que tous les webhooks Lingo – et le résultat n’est pas prisonnier du callback. Les enregistrements créés par l’IA constituent la configuration réelle du moteur ; le récapitulatif completed est un rapport sur un travail déjà effectué sur un vrai moteur, pas son unique copie. Autrement dit, une période d’indisponibilité vous coûte une notification, jamais le moteur. Le calendrier de nouvelles tentatives lui-même figure sur la page signature et livraison.
Et si ce que vous voulez, c’est un suivi en direct pendant que le moteur se configure – un statut d’exploration puis de configuration dans une interface, plutôt qu’un unique callback vers votre serveur à la fin – alors c’est le WebSocket de la tâche de provisioning qu’il vous faut, pas le webhook. Il diffuse un instantané à la connexion ainsi que des événements de progression au fil de l’exécution, et vous pouvez vous connecter à tout moment, même après la fin de la tâche.
