API de Webhooks
Payloads e tipos de eventos de webhook
A Antonnia envia eventos de webhook para o endpoint configurado no seu app. Para começar a receber eventos:
- Crie um App em Settings > Apps no painel da Antonnia
- Inscreva-se nos eventos que você precisa (ex.:
message.created,session.finished) - Configure sua URL de webhook no app
- Clientes que se conectam ao seu app dispararão eventos entregues ao seu webhook
Todos os eventos são entregues como requisições HTTP POST com corpo JSON.
Envelope do evento
Todo evento segue esta estrutura:
{
"id": "evt_abc123",
"timestamp": 1710000000,
"type": "message.created",
"organization_id": "org_xyz",
"data": {
"object": { ... }
}
}| Field | Type | Description |
|---|---|---|
id | string | Identificador único do evento |
timestamp | integer | Timestamp Unix |
type | string | Tipo do evento |
organization_id | string | Organização proprietária do recurso |
data.object | object | O objeto completo do recurso |
message.created
Disparado quando uma nova mensagem é adicionada a uma sessão. Este é o evento principal para integrações de canal — escute mensagens com role: "assistant" para entregar respostas de saída.
{
"id": "evt_abc123",
"timestamp": 1710000000,
"type": "message.created",
"organization_id": "org_xyz",
"data": {
"object": {
"id": "msg_123",
"session_id": "sess_456",
"conversation_id": "conv_789",
"organization_id": "org_xyz",
"role": "assistant",
"content": { "type": "text", "text": "Hello! How can I help?" },
"delivery_status": "pending",
"provider_message_id": null,
"replied_provider_message_id": null,
"run_id": "run_001",
"metadata": {},
"created_at": "2025-01-15T10:30:00Z",
"updated_at": null
}
}
}Você receberá message.created para todas as mensagens — tanto com role user quanto assistant. Filtre por role: "assistant" para evitar processar suas próprias mensagens de entrada.
Ignore mensagens onde content.type seja "function_call", "function_result" ou "thought". Essas são mensagens internas da IA e não são destinadas aos usuários finais.
Tratando este evento
@app.post("/webhook")
async def handle_webhook(request: Request):
event = await request.json()
if event["type"] == "message.created":
message = event["data"]["object"]
# Only process assistant messages
if message["role"] != "assistant":
return {"ok": True}
# Skip internal content types
if message["content"]["type"] in ("function_call", "function_result", "thought"):
return {"ok": True}
# Deliver through your channel
await deliver_to_channel(message)
return {"ok": True}session.created
Disparado quando uma nova sessão é criada.
{
"id": "evt_def456",
"timestamp": 1710000000,
"type": "session.created",
"organization_id": "org_xyz",
"data": {
"object": {
"id": "sess_456",
"contact_id": "5511999888777",
"organization_id": "org_xyz",
"conversation_id": "conv_789",
"status": "open",
"agent": {
"id": "agent_abc",
"name": "Support Bot",
"type": "ai"
},
"metadata": {
"whatsapp_phone_number": "5511999888777"
},
"created_at": "2025-01-15T10:30:00Z"
}
}
}session.transferred
Disparado quando o agente de uma sessão é alterado via POST /sessions/{id}/transfer.
{
"id": "evt_ghi789",
"timestamp": 1710000000,
"type": "session.transferred",
"organization_id": "org_xyz",
"data": {
"object": {
"id": "sess_456",
"contact_id": "5511999888777",
"status": "open",
"agent": {
"id": "agent_human_123",
"name": "João Silva",
"type": "human"
},
"metadata": {}
}
}
}Use este evento para atualizar a UI do seu canal — por exemplo, exibindo "Agora você está conversando com um agente humano."
session.finished
Disparado quando uma sessão é encerrada via POST /sessions/{id}/finish.
{
"id": "evt_jkl012",
"timestamp": 1710000000,
"type": "session.finished",
"organization_id": "org_xyz",
"data": {
"object": {
"id": "sess_456",
"contact_id": "5511999888777",
"status": "closed",
"agent": null,
"metadata": {}
}
}
}O data.object pode incluir um campo action:
| Action | Meaning |
|---|---|
null | Encerrado manualmente |
"expired" | Expirado automaticamente pelo sistema |
Use este evento para limpar recursos do lado do canal (fechar tickets, encerrar chats ao vivo).
Boas práticas
- Retorne 200 rapidamente — processe eventos de forma assíncrona se exigirem trabalho pesado
- Seja idempotente — você pode receber o mesmo evento mais de uma vez; use
event.idpara deduplicar - Filtre por tipo e role — processe apenas os eventos relevantes para sua integração
- Trate sessões ausentes com elegância — eventos podem chegar fora de ordem