# Webhook events

> Every event type Nexafon delivers to webhook endpoints, when it is sent, and what its data contains.

Source: https://docs.nexafone.so/v1/webhooks/events/

`GET /api/v1/workspaces/{workspaceId}/webhook-event-types` lists the same catalog at runtime. This table is generated
from the backend’s event catalog:

| Event | Sent when |
| --- | --- |
| `message.received` | A customer's WhatsApp message arrived |
| `message.status` | A message the business sent was sent, delivered, read or failed |
| `conversation.assigned` | A conversation was assigned to a member or unassigned |
| `conversation.closed` | A conversation was closed |
| `call.ringing` | A call started ringing |
| `call.answered` | A call was answered |
| `call.ended` | An answered call ended |
| `call.missed` | A call ended without anyone answering |
| `meeting.scheduled` | A meeting was scheduled |
| `meeting.ended` | A meeting ended |
| `template.status_changed` | Meta approved, rejected, paused or disabled a message template, or changed its category |
| `contact.created` | A new contact was added |
| `billing.low_balance` | The wallet balance fell below its alert threshold |
| `invoice.created` | An invoice was issued |
| `invoice.paid` | An invoice was paid |
| `billing.dunning` | An unpaid invoice's dunning step: a reminder, the workspace going past due or read-only, or reactivated once paid |
| `catalog.product_status` | Meta approved or rejected a product of the store's WhatsApp catalog; a rejection carries Meta's reason |
| `order.created` | A customer's WhatsApp cart became an order, priced from the store's current prices |
| `order.paid` | An order's payment succeeded |
| `order.payment_failed` | An order's payment failed; the order still awaits payment |
| `order.status_changed` | An order moved to another status; carries the previous status and who changed it |
| `order.cancelled` | An order was cancelled |

## Payloads

`data` holds the objects the event is about, in the shapes the [API reference](/v1/api/schemas/) documents:

| Events | `data` |
| --- | --- |
| `message.received`, `message.status` | `message`, `conversation` |
| `conversation.assigned` | `conversation`, `previousAssigneeMemberId` |
| `conversation.closed` | `conversation` |
| `contact.created` | `contact` |
| `call.ringing`, `call.answered`, `call.ended`, `call.missed` | `call`: kind, status, caller, team, ring settings, participants, `endReason`, timestamps |
| `meeting.scheduled` | `meeting`, and `occurrence` when one occurrence of a recurring meeting changed |
| `meeting.ended` | `meeting`, `occurrence`, `attendance` |
| `template.status_changed` | `template`, `previousStatus`, `previousCategory` |
| `billing.low_balance` | `balanceCents`, `thresholdCents`, `currency`, `ledgerEntryId` |
| `invoice.created`, `invoice.paid` | `id`, `number`, `status`, `currency`, `totalCents`, `amountDueCents`, `periodStart`, `periodEnd`, `issuedAt`, `dueAt` |
| `billing.dunning` | `invoiceId`, `number`, `stage` (`reminder`, `past_due`, `suspended`, `reactivated`), `step`, `amountDueCents`, `currency`, `suspendOn` |
| `catalog.product_status` | `retailerId`, `product` (`externalId`, `name`), `variant` (`externalId`, `size`, `color`), `status` (`approved`, `rejected`), `reason`, `previousStatus`, `reviewedAt` |
| `order.created`, `order.paid`, `order.cancelled` | `order` |
| `order.payment_failed` | `order`, `reason` |
| `order.status_changed` | `order`, `previousStatus`, `status`, `changedBy` (`type`, `id`) |

An `order` carries `id`, `number`, `status`, the customer, `currency`, `subtotalCents`, `discountCents`,
`deliveryFeeCents`, `totalCents`, the discount and coupon, fulfilment and delivery details, `items` and timestamps.
Money is always in integer cents (USD).

Reactions to messages are not sent as `message.received`.

## Test events

**Send test** in the dashboard, or `POST …/webhook-endpoints/{endpointId}/test`, delivers one `webhook.test` event
at once, signed like any other. It does not count towards the endpoint’s health; endpoints cannot subscribe to it.
