# DELETE /partner/webhooks/{webhook_id}

Supprimer définitivement un abonnement aux notifications et le secret de signature qui lui est attaché. Droit webhooks:write, et confirmation obligatoire par l'adresse de l'abonnement.

Source : https://docs.sealtrust.io/reference/delete-partner-webhooks-id/

---

Vous supprimez définitivement un abonnement aux notifications de votre marque.
En quittant cette page, vous saurez construire l'appel, y compris la
confirmation obligatoire, et vous saurez ce que la suppression détruit avec
l'abonnement.

Adresse complète :

```http
DELETE https://api.sealtrust.io/v1/partner/webhooks/{webhook_id}?confirm={url}
```

Le même point d'entrée répond aussi sans le préfixe `/v1`, à
`https://api.sealtrust.io/partner/webhooks/{webhook_id}`. Les deux adresses
appellent le même code. Utilisez la forme `/v1` pour une nouvelle intégration.

> [!DANGER] Cette suppression est définitive
> L'abonnement cesse de recevoir des événements et le secret que vous aviez
> fourni à la création, ou lors d'une modification, est effacé de notre base.
> Si vous recréez ensuite un abonnement pour la même adresse, c'est vous qui
> choisissez son secret : reprenez le même et votre système de réception
> continue de vérifier les signatures, choisissez-en un autre et vous devez le
> reconfigurer. Un abonnement créé sans secret reçoit des livraisons non
> signées, il n'y a alors aucun secret à détruire. Il n'existe aucune
> annulation.

## Autorisation

Clef d'API dans l'en-tête `Authorization`, au format `Bearer`.

La suppression elle-même exige le droit `webhooks:write`. La lecture préalable
de l'adresse, nécessaire pour construire la confirmation, exige en plus le
droit `webhooks:read`. En pratique, la clef qui exécute cette séquence porte
les deux droits. Une clef qui ne porte pas le droit exigé reçoit un 403 dont le
message nomme le droit manquant.

Un abonnement n'est visible et supprimable que par une clef de la marque à
laquelle il appartient. Un numéro d'abonnement qui appartient à une autre
marque répond 404, comme un numéro qui n'existe pas. La réponse ne dit jamais
si l'abonnement existe ailleurs.

Cette suppression reste ouverte quelle que soit votre offre. Si votre offre ne
comprend plus les notifications, vous pouvez toujours supprimer les abonnements
enregistrés en votre nom. Ce sont la création et la modification qui exigent
que l'offre comprenne les notifications.

### Confirmation obligatoire

En plus des droits, l'appel exige une confirmation. Le serveur compare la
valeur du paramètre de requête `confirm` à l'adresse qu'il a stockée pour ce
numéro d'abonnement. Trois cas.

| Ce que vous envoyez | Réponse | Effet |
| --- | --- | --- |
| `confirm` absent ou vide | 400, code `CONFIRMATION_REQUIRED` | Rien n'est supprimé. |
| `confirm` différent de l'adresse stockée | 400, code `CONFIRMATION_MISMATCH` | Rien n'est supprimé. |
| `confirm` égal à l'adresse stockée | 204 | L'abonnement et son secret sont détruits. |

La comparaison tolère la casse, les espaces de début et de fin, et les formes
Unicode équivalentes. Elle ne tolère rien d'autre. Un caractère de ponctuation
en trop ou un segment d'adresse manquant donne un `CONFIRMATION_MISMATCH`.

Le message d'erreur ne vous renvoie jamais l'adresse attendue. Lisez-la avec
`GET /v1/partner/webhooks/{webhook_id}` ou dans la liste rendue par
`GET /v1/partner/webhooks`, champ `url`. Ces deux lectures exigent le droit
`webhooks:read`.

> [!ATTENTION] Un appel qui n'envoie que le numéro d'abonnement est refusé
> C'est une rupture de compatibilité assumée. Un appel qui fonctionnait en
> envoyant uniquement le numéro reçoit aujourd'hui un 400
> `CONFIRMATION_REQUIRED`. Ajoutez la confirmation dans votre code.

## Plafond d'appels

Le débit est mesuré sur une fenêtre fixe de 60 secondes. Nous appliquons
d'abord la valeur posée sur votre marque, si nous en avons posé une. Sinon
celle de votre offre. En l'absence des deux, la valeur de repli est de 120
appels par fenêtre.

Deux compteurs se superposent, avec le même plafond : un par clef, un pour la
somme de toutes les clefs de votre marque. Créer des clefs supplémentaires
n'augmente donc pas le débit total autorisé.

