> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lazyapp.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Event reference

> Every webhook LazyApp sends.

Subscribe to what you handle by listing types in `subscribed_events`, or omit it to receive everything.

## Messages

| Event | When |
| - | - |
| `message.received` | A contact messaged you. Includes replies, button taps, media, location and order carts (`content.order`) |
| `message.queued` | Accepted by LazyApp, not yet handed to the provider |
| `message.sent` | The provider accepted it |
| `message.delivered` | It reached the recipient's device |
| `message.read` | The recipient opened it |
| `message.played` | A voice note was played |
| `message.failed` | Delivery failed. `error_message` carries the reason |
| `message.deleted` | A coexistence revoke deleted a previously stored message. Payload is the original message plus `deleted_at` |
| `message.edited` | A contact edited a message within 15 minutes (WhatsApp Business app numbers only). Payload is the updated message plus `previous_body`, `edited_at` and `edit_provider_message_id` |
| `message.echo` | Someone replied from the WhatsApp Business app on a coexistence number. The message never passed through the API, so this is the only way you hear about it. Imported chat history is not sent |
| `reaction.received` | Someone added or removed an emoji reaction. Also still arrives as `message.received` with `type: reaction` |
| `conversation.started` | First time this contact opens a thread on a connection (not on reopen) |
| `address.received` | A contact submitted an India [address form](https://docs.lazyapp.in/sending/interactive-messages.md#address-messages-india). `data.address.values` has the fields |
| `commerce.order` | A contact sent a cart from your catalog. `data.order` is the message, with the cart in `content.order` (`catalog_id`, `product_items`). It also arrives as `message.received` |

`data.message` includes `conversation_id` (`cnv_…`), `metadata` you attached when sending, the `request_id` of the originating API call, `provider_message_id`, `contact.bsuid` when Meta provides one, and `contact.profile_name`: the WhatsApp profile name Meta sent with an inbound message, so you can greet the sender without looking the contact up. Messages sent to or received in a [group](https://docs.lazyapp.in/guides/groups.md) carry `group` (`uuid`, `provider_group_id`) and no `conversation_id`. The first message from someone who tapped a Click-to-WhatsApp ad carries the ad in `content.referral` (see [Ad welcome messages](https://docs.lazyapp.in/guides/ad-welcome-messages.md)).

`content` carries the structured parts: `content.group_id` when the message was sent in a WhatsApp group, `content.voicemail.call_id` when it is a voicemail left after a missed call, and `content.automatic_events` once Meta detects a lead or purchase in a chat that began from an ad.

> [!NOTE]
>
> These do not arrive in order. A `message.read` may land before the `message.delivered`
> for the same message.

## Templates

| Event | When |
| - | - |
| `template.pending` | Submitted to Meta for review |
| `template.approved` | Approved and sendable |
| `template.rejected` | Declined. `rejection_reason` says why |
| `template.paused` | Paused on quality grounds — temporarily unsendable |
| `template.disabled` | Disabled after repeated problems |
| `template.category_changed` | Meta re-categorised it, which changes what you pay |
| `template.deleted` | Deleted in WhatsApp Manager, found on the next sync |
| `template.quality_changed` | Meta's quality score moved (`GREEN`, `YELLOW`, `RED`). `previous_quality_score` is included |
| `template.updated` | The template's text was edited in WhatsApp Manager. `body_text` and `footer_text` hold the new copy |

## Marketing

| Event | When |
| - | - |
| `marketing.link_clicked` | Someone tapped a link in a marketing message. `data.marketing` has `click_id`, `component` (`cta` or `body`), `product_id`, `clicked_at` and `phone_number_id`. See [marketing messages](https://docs.lazyapp.in/sending/marketing-messages.md#link-clicks) |

## Verify

| Event | When |
| - | - |
| `otp.requested` | A passcode was sent |
| `otp.verified` | A correct code was submitted |
| `otp.failed` | A wrong code, or the challenge expired |

Codes are redacted from all three payloads.

## Contacts

| Event | When |
| - | - |
| `contact.updated` | Contact details or identifiers changed |
| `contact.opted_in` | Consent recorded |
| `contact.opted_out` | Opt-out recorded. Stop sending marketing to them |
| `contact.identity_changed` | With the [identity check](https://docs.lazyapp.in/guides/identity-and-privacy.md#identity-change-check) on, the person behind this contact's WhatsApp may have changed. Messages to them are held until you acknowledge |

## Groups

| Event | When |
| - | - |
| `group.created` | Meta created a group (with `invite_link`), or creation failed (`errors`) |
| `group.updated` | Name, description or photo changed (`changed`, `errors`) |
| `group.deleted` | A group was deleted |
| `group.participants_changed` | Someone joined (`added`) or left / was removed (`removed`, `initiated_by`) |
| `group.join_requested` | Someone asked to join, or cancelled (`cancelled: true`) |
| `group.suspended` | WhatsApp suspended a group (`suspended: true`) or lifted it |

See [Group chats](https://docs.lazyapp.in/guides/groups.md).

## Numbers and connections

| Event | When |
| - | - |
| `phone_number.updated` | Display name, tier or configuration changed |
| `phone_number.quality_changed` | Meta's quality rating moved. Worth alerting on |
| `connection.connected` | A WhatsApp account finished connecting |
| `connection.attention_required` | Action needed, e.g. a credential or verification problem |
| `connection.disconnected` | The connection stopped working |
| `account.updated` | Meta told LazyApp something about the WhatsApp account. See below |

### `account.updated`

One event for every account-level notice Meta sends, so you do not have to subscribe to a dozen. `data.account` holds:

| Field | Meaning |
| - | - |
| `field` | The Meta webhook field it came from: `account_update`, `account_review_update`, `account_alerts`, `business_capability_update`, `security`, `payment_configuration_update`, `partner_solutions`, `business_username_update`, or `messages` for an account-wide sending error |
| `event` | The headline, in capitals: for example `ACCOUNT_RESTRICTION`, `APPROVED`, `INCREASED_CAPABILITIES_ELIGIBILITY_DEFERRED`, `PIN_CHANGED`, `NEEDS_CONNECTING` or `ERROR` |
| `details` | Meta's own value, unchanged |
| `connection` | The connection it applies to, as in `connection.*` events |

Bans, restrictions and reconnections also move the connection's status, so you get the matching `connection.*` event as well.

```json theme={null}
{
  "id": "evt_…",
  "type": "account.updated",
  "created_at": "2026-10-20T10:00:00+00:00",
  "data": {
    "account": {
      "field": "account_alerts",
      "event": "INCREASED_CAPABILITIES_ELIGIBILITY_DEFERRED",
      "details": {
        "entity_type": "BUSINESS",
        "alert_info": { "alert_severity": "WARNING", "alert_status": "ACTIVE", "alert_type": "INCREASED_CAPABILITIES_ELIGIBILITY_DEFERRED" }
      },
      "connection": { "uuid": "…", "phone_number_id": "106540352242922", "status": "active" }
    }
  }
}
```

## Flows

| Event | When |
| - | - |
| `flow.published` | A flow became sendable |
| `flow.failed` | Publishing failed, or the data endpoint is unhealthy |
| `flow.response_received` | A contact completed a flow. `data.flow_response` carries the submission, `flow_token` and `message_uuid`. Endpoints restricted to a number receive it for completions on that number |
| `flow.status_changed` | Meta changed the flow's status (for example `blocked` or `throttled`) or raised an endpoint health alert. `event` is Meta's (`FLOW_STATUS_CHANGE`, `ENDPOINT_ERROR_RATE`, …) and `details` its full value |

## Workflows

| Event | When |
| - | - |
| `workflow.started` | An automation began for a contact |
| `workflow.completed` | It reached an end node |
| `workflow.failed` | A node errored and the run stopped |

## Campaigns

| Event | When |
| - | - |
| `campaign.started` | A broadcast began sending |
| `campaign.completed` | All recipients processed |
| `campaign.failed` | The broadcast stopped early |

## Calls

| Event | When |
| - | - |
| `call.received` | An inbound WhatsApp call is set up, or an outbound call is originated |
| `call.ended` | A call finished (answered hangup, no-answer, rejected). Includes duration when known |
| `call.failed` | Meta reported a hard `FAILED` status before or during the call |
| `call.permission_request` | The contact accepted or rejected a call-permission request (`response`: `accept` / `reject`) |
| `call.recording_available` | The recording of a call you asked to record is stored. Fetch it from [`GET /v1/calls/{uuid}/recording`](https://docs.lazyapp.in/guides/calling#recordings-and-transcripts) |
| `call.transcript_available` | The transcript is ready. `transcript.text` and `transcript_segments` are in the payload |

Only fires on numbers where Meta has enabled calling. Check [capabilities](https://docs.lazyapp.in/concepts/capabilities.md).

## Ads

| Event | When |
| - | - |
| `conversion.detected` | Meta detected a lead (`LeadSubmitted`) or purchase (`Purchase`) in a chat that started from a Click-to-WhatsApp ad. Purchases carry `currency` and `amount` |

## Payments

| Event | When |
| - | - |
| `payment.captured` | The contact paid a [payment request](https://docs.lazyapp.in/guides/payments-india.md) |
| `payment.failed` | A payment attempt failed. The contact can try again |
| `payment.refunded` | A refund went through. `amount_refunded` has the total so far |
| `payment.order_status_updated` | An order status update was sent to the contact |

The payload is the payment object from `GET /v1/payments/{id}`, including your `reference_id` and `metadata`.

## Platform

These matter if you resell LazyApp.

| Event | When |
| - | - |
| `customer.created` | A customer workspace was created |
| `customer.updated` | Customer details changed |
| `customer.connected` | Your customer finished connecting their WhatsApp account |
| `customer.suspended` | Sending was blocked for that customer |
| `customer.archived` | The workspace was retired |
| `customer.deleted` | The workspace was erased |
| `customer.usage_alert` | Usage crossed the configured threshold |
| `setup_link.failed` | A customer's connection attempt failed |

`customer.connected` and `setup_link.failed` are the two to handle first — they tell you whether onboarding actually worked. See [setup links](https://docs.lazyapp.in/platform/setup-links.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.