Webhooks
Webhooks
Events we post to your HTTPS endpoint as they happen, signed so you can verify them, delivered at least once.
When something happens in your account (a customer writes, a conversation is handed to
your team, an appointment is booked) we send a POST with a JSON body to every endpoint
subscribed to that event. Webhooks are part of the Business plan; an Owner or Admin sets
them up under Integrations → Webhooks.
The envelope
Every event has the same outer shape. data depends on type; each
event page documents it.
{
"id": "evt_5dabddce7c097ab703f21e8fdf0ab52b",
"type": "message.received",
"apiVersion": "2026-10",
"createdAt": "2026-10-01T09:30:05+00:00",
"test": false,
"company": {
"id": "0b3d6f2e-8a41-4c75-9e20-5f7a1c3d9b84",
"name": "متجر الرياض"
},
"data": {
"conversation": {
"id": "WhatsApp_3f6a2d18-0b7c-4e91-8a5d-c24e1f9b7a60",
"channelId": "7c1e4b2a-9d3f-4e58-a6b1-2f0c8d7e5a13",
"channelType": "whatsapp"
},
"contact": {
"id": "3f6a2d18-0b7c-4e91-8a5d-c24e1f9b7a60",
"name": "نورة العتيبي",
"phone": "+966501234567",
"whatsAppId": "966501234567"
},
"message": {
"id": "m_wamid.HBgMOTY2NTAxMjM0NTY3FQIAEhggQTNFQjU2RkQ5RTcyOEIyRDQ1",
"text": "السلام عليكم، متى يوصل طلبي رقم 10482؟",
"type": "text",
"receivedAt": "2026-10-01T09:30:00+00:00"
}
}
}| Field | Type | Meaning |
|---|---|---|
id | string | The event's id, evt_…. The same on every retry and resend: deduplicate on it. |
type | string | The event, such as message.received. Acknowledge types you do not know. |
apiVersion | string | The shape of data, currently 2026-10. See Versioning. |
createdAt | string | When it happened, UTC. |
test | boolean | true for what Send test posts: sample data about nobody real. Always present. |
company.id | string (UUID) | The account or project it happened in. |
company.name | string or null | That company's name. |
data | object | The event's details. |
Headers
| Header | Value |
|---|---|
Content-Type | application/json; charset=utf-8 |
User-Agent | RevoplyAI-Webhooks/1.0 |
X-Revoply-Signature | t=<unix seconds>,v1=<hex HMAC-SHA256>; see Signatures |
X-Revoply-Event | The event's type, so you can route before parsing |
X-Revoply-Delivery | The delivery's id (a UUID), as the delivery log shows it; quote it to support |
Delivery
- Answer with any
2xxwithin 10 seconds. Acknowledge first, then do the work: a receiver that holds the request open while it calls other systems will time out. Anything else (another status, a redirect, a timeout, a refused connection) is a failure and is retried. - At least once. An event can arrive more than once, for example when your
2xxwas lost on the way back. Every delivery of it carries the sameid; record the ids you have handled and skip repeats. - No ordering guarantee. Deliveries are sent in parallel and retried on a schedule, so
a later event can arrive before an earlier one. Order by
createdAt, and do not assume, for example, thatconversation.startedarrives before the firstmessage.received. - Verify before you trust. Check the signature and its timestamp on every request; see Verify webhook signatures.
When nothing is sent
- Switched-off endpoints receive nothing; events that happen while an endpoint is off are not sent to it later.
- Outside the Business plan, endpoints are kept but receive nothing until the account is back on it.
- A pause on our side. We can pause all calls to merchants' systems, for example during an incident. The Webhooks page then shows a notice; events that happen during a pause are not sent later, and tests and resends are refused until it ends.
Events
| Event | What happened |
|---|---|
message.received | A customer wrote. |
conversation.started | A new conversation began. |
conversation.handover | The conversation was handed to the team. |
conversation.assigned | The conversation was assigned, or unassigned. |
conversation.resolved | The conversation was resolved or closed. |
contact.created | A contact was added. |
contact.updated | A contact's details changed. |
contact.opted_out | A contact opted out of messages. |
lead.qualified | A conversation became a qualified lead. |
appointment.booked | An appointment was booked. |
appointment.cancelled | An appointment was cancelled. |
flow.completed | An automation finished. |
flow.failed | An automation failed. |
ping | A test from the dashboard. |