Webhooks (gestão)
Estes endpoints gerenciam os endereços que recebem eventos. Para entender os eventos em si, como validar a assinatura e como funcionam as retentativas, veja a seção Webhooks.
Você também pode fazer tudo isso no painel, em Configurações → Desenvolvedor → Webhooks.
O objeto webhook
Seção intitulada “O objeto webhook”{ "id": "f03b0773-5912-4a45-9139-c29375485843", "object": "webhook_endpoint", "url": "https://meusistema.com.br/webhooks/toptalking", "description": "CRM interno", "events": ["message.received", "contact.stage_changed"], "enabled": true, "disabled_reason": null, "last_delivery_at": "2026-11-11T14:12:41Z", "last_delivery_status": 200, "created_at": "2026-11-01T10:00:00Z", "updated_at": "2026-11-01T10:00:00Z"}| Campo | Tipo | Descrição |
|---|---|---|
id |
UUID | ID do webhook. |
object |
string | Sempre webhook_endpoint. |
url |
string | Endereço HTTPS que recebe os eventos. |
description |
string ou null |
Descrição livre. |
events |
lista | Eventos assinados, ou ["*"] para todos. |
enabled |
booleano | Se está recebendo eventos. |
disabled_reason |
string ou null |
Preenchido quando a TopTalking desativou o webhook por falhas seguidas. |
last_delivery_at |
data ou null |
Última tentativa de entrega. |
last_delivery_status |
inteiro ou null |
Status HTTP que o seu sistema respondeu na última entrega. |
created_at |
data | Criação. |
updated_at |
data | Última alteração. |
Eventos disponíveis
Seção intitulada “Eventos disponíveis”Valores aceitos em events:
| Valor | Quando chega |
|---|---|
* |
Todos os eventos. |
message.received |
Um contato mandou mensagem. |
message.sent |
Uma mensagem saiu pela conta. |
message.status_updated |
O status de entrega de uma mensagem enviada mudou. |
contact.created |
Um contato novo entrou na base. |
contact.updated |
Mudou nome, e-mail, etapa, responsável, IA, arquivamento ou finalização. |
contact.stage_changed |
O card mudou de etapa no Kanban. |
scheduled_message.sent |
Uma mensagem agendada foi enviada. |
scheduled_message.failed |
Uma mensagem agendada falhou. |
channel.status_updated |
Um WhatsApp conectou, caiu ou foi desconectado. |
campaign.status_updated |
Uma campanha mudou de status (aprovada, ajustes pedidos, enviando, pausada, concluída…). |
O evento de teste ping não precisa ser assinado: ele sempre é entregue quando você pede um teste. Os payloads de cada evento estão em Eventos e payloads.
Listar webhooks
Seção intitulada “Listar webhooks”GET/v1/webhooks
Todos os webhooks da organização (no máximo 10). Use para conferir se o seu endereço já está cadastrado antes de criar outro.
Não tem parâmetros. A lista vem inteira numa página (has_more: false).
curl https://platform.toptalking.com.br/v1/webhooks \ -H "Authorization: Bearer $TOPTALKING_API_KEY"const res = await fetch('https://platform.toptalking.com.br/v1/webhooks', { headers: { Authorization: `Bearer ${process.env.TOPTALKING_API_KEY}` },});const { data: webhooks } = await res.json();const desativados = webhooks.filter((w) => !w.enabled);import osimport requests
res = requests.get( "https://platform.toptalking.com.br/v1/webhooks", headers={"Authorization": f"Bearer {os.environ['TOPTALKING_API_KEY']}"}, timeout=30,)res.raise_for_status()webhooks = res.json()["data"]Resposta 200
Seção intitulada “Resposta 200”{ "object": "list", "data": [ { "id": "f03b0773-5912-4a45-9139-c29375485843", "object": "webhook_endpoint", "url": "https://meusistema.com.br/webhooks/toptalking", "description": "CRM interno", "events": ["message.received", "contact.stage_changed"], "enabled": true, "disabled_reason": null, "last_delivery_at": "2026-11-11T14:12:41Z", "last_delivery_status": 200, "created_at": "2026-11-01T10:00:00Z", "updated_at": "2026-11-01T10:00:00Z" } ], "has_more": false, "next_cursor": null}Só os gerais: 401 (chave) e 429 (limite por minuto). Veja Erros.
Criar webhook
Seção intitulada “Criar webhook”POST/v1/webhooks
Cadastra um endereço do seu sistema para receber eventos. A resposta traz o secret (só desta vez), usado para validar a assinatura. Máximo de 10 webhooks por organização.
| Parâmetro | Onde | Tipo | Obrigatório | Descrição |
|---|---|---|---|---|
url |
corpo | string | sim | Endereço HTTPS público do seu sistema. |
events |
corpo | lista | não | Eventos a receber. Padrão: ["*"] (todos). |
description |
corpo | string | não | Descrição (até 200 caracteres). |
enabled |
corpo | booleano | não | Padrão: true. |
Idempotency-Key |
cabeçalho | string | não | Evita criar dois webhooks numa retentativa. |
curl https://platform.toptalking.com.br/v1/webhooks \ -H "Authorization: Bearer $TOPTALKING_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: webhook-crm-interno" \ -d '{ "url": "https://meusistema.com.br/webhooks/toptalking", "events": ["message.received", "contact.stage_changed"], "description": "CRM interno" }'const res = await fetch('https://platform.toptalking.com.br/v1/webhooks', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOPTALKING_API_KEY}`, 'Content-Type': 'application/json', 'Idempotency-Key': 'webhook-crm-interno', }, body: JSON.stringify({ url: 'https://meusistema.com.br/webhooks/toptalking', events: ['message.received', 'contact.stage_changed'], description: 'CRM interno', }),});const webhook = await res.json();// Guarde webhook.secret AGORA (ex.: na variável TOPTALKING_WEBHOOK_SECRET).import osimport requests
res = requests.post( "https://platform.toptalking.com.br/v1/webhooks", headers={ "Authorization": f"Bearer {os.environ['TOPTALKING_API_KEY']}", "Idempotency-Key": "webhook-crm-interno", }, json={ "url": "https://meusistema.com.br/webhooks/toptalking", "events": ["message.received", "contact.stage_changed"], "description": "CRM interno", }, timeout=30,)res.raise_for_status()webhook = res.json()# Guarde webhook["secret"] AGORA (ex.: na variável TOPTALKING_WEBHOOK_SECRET).Resposta 201
Seção intitulada “Resposta 201”O webhook criado com o secret:
{ "id": "f03b0773-5912-4a45-9139-c29375485843", "object": "webhook_endpoint", "url": "https://meusistema.com.br/webhooks/toptalking", "description": "CRM interno", "events": ["message.received", "contact.stage_changed"], "enabled": true, "disabled_reason": null, "last_delivery_at": null, "last_delivery_status": null, "created_at": "2026-11-01T10:00:00Z", "updated_at": "2026-11-01T10:00:00Z", "secret": "whsec_d8d10826ecb93b4679de7409553d10982e864a172f6df97b"}| HTTP | code |
Quando acontece |
|---|---|---|
| 400 | missing_field |
Faltou url. |
| 400 | invalid_field |
URL sem HTTPS ou não pública (localhost, rede interna), ou evento desconhecido em events. |
| 403 | read_only_key |
Chave somente leitura. |
| 409 | idempotency_conflict |
Idempotency-Key reutilizada com outro corpo. |
| 422 | limit_reached |
A organização já tem 10 webhooks. |
{ "error": { "type": "invalid_request_error", "code": "limit_reached", "message": "Limite de 10 webhooks por organização atingido.", "request_id": "req_6f1d2c3b4a5e" }}Buscar webhook
Seção intitulada “Buscar webhook”GET/v1/webhooks/{webhook_id}
Um webhook pelo ID, sem o secret. Útil para conferir enabled, disabled_reason e o resultado da última entrega.
| Parâmetro | Onde | Tipo | Obrigatório | Descrição |
|---|---|---|---|---|
webhook_id |
caminho | UUID | sim | ID do webhook. |
curl https://platform.toptalking.com.br/v1/webhooks/f03b0773-5912-4a45-9139-c29375485843 \ -H "Authorization: Bearer $TOPTALKING_API_KEY"const id = 'f03b0773-5912-4a45-9139-c29375485843';const res = await fetch(`https://platform.toptalking.com.br/v1/webhooks/${id}`, { headers: { Authorization: `Bearer ${process.env.TOPTALKING_API_KEY}` },});const webhook = await res.json();if (!webhook.enabled) console.warn('Webhook desativado:', webhook.disabled_reason);import osimport requests
webhook_id = "f03b0773-5912-4a45-9139-c29375485843"res = requests.get( f"https://platform.toptalking.com.br/v1/webhooks/{webhook_id}", headers={"Authorization": f"Bearer {os.environ['TOPTALKING_API_KEY']}"}, timeout=30,)res.raise_for_status()webhook = res.json()Resposta 200
Seção intitulada “Resposta 200”{ "id": "f03b0773-5912-4a45-9139-c29375485843", "object": "webhook_endpoint", "url": "https://meusistema.com.br/webhooks/toptalking", "description": "CRM interno", "events": ["message.received", "contact.stage_changed"], "enabled": true, "disabled_reason": null, "last_delivery_at": "2026-11-11T14:12:41Z", "last_delivery_status": 200, "created_at": "2026-11-01T10:00:00Z", "updated_at": "2026-11-01T10:00:00Z"}| HTTP | code |
Quando acontece |
|---|---|---|
| 404 | resource_not_found |
O webhook não existe. |
Atualizar webhook
Seção intitulada “Atualizar webhook”PATCH/v1/webhooks/{webhook_id}
Muda o endereço, os eventos ou a descrição, ou pausa/reativa o webhook — inclusive um que a TopTalking desativou por falhas seguidas. Envie só o que quer mudar.
| Parâmetro | Onde | Tipo | Obrigatório | Descrição |
|---|---|---|---|---|
webhook_id |
caminho | UUID | sim | ID do webhook. |
url |
corpo | string | não | Novo endereço HTTPS. |
events |
corpo | lista | não | Nova lista de eventos (substitui a anterior). |
description |
corpo | string ou null |
não | Nova descrição. |
enabled |
corpo | booleano | não | false pausa; true reativa. |
# Reativar e passar a receber também os eventos de conexãocurl -X PATCH https://platform.toptalking.com.br/v1/webhooks/f03b0773-5912-4a45-9139-c29375485843 \ -H "Authorization: Bearer $TOPTALKING_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "enabled": true, "events": ["message.received", "contact.stage_changed", "channel.status_updated"] }'const id = 'f03b0773-5912-4a45-9139-c29375485843';const res = await fetch(`https://platform.toptalking.com.br/v1/webhooks/${id}`, { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.TOPTALKING_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ enabled: true, events: ['message.received', 'contact.stage_changed', 'channel.status_updated'], }),});const webhook = await res.json();import osimport requests
webhook_id = "f03b0773-5912-4a45-9139-c29375485843"res = requests.patch( f"https://platform.toptalking.com.br/v1/webhooks/{webhook_id}", headers={"Authorization": f"Bearer {os.environ['TOPTALKING_API_KEY']}"}, json={ "enabled": True, "events": ["message.received", "contact.stage_changed", "channel.status_updated"], }, timeout=30,)res.raise_for_status()webhook = res.json()Resposta 200
Seção intitulada “Resposta 200”{ "id": "f03b0773-5912-4a45-9139-c29375485843", "object": "webhook_endpoint", "url": "https://meusistema.com.br/webhooks/toptalking", "description": "CRM interno", "events": ["message.received", "contact.stage_changed", "channel.status_updated"], "enabled": true, "disabled_reason": null, "last_delivery_at": "2026-11-11T14:12:41Z", "last_delivery_status": 200, "created_at": "2026-11-01T10:00:00Z", "updated_at": "2026-11-11T15:05:30Z"}| HTTP | code |
Quando acontece |
|---|---|---|
| 400 | missing_field |
O corpo não tem nenhum campo para atualizar. |
| 400 | invalid_json, invalid_field |
Corpo inválido, URL sem HTTPS ou evento desconhecido. |
| 403 | read_only_key |
Chave somente leitura. |
| 404 | resource_not_found |
O webhook não existe. |
Excluir webhook
Seção intitulada “Excluir webhook”DELETE/v1/webhooks/{webhook_id}
Remove o webhook: o endereço para de receber eventos imediatamente. Para só pausar, use PATCH com enabled: false.
| Parâmetro | Onde | Tipo | Obrigatório | Descrição |
|---|---|---|---|---|
webhook_id |
caminho | UUID | sim | ID do webhook. |
curl -X DELETE https://platform.toptalking.com.br/v1/webhooks/f03b0773-5912-4a45-9139-c29375485843 \ -H "Authorization: Bearer $TOPTALKING_API_KEY"const id = 'f03b0773-5912-4a45-9139-c29375485843';const res = await fetch(`https://platform.toptalking.com.br/v1/webhooks/${id}`, { method: 'DELETE', headers: { Authorization: `Bearer ${process.env.TOPTALKING_API_KEY}` },});const { deleted } = await res.json(); // trueimport osimport requests
webhook_id = "f03b0773-5912-4a45-9139-c29375485843"res = requests.delete( f"https://platform.toptalking.com.br/v1/webhooks/{webhook_id}", headers={"Authorization": f"Bearer {os.environ['TOPTALKING_API_KEY']}"}, timeout=30,)res.raise_for_status()Resposta 200
Seção intitulada “Resposta 200”{ "id": "f03b0773-5912-4a45-9139-c29375485843", "object": "webhook_endpoint", "deleted": true}| HTTP | code |
Quando acontece |
|---|---|---|
| 403 | read_only_key |
Chave somente leitura. |
| 404 | resource_not_found |
O webhook não existe. |
Enviar evento de teste
Seção intitulada “Enviar evento de teste”POST/v1/webhooks/{webhook_id}/test
Coloca na fila um evento ping para o endereço — mesmo se o webhook estiver desativado. É o mesmo que o botão Enviar teste do painel. Use para conferir se o seu endpoint recebe e valida a assinatura.
| Parâmetro | Onde | Tipo | Obrigatório | Descrição |
|---|---|---|---|---|
webhook_id |
caminho | UUID | sim | ID do webhook. |
curl -X POST https://platform.toptalking.com.br/v1/webhooks/f03b0773-5912-4a45-9139-c29375485843/test \ -H "Authorization: Bearer $TOPTALKING_API_KEY"const id = 'f03b0773-5912-4a45-9139-c29375485843';const res = await fetch(`https://platform.toptalking.com.br/v1/webhooks/${id}/test`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.TOPTALKING_API_KEY}` },});const entrega = await res.json(); // status 202import osimport requests
webhook_id = "f03b0773-5912-4a45-9139-c29375485843"res = requests.post( f"https://platform.toptalking.com.br/v1/webhooks/{webhook_id}/test", headers={"Authorization": f"Bearer {os.environ['TOPTALKING_API_KEY']}"}, timeout=30,)entrega = res.json() # res.status_code == 202Resposta 202
Seção intitulada “Resposta 202”A entrega criada, ainda na fila:
{ "id": "d94d8ee3-4eb6-41f1-8c44-44bd0907d99f", "object": "webhook_delivery", "webhook_id": "f03b0773-5912-4a45-9139-c29375485843", "event_id": "252a2c18-7b60-47a6-9feb-9c8322f2ba50", "event_type": "ping", "status": "pending", "attempts": 0, "response_status": null, "error": null, "duration_ms": null, "next_attempt_at": "2026-11-11T15:10:00Z", "delivered_at": null, "created_at": "2026-11-11T15:10:00Z"}| HTTP | code |
Quando acontece |
|---|---|---|
| 403 | read_only_key |
Chave somente leitura. |
| 404 | resource_not_found |
O webhook não existe. |
Histórico de entregas
Seção intitulada “Histórico de entregas”GET/v1/webhooks/{webhook_id}/deliveries
As últimas tentativas de entrega deste webhook, com paginação. Os eventos ficam guardados por 30 dias. Use para investigar por que o seu sistema não recebeu um evento.
| Parâmetro | Onde | Tipo | Obrigatório | Descrição |
|---|---|---|---|---|
webhook_id |
caminho | UUID | sim | ID do webhook. |
limit |
query | inteiro | não | Itens por página, 1 a 100 (padrão 20). |
cursor |
query | string | não | next_cursor da página anterior. |
curl "https://platform.toptalking.com.br/v1/webhooks/f03b0773-5912-4a45-9139-c29375485843/deliveries?limit=20" \ -H "Authorization: Bearer $TOPTALKING_API_KEY"const id = 'f03b0773-5912-4a45-9139-c29375485843';const res = await fetch( `https://platform.toptalking.com.br/v1/webhooks/${id}/deliveries?limit=20`, { headers: { Authorization: `Bearer ${process.env.TOPTALKING_API_KEY}` } },);const { data: entregas } = await res.json();const comFalha = entregas.filter((e) => e.status !== 'succeeded');import osimport requests
webhook_id = "f03b0773-5912-4a45-9139-c29375485843"res = requests.get( f"https://platform.toptalking.com.br/v1/webhooks/{webhook_id}/deliveries", headers={"Authorization": f"Bearer {os.environ['TOPTALKING_API_KEY']}"}, params={"limit": 20}, timeout=30,)res.raise_for_status()entregas = res.json()["data"]Resposta 200
Seção intitulada “Resposta 200”{ "object": "list", "data": [ { "id": "7c8f5d3c-c721-44aa-a161-3fe74f6ad736", "object": "webhook_delivery", "webhook_id": "f03b0773-5912-4a45-9139-c29375485843", "event_id": "597b7d23-208d-4b5b-82a2-fb1703a81d63", "event_type": "message.received", "status": "pending", "attempts": 2, "response_status": 500, "error": "HTTP 500", "duration_ms": 1240, "next_attempt_at": "2026-11-11T14:18:42Z", "delivered_at": null, "created_at": "2026-11-11T14:12:41Z" }, { "id": "d94d8ee3-4eb6-41f1-8c44-44bd0907d99f", "object": "webhook_delivery", "webhook_id": "f03b0773-5912-4a45-9139-c29375485843", "event_id": "252a2c18-7b60-47a6-9feb-9c8322f2ba50", "event_type": "ping", "status": "succeeded", "attempts": 1, "response_status": 200, "error": null, "duration_ms": 184, "next_attempt_at": null, "delivered_at": "2026-11-11T15:10:01Z", "created_at": "2026-11-11T15:10:00Z" } ], "has_more": false, "next_cursor": null}| Campo | Tipo | Descrição |
|---|---|---|
id |
UUID | ID da entrega (o mesmo do cabeçalho X-TopTalking-Delivery-Id). |
object |
string | Sempre webhook_delivery. |
webhook_id |
UUID | Webhook de destino. |
event_id |
UUID | ID do evento (o mesmo em todas as tentativas). |
event_type |
string | Tipo do evento (ex.: message.received). |
status |
string | pending (na fila ou esperando nova tentativa), processing (enviando), succeeded (seu sistema respondeu 2xx) ou failed. |
attempts |
inteiro | Quantas tentativas já foram feitas. |
response_status |
inteiro ou null |
Status HTTP que o seu sistema respondeu na última tentativa. |
error |
string ou null |
Motivo da falha (timeout, erro de conexão, status não 2xx…). |
duration_ms |
inteiro ou null |
Quanto o seu sistema demorou para responder. |
next_attempt_at |
data ou null |
Quando será a próxima tentativa, se houver. |
delivered_at |
data ou null |
Quando foi entregue com sucesso. |
created_at |
data | Quando a entrega foi criada. |
Entregas que falharam podem ser reenviadas pelo painel (botão Reenviar, em Ver entregas). Veja Entregas e novas tentativas.
| HTTP | code |
Quando acontece |
|---|---|---|
| 404 | resource_not_found |
O webhook não existe. |