La réponse porte deux jeux d'en-têtes `X-RateLimit-*`, et les deux jeux
portent les mêmes noms d'en-tête. Retenez les valeurs du jeu accompagné de
`X-RateLimit-Scope` : c'est celui qui décrit le plafond de votre clef ou celui
de votre marque. Le second jeu vient d'un compteur par adresse IP et ne décrit
pas le budget de votre clef. Lisez la liste complète des en-têtes de la réponse
avant de vous fier à une valeur.

| En-tête | Contenu |
| --- | --- |
| `X-RateLimit-Limit` | le plafond appliqué sur la fenêtre |
| `X-RateLimit-Remaining` | ce qu'il vous reste dans la fenêtre en cours |
| `X-RateLimit-Reset` | l'horodatage de fin de la fenêtre, en secondes |
| `X-RateLimit-Scope` | `key` ou `brand`, le compteur qui a servi de référence |

Le jeu qui porte `X-RateLimit-Scope` est présent sur la réponse 204 et sur les
réponses d'erreur qui suivent le contrôle de débit.

> [!ATTENTION] Ces en-têtes se lisent depuis un serveur
> Un code exécuté dans un navigateur ne voit ni `X-RateLimit-*`, ni
> `Retry-After`, ni `x-request-id`. Notre politique de partage entre origines
> n'expose que `x-total-count`. Une clef d'API partenaire n'a de toute façon
> pas sa place dans un navigateur, où elle serait lisible par n'importe qui.

Un refus renvoie 429 avec `Retry-After`, exprimé en secondes restantes dans la
fenêtre en cours. Cette valeur n'est jamais inférieure à 1.

> [!INFO] Cette suppression ne consomme aucun quota
> Le quota quotidien de votre clef n'est pas entamé par cet appel, et le quota
> mensuel de produits de votre offre non plus. Seul le plafond de débit
> s'applique.

> [!ATTENTION] Une indisponibilité du service de plafonnement refuse l'appel
> Quand le service qui compte les appels est momentanément indisponible, la
> réponse est 503 et rien n'est supprimé. Réessayez plus tard, puis vérifiez
> l'état de l'abonnement avec `GET /v1/partner/webhooks/{webhook_id}`.

## Paramètres de chemin et de requête

| Nom | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `webhook_id` | `integer` | oui | Le numéro de l'abonnement à supprimer, tel que la création, la liste et la lecture le rendent dans le champ `id`. |
| `confirm` | `string` | oui | L'adresse enregistrée de l'abonnement, exactement telle que `GET /v1/partner/webhooks/{webhook_id}` la rend dans le champ `url`. Absente ou différente, la suppression est refusée en 400. |

### En-têtes

| Nom | Type | Obligatoire | Description |
| --- | --- | --- | --- |
| `Authorization` | `string` | oui | `Bearer` suivi de votre clef d'API. |

## Corps de la requête

Ce point d'entrée n'a pas de corps de requête. Toute l'information que vous
envoyez tient dans le numéro d'abonnement et dans le paramètre `confirm`.

## Requête d'exemple

Suppression de l'abonnement numéro 7, dont l'adresse enregistrée est
`https://exemple-sas.test/sealtrust/evenements`. Les trois exemples font la
même chose : ils lisent l'abonnement, puis ils le suppriment en renvoyant son
adresse. La clef utilisée porte les deux droits `webhooks:read` et
`webhooks:write`, la lecture de la première étape exigeant le premier et la
suppression de la seconde exigeant le second.

:::onglets
```bash title="curl"
# 1. Lire l'abonnement pour connaître son adresse enregistrée.
curl -i https://api.sealtrust.io/v1/partner/webhooks/7 \
  -H "Authorization: Bearer st_test_0000000000000000000000000000000000000000000000"

# 2. Supprimer en renvoyant cette adresse dans confirm.
curl -i -X DELETE \
  "https://api.sealtrust.io/v1/partner/webhooks/7?confirm=https://exemple-sas.test/sealtrust/evenements" \
  -H "Authorization: Bearer st_test_0000000000000000000000000000000000000000000000"
```
```typescript
import { SealTrustClient } from "@sealtrust-io/sdk";

const sealtrust = new SealTrustClient({
  apiKey: "st_test_0000000000000000000000000000000000000000000000",
});

// 1. Lire l'abonnement pour connaître son adresse enregistrée.
const abonnement = await sealtrust.webhooks.get(7);
console.log(abonnement.url); // https://exemple-sas.test/sealtrust/evenements

// 2. Supprimer en renvoyant cette adresse.
await sealtrust.webhooks.delete(abonnement.id, abonnement.url);
```
```python
import requests

entetes = {
    "Authorization": "Bearer st_test_0000000000000000000000000000000000000000000000",
}

# 1. Lire l'abonnement pour connaître son adresse enregistrée.
lecture = requests.get(
    "https://api.sealtrust.io/v1/partner/webhooks/7",
    headers=entetes,
    timeout=30,
)
lecture.raise_for_status()
adresse = lecture.json()["url"]
print(adresse)  # https://exemple-sas.test/sealtrust/evenements

# 2. Supprimer en renvoyant cette adresse.
suppression = requests.delete(
    "https://api.sealtrust.io/v1/partner/webhooks/7",
    headers=entetes,
    params={"confirm": adresse},
    timeout=30,
)

print(suppression.status_code)  # 204
```
:::

