Pular para o conteúdo
WbizTool

API v2 (beta)

Webhooks

Um endpoint de webhook é uma URL no seu servidor que o WbizTool chama quando algo acontece com uma mensagem: ela foi enviada, falhou, foi cancelada ou expirou. Você recebe a notícia na hora em vez de consultar periodicamente, e cada requisição é assinada para você poder verificar que veio do WbizTool.

OperaçãoEndpointPermissão
Adicionar um endpointPOST /api/v2/webhooksmessages:read
Listar endpointsGET /api/v2/webhooksmessages:read
Obter um endpointGET /api/v2/webhooks/{id}messages:read
Remover um endpointDELETE /api/v2/webhooks/{id}messages:read
Trocar o segredo de assinaturaPOST /api/v2/webhooks/{id}/rotate-secretmessages:read
Enviar um evento de testePOST /api/v2/webhooks/{id}/testmessages:read

Os endpoints pertencem ao espaço de trabalho e recebem eventos de todas as mensagens dele, seja quem for que as enviou: a API, o painel, campanhas, lembretes ou integrações. Por isso, uma chave limitada a alguns números não pode gerenciá-los: toda chamada responde 403 number_not_allowed.

Eventos#

TipoQuando
message.sentUma mensagem saiu do seu número.
message.failedUma mensagem não pôde ser enviada; error.message diz o motivo.
message.cancelledUma mensagem em espera foi cancelada: pela API, pelo painel ou porque o número ou a campanha dela foi removido.
message.expiredUma mensagem não foi enviada antes do seu expires_at.
pingUm evento de teste que você pediu.

Eventos de números (conectado, desconectado) e de mensagens recebidas virão depois. Os tiques de entregue e lida não enviam eventos; obtenha a mensagem para vê-los.

Adicionar um endpoint#

POSThttps://wbiztool.com/api/v2/webhooks

Corpo: JSON (application/json)

Corpo

urlstringobrigatório

O seu endpoint: um endereço público https://, com até 500 caracteres. Endereços http://, privados e locais (como localhost ou 192.168.x.x) são recusados.

eventsarray of stringsopcional

Os tipos de evento que ele recebe: qualquer um de message.sent, message.failed, message.cancelled e message.expired. Padrão: os quatro. ping sempre chega quando você pede um.

descriptionstringopcional

Uma anotação para você, com até 100 caracteres, como Order system.

Um espaço de trabalho pode ter até 5 endpoints. A resposta é 201 com o endpoint e o secret de assinatura, exibido só desta vez. Guarde-o onde o seu receptor possa lê-lo, como uma variável de ambiente. As respostas seguintes mostram só secret_last4; se você perder o segredo, troque-o.

curl -X POST https://wbiztool.com/api/v2/webhooks \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/wbiztool/events",
    "events": ["message.sent", "message.failed"],
    "description": "Order system"
  }'

Resposta (201):

{
  "id": 41,
  "url": "https://example.com/wbiztool/events",
  "description": "Order system",
  "events": ["message.sent", "message.failed"],
  "secret_last4": "9c1e",
  "active": true,
  "disabled_reason": null,
  "created_at": "2026-10-18T11:20:05.733Z",
  "last_delivery": null,
  "secret": "3f0b…9c1e"
}

O secret real tem 64 caracteres hexadecimais. Uma nova tentativa desta requisição com a mesma Idempotency-Key não adiciona um segundo endpoint, e a resposta dela não traz o segredo.

Erros ao adicionar um endpoint#

HTTPCódigoQuando
400validation_failedurl está ausente ou é longa demais, events está vazio ou tem um tipo desconhecido, ou um campo é desconhecido
403webhook_limit_reachedO espaço de trabalho já tem 5 endpoints
403number_not_allowedA chave está limitada a alguns números
422invalid_webhook_urlurl não é um endereço público https://

Listar endpoints#

GEThttps://wbiztool.com/api/v2/webhooks

Os endpoints do espaço de trabalho que recebem eventos, do mais antigo para o mais recente, em uma única lista data.

