/v1/account/webhook-endpoints

account/webhook-endpoints

Webhooks : où le Monitoring envoie les nouveaux Signals et comment les vérifier.

Coûts et limites

Coûts et limites
Quoi Crédits
Gérer les endpoints webhook et les livraisons gratuit

Limite : 30 requêtes par minute. Créer, modifier et supprimer : 10 par minute. Vérifier, tester et nouveau secret : 6 par minute.

Token admin ou clé API

Endpoints

Méthode
Méthode Chemin Usage Accès
GET /v1/account/webhook-endpoints Tous les endpoints webhook, sans les archivés. Clé API ou token admin
POST /v1/account/webhook-endpoints Créer un endpoint webhook. Token admin
POST /v1/account/webhook-endpoints/{id}/verify Vérifier. Clé API ou token admin
POST /v1/account/webhook-endpoints/{id}/test Envoyer un message de test. Clé API ou token admin
POST /v1/account/webhook-endpoints/{id}/rotate-secret Nouveau secret de signature. Token admin
POST /v1/account/webhook-endpoints/{id}/enable Activer. Token admin
POST /v1/account/webhook-endpoints/{id}/disable Désactiver. Token admin
DELETE /v1/account/webhook-endpoints/{id} Archiver. Token admin
GET /v1/account/webhook-deliveries Les 50 dernières livraisons. Clé API ou token admin
POST /v1/account/webhook-deliveries/{id}/retry Renvoyer une livraison échouée. Clé API ou token admin
GET /v1/account/webhook-events Les 50 derniers événements. Clé API ou token admin

Créer un endpoint webhook

curl -X POST "https://handelsregister.ai/api/v1/account/webhook-endpoints" \
  -H "Authorization: Bearer TON_TOKEN_ADMIN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CRM-Sync",
    "url": "https://hooks.example.com/handelsregister",
    "headers": {
        "X-Receiver-Token": "TON_TOKEN_RECEPTEUR"
    }
}'
Paramètres
Nom Type Description Exemple
Idempotency-KeyHeader chaîneobligatoire Une valeur unique par opération, idéalement un UUID. Voir Idempotency-Key.Limites: 1 à 128 caractères req-20260802-01
nameBody chaîneobligatoire Un nom pour ta propre référence.Limites: 1 à 120 caractères CRM-Sync
urlBody chaîne (uri)obligatoire L’adresse de ton serveur : accessible publiquement, https sur le port 443, avec un nom d’hôte au lieu d’une adresse IP.Limites: 1 à 2 048 caractères https://hooks.example.com/handelsregister
headersBody objetfacultatif Headers personnalisés envoyés avec chaque message, comme un token pour ton serveur.Limites: au plus 10 entrées {"X-Receiver-Token":"TON_TOKEN_RECEPTEUR"}
1{2  "endpoint": {3    "id": "wep_01m6b3j1g0cdz98hw8zdefbf52",4    "name": "CRM-Sync",5    "url": "hooks.example.com/…",6    "status": "pending_verification",7    "verified_at": null,8    "header_names": [9      "X-Receiver-Token"10    ],11    "consecutive_failures": 0,12    "created_at": "2026-11-01T08:28:01+00:00"13  },14  "signing_secret": "whsec_…",15  "meta": {16    "message": "Endpoint created. Store the signing secret now — it is shown only once.",17    "request_credit_cost": 0,18    "credits_remaining": 14519  }20}
201 · Exemple de réponse : un nouvel endpoint webhook, le secret raccourci ici

Vérifier

1{2  "id": "msg_01m6b3jsqq7ntwzkdj099ayraz",3  "type": "endpoint.verification",4  "timestamp": "2026-11-01T08:28:26.743Z",5  "schema_version": 1,6  "data": {7    "challenge": "189fb34b2af819bb13cb47d9806dbf30"8  }9}
Le message que ton serveur reçoit lors de la vérification
curl -X POST "https://handelsregister.ai/api/v1/account/webhook-endpoints/wep_01m6b3j1g0cdz98hw8zdefbf52/verify" \
  -H "x-api-key: TA_CLE_API" \
  -H "Idempotency-Key: $(uuidgen)"
