Pour déclencher des agents de programmation IA avec des webhooks GitHub, faites pointer le webhook d'un dépôt vers votre propre endpoint de réception, vérifiez l'en-tête X-Hub-Signature-256 par rapport au corps brut de la requête, répondez par un code 202 dans la limite des 10 secondes imparties par GitHub, puis placez l'événement dans une file d'attente. Un worker filtre ensuite l'événement, l'associe à un fil de discussion (dépôt et numéro de PR), puis lance ou alimente l'agent.
La suite de ce guide détaille chaque étape en code et vous montre comment faire tester cet endpoint à votre agent de code à l'aide d'Apidog CLI.
Pourquoi déclencher des agents de code IA avec des webhooks GitHub plutôt que par polling
Un déclencheur par webhook est un appel HTTP que GitHub envoie à votre serveur dès qu'un événement survient dans un dépôt : un commentaire, une revue ou la fin d'un workflow. Votre agent reste en veille jusqu'à la réception d'une notification, ce qui lui évite de consommer des tokens ou des appels API lorsque rien ne se passe, tout en réagissant en quelques secondes plutôt que d'attendre la prochaine interrogation.
Interroger l'API chaque minute gaspille vos quotas de requêtes avec des réponses vides, tout en induisant un temps de latence pouvant aller jusqu'à une minute. Pour en savoir plus, consultez notre article détaillé sur webhooks vs polling.
L'équipe DeepSeek Harness a développé le même argument dans son article « Exploring Super-agent Design », publié le 1er novembre 2026. Elle qualifie ces entrées de déclencheurs (Triggers) : l'agent surveille les événements et reste inactif le reste du temps. L'article présente une architecture et un prototype de plugin, et non une fonctionnalité officielle intégrée à DeepSeek. Nous avons décortiqué cette conception dans notre guide comment concevoir un super-agent ; ce billet se concentre quant à lui sur la couche de déclenchement, applicable à n'importe quel agent de développement.

