# Déclencheur Webhook

Le déclencheur Webhook expose un point d'accès HTTP public qui exécute votre workflow chaque fois qu'un système externe envoie une requête (POST, GET, PUT, PATCH, DELETE). Idéal pour les callbacks de Stripe, GitHub, Typeform, votre propre backend — tout ce qui peut appeler une URL.

## Ajouter le déclencheur

1. Glissez un nœud **Webhook** depuis la palette sur le canevas.
2. Ouvrez le panneau de configuration et renseignez :
   - **Méthode** — `GET`, `POST`, `PUT`, `PATCH` ou `DELETE` (défaut `POST`).
   - **Chemin** — n'importe quel suffixe (ex. `/stripe`). Le `/` initial est optionnel.
   - **Authentification** — voir ci-dessous.
   - **Mode de réponse** — `lastNode` (synchrone, défaut) ou `asyncAck` (fire-and-forget).
3. **Sauvegardez** le workflow et vérifiez qu'il est actif (bouton Live dans la Production space). Les agents inactifs renvoient `404` — l'endpoint n'est actif qu'une fois le workflow activé.

## URL publique

Une fois publié, votre endpoint est :

```
https://<votre-host>/api/v1/wh/<workflow_id>/<chemin>
```

`<workflow_id>` peut être l'`id` numérique ou le `public_id`. Exemple :

```
https://app.systalink.io/api/v1/wh/42/stripe
https://app.systalink.io/api/v1/wh/wf_8ab3c1.../stripe
```

Le routeur matche sur **chemin** ET **méthode** — vous pouvez câbler plusieurs nœuds Webhook dans le même workflow (ex. `POST /stripe` et `POST /github`).

## Authentification

Un déclencheur Webhook **doit être authentifié** — `authType: none` est refusé à la sauvegarde avec `400 "The Webhook trigger must be authenticated…"`, et le nœud exige aussi un **chemin**. Choisissez l'un des modes :

| `authType`        | Ce que l'appelant envoie                                  |
| ------------------ | --------------------------------------------------------- |
| `bearerSecret`    | `Authorization: Bearer <token>` (token brut accepté).    |
| `apiKeySecret`    | En-tête personnalisé (défaut `X-API-Key: <token>`).      |
| `basic`           | `Authorization: Basic <base64 user:pass>`.               |
| `hmac`            | Corps de requête signé (signature HMAC à secret partagé). |

Les secrets sont chiffrés au repos. Le serveur échoue en mode fermé : si l'auth est requise mais sans secret configuré, tous les appels reçoivent `401`.

## Payload reçu par le workflow

Le déclencheur normalise la requête en un seul objet disponible pour les nœuds en aval :

```json
{
  "trigger_kind": "webhook",
  "webhook": {
    "body":    { ... },          // JSON parsé, ou string brute si non-JSON
    "headers": { "host": "...", "content-type": "..." },
    "query":   { "foo": "bar" },
    "method":  "POST",
    "path":    "/stripe",
    "raw_body": "{\n  \"event\": \"ping\"\n}",
    "raw_body_base64": "ewogICJldmVudCI6ICJwaW5nIgp9",
    "raw_body_sha256": "..."
  },
  "event":       { ... },        // alias agnostique au trigger de `webhook`
  "input":       { ... },        // alias de webhook.body
  "last_output": { ... }         // également alias de webhook.body
}
```

Dans un nœud en aval, utilisez les templates directement dans les prompts ou les champs. Les deux préfixes sont équivalents :

- `{event.body}` / `{webhook.body}` — corps complet
- `{event.body.customer.email}` — accès profond dans le JSON
- `{event.headers.x-github-event}` — lecture d'un en-tête
- `{event.query.token}` — lecture d'un paramètre query-string
- `{event.raw_body}` — corps UTF-8 exact, espaces inclus
- `{event.raw_body_base64}` — bytes exacts du corps en base64 pour les flux binaires/HMAC
- `{event.raw_body_sha256}` — hash SHA-256 du corps exact
- `{last_output}` — corps à nouveau (pratique pour Webhook → Agent)

Pour les signatures fournisseur, pointez un nœud HMAC vers `event.raw_body` pour les webhooks JSON/texte. Pour un payload binaire ou non UTF-8, utilisez `event.raw_body_base64` et réglez l'encodage d'entrée HMAC sur **Base64 bytes**.

> `event.*` est la forme recommandée car elle fonctionne aussi pour les triggers **schedule** et **event listener**. Préférez-la pour la portabilité.

## Sémantique de la réponse

- **`lastNode`** (défaut) — l'appel HTTP bloque jusqu'à **30 secondes** pour attendre la fin du run, puis renvoie sa dernière sortie en JSON (ou ce que définit un nœud `Respond to Webhook` en aval). Si le run dure plus de 30s, vous recevez `202 Accepted` avec `{run_id, status: "in_progress"}` — récupérez le résultat final via l'endpoint de poll ci-dessous.
- **`asyncAck`** — renvoie `202` immédiatement avec `{run_id, status: "pending"}`. Le workflow tourne en arrière-plan ; récupérez le résultat via l'endpoint de poll ci-dessous. Si vous incluez un nœud `Respond to Webhook` en aval, le routeur attend automatiquement même en mode async.

## Récupérer le résultat (poll du run)

Dès qu'un appel renvoie `202` (async, ou synchrone ayant dépassé 30s), interrogez le run avec les **mêmes identifiants que le webhook lui-même** (l'auth bearer / clé API / basic / HMAC configurée sur le nœud) :

```
GET /api/v1/wh/{workflow_id}/runs/{run_id}
```

```json
{
  "run_id":           "run_abc123",
  "status":           "completed",
  "result":           { ... },
  "webhook_response": { ... },
  "error":            null,
  "finished_at":      "..."
}
```

`status` vaut `pending`, `running`, `completed` ou `failed`. Pollez jusqu'à un état terminal (`completed` ou `failed`). Les résultats de run restent interrogeables pendant **30 jours**, après quoi cet endpoint renvoie `404`.

## Exemple : curl

```bash
curl -X POST https://app.systalink.io/api/v1/wh/42/stripe \
  -H 'Authorization: Bearer sk_test_abc123' \
  -H 'Content-Type: application/json' \
  -d '{"event":"invoice.paid","amount":4200}'
```

## Dépannage

| Symptôme                               | Cause                                                                            |
| -------------------------------------- | -------------------------------------------------------------------------------- |
| `404 Not Found`                       | Mauvais id de workflow, workflow non publié, ou aucun nœud Webhook ne matche ce chemin+méthode. |
| `401 Invalid webhook credentials`     | En-tête `Authorization` (ou clé API) manquant/incorrect, ou auth requise sans secret défini. |
| `500`                                  | Le workflow a tourné et **échoué** — le corps contient `{error: "..."}`. Voir l'onglet Runs. |
| `202 in_progress`                     | Le mode synchrone a expiré à 30s. Interrogez `GET /api/v1/wh/{workflow_id}/runs/{run_id}`. |

> L'endpoint est public par conception — l'authentification est par nœud, pas par route. Configurez toujours `bearerSecret` ou `apiKeySecret` pour tout ce qui déclenche un vrai traitement.

---

*Source: https://agentbuilder.systalink.sn/docs/trigger-webhook — human documentation.*
*Other language: [/docs-md/en/trigger-webhook.md](/docs-md/en/trigger-webhook.md).*
*Machine-readable index: [/llms.txt](/llms.txt).*
