Event Payload Examples
EasyConfirm fires webhooks for orders created via the Public API (POST /api/v1/orders). Below are example payloads for each event.
order.created
Fired after a new order is created and the WhatsApp template message is sent to the customer successfully.
{
"event": "order.created",
"timestamp": "2026-01-15T10:00:00.000Z",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"externalOrderId": "EO-12345",
"status": "pending",
"customerAction": null,
"deliveryStatus": null,
"customerName": "Ahmed Mohamed",
"customerPhone": "201234567890",
"customerAddress": "15 Tahrir St, Cairo",
"subtotal": 150,
"shippingCost": 25,
"totalCost": 175,
"currency": "EGP",
"failureReason": null,
"errorCode": null,
"items": [
{
"id": "item-uuid-1",
"productName": "iPhone Case",
"variantName": "Black / Large",
"quantity": 2,
"unitPrice": 75,
"totalPrice": 150
}
],
"createdAt": "2026-01-15T10:00:00.000Z",
"updatedAt": "2026-01-15T10:00:00.000Z"
}
}
order.confirmed
Fired when the customer taps the Approve button on the WhatsApp confirmation message.
{
"event": "order.confirmed",
"timestamp": "2026-01-15T10:05:30.000Z",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"externalOrderId": "EO-12345",
"status": "confirmed",
"customerAction": "approved",
"deliveryStatus": "read",
"customerName": "Ahmed Mohamed",
"customerPhone": "201234567890",
"customerAddress": "15 Tahrir St, Cairo",
"subtotal": 150,
"shippingCost": 25,
"totalCost": 175,
"currency": "EGP",
"failureReason": null,
"errorCode": null,
"items": [
{
"id": "item-uuid-1",
"productName": "iPhone Case",
"variantName": "Black / Large",
"quantity": 2,
"unitPrice": 75,
"totalPrice": 150
}
],
"createdAt": "2026-01-15T10:00:00.000Z",
"updatedAt": "2026-01-15T10:05:30.000Z"
}
}
order.canceled
Fired when the customer taps the Cancel button on WhatsApp, or the order is canceled via the API.
{
"event": "order.canceled",
"timestamp": "2026-01-15T10:05:30.000Z",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"externalOrderId": "EO-12345",
"status": "canceled",
"customerAction": "canceled",
"deliveryStatus": "read",
"customerName": "Ahmed Mohamed",
"customerPhone": "201234567890",
"customerAddress": "15 Tahrir St, Cairo",
"subtotal": 150,
"shippingCost": 25,
"totalCost": 175,
"currency": "EGP",
"failureReason": null,
"errorCode": null,
"items": [
{
"id": "item-uuid-1",
"productName": "iPhone Case",
"variantName": "Black / Large",
"quantity": 2,
"unitPrice": 75,
"totalPrice": 150
}
],
"createdAt": "2026-01-15T10:00:00.000Z",
"updatedAt": "2026-01-15T10:05:30.000Z"
}
}
order.failed
Fired when the WhatsApp message delivery fails asynchronously — i.e., the order was created successfully, Meta accepted the send request, but the message later failed to be delivered (e.g., the recipient's device is offline for an extended period, or Meta reports a delivery failure via webhook callback).
:::warning When this event fires (and when it does NOT) This event fires only for asynchronous delivery failures reported by Meta after the order was successfully created.
It does NOT fire when Meta synchronously rejects the send during the API call itself (e.g., recipient not in test allowlist, template paused, template not approved). In that case POST /api/v1/orders returns a 400 response containing errorCode and failureReason directly — there is no webhook callback for that scenario, because the caller already received the failure in the API response.
| Failure type | How you learn about it |
|---|---|
| Meta rejects the send synchronously | POST /api/v1/orders → 400 with errorCode + failureReason |
| Meta accepts the send, then delivery fails later | order.failed webhook with errorCode + failureReason |
In both cases the order is persisted with status: failed and the same failureReason + errorCode, so GET /orders/:id returns the full failure context regardless of which path failed.
:::
{
"event": "order.failed",
"timestamp": "2026-01-15T10:01:00.000Z",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"externalOrderId": "EO-12345",
"status": "failed",
"customerAction": null,
"deliveryStatus": "failed",
"customerName": "Ahmed Mohamed",
"customerPhone": "201234567890",
"customerAddress": "15 Tahrir St, Cairo",
"subtotal": 150,
"shippingCost": 25,
"totalCost": 175,
"currency": "EGP",
"failureReason": "Recipient phone number not in allowed list",
"errorCode": 131030,
"items": [
{
"id": "item-uuid-1",
"productName": "iPhone Case",
"variantName": "Black / Large",
"quantity": 2,
"unitPrice": 75,
"totalPrice": 150
}
],
"createdAt": "2026-01-15T10:00:00.000Z",
"updatedAt": "2026-01-15T10:01:00.000Z"
}
}
Understanding failureReason and errorCode
Both fields are populated directly from Meta's WhatsApp Cloud API error payload — EasyConfirm does not define its own enum of failure values. This means:
errorCode(integer, nullable) — the numeric error code from Meta. Use this for programmatic handling. It is stable and documented by Meta. May benullif the failure occurred before reaching Meta (e.g. internal validation) or for orders that failed before this field was introduced.failureReason(string, nullable) — the human-readable error text from Meta (errors[0].message, falling back toerrors[0].title, then"Unknown failure"). Do not match on the text — Meta may change the wording without notice, and it can be returned in different languages. Use it for display only.
Common Meta error codes
The full, authoritative list is maintained by Meta: 👉 Meta WhatsApp Cloud API — Error Codes Reference
Codes you are most likely to encounter on order.failed:
| Code | Meaning | Suggested handling |
|---|---|---|
131026 | Message undeliverable (recipient not on WhatsApp, device offline) | Mark order for phone-call follow-up |
131030 | Recipient phone number not in the allowed list (test mode only) | Add recipient to allowed list, or move the WABA out of test mode |
131042 | Business eligibility / payment issue (e.g., PAYG funding) | Check WhatsApp Business billing in Meta Business Suite |
131045 | Template not approved by Meta | Re-submit the template or pick an approved one |
131047 | Re-engagement window expired (24h customer service window closed) | Use a pre-approved template message |
131048 | Spam rate limit reached | Throttle outgoing sends; review opt-in compliance |
131049 | User has stopped marketing messages | Suppress this recipient from marketing campaigns |
131056 | Pair rate limit (too many messages to the same recipient) | Back off and retry later |
132000 | Template parameter count mismatch | Verify your template variable bindings |
132001 | Template does not exist (deleted or wrong language) | Re-create the template or correct the language code |
132005 | Translated text too long | Shorten the rendered template |
132007 | Template format character policy violated | Remove disallowed characters |
132012 | Template parameter format mismatch | Match Meta's required format for that variable |
132015 | Template paused due to quality drop | Improve template quality; wait for un-pausing |
132016 | Template disabled | Choose another template |
133010 | Phone number not registered | Re-register the WABA phone number |
:::note Key Differences Between Events
order.created:statusispending,customerActionanddeliveryStatusarenullorder.confirmed:statusisconfirmed,customerActionisapprovedorder.canceled:statusiscanceled,customerActioniscanceledorder.failed:statusisfailed,failureReasoncontains the error text anderrorCodecontains Meta's numeric error code :::