> ## Documentation Index
> Fetch the complete documentation index at: https://docs.corgea.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Automatisez les callbacks HTTP de Corgea vers tout système externe

## Qu’est-ce qu’un webhook ?

Les webhooks sont des callbacks HTTP automatisés qui permettent à Corgea d’envoyer des notifications en temps réel à vos systèmes externes lorsque des événements précis se produisent. Au lieu d’interroger continuellement l’API, les données sont envoyées directement à l’endpoint configuré.

### Principaux avantages

* **Notifications en temps réel** — recevez immédiatement les mises à jour lorsqu’un problème de sécurité est détecté, qu’un statut change ou qu’un scan se termine
* **Automatisation** — déclenchez des workflows dans des outils externes tels que Slack, Zapier ou des applications personnalisées
* **Efficacité** — évitez d’interroger l’API : les données vous sont envoyées dès qu’un événement se produit
* **Flexibilité** — abonnez-vous uniquement aux événements qui vous intéressent et filtrez-les par projet, statut ou scan planifié
* **Fiabilité** — bénéficiez d’une logique de réessai intégrée et du suivi des livraisons

### Types d’événements pris en charge

Corgea prend en charge les webhooks pour les événements suivants :

**Événements liés aux problèmes :**

* `issue.status_changed` - Déclenché lorsque le statut d’un problème est mis à jour (par exemple, ouvert → corrigé)
* `issue.assigned` - Déclenché lorsqu’un problème est attribué à un membre de l’équipe

**Événements SLA :**

* `sla.violation` - Déclenché lorsque la tâche SLA quotidienne trouve un ou plusieurs problèmes SAST ou SCA ayant dépassé leur échéance de remédiation ou d’escalade (configurée par SLA dans [Gestion des SLA](sla_management))

**Événements de scan :**

