Webhooks
DoneTalk tells your system what happens, with a signed POST to an address of yours: a campaign started or finished, a message was delivered or read, a contact replied, a conversation was closed with its outcome.
Register an address
In Settings › Integrations › Outgoing webhooks, or through the API with the webhooks:manage scope:
curl -X POST https://api.donetalk.com/v1/c/{company}/webhooks \
-H "Authorization: Bearer $DONETALK_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://your-system.com/donetalk/events", "events": ["campaign.completed", "campaign.recipient.replied", "conversation.closed"]}'The answer carries the secret only once: keep it to check the signatures.
What arrives
POST /donetalk/events HTTP/1.1
Content-Type: application/json
User-Agent: DoneTalk-Webhooks/1.0
DoneTalk-Signature: t=1792756800,v1=5f0c…
X-DoneTalk-Event: conversation.closed
X-DoneTalk-Delivery: 01a3e4f5-a6b7-7c8d-9e0f-1a2b3c4d5e6f{
"id": "01a3e4f5-…",
"type": "conversation.closed",
"occurredAt": "2026-10-24T12:20:41.000Z",
"customerId": "01a0c0de-…",
"data": { "...": "the event's content" }
}Events from a test key carry "test": true.
Check the signature
DoneTalk-Signature carries t (when it was sent, in seconds) and v1, the HMAC SHA-256 of "<t>.<exact body>" with your secret. Refuse events with a t older than 5 minutes: then no one can replay an old event.
import crypto from "node:crypto";
function validEvent(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}import hmac, hashlib, time
def valid_event(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
if abs(time.time() - int(parts["t"])) > 300:
return False
expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts["v1"])The older x-donetalk-signature header (sha256= + HMAC of the body, without the time) goes along until 2027-01-21.
Answering and retries
Answer 2xx within 10 seconds; do heavy work afterwards. Without a 2xx, DoneTalk retries after 1 min, 5 min, 30 min, 2 h and 12 h. After 20 failures in a row the address shows as "Failing" (it keeps receiving). The same event may arrive more than once: use its id to process it once. Arrival order is not guaranteed: use occurredAt.
Events
| Event | When it arrives |
|---|---|
conversation.opened | A conversation started (the contact wrote or clicked an ad). |
conversation.closed | A conversation was closed, with the outcome, who closed it (person, AI assistant or automatic rule), the closing note, the contact, team, tags, how long it took and the campaign it came from. |
conversation.assigned | A conversation was assigned to a person. |
conversation.transferred | A conversation moved to another team or person. |
conversation.reopened | A closed conversation was reopened. |
contact.updated | A contact's data changed. |
contact.consent_changed | The contact opted in or out of a purpose (marketing, for example). |
message.received | The contact sent a message. |
message.sent | A message of ours left for WhatsApp. |
message.delivered | A message reached the contact's phone. |
message.read | The contact read a message. |
message.failed | A message could not be delivered; error.code is Meta's code. |
flow.event | A flow reached a “Record event” block, with the name and data the block sets. |
appointment.booked | An appointment was booked. |
appointment.rescheduled | An appointment was moved. |
appointment.cancelled | An appointment was cancelled. |
appointment.confirmed | The contact confirmed the appointment. |
appointment.attended | The contact attended. |
appointment.no_show | The contact did not show up. |
campaign.started | The campaign started sending; its list was frozen. |
campaign.paused | The campaign paused: by a person, the API or a rule (template paused, low quality, many opt-outs, budget). |
campaign.resumed | The campaign resumed sending. |
campaign.completed | The campaign finished sending, with its totals. |
campaign.cancelled | The campaign was cancelled. |
campaign.recipient.sent | The campaign's message left for a contact. |
campaign.recipient.delivered | The campaign's message reached the contact. |
campaign.recipient.read | The contact read the campaign's message. |
campaign.recipient.replied | The contact answered the campaign (the first answer), by text or tapping a button. |
campaign.recipient.failed | The campaign's message failed for a contact; errorCode is Meta's code. |
campaign.recipient.opted_out | The contact asked for no more campaigns (the “Stop promotions” button or a refusal at Meta). |
Example of each event
conversation.opened
A conversation started (the contact wrote or clicked an ad).
{
"id": "01a3e4f5-…",
"type": "conversation.opened",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"channelId": "01a0cccc-0000-7000-8000-000000000002",
"handler": "flow",
"source": "inbound"
}
}conversation.closed
A conversation was closed, with the outcome, who closed it (person, AI assistant or automatic rule), the closing note, the contact, team, tags, how long it took and the campaign it came from.
{
"id": "01a3e4f5-…",
"type": "conversation.closed",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"channelId": "01a0cccc-0000-7000-8000-000000000002",
"teamId": "01a0cb22-89c0-7e02-b96b-3f4731dde701",
"assigneeId": "01a0cac1-4a6f-7646-b5f8-c1d19090016a",
"outcome": "converted",
"isSuccess": true,
"closedBy": {
"kind": "member",
"id": "01a0cac1-4a6f-7646-b5f8-c1d19090016a",
"name": "Tayomara Batista"
},
"actorKind": "member",
"openedAt": "2026-10-24T12:00:04.000Z",
"firstResponseAt": "2026-10-24T12:05:10.000Z",
"messagesIn": 6,
"messagesOut": 7,
"outcomeLabel": {
"pt-BR": "Venda",
"en": "Sale",
"es": "Venta"
},
"outcomeCategory": "success",
"note": "Fechou o plano anual com o cupom ANA10.",
"contact": {
"name": "Ana Souza",
"phone": "5548999990001"
},
"team": {
"id": "01a0cb22-89c0-7e02-b96b-3f4731dde701",
"name": "Vendas"
},
"tags": [
{
"id": "01a12150-3610-7c00-b680-188c2b4c7313",
"name": {
"pt-BR": "VIP",
"en": "VIP",
"es": "VIP"
}
}
],
"durationSeconds": 1237,
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b"
}
}conversation.assigned
A conversation was assigned to a person.
{
"id": "01a3e4f5-…",
"type": "conversation.assigned",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"assigneeId": "01a0cac1-4a6f-7646-b5f8-c1d19090016a",
"teamId": "01a0cb22-89c0-7e02-b96b-3f4731dde701",
"reason": "distribution",
"previousAssigneeId": null,
"actorKind": "system"
}
}conversation.transferred
A conversation moved to another team or person.
{
"id": "01a3e4f5-…",
"type": "conversation.transferred",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"teamId": "01a0cb22-89c0-7e02-b96b-3f4731dde701",
"assigneeId": null,
"previousTeamId": null,
"previousAssigneeId": null,
"previousHandler": "flow",
"actorKind": "flow",
"reason": "Gestor de conta: Tayomara Batista"
}
}conversation.reopened
A closed conversation was reopened.
{
"id": "01a3e4f5-…",
"type": "conversation.reopened",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677"
}
}contact.updated
A contact's data changed.
{
"id": "01a3e4f5-…",
"type": "contact.updated",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"changes": [
"fields",
"displayName"
]
}
}contact.consent_changed
The contact opted in or out of a purpose (marketing, for example).
{
"id": "01a3e4f5-…",
"type": "contact.consent_changed",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"channel": "whatsapp",
"purpose": "marketing",
"status": "opted_out",
"source": "keyword",
"occurredAt": "2026-10-24T12:06:00.000Z"
}
}message.received
The contact sent a message.
{
"id": "01a3e4f5-…",
"type": "message.received",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"messageId": "01a3c0de-8b22-7c33-9d44-0e55f6677889",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"channelId": "01a0cccc-0000-7000-8000-000000000002",
"type": "text"
}
}message.sent
A message of ours left for WhatsApp.
{
"id": "01a3e4f5-…",
"type": "message.sent",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"messageId": "01a3c0de-8b22-7c33-9d44-0e55f6677889",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"providerMessageId": "wamid.HBgMNTU0ODk5OTk5MDAwMRUCABEYEjE="
}
}message.delivered
A message reached the contact's phone.
{
"id": "01a3e4f5-…",
"type": "message.delivered",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"messageId": "01a3c0de-8b22-7c33-9d44-0e55f6677889",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"status": "delivered",
"occurredAt": "2026-10-24T12:00:06.000Z"
}
}message.read
The contact read a message.
{
"id": "01a3e4f5-…",
"type": "message.read",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"messageId": "01a3c0de-8b22-7c33-9d44-0e55f6677889",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"status": "read",
"occurredAt": "2026-10-24T12:03:51.000Z"
}
}message.failed
A message could not be delivered; error.code is Meta's code.
{
"id": "01a3e4f5-…",
"type": "message.failed",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"messageId": "01a3c0de-8b22-7c33-9d44-0e55f6677889",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"status": "failed",
"occurredAt": "2026-10-24T12:00:06.000Z",
"error": {
"code": "131026",
"detail": "Message undeliverable"
}
}
}flow.event
A flow reached a “Record event” block, with the name and data the block sets.
{
"id": "01a3e4f5-…",
"type": "flow.event",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"name": "lead.qualified",
"data": {
"plano": "anual",
"origem": "site"
}
}
}appointment.booked
An appointment was booked.
{
"id": "01a3e4f5-…",
"type": "appointment.booked",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"id": "01a2f00d-1234-7abc-8def-0123456789ab",
"agendaId": "01a1228c-c584-73f7-b7e7-bfaa0d02fed0",
"agendaName": "Visitas aos imóveis",
"typeId": "01a1228c-c58f-796a-b3aa-54a953711c71",
"typeName": "Visita ao imóvel",
"typeColor": "#1daa61",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"contactName": "Ana Souza",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"channelId": "01a0cccc-0000-7000-8000-000000000002",
"memberId": "01a0cac1-4a6f-7646-b5f8-c1d19090016a",
"memberName": "Tayomara Batista",
"holderIds": [
"01a0cac1-4a6f-7646-b5f8-c1d19090016a"
],
"status": "booked",
"startsAt": "2026-10-27T13:00:00.000Z",
"endsAt": "2026-10-27T14:00:00.000Z",
"timezone": "America/Sao_Paulo",
"location": "Rua Bahia, 120 – Higienópolis, São Paulo",
"locationKind": "address",
"onlineUrl": null,
"answers": {
"imovel": "AP-2231"
},
"notes": null,
"source": "api",
"createdByKind": "api_key",
"createdById": null,
"confirmedAt": null,
"cancelledAt": null,
"cancelledByKind": null,
"cancelReason": null,
"rescheduleCount": 0,
"previousStartsAt": null,
"publicToken": "r3WqZ8",
"createdAt": "2026-10-23T13:02:11.000Z"
}
}appointment.rescheduled
An appointment was moved.
{
"id": "01a3e4f5-…",
"type": "appointment.rescheduled",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"id": "01a2f00d-1234-7abc-8def-0123456789ab",
"agendaId": "01a1228c-c584-73f7-b7e7-bfaa0d02fed0",
"agendaName": "Visitas aos imóveis",
"typeId": "01a1228c-c58f-796a-b3aa-54a953711c71",
"typeName": "Visita ao imóvel",
"typeColor": "#1daa61",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"contactName": "Ana Souza",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"channelId": "01a0cccc-0000-7000-8000-000000000002",
"memberId": "01a0cac1-4a6f-7646-b5f8-c1d19090016a",
"memberName": "Tayomara Batista",
"holderIds": [
"01a0cac1-4a6f-7646-b5f8-c1d19090016a"
],
"status": "booked",
"startsAt": "2026-10-27T13:00:00.000Z",
"endsAt": "2026-10-27T14:00:00.000Z",
"timezone": "America/Sao_Paulo",
"location": "Rua Bahia, 120 – Higienópolis, São Paulo",
"locationKind": "address",
"onlineUrl": null,
"answers": {
"imovel": "AP-2231"
},
"notes": null,
"source": "api",
"createdByKind": "api_key",
"createdById": null,
"confirmedAt": null,
"cancelledAt": null,
"cancelledByKind": null,
"cancelReason": null,
"rescheduleCount": 1,
"previousStartsAt": "2026-10-27T12:00:00.000Z",
"publicToken": "r3WqZ8",
"createdAt": "2026-10-23T13:02:11.000Z"
}
}appointment.cancelled
An appointment was cancelled.
{
"id": "01a3e4f5-…",
"type": "appointment.cancelled",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"id": "01a2f00d-1234-7abc-8def-0123456789ab",
"agendaId": "01a1228c-c584-73f7-b7e7-bfaa0d02fed0",
"agendaName": "Visitas aos imóveis",
"typeId": "01a1228c-c58f-796a-b3aa-54a953711c71",
"typeName": "Visita ao imóvel",
"typeColor": "#1daa61",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"contactName": "Ana Souza",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"channelId": "01a0cccc-0000-7000-8000-000000000002",
"memberId": "01a0cac1-4a6f-7646-b5f8-c1d19090016a",
"memberName": "Tayomara Batista",
"holderIds": [
"01a0cac1-4a6f-7646-b5f8-c1d19090016a"
],
"status": "cancelled",
"startsAt": "2026-10-27T13:00:00.000Z",
"endsAt": "2026-10-27T14:00:00.000Z",
"timezone": "America/Sao_Paulo",
"location": "Rua Bahia, 120 – Higienópolis, São Paulo",
"locationKind": "address",
"onlineUrl": null,
"answers": {
"imovel": "AP-2231"
},
"notes": null,
"source": "api",
"createdByKind": "api_key",
"createdById": null,
"confirmedAt": null,
"cancelledAt": "2026-10-26T18:00:00.000Z",
"cancelledByKind": "contact",
"cancelReason": null,
"rescheduleCount": 0,
"previousStartsAt": null,
"publicToken": "r3WqZ8",
"createdAt": "2026-10-23T13:02:11.000Z"
}
}appointment.confirmed
The contact confirmed the appointment.
{
"id": "01a3e4f5-…",
"type": "appointment.confirmed",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"id": "01a2f00d-1234-7abc-8def-0123456789ab",
"agendaId": "01a1228c-c584-73f7-b7e7-bfaa0d02fed0",
"agendaName": "Visitas aos imóveis",
"typeId": "01a1228c-c58f-796a-b3aa-54a953711c71",
"typeName": "Visita ao imóvel",
"typeColor": "#1daa61",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"contactName": "Ana Souza",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"channelId": "01a0cccc-0000-7000-8000-000000000002",
"memberId": "01a0cac1-4a6f-7646-b5f8-c1d19090016a",
"memberName": "Tayomara Batista",
"holderIds": [
"01a0cac1-4a6f-7646-b5f8-c1d19090016a"
],
"status": "confirmed",
"startsAt": "2026-10-27T13:00:00.000Z",
"endsAt": "2026-10-27T14:00:00.000Z",
"timezone": "America/Sao_Paulo",
"location": "Rua Bahia, 120 – Higienópolis, São Paulo",
"locationKind": "address",
"onlineUrl": null,
"answers": {
"imovel": "AP-2231"
},
"notes": null,
"source": "api",
"createdByKind": "api_key",
"createdById": null,
"confirmedAt": "2026-10-26T14:00:00.000Z",
"cancelledAt": null,
"cancelledByKind": null,
"cancelReason": null,
"rescheduleCount": 0,
"previousStartsAt": null,
"publicToken": "r3WqZ8",
"createdAt": "2026-10-23T13:02:11.000Z"
}
}appointment.attended
The contact attended.
{
"id": "01a3e4f5-…",
"type": "appointment.attended",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"id": "01a2f00d-1234-7abc-8def-0123456789ab",
"agendaId": "01a1228c-c584-73f7-b7e7-bfaa0d02fed0",
"agendaName": "Visitas aos imóveis",
"typeId": "01a1228c-c58f-796a-b3aa-54a953711c71",
"typeName": "Visita ao imóvel",
"typeColor": "#1daa61",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"contactName": "Ana Souza",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"channelId": "01a0cccc-0000-7000-8000-000000000002",
"memberId": "01a0cac1-4a6f-7646-b5f8-c1d19090016a",
"memberName": "Tayomara Batista",
"holderIds": [
"01a0cac1-4a6f-7646-b5f8-c1d19090016a"
],
"status": "attended",
"startsAt": "2026-10-27T13:00:00.000Z",
"endsAt": "2026-10-27T14:00:00.000Z",
"timezone": "America/Sao_Paulo",
"location": "Rua Bahia, 120 – Higienópolis, São Paulo",
"locationKind": "address",
"onlineUrl": null,
"answers": {
"imovel": "AP-2231"
},
"notes": null,
"source": "api",
"createdByKind": "api_key",
"createdById": null,
"confirmedAt": null,
"cancelledAt": null,
"cancelledByKind": null,
"cancelReason": null,
"rescheduleCount": 0,
"previousStartsAt": null,
"publicToken": "r3WqZ8",
"createdAt": "2026-10-23T13:02:11.000Z"
}
}appointment.no_show
The contact did not show up.
{
"id": "01a3e4f5-…",
"type": "appointment.no_show",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"id": "01a2f00d-1234-7abc-8def-0123456789ab",
"agendaId": "01a1228c-c584-73f7-b7e7-bfaa0d02fed0",
"agendaName": "Visitas aos imóveis",
"typeId": "01a1228c-c58f-796a-b3aa-54a953711c71",
"typeName": "Visita ao imóvel",
"typeColor": "#1daa61",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"contactName": "Ana Souza",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"channelId": "01a0cccc-0000-7000-8000-000000000002",
"memberId": "01a0cac1-4a6f-7646-b5f8-c1d19090016a",
"memberName": "Tayomara Batista",
"holderIds": [
"01a0cac1-4a6f-7646-b5f8-c1d19090016a"
],
"status": "no_show",
"startsAt": "2026-10-27T13:00:00.000Z",
"endsAt": "2026-10-27T14:00:00.000Z",
"timezone": "America/Sao_Paulo",
"location": "Rua Bahia, 120 – Higienópolis, São Paulo",
"locationKind": "address",
"onlineUrl": null,
"answers": {
"imovel": "AP-2231"
},
"notes": null,
"source": "api",
"createdByKind": "api_key",
"createdById": null,
"confirmedAt": null,
"cancelledAt": null,
"cancelledByKind": null,
"cancelReason": null,
"rescheduleCount": 0,
"previousStartsAt": null,
"publicToken": "r3WqZ8",
"createdAt": "2026-10-23T13:02:11.000Z"
}
}campaign.started
The campaign started sending; its list was frozen.
{
"id": "01a3e4f5-…",
"type": "campaign.started",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"status": "running",
"audience": 1240,
"skipped": 24,
"startedAt": "2026-10-24T12:00:00.000Z"
}
}campaign.paused
The campaign paused: by a person, the API or a rule (template paused, low quality, many opt-outs, budget).
{
"id": "01a3e4f5-…",
"type": "campaign.paused",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"status": "paused",
"reason": "optout_rate",
"by": "system"
}
}campaign.resumed
The campaign resumed sending.
{
"id": "01a3e4f5-…",
"type": "campaign.resumed",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"status": "running",
"by": "api_key"
}
}campaign.completed
The campaign finished sending, with its totals.
{
"id": "01a3e4f5-…",
"type": "campaign.completed",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"status": "completed",
"totals": {
"audience": 1216,
"sent": 1216,
"delivered": 1198,
"read": 874,
"replied": 141,
"failed": 18,
"skipped": 24,
"optedOut": 6
}
}
}campaign.cancelled
The campaign was cancelled.
{
"id": "01a3e4f5-…",
"type": "campaign.cancelled",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"status": "cancelled",
"by": "member"
}
}campaign.recipient.sent
The campaign's message left for a contact.
{
"id": "01a3e4f5-…",
"type": "campaign.recipient.sent",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"phone": "5548999990001",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"messageId": "01a3c0de-8b22-7c33-9d44-0e55f6677889",
"at": "2026-10-24T12:00:04.000Z"
}
}campaign.recipient.delivered
The campaign's message reached the contact.
{
"id": "01a3e4f5-…",
"type": "campaign.recipient.delivered",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"phone": "5548999990001",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"messageId": "01a3c0de-8b22-7c33-9d44-0e55f6677889",
"at": "2026-10-24T12:00:06.000Z"
}
}campaign.recipient.read
The contact read the campaign's message.
{
"id": "01a3e4f5-…",
"type": "campaign.recipient.read",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"phone": "5548999990001",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"messageId": "01a3c0de-8b22-7c33-9d44-0e55f6677889",
"at": "2026-10-24T12:03:51.000Z"
}
}campaign.recipient.replied
The contact answered the campaign (the first answer), by text or tapping a button.
{
"id": "01a3e4f5-…",
"type": "campaign.recipient.replied",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"buttonIndex": 0,
"text": "Quero o cupom"
}
}campaign.recipient.failed
The campaign's message failed for a contact; errorCode is Meta's code.
{
"id": "01a3e4f5-…",
"type": "campaign.recipient.failed",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"phone": "5548999990001",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"messageId": "01a3c0de-8b22-7c33-9d44-0e55f6677889",
"errorCode": "131026"
}
}campaign.recipient.opted_out
The contact asked for no more campaigns (the “Stop promotions” button or a refusal at Meta).
{
"id": "01a3e4f5-…",
"type": "campaign.recipient.opted_out",
"occurredAt": "2026-10-24T12:04:02.000Z",
"customerId": "01a0c0de-…",
"data": {
"campaignId": "01a2b3c4-5d6e-7f80-9a1b-2c3d4e5f6a7b",
"contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
"conversationId": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
"via": "button"
}
}