1{2  "verified": true,3  "endpoint": {4    "id": "wep_01m6b3j1g0cdz98hw8zdefbf52",5    "name": "CRM-Sync",6    "url": "hooks.example.com/…",7    "status": "active",8    "verified_at": "2026-11-01T08:28:26+00:00",9    "header_names": [10      "X-Receiver-Token"11    ],12    "consecutive_failures": 0,13    "created_at": "2026-11-01T08:28:01+00:00"14  },15  "meta": {16    "request_credit_cost": 0,17    "credits_remaining": 14518  }19}
200 · Exemple de réponse à une vérification réussie
1{2  "delivery": {3    "id": "del_01m6b3jsyrnc3sz1mt31dq6107",4    "message_id": "msg_01m6b3jsynxzhvagm7n2nq7mpv",5    "event_id": "evt_01m6b3jsynxzhvagm7n2nq7mpt",6    "event_type": "endpoint.test",7    "endpoint_id": "wep_01m6b3j1g0cdz98hw8zdefbf52",8    "status": "succeeded",9    "attempts": 1,10    "last_status_code": 200,11    "last_error_category": null,12    "next_attempt_at": "2026-11-01T08:28:26+00:00",13    "succeeded_at": "2026-11-01T08:28:26+00:00",14    "created_at": "2026-11-01T08:28:26+00:00"15  },16  "meta": {17    "request_credit_cost": 0,18    "credits_remaining": 14519  }20}
200 · Exemple de réponse à un message de test

Vérifier la signature

Header
Header Signification
webhook-id Identifiant du message (msg_…). Il reste le même lors des nouvelles tentatives. Utilise-le pour repérer les doublons.
webhook-timestamp Heure de cette tentative de livraison en secondes Unix.
webhook-signature Une ou plusieurs signatures de la forme v1,<Base64>, séparées par des espaces.
import base64, hashlib, hmac, time

def verify_webhook(secret: str, headers: dict, body: bytes) -> bool:
    msg_id = headers["webhook-id"]
    timestamp = headers["webhook-timestamp"]
    # Rejeter les messages de plus de cinq minutes
    if abs(time.time() - int(timestamp)) > 300:
        return False
    key = base64.b64decode(secret.removeprefix("whsec_"))
    signed = f"{msg_id}.{timestamp}.".encode() + body
    expected = base64.b64encode(hmac.new(key, signed, hashlib.sha256).digest()).decode()
    # Pendant une rotation de secret, l’en-tête porte deux signatures
    for part in headers["webhook-signature"].split(" "):
        version, _, signature = part.partition(",")
        if version == "v1" and hmac.compare_digest(signature, expected):
            return True
    return False

Payload

Champ
Champ Signification
id Identifiant du message, égal au header webhook-id.
event_id Identifiant de l’événement (evt_…).
type Type de l’événement, voir ci-dessous.
timestamp Moment où nous avons détecté l’événement, en UTC.
schema_version Version de la structure, actuellement 1.
data Les données de l’événement.
Types d’événements
Type d’événement Signification
organization.signal.detected Un moniteur a trouvé un nouveau signal. data.signal a la même structure qu’un signal dans signals, plus data.monitor et, sous data.links.signal, le lien vers le signal dans l’API.
organization.signal.sample Un exemple tiré de l’historique réel de l’entreprise, envoyé sous Compte › Monitoring. Même structure que ci-dessus, plus data.sample: true.
endpoint.test Message de test via /test.
endpoint.verification Challenge lors de la vérification.
1{2  "id": "msg_01m65pqg9x0176cteqvtxw68sa",3  "event_id": "evt_01m65pqg9sx7mwmw0edc1mfbbe",4  "type": "organization.signal.sample",5  "timestamp": "2026-10-30T06:07:37.000Z",6  "schema_version": 1,7  "data": {8    "monitor": {9      "id": "mon_01m65pn3vm11sjjp1j076cbvec",10      "type": "organization.signals"11    },12    "sample": true,13    "signal": {14      "event": {15        "id": "36c7c8fddf99bb0299d6815bcaa01013",16        "topic": "TRANSFORMATIONS",17        "topic_name": {18          "de": "Umwandlungen & M&A",19          "en": "Transformations & M&A"20        },21        "occurred_on": "2022-12-22",22        "announced_on": "2023-08-10",23        "date_basis": "SOURCE_EVENT"24      },25      "organization": {26        "type": "ORGANIZATION",27        "entity_id": "94eb910fef13f94585c48c263fa446d4",28        "current_profile": {29          "name": "Hetzner Online GmbH",30          "registration": {31            "register_type": "HRB",32            "register_number": "6089",33            "court": "Ansbach",34            "register_locality": "Ansbach",35            "registration_authority_id": "D3201",36            "register_entity_name": "Ansbach HRB 6089"37          },38          "legal_form": {39            "name": {40              "de": "Gesellschaft mit beschränkter Haftung"41            },42            "short": {43              "de": "GmbH"44            }45          },46          "seat": {47            "city": "Gunzenhausen"48          },49          "status": {50            "code": "ACTIVE"51          }52        }53      },54      "parties": {55        "counterparty": {56          "entity": {57            "type": "ORGANIZATION",58            "entity_id": "dd4d2d6854b2dbd1ffce74e669f3852e",59            "current_profile": {60              "name": "Headtrip GmbH",61              "registration": {62                "register_type": "HRB",63                "register_number": "33432",64                "court": "Nürnberg",65                "register_locality": "Nuremberg",66                "registration_authority_id": "D3310",67                "register_entity_name": "Nürnberg HRB 33432"68              },69              "legal_form": {70                "name": {71                  "de": "Gesellschaft mit beschränkter Haftung"72                },73                "short": {74                  "de": "GmbH"75                }76              },77              "seat": {78                "city": "Nürnberg"79              },80              "status": {81                "code": "INACTIVE"82              }83            }84          },85          "relationship": "TRANSFERRING_COMPANY"86        }87      },88      "register_entry": {89        "entry_number": "3",90        "entry_date": "2023-08-10",91        "description_text": "Verschmelzung zur Aufnahme der Headtrip GmbH",92        "context": "PRIMARY",93        "flags": []94      },95      "source": {96        "kind": "COMMERCIAL_REGISTER"97      },98      "details": {99        "schema": "TRANSFORMATION",100        "kind": "MERGER",101        "specifics": {102          "merger_target": "ABSORPTION"103        },104        "direction": "INCOMING",105        "is_cross_border": false,106        "resolution_date": "2022-12-22",107        "agreement_date": "2022-12-22"108      }109    },110    "links": {111      "signal": "https://handelsregister.ai/api/v1/signals/36c7c8fddf99bb0299d6815bcaa01013"112    }113  }114}
Exemple de message pour Hetzner Online GmbH, Ansbach HRB 6089 : la fusion de Headtrip GmbH, Nürnberg HRB 33432, envoyée comme exemple tiré de l’historique

