Méthode PUT/partner /webhooks /{webhook_id}
Modifier un abonnement aux notifications : son adresse de destination, sa liste d'événements, son secret de signature, son activation. Droit webhooks:write.
Sur cette page
Vous modifiez un abonnement aux notifications que votre marque possède déjà, et vous recevez l'abonnement dans son nouvel état.
#Autorisation
Envoyez votre clef d'API dans l'en-tête Authorization, au format Bearer
suivi d'un espace puis de la clef. La clef doit porter le droit
webhooks:write. Une clef qui ne porte pas ce droit reçoit un 403 dont le
message nomme le droit manquant.
| Ce que nous exigeons | Valeur |
|---|---|
| Authentification | clef d'API de votre marque |
| Droit porté par la clef | webhooks:write |
| Fonctionnalité de votre offre | les notifications par webhook |
Deux conditions s'ajoutent au droit de la clef.
- L'abonnement doit appartenir à la marque de la clef. Nous cherchons l'abonnement par son numéro et par votre marque. Quand cette recherche ne trouve rien, vous recevez un 404. Un abonnement qui appartient à une autre marque donne exactement la même réponse. Cette route ne vous apprend donc jamais qu'un numéro existe ailleurs.
- L'offre de votre marque doit comprendre les notifications. Sinon vous recevez
un 403 portant le code
FEATURE_NOT_AVAILABLE. Une exception existe, décrite juste en dessous.
L'adresse complète de ce point d'entrée est
https://api.sealtrust.io/v1/partner/webhooks/{webhook_id}. 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.
#Plafond d'appels
Nous mesurons le débit sur une fenêtre fixe de 60 secondes. Le plafond monte avec votre offre, et nous pouvons poser une valeur sur votre marque qui gagne sur celle de votre offre. Nous lisons donc, dans cet ordre : la valeur posée sur votre marque, puis celle de votre offre, puis une valeur de repli de 120 appels par fenêtre. Cette valeur de repli ne sert que si votre marque et votre offre n'en portent aucune.
Ne devinez pas votre plafond du moment. Vous le lisez sur chaque réponse qui franchit le contrôle de débit.
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é.
Quatre en-têtes décrivent le compteur le plus contraignant des deux.
| 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 |
Un refus de débit renvoie 429 avec Retry-After, exprimé en secondes restantes
dans la fenêtre en cours. Cette valeur n'est jamais inférieure à 1.
Ce point d'entrée ne consomme aucun quota quotidien de clef et aucun quota mensuel d'offre. Le plafond de débit est le seul compteur qui s'applique ici.
#Paramètres de chemin et de requête
| Nom | Type | Obligatoire | Description |
|---|---|---|---|
webhook_id | integer | oui | Le numéro de l'abonnement à modifier, dans le chemin. Une valeur qui n'est pas un entier donne un 422. |
Ce point d'entrée n'a aucun paramètre de requête.
#En-têtes
| Nom | Type | Obligatoire | Description |
|---|---|---|---|
Authorization | string | oui | Bearer suivi d'un espace puis de votre clef d'API. |
Content-Type | string | oui | application/json. |
Idempotency-Key | string | non | Ce point d'entrée ne déclare pas cet en-tête. Il ne le lit pas et ne le mémorise pas. |
#Corps de la requête
Le corps est un objet JSON. Les quatre champs sont facultatifs. Envoyez uniquement les champs que vous voulez changer. Un champ absent du corps garde sa valeur.
| Nom | Type | Obligatoire | Description |
|---|---|---|---|
url | string | non | La nouvelle adresse de destination, de 10 à 2048 caractères. Elle doit commencer par https://. N'envoyez jamais null dans ce champ, lisez l'avertissement ci-dessous. |
events | array de string | non | La nouvelle liste des types d'événements. Elle remplace l'ancienne liste en entier. Chaque valeur doit appartenir à la liste ci-dessous. |
is_active | boolean | non | true pour recevoir les événements, false pour arrêter les livraisons sans détruire l'abonnement. Ce champ accepte true ou false. Omettez-le si vous ne voulez pas le changer. |
secret | string | non | Le nouveau secret de signature, jusqu'à 128 caractères. Nous l'utilisons pour calculer l'en-tête X-Webhook-Signature de chaque livraison. null efface le secret, et les livraisons suivantes partent alors sans signature. |
Le serveur refuse tout champ que ce tableau ne nomme pas. Un champ inconnu fait échouer la requête en 422, et nous ne modifions rien.
Un corps vide, écrit {}, est valide. Il ne modifie rien, il renvoie
l'abonnement inchangé, et nous exigeons l'offre comme pour n'importe quelle
autre modification.
#Les 23 types d'événements
Une valeur de events qui n'est pas dans cette liste fait échouer la requête en
422, et le message nomme les valeurs refusées.
| Famille | Types |
|---|---|
| Cycle de vie du produit | product.minted, product.transferred, product.burned, product.status_changed |
| Lots | batch.completed, batch.failed |
| Certificat | certificate.issued |
| Distribution et sécurité | product.scanned, product.gray_market, clone.alert, transfer.accepted |
| Retours | return.requested, return.received, return.completed, return.rejected, return.expired |
| Garantie | warranty.claimed, warranty.expiring_soon |
| Rachat | buyback.offered, buyback.accepted, buyback.declined, buyback.completed, buyback.expired |
#Requête d'exemple
Vous repointez l'abonnement numéro 128 vers une nouvelle adresse et vous
réduisez sa liste à deux types d'événements.
curl -i -X PUT https://api.sealtrust.io/v1/partner/webhooks/128 \
-H "Authorization: Bearer st_test_0000000000000000000000000000000000000000000000" \
-H "Content-Type: application/json" \
-d '{
"url": "https://exemple-sas.example.com/sealtrust/evenements",
"events": ["product.minted", "batch.completed"]
}'import { SealTrustClient } from "@sealtrust-io/sdk";
const sealtrust = new SealTrustClient({
apiKey: "st_test_0000000000000000000000000000000000000000000000",
});
const abonnement = await sealtrust.webhooks.update(128, {
url: "https://exemple-sas.example.com/sealtrust/evenements",
events: ["product.minted", "batch.completed"],
});
console.log(abonnement.id, abonnement.url, abonnement.events);import requests
response = requests.put(
"https://api.sealtrust.io/v1/partner/webhooks/128",
headers={
"Authorization": "Bearer st_test_0000000000000000000000000000000000000000000000",
},
json={
"url": "https://exemple-sas.example.com/sealtrust/evenements",
"events": ["product.minted", "batch.completed"],
},
timeout=30,
)
print(response.status_code)
print(response.headers.get("X-RateLimit-Remaining"))
print(response.json())#Réponse d'exemple
Code HTTP 200OK
Code HTTP 200.
{
"id": 128,
"brand_id": 12,
"url": "https://exemple-sas.example.com/sealtrust/evenements",
"events": ["product.minted", "batch.completed"],
"is_active": true,
"health": "healthy",
"created_at": "2026-08-18T09:12:44.512038+00:00",
"updated_at": "2026-08-20T14:03:21.884517+00:00"
}La réponse compte huit champs et rien d'autre. Le secret n'y figure jamais.
| Champ | Type | Description |
|---|---|---|
id | integer | Le numéro de l'abonnement. |
brand_id | integer | Le numéro de votre marque. |
url | string | L'adresse de destination enregistrée. Relisez-la après chaque modification. |
events | array de string | La liste des types d'événements enregistrée. |
is_active | boolean | true si l'abonnement reçoit les événements. |
health | string | healthy ou degraded. Vaut degraded après l'échec définitif d'une livraison, et revient à healthy à la première livraison réussie. |
created_at | string | La date de création de l'abonnement, en temps universel. |
updated_at | string | La date de la dernière modification, en temps universel. |
#Erreurs
Le corps d'une réponse d'erreur porte un champ detail. Selon le cas, ce champ
contient une phrase, une liste ou un objet.
| Code | Condition | Que faire |
|---|---|---|
| 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. La réponse porte aussi WWW-Authenticate: Bearer. | Corrigez la forme de l'en-tête. |
| 401 | La clef envoyée est vide, ou fait moins de 40 caractères. detail vaut Invalid API key format. | Envoyez la clef entière. Une clef tronquée à l'affichage donne cette réponse. |
| 401 | La clef envoyée est inconnue. detail vaut Invalid API key. | Vérifiez que vous envoyez la clef complète, sans espace ni retour à la ligne. |
| 403 | La clef n'est plus active, parce qu'elle a été révoquée. detail nomme son état. | 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. |
| 403 | L'offre de votre marque ne comprend pas les notifications. detail vaut {"code": "FEATURE_NOT_AVAILABLE", "feature": "webhooks"}. | Changez d'offre depuis la console, ou contactez-nous. Vous pouvez toujours éteindre l'abonnement avec un corps réduit à {"is_active": false}. |
| 404 | Aucun abonnement ne porte ce numéro pour votre marque. detail vaut Webhook subscription not found. | Vérifiez le numéro avec GET /v1/partner/webhooks. Vous recevez la même réponse si l'abonnement appartient à une autre marque. |
| 422 | Le webhook_id du chemin n'est pas un entier. | Envoyez le numéro rendu par GET /v1/partner/webhooks. |
| 422 | Le webhook_id du chemin est un entier trop grand pour être un numéro d'abonnement. Le message parle de paramètre de requête, alors que la valeur fautive est dans le chemin. | Envoyez le numéro rendu par GET /v1/partner/webhooks. |
| 422 | Le corps contient un champ que ce point d'entrée ne connaît pas. | Retirez ce champ. Nous n'acceptons que url, events, is_active et secret. |
| 422 | url est une chaîne qui ne commence pas par https://. | Corrigez l'adresse pour qu'elle commence par https://. |
| 422 | url est une chaîne de moins de 10 ou de plus de 2048 caractères. | Corrigez la longueur de l'adresse. |
| 422 | events contient au moins un type inconnu. Le message nomme les valeurs refusées. | Reprenez les valeurs du tableau des 23 types d'événements. |
| 422 | secret dépasse 128 caractères. | Raccourcissez le secret. |
| 422 | Un champ ne porte pas le type annoncé, par exemple url reçoit un nombre ou is_active reçoit une chaîne. | Corrigez le type. Le message nomme le champ fautif. |
| 422 | Le corps n'est pas un objet JSON, ou le corps est absent. | Envoyez un objet JSON, même vide, avec Content-Type: application/json. |
| 429 | Le plafond de débit de la clef est atteint. Les en-têtes Retry-After et la famille X-RateLimit-* accompagnent la réponse, avec X-RateLimit-Scope: key. | 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. | Attendez le nombre de secondes indiqué par Retry-After. Créer une clef supplémentaire ne relève pas ce plafond. |
| 500 | Une erreur inattendue s'est produite. detail vaut Internal Server Error. | Réessayez. Si l'erreur persiste, contactez le support en donnant l'en-tête X-Request-Id de la réponse. |
| 503 | Le service de plafonnement des appels est momentanément indisponible. Nous refusons l'appel avant toute lecture. | Réessayez dans quelques instants. L'abonnement n'a pas été modifié. |
#Voir aussi
GET /partner/webhooks/{webhook_id}, lire un abonnement et son état de livraison.GET /partner/webhooks, lister vos abonnements aux notifications, page par page.DELETE /partner/webhooks/{webhook_id}, supprimer un abonnement et le secret de signature qui lui est attaché.- Recevoir les événements par webhook, créer un abonnement, vérifier une signature, rattraper les événements perdus.
Cette page vous a-t-elle été utile ?
Votre réponse ouvre un courriel pré-rempli dans votre messagerie, à destination de contact@sealtrust.io. Vous le relisez avant de l'envoyer.