Documentação
API de eventos
O seu sistema avisa o Speakus quando algo acontece com um usuário — e o funcionário de IA puxa a conversa no WhatsApp. É uma requisição HTTP assinada, sem SDK e sem dependência nova.
Os dois momentos da integração
O mesmo endpoint recebe os dois. Muda apenas o campo event.
- Evento de ciclo de vida —
trial_ended,checkout_abandonado,cadastro_sem_ativacao,assinatura_cancelada… O Speakus cria ou atualiza o lead e prepara a abordagem. - Aviso de conversão —
event: "converted". Fecha o ciclo: o lead vira recuperado nas métricas e abordagens pendentes são canceladas. Não envia mensagem nenhuma.
Implementar só o primeiro deixa o loop pela metade: sem o aviso de conversão, o Speakus mostra quantos você reabordou, mas não quantos voltaram a pagar.
Credenciais
A URL e o segredo são emitidos por workspace no painel, em Configurações → Integrações. A URL já contém a sua chave de ingestão:
POST https://app.speakus.app/v1/hooks/inbound/{ingestKey}Guarde o segredo em variável de ambiente. Na mesma tela há um arquivo de instruções pronto para colar numa IA de código — ela implementa a integração inteira a partir dele.
Assinatura
Envie o header X-Speakus-Signature com sha256= seguido do HMAC-SHA256 hexadecimal do corpo cru da requisição.
Serialize o JSON uma única vez, assine essa string e envie essa mesma string. Re-serializar o objeto depois de assinar é a causa nº 1 de 401.
Exemplo
curl -X POST https://app.speakus.app/v1/hooks/inbound/wk_SUA_CHAVE \
-H "Content-Type: application/json" \
-H "X-Speakus-Signature: sha256=ASSINATURA_DO_CORPO" \
-d '{
"eventId": "trial_usr_412",
"event": "trial_ended",
"occurredAt": "2026-07-27T18:00:00Z",
"lead": {
"phone": "+5585999998888",
"name": "Marina Silva",
"email": "marina@empresa.com",
"externalId": "usr_412"
},
"data": {
"plan": "pro",
"trial_days": 14,
"last_feature_used": "relatorios",
"login_count": 7
}
}'Os dados do lead são dinâmicos
Em data você manda o que quiser sobre o usuário — qualquer chave escalar válida é aceita e vira contexto para a conversa. Quanto mais o funcionário de IA souber, melhor a primeira mensagem: plano testado, dias de trial, última funcionalidade usada, etapa onde a pessoa travou no onboarding, valor do carrinho.
- Chaves em
snake_casecomeçando por letra; até 30 por evento. - Valores escalares: texto, número, booleano ou data ISO. Objetos aninhados são ignorados.
- O tipo é inferido automaticamente e o contrato do evento aprende as chaves novas — elas aparecem na tela de Gatilhos do funcionário.
- Um dado que a IA já descobriu conversando nunca é sobrescrito pelo webhook.
Idempotência
Use um eventId único e determinístico por acontecimento, como trial_<userId>. Reenviar o mesmo eventId devolve a mesma resposta sem criar lead nem abordagem duplicados — então retry após timeout é seguro.
Node.js
import crypto from 'node:crypto'
async function speakusNotify(event, eventId, lead, data = {}) {
const raw = JSON.stringify({ eventId, event, occurredAt: new Date().toISOString(), lead, data })
const signature = 'sha256=' + crypto
.createHmac('sha256', process.env.SPEAKUS_WEBHOOK_SECRET)
.update(raw, 'utf8')
.digest('hex')
const res = await fetch(process.env.SPEAKUS_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Speakus-Signature': signature },
body: raw, // a MESMA string que foi assinada
})
if (res.status >= 500) throw new Error('retry seguro: a chamada é idempotente por eventId')
return res.json()
}
// 1) o trial acabou e o usuário não assinou
await speakusNotify('trial_ended', `trial_${user.id}`,
{ phone: user.phoneE164, name: user.name, email: user.email, externalId: String(user.id) },
{ plan: user.trialPlan, trial_days: 14, login_count: user.loginCount })
// 2) o usuário voltou e assinou — fecha o ciclo
await speakusNotify('converted', `conv_${user.id}`,
{ phone: user.phoneE164 }, { plan_purchased: user.plan, mrr: user.mrr })Respostas
| Código | Significado |
|---|---|
202 | Aceito. O corpo traz leadId, scheduledMessageId e avisos não bloqueantes. |
400 | eventId ausente, JSON inválido ou corpo acima de 64 KB. |
401 | Assinatura ausente ou inválida — confira se assinou o corpo cru com o segredo certo. |
403 | Webhook pausado no painel. |
404 | ingestKey desconhecida. |
422 | Evento fora do catálogo do workspace, ou telefone fora do formato E.164. |
5xx | Falha nossa. Refaça a chamada com o mesmo eventId — é idempotente. |
Recursos para máquinas
- Especificação OpenAPI 3.1 —
/openapi.json - Catálogo de APIs —
/.well-known/api-catalog(RFC 9727) - Resumo para agentes de IA —
/llms.txt - Esta pagina em Markdown — mande
Accept: text/markdownnesta mesma URL e a resposta vem comotext/markdown, comx-markdown-tokensestimando o tamanho do documento.