Livraisons et nouvelles tentatives

Nous livrons chaque message au moins une fois, mais pas dans un ordre fixe. Repère les doublons par webhook-id. Réponds rapidement et traite le message seulement ensuite.
Statut d’une livraison
Statut Signification
withheld Attend que la vérification soit facturée.
pending Attend d’être envoyée.
in_flight En cours d’envoi.
retry_wait Attend la prochaine tentative.
succeeded Livrée.
exhausted Toutes les tentatives ont échoué.
blocked_endpoint L’endpoint webhook ne peut rien recevoir pour le moment.
cancelled Annulée, par exemple parce que le message a expiré.

Activer, désactiver, archiver

curl -X POST "https://handelsregister.ai/api/v1/account/webhook-endpoints/wep_01m6b3j1g0cdz98hw8zdefbf52/disable" \
  -H "Authorization: Bearer TON_TOKEN_ADMIN" \
  -H "Idempotency-Key: $(uuidgen)"

Erreurs

Erreurs
Statut Cause Que faire
400 api_key figure dans l’URL. Envoie la clé dans le header x-api-key.
400 L’URL n’est pas autorisée comme destination, un header n’est pas permis, le nombre maximal est atteint, ou l’endpoint webhook n’est pas actif. meta.message indique la raison. Corrige la valeur ou vérifie d’abord.
400 L’Idempotency-Key a un format invalide. Corrige le format, par exemple en utilisant un UUID.
401 Aucune clé API ni aucun token, ou une valeur invalide. Envoie la clé dans le header x-api-key.
403 Il manque au bearer token le droit account:read. Utilise la clé API ou un token avec account:read.
403 L’adresse e-mail de ton compte n’est pas encore confirmée, ou le compte est bloqué. Ouvre le lien de l’e-mail de confirmation. Si le compte est bloqué, le support peut t’aider.
403 Cet appel nécessite le token admin. Une clé API ne suffit pas, pas plus qu’un autre token. Envoie-le avec Authorization: Bearer et le token admin.
403 Il manque au bearer token le droit monitoring:manage. Utilise la clé API ou le token admin.
404 Aucun endpoint webhook ni aucune livraison avec cet identifiant. Vérifie l’identifiant.
409 L’Idempotency-Key a déjà été utilisée avec d’autres données, date de plus de 24 heures ou est encore en cours de traitement. Utilise une nouvelle clé ou attends brièvement.
422 Une valeur manque ou est invalide, comme name ou url. errors nomme le champ. Corrige la valeur et réessaie avec une nouvelle clé.
422 La vérification a échoué. Vérifie le header de challenge et le statut 2xx, puis réessaie avec une nouvelle clé.
428 Le header Idempotency-Key manque. Envoie le header.
429 Trop de requêtes. Réessaie après Retry-After.
503 La vérification, le test et le renvoi sont temporairement indisponibles. Réessaie un peu plus tard.
1{2  "error": "invalid_request",3  "meta": {4    "message": "The endpoint is not active.",5    "request_credit_cost": 0,6    "credits_remaining": 1457  }8}
400 · Un endpoint webhook pas encore vérifié ne peut pas recevoir de message de test