Webhooks in EvolutionAPI
How to configure and receive EvolutionAPI webhooks with retries, idempotency and production-grade security, with real payload examples.
EvolutionAPI sends events via HTTP POST webhook to a URL you define. The webhook is how your automation (n8n, your own API, etc.) knows that a message has arrived.
Available events
| Event | When it fires |
|---|---|
MESSAGES_UPSERT | Message received or sent |
MESSAGES_UPDATE | Status changed (delivered, read) |
CONNECTION_UPDATE | Connected/disconnected |
PRESENCE_UPDATE | ”Typing…” / online |
QRCODE_UPDATED | New QR code for pairing |
Configure the global webhook
Set it when you create the instance:
curl -X POST https://sua-evolution.rollinhost.com.br/instance/create \
-H "Content-Type: application/json" \
-H "apikey: SUA_API_KEY" \
-d '{
"instanceName": "atendimento",
"qrcode": true,
"webhook": {
"url": "https://seu-n8n.exemplo.com/webhook/whats-in",
"events": ["MESSAGES_UPSERT", "CONNECTION_UPDATE"],
"webhook_by_events": false
}
}'
Payload structure
{
"event": "messages.upsert",
"instance": "atendimento",
"data": {
"key": {
"remoteJid": "5511999999999@s.whatsapp.net",
"fromMe": false,
"id": "3EB0..."
},
"pushName": "João Silva",
"message": {
"conversation": "Oi, gostaria de saber sobre os planos"
},
"messageTimestamp": 1735689600
}
}
Retries and idempotency
Best practices:
- Always return 200 quickly (< 5s) and process in a queue
- Idempotency by
data.key.id: webhooks may arrive duplicated after a reconnection - Persist the raw event before processing it (if there is a bug, you can reprocess)
Security
EvolutionAPI does not sign webhooks by default. To make sure the request came from it:
- Restrict by IP in the firewall (only the Evolution server’s IP)
- Use a URL with a secret path (
/webhook/abc123-supersecreto) - Validate a custom
apikeyin the header (configure n8n to check it)
Next steps
Last updated: