For the complete documentation index, see llms.txt. This page is also available as Markdown.

🔔Webhook de status

O Webhook de status entrega, na sua URL, o que aconteceu com cada mensagem — em vez de você consultar. Vale para todo disparo da conta: broadcast, automação, pela API ou pelo painel, envio real ou de teste.

A URL de base de todos os endpoints é: https://web.smsfunnel.com.br/api/parceiros/v1

O webhook não substitui o polling como fonte da verdade. O status do POST é o mesmo que GET /sms/messages/{id} devolve naquele instante; se os dois divergirem, a API é a fonte da verdade.

São até dois eventos por mensagem

O primeiro evento sai no despacho e tem dois desfechos possíveis: ou a mensagem saiu, ou não saiu. O segundo sai quando a confirmação de entrega chega até nós — quando e se chegar.

Evento
Quando
Garantido?

sent_to_carrier

No instante em que a mensagem é despachada da nossa fila para envio

Sim, se a mensagem saiu

cancelled ou blocked_blacklist

Quando a mensagem não sai: telefone na sua blacklist, telefone inválido ou crédito insuficiente. O crédito é estornado

Sim, no lugar do primeiro

delivered

Quando a confirmação de entrega no aparelho chega até nós

Não

Quando a mensagem não sai, não haverá segundo evento — não há confirmação de entrega a receber.

Não há prazo e não há desfecho garantido. Nem todo envio produz confirmação de entrega; quando não produz, a mensagem fica em sent_to_carrier e não muda mais. Não trate a ausência do delivered como falha: sent_to_carrier é um estado possivelmente final. Use o delivered como confirmação positiva. Em geral, retornos de delivered chegam em até 2 horas após o envio. Em alguns casos de telefone desligado ou retentativas o retorno pode demorar mais.

Isso é a mesma regra da consulta por API, e é deliberado: não inventamos desfecho. Um delivered que você recebe é uma confirmação real que chegou até nós.

O cancelamento que parte de você não gera evento. PUT /sms/broadcasts/{id}/cancel é um pedido seu, e devolver por POST o que você acabou de pedir não acrescenta informação. Os eventos de cancelamento existem para o que você não pediu.

Quando você não recebe nada

O webhook começa a valer no momento do envio, não no da mudança de status. Uma mensagem só entra na fila de eventos se, quando ela saiu, a sua conta já tinha URL cadastrada.

Situação
O que você recebe

Cadastrou a URL depois de disparar

Nada daquela mensagem — nem o sent_to_carrier, nem o delivered que chegar depois

Removeu a URL e cadastrou de novo

Nada do que foi disparado no intervalo

Mensagem anterior à ativação do recurso na conta

Nada

Mensagem anterior a 02/09/2026 criada fora da API

Nada — antes dessa data só o envio criado pela API recebia o id público que identifica a mensagem. Não houve backfill

Em todos os casos o status continua correto em GET /sms/messages/{id} — só o POST não sai.

Endpoints

PUT /me/webhook

Função: cadastra ou substitui a URL que recebe os eventos e o segredo usado para assinar.

Corpo de envio:

Corpo de resposta — 200 OK:

Guarde o secret nesta resposta. Ela é a única em que ele aparece — o GET devolve apenas has_secret. Se perder, faça um novo PUT: o segredo anterior é substituído.

Com o header X-On-Behalf-Of, a configuração é gravada na conta filha, que é de quem são as mensagens.

GET /me/webhook

Função: mostra a configuração atual da conta. O segredo nunca é devolvido.

Corpo de resposta — 200 OK:

DELETE /me/webhook

Função: desliga o envio de eventos e apaga URL e segredo.

Responde 200 OK. A partir daí nenhuma mensagem nova entra na fila de eventos — inclusive as disparadas antes de você cadastrar de novo.

O evento

Um único tipo de evento (message.status) para os dois POSTs. O formato não muda; o que muda é o status. Você implementa um handler só.

Os campos de mensagem são exatamente os de GET /sms/messages/{id}. Não há campo exclusivo do webhook além de origin.

O bloco origin

É o que distingue um disparo em massa de uma régua de automação sem você cruzar o id contra as suas tabelas. Em automação ele ganha um campo a mais:

Em automação o nome vem da campanha porque a sequência não tem nome próprio — ela é uma posição na régua. O campaign_id acompanha para você conseguir agrupar.

Verificando a assinatura

Todo POST leva dois headers:

Header
Conteúdo

X-SmsFunnel-Signature

sha256= seguido do HMAC-SHA256 do corpo bruto, com o seu segredo

X-SmsFunnel-Event-Id

Identificador do evento, para idempotência

Assine o corpo exatamente como recebido, antes de qualquer parse — reserializar o JSON muda os bytes e quebra a comparação.

Use o X-SmsFunnel-Event-Id para idempotência. As retentativas de um mesmo evento repetem o id: se você já processou aquele id, descarte.

Entrega e retentativas

Aspecto
Comportamento

Timeout

5 segundos por tentativa

Sucesso

Qualquer 2xx

Retentativa

5xx, 408, 429 e falha de rede — até 5 tentativas, com espera de 10s, 30s, 1min, 5min e 15min

Desistência

Demais 4xx — tratamos como endereço ou contrato errado, e não insistimos

Responda rápido: processe de forma assíncrona e devolva 200 imediatamente. Um endpoint lento gera retentativa mesmo tendo recebido o evento.

Last updated