Quels événements de webhook GitHub doivent lancer un agent
Abonnez-vous uniquement aux événements pour lesquels un développeur s'attendrait à l'intervention d'un collègue. Chaque événement supplémentaire représente une transmission que vous devrez vérifier, stocker et filtrer.
| Événement | Action à surveiller | Rôle de l'agent |
|---|---|---|
issue_comment |
created |
Répond à un commentaire sur une issue ou dans la discussion d'une PR, par exemple « @bot corrige le test qui échoue » |
pull_request_review_comment |
created |
Répond à un commentaire sur une ligne spécifique du diff |
pull_request |
opened, synchronize |
Effectue la revue d'une nouvelle PR ou effectue une nouvelle revue après un push |
workflow_run |
completed avec conclusion: failure |
Analyse les journaux d'erreur et propose un correctif |
check_run |
completed avec une conclusion d'échec |
Identique à ci-dessus, pour les vérifications remontées par des applications |
Deux détails issus de la documentation des événements de webhook GitHub vous feront gagner un temps précieux en débogage. Premièrement, issue_comment se déclenche aussi bien pour les commentaires sur les issues que sur les pull requests ; un commentaire sur une PR inclut un objet issue.pull_request, ce qui permet de les distinguer. Deuxièmement, workflow_run avec l'action completed se déclenche que l'exécution ait réussi ou échoué : vous devez donc vérifier vous-même le champ workflow_run.conclusion.
Les charges utiles (payloads) sont limitées à 25 Mo ; GitHub n'envoie jamais rien de plus volumineux.
Vérifier la signature X-Hub-Signature-256 sur le corps brut de la requête
Lorsque vous configurez un secret sur le webhook, GitHub signe chaque transmission avec un HMAC SHA-256 calculé sur le corps brut de la requête et transmet l'empreinte hexadécimale via X-Hub-Signature-256: sha256=<digest>. Votre endpoint recalcule ensuite cette empreinte et compare les deux valeurs en temps constant.
Trois règles tirées du guide de GitHub sur la validation des livraisons de webhooks :
- Calculez le hachage sur les octets bruts, et non sur un objet JSON resérialisé. L'analyse (parsing) et la resérialisation modifient les espaces et empêchent la correspondance.
- Effectuez la comparaison avec une fonction en temps constant, comme
crypto.timingSafeEqualde Node, jamais avec==. - Utilisez
X-Hub-Signature-256. L'ancien en-têteX-Hub-Signatureutilise SHA-1 et n'est conservé que pour les intégrations héritées.
Voici le service de réception en Node avec Express :
import express from "express";
import crypto from "node:crypto";
const app = express();
const SECRET = process.env.GITHUB_WEBHOOK_SECRET;
const seen = new Set(); // use Redis or a DB table in production
function validSignature(raw, header) {
if (!header) return false;
const expected = "sha256=" +
crypto.createHmac("sha256", SECRET).update(raw).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(header);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
app.post("/triggers/github", express.raw({ type: "application/json" }), (req, res) => {
if (!validSignature(req.body, req.get("X-Hub-Signature-256"))) {
return res.status(401).json({ error: "bad signature" });
}
const deliveryId = req.get("X-GitHub-Delivery");
if (seen.has(deliveryId)) {
return res.status(200).json({ duplicate: true, trigger_id: deliveryId });
}
seen.add(deliveryId);
const event = req.get("X-GitHub-Event");
const payload = JSON.parse(req.body);
const prNumber = payload.pull_request?.number ?? payload.issue?.number;
const threadId = `${payload.repository.full_name}#${prNumber}`;
queue.push({ deliveryId, event, threadId, payload }); // your queue client
res.status(202).json({ trigger_id: deliveryId, thread_id: threadId });
});
app.listen(3000);
Ce gestionnaire effectue quatre opérations très légères et aucune tâche lente. Pour découvrir les différents mécanismes de signature selon les fournisseurs, consultez notre guide sur la vérification des signatures de webhooks.
Répondre un code 2xx en moins de 10 secondes et mettre en file d'attente le travail de l'agent
Les bonnes pratiques des webhooks de GitHub préconisent que votre serveur réponde par un code 2xx en moins de 10 secondes. Si ce délai est dépassé, GitHub interrompt la connexion et enregistre la transmission comme échouée.
L'exécution d'un agent prenant plusieurs minutes, elle ne doit jamais s'effectuer dans le cycle de la requête. Envoyez l'événement dans une file d'attente (Redis, SQS, une table Postgres ou toute solution durable) et renvoyez immédiatement une réponse 202 Accepted. Un processus worker distinct dépile les événements, applique les filtres et démarre l'agent.
Ces échecs sont critiques : GitHub ne relivre pas automatiquement les transmissions ayant échoué. Vous pouvez les renvoyer manuellement ou via l'API pendant un délai de 3 jours ; par conséquent, un gestionnaire trop lent fera perdre silencieusement le déclencheur d'un commentaire, à moins que quelqu'un ne s'en rende compte.
Filtrer en deux étapes : traitement rapide en code, analyse approfondie avec le modèle
La plupart des transmissions ne devraient jamais atteindre un modèle. L'essai de DeepSeek sépare le filtrage en deux étapes : une voie rapide (« fast path ») gérée par le code et une voie plus lente (« slow path ») où un LLM applique des règles définies sous forme de prompts. Cette séparation permet d'aligner directement les coûts sur le travail utile plutôt que sur le bruit de fond du dépôt.

Traitement rapide (code, exécuté en microsecondes) :
- Liste d'autorisation des dépôts : uniquement les dépôts que vous avez explicitement activés.
- Règles sur l'émetteur : ignorez le compte bot de l'agent lui-même pour éviter de créer une boucle infinie où il se répondrait indéfiniment.
- Mode mention : ne lancez une exécution que lorsque le commentaire contient
@your-bot. L'article mentionne trois approches pertinentes : répondre uniquement aux demandes explicites, qualifier l'événement comme candidat pour le traitement lent, ou l'ignorer.
Traitement approfondi (LLM, appliqué aux événements retenus) :
Transmettez au modèle le texte du commentaire accompagné d'un prompt d'évaluation concis, tel que : « S'agit-il d'une demande de modification de code dans cette PR ? Répondez par oui ou par non, suivi d'une brève explication sur une ligne. » Seule une réponse positive (« oui ») déclenche l'agent. Cela permet d'écarter les messages du type « merci @bot, ça a l'air parfait », qui répondent au critère de mention mais ne nécessitent aucune action.
function fastPath({ event, payload }) {
if (payload.sender?.type === "Bot") return "ignore";
if (!ALLOWED_REPOS.has(payload.repository.full_name)) return "ignore";
if (event === "workflow_run")
return payload.workflow_run.conclusion === "failure" ? "run" : "ignore";
const body = payload.comment?.body ?? "";
return body.includes("@your-bot") ? "candidate" : "ignore";
}
Acheminer les suivis par thread ID pour conserver le même agent
Un fil de discussion (thread) correspond à la suite d'événements consécutifs sur une même PR. Construisez le thread_id à partir du nom du dépôt et du numéro de PR ou d'issue, comme le fait le gestionnaire ci-dessus avec acme/api#42. Selon l'architecture présentée dans l'essai, le worker créé pour le premier événement s'abonne à ce fil, et les événements de suivi lui sont directement transmis sans nécessiter de nouvel arbitrage de routage.
En pratique, il s'agit d'une table de correspondance associant le thread_id à l'identifiant de session de l'agent. Lorsqu'une transmission arrive pour un fil disposant d'une session active, ajoutez le commentaire à cette session. L'agent conserve ainsi l'ensemble de son contexte : le diff qu'il a analysé, les tests qu'il a lancés. Sans ce mécanisme, trois commentaires sur une même PR créeraient trois agents distincts susceptibles de se contredire.
L'essai apporte une idée supplémentaire très judicieuse : les déclencheurs arrivant alors que le routeur traite déjà un tour d'action sont regroupés en lot pour son appel suivant. Ainsi, une salve de cinq commentaires ne génère qu'une seule décision au lieu de cinq.
Dédupliquer grâce à X-GitHub-Delivery
Chaque transmission comporte un identifiant unique (GUID) X-GitHub-Delivery. La documentation de GitHub précise qu'une relivraison réutilise la même valeur que l'envoi initial, ce qui en fait une clé d'idempotence idéale. Enregistrez chaque identifiant (un index unique dans votre base de données suffit) et traitez les doublons comme une opération sans effet (no-op) renvoyant malgré tout un statut 2xx, pour éviter que GitHub ne signale un échec.
Cela protège également contre les attaques par rejeu : même si la signature d'une transmission interceptée reste valide, son identifiant est déjà enregistré.
Laisser votre agent de code tester l'endpoint de déclenchement avec Apidog CLI
Vous ne devriez pas tester manuellement les calculs cryptographiques de signature. Laissez l'agent de programmation qui a rédigé le service de réception écrire et exécuter ses propres tests avec Apidog CLI. La configuration s'effectue en quelques commandes :
npm install -g apidog-cli@latest
apidog auth login --with-token <YOUR_TOKEN>
npx -y skills add https://apidog.com # pick your agent when prompted
Transmettez ensuite cette consigne à Claude Code, Codex ou Cursor :
In Apidog project <projectId>, create the endpoint POST /triggers/github from the
sample issue_comment payload in fixtures/issue_comment.json. Then create test cases
against the staging environment:
1. valid X-Hub-Signature-256 -> 202 with trigger_id and a thread_id of "<repo>#<number>"
2. a second comment on the same PR -> same thread_id
3. bad signature -> 401
4. same X-GitHub-Delivery sent twice -> second call returns duplicate: true, no new job
Sign the bodies with the staging webhook secret in a pre-request script.
Run them and summarize any failures.
L'agent consulte chaque schéma, valide sa charge utile, crée les ressources nécessaires et lance l'exécution :
apidog cli-schema get endpoint-create
apidog cli-schema validate endpoint-create --file endpoint.json
apidog endpoint create --project <projectId> --file endpoint.json
apidog cli-schema get test-case-create
apidog cli-schema validate test-case-create --file case-valid-signature.json
apidog test-case create --project <projectId> --file case-valid-signature.json
apidog run --test-case <caseId> --project <projectId> -e <stagingEnvId> -r cli,json
Le rapporteur cli affiche le succès ou l'échec pour chaque assertion, et le rapport json est généré dans ./apidog-reports, ce qui permet à l'agent d'identifier le test en échec (obtenir un code 200 au lieu de 401 indique généralement l'absence du middleware de traitement du corps brut).
La même commande apidog run s'intègre facilement dans votre CI avec -r junit ; consultez notre article sur Apidog CLI dans GitHub Actions. Pour en savoir plus sur la configuration de l'agent, lisez Apidog CLI dans Claude Code, et pour une approche plus globale du test de webhooks, consultez comment tester les webhooks. Le forfait gratuit d'Apidog prend en charge les équipes jusqu'à 4 utilisateurs.
Avant d'activer le webhook
- Secret configuré : une signature absente ou invalide renvoie un code 401.
- Code 202 renvoyé bien avant la limite des 10 secondes, travail de l'agent mis en file d'attente.
- Identifiants de livraison stockés avec une contrainte d'unicité.
- Un job planifié rejoue les transmissions échouées des 3 derniers jours.
Si vous préférez utiliser l'environnement d'exécution de GitHub, Claude Code GitHub Actions offre une alternative hébergée ; la réception par webhook y ajoute le filtrage et le routage par fil de discussion. Pour gérer les nouvelles tentatives de votre côté, consultez notre guide sur la conception de webhooks fiables.
FAQ
Dois-je utiliser un webhook de dépôt ou une GitHub App ? Un webhook de dépôt ou d'organisation suffit amplement pour une seule équipe. Une GitHub App confère à l'agent sa propre identité de bot, des autorisations plus granulaires et la possibilité d'être installée sur plusieurs organisations.
Que se passe-t-il si mon endpoint est indisponible ? GitHub marque la transmission comme échouée et ne la retente pas automatiquement. Vous pouvez relancer manuellement les transmissions des 3 derniers jours depuis les paramètres du webhook ou via l'API REST.
Comment empêcher l'agent de se répondre à lui-même ? Ignorez toute transmission dont le champ sender correspond au compte de votre bot dès l'étape du filtre rapide (fast path), avant d'exécuter la moindre logique.
Pourquoi renvoyer un code 202 plutôt que 200 ? GitHub considère ces deux codes comme des succès. Le statut 202 Accepted indique clairement dans vos journaux que la tâche a été mise en file d'attente et non finalisée.
L'architecture de super-agent de DeepSeek est-elle une option prête à l'emploi ? Non. Cet essai décrit une architecture conceptuelle et son prototype de plugin n'est pas un produit officiel de DeepSeek. Il vous appartient de développer vous-même la couche de déclenchement, comme illustré ci-dessus.