Le paramètre `confirm` voyage dans l'adresse de la requête. Si votre outil ne
le fait pas pour vous, encodez sa valeur au format pourcent avant de l'écrire.

> [!INFO] Ce que la confirmation attrape, et ce qu'elle n'attrape pas
> Elle empêche la suppression d'agir sur un numéro seul. Elle attrape donc un
> numéro périmé, un numéro deviné en parcourant une suite d'entiers, ou un
> numéro copié depuis un autre environnement : dans ces trois cas, l'adresse
> que vous envoyez ne correspond pas à celle qui est stockée, et vous recevez
> un 400 au lieu d'une suppression. Elle n'attrape rien d'autre. Un script qui
> relit toujours l'adresse à partir du même numéro confirmera le mauvais
> abonnement aussi bien que le bon. Quand vous détenez déjà l'adresse dans
> votre configuration, envoyez-la depuis votre configuration.

## Réponse d'exemple

Code HTTP `204`. Le corps est vide.

```http
HTTP/1.1 204 No Content
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
X-RateLimit-Reset: 1755676800
X-RateLimit-Scope: key
x-ratelimit-limit: 600
x-ratelimit-remaining: 597
x-ratelimit-reset: 1755676800
x-request-id: 00000000000000000000000000000000
```

Les quatre premiers en-têtes décrivent votre plafond de clef ou de marque. Les
trois suivants viennent du compteur par adresse IP. `x-request-id` identifie
l'appel dans nos journaux et accompagne toutes les réponses.

Après ce 204, l'abonnement n'apparaît plus dans `GET /v1/partner/webhooks`, et
`GET /v1/partner/webhooks/{webhook_id}` répond 404 pour ce numéro. Les
événements ne sont plus livrés à cette adresse.

## Erreurs

Le corps d'une réponse d'erreur porte un champ `detail`. Sur les deux refus de
confirmation, ce champ est un objet qui contient `code`, `message` et
`what_to_type`. Dans les autres cas, il contient une phrase ou une liste.

Exemple de corps d'un refus de confirmation, code HTTP `400` :

```json
{
  "detail": {
    "code": "CONFIRMATION_MISMATCH",
    "message": "What you typed is not the subscription's url. Nothing was changed. This endpoint stops receiving events and its signing secret is destroyed. A new subscription for the same url gets a different secret, so the receiver must be reconfigured. Read the url from GET /partner/webhooks/{id}.",
    "what_to_type": "the subscription's url"
  }
}
```

Ce message est renvoyé tel quel par le service, en anglais. Sur le secret, la
phrase à retenir est celle de l'encadré en haut de page : le secret d'un
nouvel abonnement est celui que vous choisissez.

