/v1/account/webhook-endpoints

account/webhook-endpoints

Webhooks: para onde o Monitoramento envia novos Signals e como você os verifica.

Custos e limites

Custos e limites
O quê Créditos
Gerenciar endpoints e entregas de webhook grátis

Limite: 30 requisições por minuto. Criar, alterar e excluir: 10 por minuto. Verificar, testar e novo secret: 6 por minuto.

Admin token ou chave de API

Endpoints

Método
Método Caminho Finalidade Acesso
GET /v1/account/webhook-endpoints Todos os endpoints de webhook, sem os arquivados. Chave de API ou admin token
POST /v1/account/webhook-endpoints Criar um endpoint de webhook. Admin token
POST /v1/account/webhook-endpoints/{id}/verify Verificar. Chave de API ou admin token
POST /v1/account/webhook-endpoints/{id}/test Enviar uma mensagem de teste. Chave de API ou admin token
POST /v1/account/webhook-endpoints/{id}/rotate-secret Novo secret de assinatura. Admin token
POST /v1/account/webhook-endpoints/{id}/enable Ativar. Admin token
POST /v1/account/webhook-endpoints/{id}/disable Desativar. Admin token
DELETE /v1/account/webhook-endpoints/{id} Arquivar. Admin token
GET /v1/account/webhook-deliveries As últimas 50 entregas. Chave de API ou admin token
POST /v1/account/webhook-deliveries/{id}/retry Reenviar uma entrega que falhou. Chave de API ou admin token
GET /v1/account/webhook-events Os últimos 50 eventos. Chave de API ou admin token

Criar um endpoint de webhook

curl -X POST "https://handelsregister.ai/api/v1/account/webhook-endpoints" \
  -H "Authorization: Bearer SEU_ADMIN_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CRM-Sync",
    "url": "https://hooks.example.com/handelsregister",
    "headers": {
        "X-Receiver-Token": "SEU_TOKEN_RECEPTOR"
    }
}'
Parâmetros
Nome Tipo Descrição Exemplo
Idempotency-KeyHeader stringobrigatório Um valor único por operação, de preferência um UUID. Veja Idempotency-Key.Limites: 1 a 128 caracteres req-20260802-01
nameBody stringobrigatório Um nome para a sua própria referência.Limites: 1 a 120 caracteres CRM-Sync
urlBody string (uri)obrigatório O endereço do seu servidor: acessível publicamente, https na porta 443, com nome de host em vez de endereço IP.Limites: 1 a 2.048 caracteres https://hooks.example.com/handelsregister
headersBody objetoopcional Headers personalizados enviados com cada mensagem, como um token para o seu servidor.Limites: no máximo 10 entradas {"X-Receiver-Token":"SEU_TOKEN_RECEPTOR"}
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 · Resposta de exemplo: um novo endpoint de webhook, o secret encurtado aqui

Verificar

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}
A mensagem que o seu servidor recebe na verificação
curl -X POST "https://handelsregister.ai/api/v1/account/webhook-endpoints/wep_01m6b3j1g0cdz98hw8zdefbf52/verify" \
  -H "x-api-key: SUA_CHAVE_DE_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 · Resposta de exemplo a uma verificação bem-sucedida
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 · Resposta de exemplo a uma mensagem de teste

Verificar a assinatura

Header
Header Significado
webhook-id ID da mensagem (msg_…). Ele permanece igual nas novas tentativas. Use-o para detectar duplicatas.
webhook-timestamp Momento desta tentativa de entrega em segundos Unix.
webhook-signature Uma ou mais assinaturas no formato v1,<Base64>, separadas por espaços.
import base64, hashlib, hmac, time

def verify_webhook(secret: str, headers: dict, body: bytes) -> bool:
    msg_id = headers["webhook-id"]
    timestamp = headers["webhook-timestamp"]
    # Rejeitar mensagens com mais de cinco minutos
    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()
    # Durante uma rotação de secret, o header traz duas assinaturas
    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

Campo
Campo Significado
id ID da mensagem, igual ao header webhook-id.
event_id ID do evento (evt_…).
type Tipo do evento, veja abaixo.
timestamp Quando detectamos o evento, em UTC.
schema_version Versão da estrutura, atualmente 1.
data Os dados do evento.
Tipos de evento
Tipo de evento Significado
organization.signal.detected Um monitor encontrou um novo sinal. data.signal tem a mesma estrutura de um sinal em signals, mais data.monitor e, em data.links.signal, o link para o sinal na API.
organization.signal.sample Um exemplo do histórico real da empresa, enviado em Conta › Monitoramento. Mesma estrutura de acima, mais data.sample: true.
endpoint.test Mensagem de teste via /test.
endpoint.verification Desafio na verificação.
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}
Mensagem de exemplo para a Hetzner Online GmbH, Ansbach HRB 6089: a fusão da Headtrip GmbH, Nürnberg HRB 33432, enviada como exemplo do histórico

Entregas e novas tentativas

Entregamos cada mensagem pelo menos uma vez, mas não numa ordem fixa. Detecte duplicatas por webhook-id. Responda rápido e só depois processe a mensagem.
Status de uma entrega
Status Significado
withheld Aguarda até a verificação ser cobrada.
pending Aguarda o envio.
in_flight Sendo enviada agora.
retry_wait Aguarda a próxima tentativa.
succeeded Entregue.
exhausted Todas as tentativas falharam.
blocked_endpoint O endpoint de webhook não pode receber nada no momento.
cancelled Cancelada, por exemplo porque a mensagem expirou.

Ativar, desativar, arquivar

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

Erros

Erros
Status Causa O que você pode fazer
400 api_key está na URL. Envie a chave no header x-api-key.
400 A URL não é permitida como destino, um header não é permitido, o número máximo foi atingido ou o endpoint de webhook não está ativo. meta.message informa o motivo. Corrija o valor ou verifique primeiro.
400 O Idempotency-Key tem formato inválido. Corrija o formato, por exemplo use um UUID.
401 Nenhuma chave de API ou token, ou um inválido. Envie a chave no header x-api-key.
403 Falta ao bearer token a permissão account:read. Use a chave de API ou um token com account:read.
403 O endereço de e-mail da sua conta ainda não foi confirmado, ou a conta está bloqueada. Abra o link do e-mail de confirmação. Se a conta estiver bloqueada, o suporte pode ajudar.
403 Esta chamada precisa do admin token. Uma chave de API não basta, nem outro token. Envie-o com Authorization: Bearer e o admin token.
403 Falta ao bearer token a permissão monitoring:manage. Use a chave de API ou o admin token.
404 Nenhum endpoint de webhook ou entrega com este ID. Confira o ID.
409 O Idempotency-Key já foi usado com outros dados, tem mais de 24 horas ou ainda está sendo processado. Use uma chave nova ou espere um pouco.
422 Um valor está faltando ou é inválido, como name ou url. errors indica o campo. Corrija o valor e tente de novo com uma chave nova.
422 A verificação falhou. Confira o header do desafio e o status 2xx e tente de novo com uma chave nova.
428 O header Idempotency-Key está faltando. Envie o header.
429 Requisições demais. Tente de novo depois de Retry-After.
503 Verificar, testar e reenviar estão temporariamente indisponíveis. Tente de novo um pouco mais tarde.
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 · Um endpoint de webhook ainda não verificado não pode receber mensagem de teste