* `scan.started` - Déclenché lors du début d’un scan de sécurité
* `scan.completed` - Déclenché lorsqu’un scan se termine avec succès
* `scan.failed` - Déclenché lorsqu’un scan rencontre une erreur
* `scheduled_scan.daily_report` - Déclenché chaque jour à la fin des scans planifiés ; récapitule les nouveaux problèmes détectés pendant toutes les exécutions des 24 dernières heures. Consultez [Notifications](notifications#daily-scan-report) pour le schéma de l’e-mail et du payload.

<Note>
  Les événements du cycle de vie d’un scan (`scan.started`, `scan.completed`, `scan.failed`) incluent `data.message`, un court résumé en texte brut utilisable dans Slack, Zapier ou un autre outil de messagerie. Ils incluent également les champs de triage `pull_request_id`, `scan_url`, `true_positive_count`, `project_name` et `status`.

  Pour Slack Workflow Builder (`Type = Slack` + `hooks.slack.com/triggers/...`), Corgea aplatit **uniquement** `scan.started`, `scan.completed`, `scan.failed` et `webhook.test` en champs de premier niveau. Ne mappez pas l’objet imbriqué `data.*` dans Slack : cela provoque une erreur HTTP 400. Les autres types d’événements envoyés au même webhook Slack conservent leur enveloppe imbriquée. Voir [Slack](slack).
</Note>

**Événements d’authentification des utilisateurs :**

* `user.login` - Déclenché lorsqu’un utilisateur se connecte avec succès
* `user.login_failed` - Déclenché lorsqu’une tentative de connexion utilisateur échoue

***

## Fonctionnement des webhooks

### Cycle de vie d’un webhook

<Steps>
  <Step title="Événement survenu">
    Un événement se produit dans Corgea, par exemple la fin d’un scan ou le changement de statut d’un problème
  </Step>

  <Step title="Webhook déclenché">
    Le système identifie tous les webhooks abonnés à ce type d’événement
  </Step>

  <Step title="Filtrage appliqué">
    Les filtres de projet, de statut, de scan planifié, de pull request et de résultats déterminent si le webhook doit être déclenché
  </Step>

  <Step title="Construction du payload">
    Par défaut, Corgea construit une enveloppe JSON normalisée avec les détails de l’événement. Si vous avez configuré un modèle de corps personnalisé, celui-ci est utilisé à la place. Pour Slack Workflow Builder (`Type = Slack` et URL `triggers/`), Corgea aplatit le corps HTTP uniquement pour `scan.*` et `webhook.test` ; les autres événements restent imbriqués.
  </Step>

  <Step title="Requête HTTP POST">
    Le payload est envoyé à l’URL de votre webhook avec les en-têtes de sécurité
  </Step>

  <Step title="Logique de réessai">
    Si la requête échoue, de nouvelles tentatives sont effectuées automatiquement avec un backoff exponentiel
  </Step>

  <Step title="Livraison enregistrée">
    Toutes les tentatives sont suivies dans l’historique de livraison pour le dépannage
  </Step>
</Steps>

### Structure du payload

Par défaut, les payloads des webhooks utilisent une enveloppe imbriquée normalisée (Zapier / Autre). Les événements du cycle de vie d’un scan incluent `data.message` ainsi que les champs de triage :

```json webhook-payload.json theme={null}
{
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_type": "scan.completed",
  "timestamp": "2025-01-15T14:30:00.000Z",
  "data": {
    "company": "company-uuid",
    "scan_id": "scan-uuid",
    "run_id": "run-12345",
    "project": {
      "id": "project-uuid",
      "name": "My Application"
    },
    "project_name": "My Application",
    "branch": "feature/auth",
    "engine": "corgea-blast",
    "scan_type": "full",
    "status": "completed",
    "pull_request_id": "42",
    "scan_url": "https://app.corgea.app/project/project-uuid/?scan_id=scan-uuid",
    "true_positive_count": 5,
    "summary": {
      "total_issues": 12,
      "issues_with_fixes": 7,
      "issues_without_fixes": 5,
      "true_positive_count": 5,
      "true_positive_issues_with_fixes": 3
    },
    "message": "Scan completed for My Application (PR #42): 5 true-positive findings (3 with fixes). View: https://app.corgea.app/project/project-uuid/?scan_id=scan-uuid",
    "scheduled_scan_ids": ["scheduled-scan-uuid"],
    "processed_at": "2025-01-15T14:30:00.000Z",
    "created_at": "2025-01-15T14:00:00.000Z"
  }
}
```

`summary.total_issues` compte tous les problèmes non supprimés, y compris les faux positifs et les problèmes de qualité du code. `true_positive_count` correspond au nombre issu du triage utilisé dans `message` et dans les filtres d’événements de scan.

| Événement        | Exemple `data.message`                                                            |
| ---------------- | --------------------------------------------------------------------------------- |
| `scan.started`   | `Scan started for My Application (PR #42).`                                       |
| `scan.completed` | `Scan completed for My Application (PR #42): 5 true-positive findings. View: ...` |
| `scan.failed`    | `Scan failed for My Application (PR #42): Scanner timed out. View: ...`           |

`true_positive_count` compte les résultats de sécurité non supprimés qui ne sont pas des faux positifs, selon la même logique que l’interface du scan : les valeurs `status=false_positive`, `hold_reason=false_positive` et `detected_by=code-quality` sont exclues. Le suffixe facultatif `(N with fixes)` des messages `scan.completed` ne compte les correctifs que parmi ces vrais positifs, et non parmi tous les problèmes du scan.

<Tip>
  **Slack Workflow Builder :** lorsque `Type = Slack` et que l’URL est `hooks.slack.com/triggers/...`, Corgea envoie un corps **plat** pour `scan.*` et `webhook.test`, avec `message`, `pull_request_id`, `scan_url`, `true_positive_count`, `company`, etc. au premier niveau. Le mappage de `data.*` imbriqué n’est pas pris en charge dans Slack et provoque une erreur HTTP 400. Les événements qui ne concernent pas une analyse ne sont **pas** aplatis. Voir [Slack](slack).
</Tip>

**Exemple de payload `sla.violation`** (issu de la tâche quotidienne de gestion des SLA) :

```json sla-violation-payload.json theme={null}
{
  "event_id": "550e8400-e29b-41d4-a716-446655440001",
  "event_type": "sla.violation",
  "timestamp": "2025-01-15T14:30:00.000Z",
  "data": {
    "company": "1",
    "sla": {
      "id": 3,
      "rule_type": "code",
      "urgency": ["CR", "HI"],
      "remediation_days": 7,
      "escalation_days": 3
    },
    "notification_type": "remediation",
    "issue_kind": "SAST",
    "issue_count": 5,
    "summary_message": "Plain-text summary (same style as email body)...",
    "projects": [
      {
        "id": "project-uuid",
        "name": "My Application",
        "url": "https://app.corgea.com/project/project-uuid",
        "issue_count": 5,
        "urgency_counts": {
          "Critical": 2,
          "High": 3
        }
      }
    ]
  }
}
```

| Champ               | Description                                                                        |
| ------------------- | ---------------------------------------------------------------------------------- |
| `notification_type` | `remediation` ou `escalation`                                                      |
| `issue_kind`        | `SAST` ou `SCA`                                                                    |
| `sla.rule_type`     | `code` (SAST) ou `sca` (dépendance)                                                |
| `projects`          | Une entrée par projet concerné ; utilisée par les **filtres de projet** du webhook |

Abonnez-vous à `sla.violation` sous **Intégrations → Webhooks**, ou associez un webhook depuis le formulaire [Gestion des SLA](sla_management) ; les webhooks existants sont automatiquement abonnés.

**Exemple de payload `scheduled_scan.daily_report`** :

```json scheduled-scan-daily-report-payload.json theme={null}
{
  "event_id": "550e8400-e29b-41d4-a716-446655440002",
  "event_type": "scheduled_scan.daily_report",
  "timestamp": "2025-01-15T14:30:00.000Z",
  "data": {
    "title": "Corgea Daily Scan Report",
    "company": "1",
    "company_name": "Acme Security",
    "total_new_issues": 7,
    "message": "Daily scan report for Acme Security: 7 new issues detected across 2 scan runs.",
    "scan_runs": [
      {
        "scheduled_scan_name": "Weekly Production Scan",
        "project": "Payments API",
        "new_issue_count": 4,
        "scan_url": "https://www.corgea.app/scans/scan-uuid"
      }
    ]
  }
}
```

Les administrateurs de l’entreprise peuvent contrôler si cet événement est envoyé vers des webhooks depuis **Paramètres → notifications → paramètres par défaut de l’entreprise**.

Si vous configurez un **corps personnalisé**, Corgea envoie l’objet JSON obtenu à la place de la structure de payload par défaut.

<Note>L’événement `scheduled_scan.daily_report` utilise la même enveloppe, mais possède son propre schéma `data`. Consultez les [exemples de payloads](#payload-examples) pour la référence complète.</Note>

### Fonctionnalités de sécurité

<AccordionGroup>
  <Accordion title="Vérification de la signature HMAC" icon="shield-check">
    * Corgea génère automatiquement une clé secrète lorsque vous créez un webhook
    * Chaque requête contient un en-tête `X-Corgea-Signature` avec un hash HMAC-SHA256 du payload
    * Vérifiez la signature avec votre clé secrète pour vous assurer que le webhook vient de Corgea
  </Accordion>

  <Accordion title="En-têtes personnalisés" icon="key">
    * Incluez les en-têtes requis par votre endpoint, par exemple les tokens d’authentification
    * Configurez des en-têtes personnalisés lors de la configuration du webhook
  </Accordion>

  <Accordion title="HTTPS obligatoire" icon="lock">
    * Toutes les URL de webhook doivent utiliser HTTPS (ports 443 ou 80 uniquement)
    * Les URL ne doivent pas contenir d’identifiants
    * Les destinations résolues vers des adresses privées, loopback, link-local, réservées ou multicast sont rejetées afin de protéger contre les SSRF
    * Les opérateurs peuvent restreindre les hôtes avec le paramètre `WEBHOOK_ALLOWED_HOSTS`
  </Accordion>
</AccordionGroup>

### Logique de réessai automatique

<Info>Si la livraison par webhook échoue, Corgea réessaie automatiquement avec la stratégie suivante :</Info>

* **Tentative initiale** + **2 nouvelles tentatives** = 3 tentatives au total
* **Backoff exponentiel** : 2 secondes, puis 4 secondes entre les tentatives
* **Timeout** : 10 secondes par requête
* **Mise en pause automatique** : après 10 échecs consécutifs, le webhook est automatiquement mis en pause

### En-têtes envoyés avec chaque webhook

```text webhook-headers.txt theme={null}
Content-Type: application/json
X-Corgea-Event: issue.status_changed
X-Corgea-Delivery: <delivery-uuid>
X-Corgea-Timestamp: <unix-timestamp>
X-Corgea-Signature: <hmac-signature>
User-Agent: Corgea-Webhooks/1.0
```

***

## Mise en place d’un webhook

<Frame>
  <img src="https://mintcdn.com/corgea/JgeRsjW5cn2yU52a/images/webhooks/webhooks_table.png?fit=max&auto=format&n=JgeRsjW5cn2yU52a&q=85&s=23c5fe597820ac3bdb57560ef29c3b9d" alt="Interface de gestion des webhooks affichant la liste des webhooks configurés" style={{ borderRadius: '0.5rem' }} width="3108" height="798" data-path="images/webhooks/webhooks_table.png" />
</Frame>

### Prérequis

<Check>Autorisations d’administration ou de gestion de l’intégration dans votre compte Corgea</Check>
<Check>Une URL d’endpoint webhook qui accepte les requêtes POST</Check>
<Check>Un endpoint HTTPS, obligatoire pour des raisons de sécurité</Check>

### Mise en place étape par étape

<Steps>
  <Step title="Accéder aux intégrations">
    * Ouvrez **Intégrations** dans Corgea
    * Sous **Intégrations d’automatisation**, ouvrez **Webhooks**

    <Frame>
      <img src="https://mintcdn.com/corgea/bUShOerLaxHbdmO7/images/webhooks/webhooks_integrations.png?fit=max&auto=format&n=bUShOerLaxHbdmO7&q=85&s=e84b9d7d75569f68d644ada376ea16bf" alt="Intégrations d’automatisation montrant les Webhooks actifs, avec Slack et Zapier marqués comme dépréciés" style={{ borderRadius: '0.5rem' }} width="1641" height="240" data-path="images/webhooks/webhooks_integrations.png" />
    </Frame>

    <Warning>
      Les intégrations autonomes **Slack** et **Zapier** sont obsolètes. Utilisez **Webhooks** pour les nouvelles configurations. Les intégrations Slack et Zapier existantes continuent de fonctionner ; ouvrez **Voir tout** pour les tester ou les supprimer.
    </Warning>
  </Step>

  <Step title="Configurer les paramètres de base">
    <Frame>
      <img src="https://mintcdn.com/corgea/bUShOerLaxHbdmO7/images/webhooks/create_webhook_basic.png?fit=max&auto=format&n=bUShOerLaxHbdmO7&q=85&s=64b04b74bc95600f1c4e58c9a8b94398" alt="Créer un formulaire webhook montrant Nom, Webhook URL, et champs types" style={{ borderRadius: '0.5rem' }} width="1107" height="433" data-path="images/webhooks/create_webhook_basic.png" />
    </Frame>

    * **Nom** : libellé explicite, par exemple « Notifications Slack » ou « Alertes de scan de production »
    * **URL du webhook** : votre endpoint HTTPS
    * **Type** :
      * `Slack` — destinations Slack Workflow Builder ou Incoming Webhook
      * `Zapier` — Catch Hooks Zapier
      * `Other` — endpoints personnalisés

    <Tip>
      Pour Slack, privilégiez une URL Workflow Builder (`hooks.slack.com/triggers/...`). Corgea aplatit `scan.*` et `webhook.test` pour ces destinations : mappez le champ de premier niveau `message`, et non `data.*`. Les événements autres que les scans restent imbriqués. Les Incoming Webhooks (`hooks.slack.com/services/...`) sont rejetés, sauf si vous définissez un corps personnalisé dont le JSON rendu contient un champ `text` non vide de premier niveau. `{"text": "{{message}}"}` est autorisé uniquement pour les événements du cycle de vie des scans et `scheduled_scan.daily_report`. Consultez [Slack](slack).
    </Tip>
  </Step>

  <Step title="S’abonner aux événements">
    <Frame>
      <img src="https://mintcdn.com/corgea/bUShOerLaxHbdmO7/images/webhooks/create_webhook_events.png?fit=max&auto=format&n=bUShOerLaxHbdmO7&q=85&s=dffd5f8c779ea28405555be193aae289" alt="Formulaire d’abonnement avec des boutons pour les événements de problème, de SLA, de scan, d’utilisateur et de scan planifié" style={{ borderRadius: '0.5rem' }} width="1089" height="761" data-path="images/webhooks/create_webhook_events.png" />
    </Frame>

    Activez les événements qui vous intéressent. Vous pouvez en sélectionner plusieurs :

    * Statut du problème modifié
    * Problème attribué
    * Violation de SLA (`sla.violation`)
    * Scan démarré / terminé / en échec
    * Connexion utilisateur / Échec de la connexion utilisateur
    * Rapport quotidien des scans planifiés (`scheduled_scan.daily_report`)
  </Step>

  <Step title="Configurer les filtres (facultatif)">
    <Frame>
      <img src="https://mintcdn.com/corgea/bUShOerLaxHbdmO7/images/webhooks/create_webhook_scopes.png?fit=max&auto=format&n=bUShOerLaxHbdmO7&q=85&s=b77a4be9aeb754e6b411ca55714f84f6" alt="Sections consacrées au périmètre des projets et des scans planifiés, aux en-têtes personnalisés et au corps personnalisé" style={{ borderRadius: '0.5rem' }} width="1089" height="594" data-path="images/webhooks/create_webhook_scopes.png" />
    </Frame>

    **Filtres d’événements de scan** (pour les événements `scan.*`)

    * **Uniquement les scans de pull request ou de merge request** — ignore les scans sans `pull_request_id`
    * **Uniquement les scans terminés comportant de vrais positifs** — ignore `scan.completed` lorsque `true_positive_count` vaut 0, sans affecter `scan.failed` ni `scan.started`

    **Portée du projet**

    * Laissez le filtre désactivé pour recevoir les événements de tous les projets
    * Activez le filtrage pour limiter le webhook à des projets sélectionnés
    * Pour `sla.violation`, le webhook se déclenche si **au moins un** projet du payload correspond au filtre

    **Filtre de changement de statut** (pour `issue.status_changed`)

    * Laissez vide pour tous les changements de statut
    * Vous pouvez aussi limiter le filtre à des statuts tels que `fixed` ou `false_positive`

    **Périmètre des scans planifiés** (pour les événements `scan.*`)

    * Laissez ce filtre désactivé pour recevoir tous les scans, manuels et planifiés
    * Activez-le pour ne déclencher le webhook que pour certains scans planifiés
  </Step>

  <Step title="Ajouter des en-têtes et un corps personnalisés (facultatif)">
    **En-têtes personnalisés**

    Ajoutez les en-têtes requis par votre destination webhook. Chaque service a des exigences différentes :

    <AccordionGroup>
      <Accordion title="Jira Automation" icon="jira">
        **En-tête requis :**

        ```text theme={null}
        X-Automation-Webhook-Token: <your-jira-webhook-secret>
        ```

        **Comment obtenir votre token :**

        1. Dans Jira, créez une règle d’automatisation avec un déclencheur « Incoming webhook »
        2. Copiez le token secret fourni par Jira
        3. Ajoutez-le comme valeur d’en-tête dans Corgea

        [Documentation de Jira Webhook](https://support.atlassian.com/cloud-automation/docs/configure-the-incoming-webhook-trigger-in-atlassian-automation/)
      </Accordion>

      <Accordion title="Slack" icon="slack">
        **Aucun en-tête personnalisé n’est nécessaire** — l’authentification est incluse dans l’URL Slack.

        Privilégiez une URL Workflow Builder (`https://hooks.slack.com/triggers/...`). Avec `Type = Slack`, Corgea aplatit `scan.*` et `webhook.test` : mappez `message`, `pull_request_id`, `scan_url`, `true_positive_count` et `company`. Ne mappez **pas** les champs imbriqués `data.*`, car Slack renvoie alors une erreur HTTP 400. Les autres types d’événements ne sont pas aplatis. Consultez [Slack](slack).

        Les Incoming Webhooks (`https://hooks.slack.com/services/...`) nécessitent un corps personnalisé dont le JSON rendu contient un champ `text` non vide de premier niveau. Utilisez `{"text": "{{message}}"}` uniquement avec les événements du cycle de vie des scans et `scheduled_scan.daily_report`.
      </Accordion>

      <Accordion title="Microsoft Teams" icon="microsoft">
        **Aucun en-tête personnalisé n’est nécessaire** — les URL de webhook Teams contiennent elles-mêmes les informations d’authentification.

        Collez simplement votre URL de webhook Teams, au format `https://xxx.webhook.office.com/webhookb2/xxx/IncomingWebhook/xxx`.

        <Note>Les webhooks entrants de Teams ne valident pas les en-têtes personnalisés. Leur sécurité repose sur la confidentialité de l’URL du webhook.</Note>

        [Teams Webhook Documentation](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook)
      </Accordion>

      <Accordion title="API personnalisée avec token Bearer" icon="key">
        **En-tête :**

        ```text theme={null}
        Authorization: Bearer <your-api-token>
        ```

        Configuration courante pour les API REST qui utilisent des tokens JWT ou OAuth.
      </Accordion>

      <Accordion title="Splunk HEC" icon="bolt">
        **En-tête :**

        ```text theme={null}
        Authorization: Splunk <your-hec-token>
        ```

        Utilisez cet en-tête pour envoyer des événements webhook à un endpoint Splunk HTTP Event Collector (HEC).
      </Accordion>

      <Accordion title="API personnalisée avec clé d’API" icon="lock">
        **En-têtes (en choisir un) :**

        ```text theme={null}
        X-API-Key: <your-api-key>
        ```

        ou

        ```text theme={null}
        Authorization: ApiKey <your-api-key>
        ```

        Configuration courante pour une authentification simple par clé d’API.
      </Accordion>

      <Accordion title="PagerDuty" icon="bell">
        **Aucun en-tête personnalisé n’est nécessaire** — l’API PagerDuty Events v2 utilise la clé `routing_key` du payload JSON pour l’authentification.

        Utilisez l’endpoint de l’API PagerDuty Events : `https://events.pagerduty.com/v2/enqueue`

        <Note>PagerDuty ne valide pas les en-têtes personnalisés. L’authentification s’effectue au moyen de `routing_key` dans le corps de la requête.</Note>

        [PagerDuty Webhook Documentation](https://developer.pagerduty.com/docs/ZG9jOjExMDI5NTgw-events-api-v2-overview)
      </Accordion>

      <Accordion title="Zapier" icon="bolt">
        **Aucun en-tête personnalisé n’est nécessaire** — les URL de webhook Zapier contiennent elles-mêmes les informations d’authentification.

        Créez un déclencheur « Webhooks by Zapier » et utilisez l’URL fournie.

        <Note>Zapier Catch Hook ne valide pas les en-têtes personnalisés par défaut. La sécurité repose sur la confidentialité de l’URL du webhook. Vous pouvez ajouter une validation des en-têtes dans votre Zap si nécessaire.</Note>

        [Documentation Zapier Webhook](https://zapier.com/help/create/code-webhooks/trigger-zaps-from-webhooks)
      </Accordion>
    </AccordionGroup>

    <Tip>
      Si votre service ne figure pas dans cette liste, consultez sa documentation relative aux webhooks ou aux webhooks entrants pour connaître les en-têtes requis.
    </Tip>

    <Warning>
      **Important :** Bien que Corgea envoie tous les en-têtes personnalisés que vous configurez, toutes les destinations webhook ne les valident pas. Des services comme Slack, Teams et Zapier reposent sur des URL secrètes plutôt que sur la validation des en-têtes. Ajoutez des en-têtes personnalisés uniquement si votre service de destination les nécessite ou les valide réellement (comme Jira, des API personnalisées, etc.).
    </Warning>

    **Corps personnalisé**

    * Vous pouvez fournir un modèle d’objet JSON pour le corps de la requête webhook
    * Laissez ce champ vide pour utiliser la structure de payload par défaut de Corgea
    * Variables de substitution prises en charge :
      * `{{payload}}` (payload complet par défaut)
      * `{{time}}` (secondes Unix)
      * `{{timestamp}}` (horodatage ISO 8601)
      * `{{event_type}}`
      * `{{event_id}}`
      * `{{message}}` (valeur de `data.message` lorsqu’elle existe, pour le cycle de vie des scans et le rapport quotidien)
    * Si le modèle produit un JSON non valide, la livraison échoue et l’erreur apparaît dans l’historique du webhook
  </Step>

  <Step title="Sauvegarder et activer">
    * Cliquez sur **Create Webhook**
    * Copiez la clé secrète depuis la fenêtre — Corgea ne l’affiche qu’une seule fois

    <Frame>
      <img src="https://mintcdn.com/corgea/bUShOerLaxHbdmO7/images/webhooks/webhook_secret_key.png?fit=max&auto=format&n=bUShOerLaxHbdmO7&q=85&s=e219c00690cd7873f987954a632fec23" alt="Fenêtre contextuelle de clé secrète Webhook affichée une fois après la création d’un webhook" style={{ borderRadius: '0.5rem' }} width="506" height="610" data-path="images/webhooks/webhook_secret_key.png" />
    </Frame>

    <Warning>
      Enregistrez la clé secrète avant de fermer la boîte de dialogue. Vous ne pourrez plus la consulter. Contactez le support si vous devez la renouveler.
    </Warning>

    * Cliquez sur **I've saved the Secret Key**
    * Le webhook est actif et commence à recevoir des événements
  </Step>

  <Step title="Tester le webhook">
    * Ouvrez le webhook et cliquez sur **Test Webhook**
    * Confirmez que votre endpoint renvoie une réponse 2xx
    * Pour Slack Workflow Builder, le corps est plat et contient un champ `message` non vide de premier niveau, ainsi que des exemples de clés de triage (`pull_request_id`, `scan_url`, `true_positive_count`, etc.) afin de mapper les variables pendant le test. Les configurations Workflow Builder qui utilisent uniquement des champs imbriqués ne sont pas prises en charge.
  </Step>
</Steps>

### Vérification des signatures de webhooks

<Note>Utilisez la clé secrète affichée lors de la création pour vérifier l’en-tête `X-Corgea-Signature` de chaque requête.</Note>

<Tabs>
  <Tab title="Python">
    ```python verify-signature.py theme={null}
    import hmac
    import hashlib

    def verify_webhook_signature(payload, signature, secret):
        """Verify Corgea webhook signature"""
        expected_signature = hmac.new(
            secret.encode('utf-8'),
            payload.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()

        return hmac.compare_digest(expected_signature, signature)

    # In your webhook handler:
    if not verify_webhook_signature(request.body, request.headers['X-Corgea-Signature'], SECRET_KEY):
        return HttpResponse(status=403)  # Reject invalid signatures
    ```
  </Tab>

  <Tab title="Node.js">
    ```javascript verify-signature.js theme={null}
    const crypto = require('crypto');

    function verifyWebhookSignature(payload, signature, secret) {
      const expectedSignature = crypto
        .createHmac('sha256', secret)
        .update(payload)
        .digest('hex');

      return crypto.timingSafeEqual(
        Buffer.from(expectedSignature),
        Buffer.from(signature)
      );
    }
    ```
  </Tab>
</Tabs>

***

## Cas d’utilisation

### 1. Notifications Slack en temps réel

**Scénario** : prévenez votre équipe de sécurité dans Slack lorsque des problèmes de sévérité élevée sont détectés

**Configuration** :

* Créez une URL de webhook entrant dans votre espace de travail Slack
* Dans Corgea, créez un webhook avec :
  * Type : `Slack`
  * URL : URL de votre webhook Slack
  * Événements : `scan.completed`
  * Filtre de projet : Projets de production critiques

**Résultat** : votre canal #security reçoit immédiatement une notification à la fin des scans

***

### 2. Création automatisée de tickets pour les problèmes critiques

**Scénario** : créez automatiquement des tickets dans Jira ou Linear lorsque des problèmes critiques sont détectés

**Configuration** :

* Créez un Zap ou un endpoint personnalisé qui génère des tickets
* Dans Corgea, créez un webhook avec :
  * Événements : `scan.completed`, `issue.status_changed`
  * Filtre de statut : statut `open` uniquement, afin d’éviter les doublons
  * Filtre de projet : Projets de production

**Résultat** : les problèmes de sévérité élevée ou critique deviennent automatiquement des tickets dans votre outil de gestion de projet

***

### 3. Intégration du flux de travail d’acceptation des risques

**Scénario** : documentez automatiquement les risques acceptés dans Jira ou Linear lorsque des problèmes de sécurité sont marqués comme « Risque accepté »

**Configuration** :

* Créez un endpoint ou une intégration Zapier qui génère des tickets de documentation
* En Corgea, créez un webhook avec :
  * Événements : `issue.status_changed`
  * Filtre de statut : statut `accepted_risk` uniquement
  * Filtre de projet : tous les projets ou certains projets soumis à de fortes exigences de conformité
* Configurez l’intégration pour :
  * Créer un ticket documentant l’acceptation du risque
  * Inclure les détails du problème (classification, chemin du fichier, sévérité)
  * Ajouter le libellé « acceptation du risque »
  * Attribuer le ticket au responsable de la sécurité pour examen

**Résultat** : chaque risque accepté est automatiquement consigné avec son contexte complet dans votre système de gestion de projet, ce qui crée une piste d’audit pour les revues de conformité et de gestion des risques

***

### 4. Intégration personnalisée de tableau de bord

**Scénario** : affichez les métriques de sécurité en temps réel sur votre tableau de bord interne

**Configuration** :

* Créez un endpoint qui reçoit les données du webhook et met à jour votre tableau de bord
* Dans Corgea, créez un webhook avec :
  * Événements : tous les événements de scan et de problème
  * Pas de filtres (recevoir tout)

**Résultat** : votre tableau de bord affiche en temps réel les résultats des scans de sécurité et l’évolution des problèmes

***

### 5. Routage multi-équipes

**Scénario** : acheminez les notifications de chaque projet vers l’équipe concernée

**Configuration** :

* Créez des webhooks séparés pour chaque équipe :
  * **Webhook de l’équipe backend** : filtre de projet = projets backend, canal Slack #backend-security
  * **Webhook de l’équipe frontend** : filtre de projet = projets frontend, canal Slack #frontend-security
  * **Webhook de l’équipe DevOps** : filtre de projet = projets d’infrastructure, canal Slack #devops-security

**Résultat** : chaque équipe ne voit que les problèmes de sécurité concernant ses projets

***

### 6. Rapports de conformité

**Scénario** : consignez automatiquement tous les résultats de sécurité dans un système de conformité

**Configuration** :

* Créez un endpoint qui écrit dans votre base de données de conformité
* Dans Corgea, créez un webhook avec :
  * Événements : `scan.completed`
  * Tous les projets
  * Conserver l’historique des livraisons du webhook à des fins d’audit

**Résultat** : une piste d’audit complète de tous les scans de sécurité à des fins de conformité

***

## Dépannage

### Consulter l’historique des livraisons du webhook

<Steps>
  <Step title="Accéder à l’historique du webhook">
    Accédez à **Intégrations** → **Webhooks**

    <Frame>
      <img src="https://mintcdn.com/corgea/JgeRsjW5cn2yU52a/images/webhooks/webhook_history.png?fit=max&auto=format&n=JgeRsjW5cn2yU52a&q=85&s=e0c209104347995d1bde95b867a6bb7d" alt="Historique de livraison Webhook montrant les tentatives récentes de webhook" style={{ borderRadius: '0.5rem' }} width="3112" height="1466" data-path="images/webhooks/webhook_history.png" />
    </Frame>
  </Step>

  <Step title="Ouvrir le journal des livraisons">
    Cliquez sur **History** ou **Delivery Log**
  </Step>

  <Step title="Examiner les détails des livraisons">
    <Frame>
      <img src="https://mintcdn.com/corgea/JgeRsjW5cn2yU52a/images/webhooks/webhook_history_details.png?fit=max&auto=format&n=JgeRsjW5cn2yU52a&q=85&s=14c49d0e334a55ee79a2bdb7f8b5126b" alt="Informations détaillées sur la livraison du webhook, incluant la demande et la réponse" style={{ borderRadius: '0.5rem' }} width="2806" height="2094" data-path="images/webhooks/webhook_history_details.png" />
    </Frame>

    Consultez toutes les tentatives de livraison du webhook avec :

    * Type d’événement et horodatage
    * Code de statut HTTP
    * Détails de la requête et de la réponse
    * Messages d’erreur (s’il y en a)
    * Tentatives de réessai
  </Step>
</Steps>

### Problèmes et solutions courants

<AccordionGroup>
  <Accordion title="Webhook ne reçoit pas d’événements" icon="circle-xmark">
    **Causes possibles :**

    * Le webhook est en pause ou inactif
    * Les abonnements aux événements ne sont pas configurés
    * Les filtres de projet, de statut ou de scan planifié excluent les événements
    * L’endpoint ne renvoie pas de code de statut 2xx

    **Solutions :**

    1. Vérifiez le statut du webhook et assurez-vous qu’il est actif
    2. Vérifiez que les abonnements aux événements sont sélectionnés
    3. Supprimez temporairement les filtres de projet, de statut ou de scan planifié pour effectuer un test
    4. Vérifiez les requêtes entrantes dans les logs de votre endpoint
    5. Testez le webhook en utilisant le bouton « Test Webhook »
  </Accordion>

  <Accordion title="Webhook mis en pause automatiquement" icon="pause">
    **Cause :** 10 échecs consécutifs de livraison

    **Solutions :**

    1. Vérifiez l’historique des livraisons pour les détails des erreurs
    2. Vérifiez que l’URL de votre endpoint est correcte et accessible
    3. Assurez-vous que votre endpoint renvoie un code de statut 2xx
    4. Vérifiez la présence de règles de pare-feu ou de sécurité bloquant les requêtes de Corgea
    5. Corrigez le problème sous-jacent, puis **réactivez manuellement** le webhook
    6. Utilisez « Test Webhook » pour vérifier son fonctionnement avant de le réactiver
  </Accordion>

  <Accordion title="Recevoir trop d’appels Webhook" icon="volume-high">
    **Solutions :**

    1. **Utiliser des filtres de statut** : pour `issue.status_changed`, conservez uniquement les statuts qui vous intéressent, par exemple `fixed` et `false_positive`
    2. **Utiliser des filtres de projet** : abonnez-vous uniquement aux projets critiques concernés
    3. **Utiliser des filtres de scan planifié** : sélectionnez les scans planifiés qui doivent déclencher le webhook
    4. **Réduire les abonnements aux événements** : désabonnez-vous des événements inutiles
    5. **Mettre en place une limitation de débit** : ajoutez une limitation de débit ou une file d’attente sur votre endpoint
  </Accordion>

  <Accordion title="Échec de la vérification de la signature" icon="shield-xmark">
    **Causes possibles :**

    * Mauvaise clé secrète
    * Logique incorrecte de vérification de signature
    * Problèmes d’encodage des caractères

    **Solutions :**

    1. Vérifiez que vous utilisez exactement la clé secrète de Corgea
    2. Assurez-vous d’utiliser l’algorithme HMAC-SHA256
    3. Utilisez le corps brut de la requête, et non le JSON parsé, pour la vérification
    4. Vérifiez l’encodage UTF-8 des deux côtés
    5. Utilisez `hmac.compare_digest()` (Python) ou `crypto.timingSafeEqual()` (Node.js) pour effectuer une comparaison à temps constant

    <Tip>Enregistrez à la fois la signature reçue et votre signature calculée pour comparer</Tip>
  </Accordion>

  <Accordion title="Timeout de l’endpoint" icon="clock">
    **Cause :** votre endpoint met plus de 10 secondes à répondre

    **Solutions :**

    1. **Accuser réception immédiatement** : renvoyez tout de suite 200 OK, puis effectuez le traitement de manière asynchrone
    2. **Utiliser une file d’attente** : placez les payloads des webhooks dans une file d’attente pour les traiter en arrière-plan
    3. **Optimiser le traitement** : accélérez la logique de votre handler de webhook
    4. **Augmenter les ressources** : adaptez les ressources de l’infrastructure de votre endpoint

    **Schéma de bonnes pratiques :**

    ```python webhook-handler.py theme={null}
    @app.route('/webhook', methods=['POST'])
    def handle_webhook():
        payload = request.json

        # Immediately acknowledge receipt
        queue.add(process_webhook, payload)

        # Return quickly
        return '', 200

    def process_webhook(payload):
        # Do time-consuming work here
        ...
    ```
  </Accordion>

  <Accordion title="Événements en double" icon="copy">
    **Causes possibles :**

    * Plusieurs webhooks se sont abonnés au même événement
    * Réessai déclenché après une réponse tardive pourtant réussie

    **Solutions :**

    1. Vérifiez la présence de configurations de webhook en double
    2. Utilisez le champ `event_id` pour garantir l’idempotence : stockez les identifiants traités et ignorez les doublons
    3. Implémentez des clés d’idempotence dans votre endpoint

    **Schéma d’idempotence :**

    ```python idempotency.py theme={null}
    processed_events = set()  # Or use Redis/database

    @app.route('/webhook', methods=['POST'])
    def handle_webhook():
        event_id = request.json['event_id']

        if event_id in processed_events:
            return '', 200  # Already processed

        # Process event...
        processed_events.add(event_id)
        return '', 200
    ```
  </Accordion>

  <Accordion title="Données manquantes dans le payload" icon="question">
    **Solutions :**

    1. Vérifiez le payload complet dans l’historique de livraison du webhook
    2. Certains champs peuvent valoir `null` si les données n’existent pas, par exemple pour les problèmes non attribués
    3. Gérez les valeurs nulles dans le code de votre handler
    4. Consultez dans l’historique de livraison la structure du payload propre à chaque événement
  </Accordion>
</AccordionGroup>

### Consulter les statistiques des webhooks

Consultez les métriques de performance de vos webhooks :

1. Accédez à **Intégrations** → **Webhooks**
2. Consultez les statistiques de chaque webhook :
   * **Total des livraisons** : nombre total d’appels du webhook
   * **Livraisons réussies** : appels ayant obtenu une réponse 2xx
   * **Livraisons en échec** : appels ayant échoué ou expiré
   * **Taux de réussite** : pourcentage de livraisons réussies
   * **Échecs consécutifs** : nombre actuel d’échecs successifs
   * **Dernier déclenchement** : date du dernier déclenchement du webhook

***

### Réessai manuel

Si une livraison webhook a échoué, vous pouvez la réessayer manuellement :

1. Accédez à **Intégrations** → **Webhooks** → **History**
2. Repérez la livraison en échec
3. Cliquez sur **Retry**
4. Une nouvelle tentative de livraison est créée et envoyée immédiatement

***

### Exporter l’historique des livraisons

Pour la conformité ou le débogage, exportez l’historique de livraison du webhook :

1. Accédez à **Intégrations** → **Webhooks** → **History**
2. Appliquez les filtres voulus (plage de dates, type d’événement, statut, webhook)
3. Cliquez sur **Export** pour télécharger le fichier CSV
4. Utilisez l’export pour :
   * Audits de conformité
   * Analyse des performances
   * Analyse des schémas d’erreur
   * Suivi de la résolution des problèmes

***

### Conseils pour les tests

<Accordion title="Avant la mise en production">
  1. Utilisez [webhook.site](https://webhook.site) ou [RequestBin](https://requestbin.com) pour inspecter les payloads
  2. Commencez les tests avec des projets à faible volume
  3. Surveillez le taux de réussite des livraisons pendant les premiers jours
  4. Configurez des alertes pour les défaillances de webhook dans votre propre système
</Accordion>

<Accordion title="Liste de contrôle du débogage">
  * L’URL du webhook est correcte et accessible
  * L’endpoint renvoie un code d’état 2xx dans les 10 secondes
  * Le pare-feu autorise les requêtes de Corgea
  * Les abonnements aux événements sont sélectionnés
  * Les filtres sont correctement configurés (ou retirés pour les tests)
  * La vérification de signature fonctionne, si vous utilisez une clé secrète
  * Le webhook est actif et n’est pas en pause
</Accordion>

***

## Exemples de payloads

<Tabs>
  <Tab title="Statut du problème modifié">
    ```json issue-status-changed.json theme={null}
    {
      "event_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "event_type": "issue.status_changed",
      "timestamp": "2025-01-15T14:30:00.000Z",
      "data": {
        "company": "comp-uuid-1234",
        "issue_id": "issue-uuid-5678",
        "classification": "SQL Injection",
        "urgency": "HI",
        "status": "fixed",
        "previous_status": "open",
        "file_path": "src/controllers/user.py",
        "line_num": 45,
        "project": {
          "id": "proj-uuid-9012",
          "name": "Production API"
        },
        "scan_id": "scan-uuid-3456",
        "url": "https://app.corgea.com/issue/issue-uuid-5678/"
      }
    }
    ```
  </Tab>

  <Tab title="Scan lancé">
    ```json scan-started.json theme={null}
    {
      "event_id": "a0b1c2d3-e4f5-6789-abcd-ef0123456789",
      "event_type": "scan.started",
      "timestamp": "2025-01-15T15:40:00.000Z",
      "data": {
        "company": "comp-uuid-1234",
        "scan_id": "scan-uuid-7890",
        "run_id": "run-12345",
        "project": {
          "id": "proj-uuid-9012",
          "name": "Production API"
        },
        "project_name": "Production API",
        "branch": "main",
        "engine": "corgea-blast",
        "scan_type": "full",
        "status": "started",
        "pull_request_id": "42",
        "scan_url": "https://app.corgea.app/project/proj-uuid-9012/?scan_id=scan-uuid-7890",
        "true_positive_count": 0,
        "message": "Scan started for Production API (PR #42).",
        "scheduled_scan_ids": ["scheduled-scan-uuid"],
        "created_at": "2025-01-15T15:40:00.000Z"
      }
    }
    ```
  </Tab>

  <Tab title="Scan terminé">
    ```json scan-completed.json theme={null}
    {
      "event_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "event_type": "scan.completed",
      "timestamp": "2025-01-15T15:45:00.000Z",
      "data": {
        "company": "comp-uuid-1234",
        "scan_id": "scan-uuid-7890",
        "run_id": "run-12345",
        "project": {
          "id": "proj-uuid-9012",
          "name": "Production API"
        },
        "project_name": "Production API",
        "branch": "main",
        "engine": "corgea-blast",
        "scan_type": "full",
        "status": "completed",
        "pull_request_id": "42",
        "scan_url": "https://app.corgea.app/project/proj-uuid-9012/?scan_id=scan-uuid-7890",
        "true_positive_count": 5,
        "summary": {
          "total_issues": 8,
          "issues_with_fixes": 5,
          "issues_without_fixes": 3,
          "severity_breakdown": {
            "HI": {
              "name": "High",
              "count": 2
            },
            "ME": {
              "name": "Medium",
              "count": 6
            }
          },
          "classification_breakdown": [
            {
              "classification": "SQL Injection",
              "count": 2
            },
            {
              "classification": "Cross-Site Scripting (XSS)",
              "count": 1
            }
          ]
        },
        "message": "Scan completed for Production API (PR #42): 5 true-positive findings (5 with fixes). View: https://app.corgea.app/project/proj-uuid-9012/?scan_id=scan-uuid-7890",
        "scheduled_scan_ids": ["scheduled-scan-uuid"],
        "processed_at": "2025-01-15T15:45:00.000Z",
        "created_at": "2025-01-15T15:40:00.000Z"
      }
    }
    ```

    Zapier et les destinations Other reçoivent l’enveloppe imbriquée ci-dessus, que Corgea conserve également dans l’historique des livraisons. Pour `scan.*` et `webhook.test` uniquement, Slack Workflow Builder reçoit les champs de triage sous forme de clés de **premier niveau** dans le corps de la requête HTTP : `message`, `scan_id`, `scan_url`, `pull_request_id`, `true_positive_count`, `status`, `branch`, `project_name`, `company`, `run_id`, `engine`, `scan_type`, ainsi que `error` pour `scan.failed` lorsqu’il est disponible, et `company_id`, `test` et `webhook_name` pour `webhook.test`. Les champs `summary`, `project`, `scheduled_scan_ids`, `scan_errors`, `created_at` et `processed_at` ne sont pas aplatis. `data.message`, ou `message` au premier niveau, est un résumé en texte brut ; le suffixe « (N avec corrections) » compte uniquement les correctifs associés aux vrais positifs, et non tous les problèmes du scan.
  </Tab>

  <Tab title="Scan échoué">
    ```json scan-failed.json theme={null}
    {
      "event_id": "c1d2e3f4-a5b6-7890-cdef-1234567890ab",
      "event_type": "scan.failed",
      "timestamp": "2025-01-15T15:42:00.000Z",
      "data": {
        "company": "comp-uuid-1234",
        "scan_id": "scan-uuid-7890",
        "run_id": "run-12345",
        "project": {
          "id": "proj-uuid-9012",
          "name": "Production API"
        },
        "project_name": "Production API",
        "branch": "main",
        "engine": "corgea-blast",
        "scan_type": "full",
        "status": "failed",
        "pull_request_id": "42",
        "scan_url": "https://app.corgea.app/project/proj-uuid-9012/?scan_id=scan-uuid-7890",
        "true_positive_count": 0,
        "error": "Scanner timed out",
        "scan_errors": null,
        "message": "Scan failed for Production API (PR #42): Scanner timed out. View: https://app.corgea.app/project/proj-uuid-9012/?scan_id=scan-uuid-7890",
        "scheduled_scan_ids": ["scheduled-scan-uuid"],
        "created_at": "2025-01-15T15:40:00.000Z"
      }
    }
    ```

    `data.message` inclut la raison de l’échec, tronquée au-delà de 200 caractères, et l’URL du scan lorsqu’elle est disponible. Utilisez `data.error` et `data.scan_errors` pour consulter les détails bruts de l’échec. Dans Slack Workflow Builder, `error` est également disponible sous forme de champ plat de premier niveau.
  </Tab>

  <Tab title="Issue attribuée">
    ```json issue-assigned.json theme={null}
    {
      "event_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
      "event_type": "issue.assigned",
      "timestamp": "2025-01-15T16:00:00.000Z",
      "data": {
        "company": "comp-uuid-1234",
        "issue_id": "issue-uuid-5678",
        "classification": "Cross-Site Scripting (XSS)",
        "urgency": "ME",
        "status": "open",
        "assigned_to": {
          "id": "user-uuid-1111",
          "email": "jane.doe@company.com",
          "name": "Jane Doe"
        },
        "previously_assigned_to": {
          "id": "user-uuid-2222",
          "email": "john.smith@company.com",
          "name": "John Smith"
        },
        "project": {
          "id": "proj-uuid-9012",
          "name": "Production API"
        },
        "url": "https://app.corgea.com/issue/issue-uuid-5678/"
      }
    }
    ```
  </Tab>

  <Tab title="SLA Violation">
    ```json sla-violation.json theme={null}
    {
      "event_id": "f6a7b8c9-d0e1-2345-f012-345678901234",
      "event_type": "sla.violation",
      "timestamp": "2025-01-15T16:20:00.000Z",
      "data": {
        "company": "comp-uuid-1234",
        "sla": {
          "id": 3,
          "rule_type": "sca",
          "urgency": ["CR", "HI"],
          "remediation_days": 14,
          "escalation_days": 7
        },
        "notification_type": "escalation",
        "issue_kind": "SCA",
        "issue_count": 12,
        "summary_message": "Plain-text summary of breached issues...",
        "projects": [
          {
            "id": "proj-uuid-9012",
            "name": "Production API",
            "url": "https://app.corgea.com/project/proj-uuid-9012",
            "issue_count": 12,
            "urgency_counts": {
              "Critical": 4,
              "High": 8
            }
          }
        ]
      }
    }
    ```
  </Tab>

  <Tab title="Connexion utilisateur">
    ```json user-login.json theme={null}
    {
      "event_id": "d4e5f6a7-b8c9-0123-def0-123456789012",
      "event_type": "user.login",
      "timestamp": "2025-01-15T16:10:00.000Z",
      "data": {
        "company": "comp-uuid-1234",
        "user_id": 123,
        "username": "jane.doe",
        "email": "jane.doe@company.com",
        "first_name": "Jane",
        "last_name": "Doe",
        "user_agent": "Mozilla/5.0",
        "path": "/login/"
      }
    }
    ```
  </Tab>

  <Tab title="Échec de la connexion utilisateur">
    ```json user-login-failed.json theme={null}
    {
      "event_id": "e5f6a7b8-c9d0-1234-ef01-234567890123",
      "event_type": "user.login_failed",
      "timestamp": "2025-01-15T16:12:00.000Z",
      "data": {
        "company": "comp-uuid-1234",
        "username": "jane.doe",
        "user_agent": "Mozilla/5.0",
        "path": "/login/"
      }
    }
    ```
  </Tab>

  <Tab title="Rapport quotidien de scan planifié">
    ```json scheduled-scan-daily-report.json theme={null}
    {
      "event_id": "3282dbbb-7392-476b-8ce2-19fc1070342c",
      "event_type": "scheduled_scan.daily_report",
      "timestamp": "2026-05-13T12:29:53.083616+00:00",
      "data": {
        "title": "🐕 Corgea Daily Scan Report",
        "company": "123",
        "company_name": "Acme Corp",
        "total_new_issues": 7,
        "message": "Daily scan report for Acme Corp: 7 new issues detected across 2 scan runs.",
        "scan_runs": [
          {
            "scheduled_scan_name": "Nightly API Scan",
            "project": "api-service",
            "new_issue_count": 5,
            "scan_url": "https://app.corgea.com/scans/abc123"
          },
          {
            "scheduled_scan_name": "Nightly Frontend Scan",
            "project": "frontend",
            "new_issue_count": 2,
            "scan_url": "https://app.corgea.com/scans/def456"
          }
        ]
      }
    }
    ```

    L’enveloppe externe (`event_id`, `event_type`, `timestamp`, `data`) respecte la [structure standard du payload](#payload-structure). L’objet `data` contient :

    | Champ                             | Type           | Description                                                                             |
    | --------------------------------- | -------------- | --------------------------------------------------------------------------------------- |
    | `title`                           | string         | Titre affiché du rapport                                                                |
    | `company`                         | string         | ID de l’entreprise                                                                      |
    | `company_name`                    | string         | Nom affiché de l’entreprise                                                             |
    | `total_new_issues`                | integer        | Somme des nouveaux problèmes de toutes les exécutions de scan du payload                |
    | `message`                         | string         | Résumé lisible, adapté aux notifications en texte brut telles que Slack                 |
    | `scan_runs`                       | array          | Une entrée par exécution de scan ayant produit au moins un nouveau résultat             |
    | `scan_runs[].scheduled_scan_name` | string         | Nom de la configuration du scan planifié                                                |
    | `scan_runs[].project`             | string \| null | Nom du projet, ou `null` si aucun projet n’est associé                                  |
    | `scan_runs[].new_issue_count`     | integer        | Nombre de nouveaux problèmes détectés pendant cette exécution                           |
    | `scan_runs[].scan_url`            | string \| null | Lien direct vers les résultats du scan dans Corgea, ou `null` s’il n’est pas disponible |
  </Tab>
</Tabs>

***

## FAQ

<AccordionGroup>
  <Accordion title="Puis-je utiliser la même URL de webhook pour plusieurs types d’événements ?">
    Oui. Votre endpoint reçoit un en-tête `X-Corgea-Event` et un champ `event_type` permettant d’identifier l’événement.
  </Accordion>

  <Accordion title="Combien de webhooks puis-je créer ?">
    Il n’y a pas de limite stricte, mais nous recommandons d’organiser par objectif (par exemple, un par équipe ou par outil).
  </Accordion>

  <Accordion title="Que se passe-t-il si mon endpoint est hors service ?">
    Corgea effectue trois tentatives avec un backoff exponentiel. Après 10 échecs consécutifs, le webhook se met automatiquement en pause.
  </Accordion>

  <Accordion title="Puis-je tester des webhooks sans déclencher de réels événements ?">
    Oui. Utilisez le bouton « Test Webhook » pour envoyer un exemple de payload sans attendre un événement réel. Pour Slack Workflow Builder, cet exemple est plat et comprend un champ `message` non vide ainsi que les clés de triage `pull_request_id`, `scan_url`, `true_positive_count` et `company`. `company_id` est également inclus avec la même valeur pour assurer la compatibilité avec les anciens consommateurs des événements de test.
  </Accordion>

  <Accordion title="Puis-je limiter les notifications aux échecs de scans de pull request et aux scans terminés comportant des résultats ?">
    Oui. Sous **Filtres d’événements de scan**, activez **Uniquement les scans de pull request ou de merge request** et **Uniquement les scans terminés comportant de vrais positifs**. Abonnez-vous à `scan.failed` et `scan.completed`. Le filtre des résultats ne s’applique pas à `scan.failed`.
  </Accordion>

  <Accordion title="Les webhooks prennent-ils en charge l’authentification ?">
    Oui. Corgea génère automatiquement une clé secrète permettant de vérifier la signature HMAC (`X-Corgea-Signature`). Vous pouvez aussi ajouter des en-têtes personnalisés pour les tokens d’authentification propres à la destination.
  </Accordion>

  <Accordion title="Puis-je filtrer les webhooks selon des branches spécifiques ?">
    Pas directement, mais vous pouvez filtrer par projet, puis filtrer le payload reçu dans votre endpoint.
  </Accordion>

  <Accordion title="Les payloads des webhooks sont-ils chiffrés ?">
    Les payloads sont envoyés par HTTPS (TLS), ce qui assure leur chiffrement en transit. Utilisez les signatures HMAC pour vérifier leur authenticité.
  </Accordion>

  <Accordion title="Combien de temps les journaux de livraison de webhook sont-ils conservés ?">
    Les logs de livraison sont conservés à des fins de conformité et de débogage. Consultez votre offre pour connaître la durée de conservation applicable.
  </Accordion>

  <Accordion title="Puis-je réessayer un webhook manuellement ?">
    Oui. Dans l’historique des livraisons du webhook, cliquez sur « Retry » pour la livraison en échec.
  </Accordion>

  <Accordion title="À partir de quelles adresses IP Corgea envoie-t-il les webhooks ?">
    Contactez le support pour obtenir la liste à jour des adresses IP à ajouter à la liste d’autorisation de votre pare-feu.
  </Accordion>
</AccordionGroup>

***

**Une question ou un problème ?** Contactez le [support Corgea](mailto:support@corgea.com).