curl https://wbiztool.com/api/v2/webhooks \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY"

A lista deixa de fora os endpoints que pararam. Os Proprietários também veem os endpoints, e podem removê-los, em Configurações → Chaves de API, em Endpoints de webhook.

Obter um endpoint#

GEThttps://wbiztool.com/api/v2/webhooks/{id}

Um endpoint. last_delivery mostra como foi a última entrega. Um endpoint que não existe ou foi removido responde 404 webhook_not_found; um que parou aparece com active: false.

Remover um endpoint#

DELETEhttps://wbiztool.com/api/v2/webhooks/{id}

Nada mais é enviado a ele, nem as novas tentativas que ainda estavam em espera. A resposta é {"id": 41, "deleted": true}.

Trocar o segredo de assinatura#

POSThttps://wbiztool.com/api/v2/webhooks/{id}/rotate-secret

Cria um novo segredo para o endpoint. A resposta é 200 com o endpoint e o novo secret, exibido só desta vez. O segredo antigo para de valer na hora: os eventos enviados depois disso são assinados com o novo, incluindo novas tentativas de eventos anteriores. Atualize o seu receptor imediatamente.

curl -X POST https://wbiztool.com/api/v2/webhooks/41/rotate-secret \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY"

Enviar um evento de teste#

POSThttps://wbiztool.com/api/v2/webhooks/{id}/test

Coloca na fila um evento ping para este endpoint, assinado como todos os eventos, para você testar o seu receptor. A resposta é 202:

{ "event_id": "evt_8a2f4c1d9b7e6a5f4c3b2a19", "type": "ping", "queued": true }

O seu endpoint recebe:

{
  "id": "evt_8a2f4c1d9b7e6a5f4c3b2a19",
  "type": "ping",
  "created_at": "2026-10-18T11:21:40.002Z",
  "data": { "webhook_id": 41 }
}

O conteúdo do evento#

Cada evento é um POST com um corpo JSON:

{
  "id": "evt_c41d7e2a9f3b8c6d5e4f3a21",
  "type": "message.sent",
  "created_at": "2026-10-18T10:15:09.912Z",
  "data": {
    "message": {
      "id": 9817263,
      "status": "sent",
      "from": { "id": 101, "phone": "919800000000", "platform": "whatsapp" },
      "to": { "phone": "+919876543210", "contact_id": 991 },
      "text": "Hi Asha, your order #1042 is ready.",
      "media": null,
      "send_at": null,
      "expires_at": null,
      "created_at": "2026-10-18T10:15:02.311Z",
      "sent_at": "2026-10-18T10:15:09.870Z",
      "error": null
    }
  }
}
CampoDescrição
idO id do evento: evt_ e 24 caracteres. O mesmo evento mantém o id em todas as novas tentativas.
typeUm dos tipos de evento.
created_atQuando o evento aconteceu.
data.messageNos eventos message.*: a Message como estava naquele momento. Um media.url nela funciona por pelo menos 26 horas.
data.webhook_idNo ping: o id do endpoint.

Cabeçalhos:

CabeçalhoValor
Content-Typeapplication/json
User-AgentWbizTool-Webhooks/2
WbizTool-Event-IdO id do evento, o mesmo em todas as novas tentativas
WbizTool-TimestampQuando esta tentativa foi enviada, em segundos Unix, como 1792310409
WbizTool-Signaturev1= e o HMAC-SHA256 em hexadecimal de <timestamp>.<raw body>, feito com o segredo do endpoint

Verificar a assinatura#

Verifique cada requisição antes de confiar nela: calcule a assinatura a partir do corpo bruto (antes de o seu framework interpretar o JSON), compare-a com o cabeçalho em tempo constante e recuse timestamps com mais de 5 minutos de diferença, para que uma requisição antiga não possa ser reenviada. É o mesmo esquema das assinaturas de webhook da API v1, com o segredo próprio do endpoint.

Depois, use WbizTool-Event-Id para descartar repetidos: o mesmo evento pode chegar mais de uma vez, por exemplo quando a sua resposta se perdeu e tentamos de novo.