| Code | Condition | Que faire |
| --- | --- | --- |
| 400 | `confirm` est absent ou vide. `detail.code` vaut `CONFIRMATION_REQUIRED`. Rien n'a été supprimé. | Lisez l'abonnement avec `GET /v1/partner/webhooks/{webhook_id}` et renvoyez son champ `url` dans `confirm`. |
| 400 | `confirm` ne correspond pas à l'adresse enregistrée de cet abonnement. `detail.code` vaut `CONFIRMATION_MISMATCH`. Rien n'a été supprimé. | Le numéro d'abonnement ne désigne pas l'abonnement que vous croyez. Relisez-le avant de recommencer. Le message ne vous rend jamais l'adresse attendue. |
| 401 | L'en-tête `Authorization` est absent. `detail` vaut `Missing Authorization header`. La réponse porte aussi `WWW-Authenticate: Bearer`. | Ajoutez l'en-tête. |
| 401 | L'en-tête `Authorization` ne commence pas par `Bearer ` suivi d'un espace. `detail` vaut `Invalid Authorization header format (expected 'Bearer <token>')`. La réponse porte aussi `WWW-Authenticate: Bearer`. | Corrigez la forme de l'en-tête. |
| 401 | La valeur envoyée après `Bearer ` fait moins de 40 caractères. `detail` vaut `Invalid API key format`. | Vérifiez que vous envoyez le secret complet, sans troncature, sans espace ni retour à la ligne. Cette réponse ne porte pas `WWW-Authenticate`. |
| 401 | La clef est inconnue de nos registres. `detail` vaut `Invalid API key`. | Vérifiez que vous utilisez une clef de cet environnement, et qu'elle n'a pas été remplacée. Cette réponse ne porte pas `WWW-Authenticate`. |
| 403 | La clef n'est pas au statut `active`. `detail` vaut `API key is <statut>` et nomme le statut réel, par exemple `revoked`. | Créez une nouvelle clef dans la console. |
| 403 | La clef a atteint sa date d'expiration. `detail` vaut `API key has expired`. | Créez une nouvelle clef. L'ancienne ne redeviendra jamais valide. |
| 403 | La clef ne porte pas le droit `webhooks:write`. `detail` vaut `Missing required scope: webhooks:write`. | Créez une clef portant ce droit. Les droits d'une clef existante ne se modifient pas. |
| 404 | Aucun abonnement ne porte ce numéro dans votre marque. `detail` vaut `Webhook subscription not found`. | Vérifiez le numéro avec `GET /v1/partner/webhooks`. Un abonnement d'une autre marque donne la même réponse. Un abonnement déjà supprimé aussi. |
| 422 | Le numéro envoyé dans le chemin n'est pas un entier. `detail` est une liste qui nomme le paramètre fautif. | Envoyez le champ `id` tel que la lecture le rend, sans guillemets ni décimale. |
| 422 | Le numéro envoyé est un entier hors des bornes que le service accepte. `detail` est une phrase générique qui ne nomme pas le paramètre. | Envoyez un numéro d'abonnement rendu par la liste. |
| 429 | Le plafond de débit de la clef est atteint. `Retry-After` et la famille `X-RateLimit-*` accompagnent la réponse, avec `X-RateLimit-Scope: key`. Rien n'a été supprimé. | Attendez le nombre de secondes indiqué par `Retry-After`, puis réessayez. |
| 429 | Le plafond de débit de la marque est atteint, toutes clefs confondues. `X-RateLimit-Scope` vaut `brand`. Rien n'a été supprimé. | Attendez le nombre de secondes indiqué par `Retry-After`. Créer une clef supplémentaire ne relève pas ce plafond. |
| 500 | L'abonnement n'a aucune adresse enregistrée, il n'y a donc rien à confirmer. `detail.code` vaut `CONFIRMATION_IMPOSSIBLE`. Rien n'a été supprimé. | Contactez le support en indiquant le numéro d'abonnement et la valeur de `x-request-id`. |
| 500 | Une erreur inattendue s'est produite pendant le traitement de votre appel. `detail` est une phrase courte, sans détail technique, et la réponse porte un en-tête `x-request-id`. | Vérifiez l'état de l'abonnement avec `GET /v1/partner/webhooks/{webhook_id}` avant de recommencer. Si l'erreur persiste, contactez le support en indiquant la valeur de `x-request-id`. |
| 503 | Le service de plafonnement des appels est momentanément indisponible. `detail` vaut `Rate limiting temporarily unavailable, please retry shortly`. L'appel est refusé et rien n'est supprimé. | Réessayez dans quelques instants. |

Une suppression déjà effectuée renvoie 404 au second appel. Ce point d'entrée
n'est donc pas rejouable : traitez le 404 comme la confirmation que
l'abonnement n'existe plus.

## Voir aussi

- [`GET /partner/webhooks/{webhook_id}`](/reference/get-partner-webhooks-id/),
  lire un abonnement et son état de livraison.
- [`PUT /partner/webhooks/{webhook_id}`](/reference/put-partner-webhooks-id/),
  modifier l'adresse, les événements ou le secret d'un abonnement.
- [`GET /partner/webhooks`](/reference/get-partner-webhooks/),
  lister vos abonnements aux notifications, page par page.
- [Recevoir les événements par webhook](/webhooks/),
  créer un abonnement, vérifier une signature, rattraper les événements
  perdus.