import hashlib, hmac, json, os, time

SECRET = os.environ["WBIZTOOL_WEBHOOK_SECRET"]

def verify(secret: str, body: bytes, headers) -> bool:
    ts, sig = headers.get("WbizTool-Timestamp", ""), headers.get("WbizTool-Signature", "")
    if not ts.isdigit() or abs(time.time() - int(ts)) > 300:
        return False
    mac = "v1=" + hmac.new(secret.encode(), ts.encode() + b"." + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(mac, sig)

# Flask
from flask import Flask, request

app = Flask(__name__)
seen = set()  # use your database in production

@app.post("/wbiztool/events")
def events():
    body = request.get_data()  # the raw bytes
    if not verify(SECRET, body, request.headers):
        return "", 401
    event_id = request.headers["WbizTool-Event-Id"]
    if event_id in seen:
        return "", 200  # a repeat: already handled
    seen.add(event_id)
    event = json.loads(body)
    if event["type"] == "message.failed":
        message = event["data"]["message"]
        print("Failed:", message["id"], message["error"]["message"])
    return "", 200

No Django, passe request.body e request.headers.

Responda 2xx rápido e faça o trabalho demorado depois (em uma fila, por exemplo).

Novas tentativas#

  • Responda com qualquer 2xx em até 10 segundos. Qualquer outra coisa é uma falha: outro código de status (4xx incluído), nenhuma resposta em 10 segundos ou nenhuma conexão em 3. Redirecionamentos são seguidos, no máximo 3, e cada um precisa levar a um endereço público.
  • Uma entrega que falhou é tentada de novo após 1, 5 e 15 minutos, depois 1, 2, 4, 8 e 8 horas: 9 tentativas em cerca de 23 horas. Depois da última, o evento é descartado.
  • A nova tentativa tem o mesmo corpo e o mesmo WbizTool-Event-Id, com um novo WbizTool-Timestamp e uma nova assinatura.
  • A ordem não é garantida. Um message.sent reenviado pode chegar depois de um evento posterior. Use o status da mensagem, ou obtenha a mensagem, quando a ordem importar.

last_delivery no endpoint mostra como foi a última entrega: state (pending, delivered ou failed), o status_code com que o seu servidor respondeu e quando o evento foi criado.

Quando os endpoints param#

Um endpoint para de receber eventos quando acontece uma destas coisas. Ele continua em GET /webhooks com active: false e um disabled_reason, para você ver o motivo; ainda pode ser lido e removido, mas não testado nem receber um novo segredo (404).

  • Ele falhou por 24 horas. Se nada foi entregue a ele em 24 horas enquanto as entregas continuavam falhando, ele é desativado e as novas tentativas em espera são descartadas. Configurações → Chaves de API passa a mostrá-lo como Desativado. Corrija o seu servidor e então adicione o endpoint de novo.
  • A chave que o criou é revogada ou expira. Revogar uma chave interrompe tudo o que ela configurou. Adicione o endpoint de novo com outra chave.
  • Ele é removido, com Remover um endpoint ou em Configurações → Chaves de API.

Endpoints que pararam não contam para os 5.

O objeto webhook endpoint#

CampoTipoDescrição
idintegerO id do endpoint.
urlstringPara onde os eventos são enviados.
descriptionstringA sua anotação; "" quando não há nenhuma.
eventsarrayOs tipos de evento que ele recebe.
secretstringO segredo de assinatura: só nas respostas de Adicionar um endpoint e Trocar o segredo de assinatura.
secret_last4stringOs 4 últimos caracteres do segredo, para saber qual você tem.
activebooleanfalse quando ele não recebe mais eventos – veja Quando os endpoints param.
disabled_reasonstring or nullPor que ele parou (falhando por 24 horas, ou a chave que o criou foi revogada ou expirou); null enquanto ativo.
created_atstringQuando foi adicionado.
last_deliveryobject or nullA última entrega tentada: state, status_code (ou null quando o seu servidor não respondeu) e created_at. null antes da primeira.

Relacionados#