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

# Webhook Events Reference

> Payload shape for every webhook event Orbit dispatches

# Webhook Events Reference

Payload shape for every event the platform emits. The names and
samples on this page mirror what the dispatcher actually sends —
generated from `WEBHOOK_EVENT_TYPES` in `packages/shared/src/constants.ts`
and the `dispatchTenantWebhook` / `buildWebhookJobs` call sites.

For the full catalog with one-liner descriptions, see
[Webhook Events](/webhooks/events).

## Event Envelope

Every webhook delivery wraps the event in a standard envelope:

```json theme={null}
{
  "id": "evt_abc123",
  "type": "message.delivered",
  "created_at": "2026-03-08T12:00:00Z",
  "data": { "...": "event-specific payload" }
}
```

| Field        | Type               | Description                                                                                                                                           |
| ------------ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`         | string             | Unique event ID (idempotency key)                                                                                                                     |
| `type`       | string             | Event type identifier (one of the values in this reference)                                                                                           |
| `created_at` | string             | ISO 8601 timestamp                                                                                                                                    |
| `data`       | object             | Event-specific payload                                                                                                                                |
| `truncated`  | boolean (optional) | `true` only when the original `data` exceeded 256 KB and was replaced with a pointer-style envelope. Subscribers fetch the full resource via the API. |

When `truncated: true`, `data` carries `_truncated: true`,
`_original_bytes`, and a small set of identifier fields (`id`,
`message_id`, `conversation_id`, `contact_id`, `campaign_id`,
`channel`) so consumers can locate the resource.

***

{/* AUTO-GENERATED — DO NOT EDIT — regenerate via `pnpm --filter @devotel/docs exec tsx scripts/generate-webhook-events-docs.ts` (source: packages/shared/src/constants.ts WEBHOOK_EVENT_TYPES). Edits to this file will be overwritten on the next docs build. */}

## Catalog Index

Every webhook event Orbit emits — **185** in total —
grouped by surface. Each row links to its long-form payload
section below; combined headings (e.g. campaign create / update /
delete share one section) point to the first member.

### Message Events

| Event                           | Description                                                                                                                                                                   |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `message.created`               | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                         |
| `message.sent`                  | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                         |
| `message.delivered`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                         |
| `message.failed`                | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                         |
| `message.read`                  | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                         |
| `message.received`              | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                         |
| `message.recipient_deactivated` | Carrier number deactivation sweep (R16FIX 2026-05-30) — fires once per deactivated MSISDN the nightly carrier-feed sweep flips to DNC.                                        |
| `message.replied`               | MESSAGE\_REPLIED — fires when an INBOUND message is received in response to an OUTBOUND message (i.e. there is at least one prior outbound message in the same conversation). |

### Contact Events

| Event                         | Description                                                                                                           |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `contact.created`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                 |
| `contact.updated`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                 |
| `contact.deleted`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                 |
| `contact.trait_changed`       | Computed-trait value transition for a single contact (DECISION — CDPAAS\_REAL\_TIME\_TRAIT\_RECOMPUTE\_2026\_05\_28). |
| `contact.bulk_imported`       | Fired once per bulk CSV import after all rows are processed.                                                          |
| `contact.merged`              | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                 |
| `contact.opted_out`           | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                 |
| `contact.opted_in`            | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                 |
| `contact.recertification_due` | Reassigned Number Database (RMD) annual recertification due.                                                          |
| `contact.segment_changed`     | Predictive-scoring events (migration 077).                                                                            |

### Campaign Events

| Event                          | Description                                                                                           |
| ------------------------------ | ----------------------------------------------------------------------------------------------------- |
| `campaign.started`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `campaign.completed`           | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `campaign.paused`              | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `campaign.resumed`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `campaign.drip_step.sent`      | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `campaign.drip_step.completed` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `campaign.drip.completed`      | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `campaign.created`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `campaign.updated`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `campaign.deleted`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |

### Voice Events

| Event                            | Description                                                                                                                                      |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `call.initiated`                 | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `call.answered`                  | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `call.completed`                 | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `call.failed`                    | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `call.transferred`               | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `call.dtmf_sent`                 | Mid-call DTMF inject (B-237).                                                                                                                    |
| `call.recording.paused`          | Mid-call recording pause (B-242).                                                                                                                |
| `call.recording.resumed`         | Mid-call recording resume (B-242).                                                                                                               |
| `call.hit_voicemail`             | Outbound call hit a voicemail / fax (Telnyx AMD result = machine\|fax).                                                                          |
| `call.ringing`                   | Inbound INVITE seen at the SIP edge but call not yet answered.                                                                                   |
| `conference.created`             | Conference lifecycle events (audit #BUG-R65).                                                                                                    |
| `conference.participant_joined`  | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `conference.participant_left`    | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `conference.ended`               | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `recording.started`              | Recording lifecycle events (audit #BUG-R65).                                                                                                     |
| `recording.completed`            | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `recording.failed`               | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `recording.qc_failed`            | Post-finalize QC failure (RTC-PaaS competitor-parity gap, 2026-05-29).                                                                           |
| `voicemail.received`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `voicemail.transcript_updated`   | Late-arriving transcript: fires when a voicemail's transcript was NULL at receipt (Deepgram inline failure) and a subsequent retry recovered it. |
| `call.transcript_ready`          | Telephony-aware CDP — CDP-016 parity wedge (2026-05-29).                                                                                         |
| `call.recording.ready`           | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `call.transcription.ready`       | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `call.synthesis.ready`           | AI summary / action-items / sentiment extracted from the transcript (opt-in).                                                                    |
| `call.synthesized`               | Phase 4.4 — Post-call synthesis pipeline (scheduler-driven).                                                                                     |
| `recording.retention_deleted`    | Fired ahead of a retention-driven GCS purge so tenants can mirror the recording/attachment to their own archive before it is deleted.            |
| `recording.chapters.ready`       | RTC-PaaS auto-chaptering (2026-05-28).                                                                                                           |
| `voice_eval.run_started`         | Voice eval regression suite (migration 282, 2026-05-22).                                                                                         |
| `voice_eval.run_completed`       | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |
| `voice_eval.regression_detected` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                            |

### Agent Events

| Event                          | Description                                                                                                                                                                                                                |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `agent.conversation.started`   | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                                                                      |
| `agent.conversation.ended`     | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                                                                      |
| `agent.created`                | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                                                                      |
| `agent.updated`                | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                                                                      |
| `agent.deleted`                | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                                                                      |
| `agent.deployed`               | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                                                                      |
| `agent.handoff.requested`      | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                                                                      |
| `agent.handoff_occurred`       | Phase 4.2 — Fired by agent-runtime the moment one agent delegates a conversation to another specialist agent via the enhanced `transfer_to_agent` tool.                                                                    |
| `agent.response`               | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                                                                      |
| `agent.calendar_event.created` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                                                                      |
| `agent.dnc.marked`             | AIaaS-P0-BUG fix (2026-05-30): fired by `POST /agents/dnc` when an AI voice / text agent invokes the `mark_dnc` MCP tool and the platform persists the suppression to `suppression_list` (+ `dnc_list` mirror for voice/S… |
| `agent.handed_off`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                                                                      |
| `agent.state.changed`          | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                                                                      |

### Flow Events

| Event                      | Description                                                                                           |
| -------------------------- | ----------------------------------------------------------------------------------------------------- |
| `flow.execution.started`   | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `flow.execution.completed` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `flow.created`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `flow.updated`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `flow.deleted`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `flow.published`           | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `flow.executed`            | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `flow.execution.failed`    | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |

### Verification Events

| Event                             | Description                                                                                                                              |
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `verification.sent`               | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                    |
| `verification.approved`           | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                    |
| `verification.failed`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                    |
| `verification.checked`            | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                    |
| `verification.fallback_triggered` | Fired by the `scheduler-verify-fallback` tick each time the async fallback engine advances to a new channel.                             |
| `verification.fallback_exhausted` | Fired when the async fallback engine has tried every channel in the fallbackConfig.channels array without obtaining a `verified` status. |

### Number / Porting Events

| Event                                    | Description                                                                                           |
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `number.purchased`                       | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `number.released`                        | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `number.ported`                          | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `number.inventory.low`                   | Low DID inventory alert (NaaS gap, anchor: PROTOCOL — NAAS\_TN\_LOW\_STOCK\_ALERT\_2026\_05\_31).     |
| `number.updated`                         | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `porting.request.cancelled`              | Number porting customer-cancellation event.                                                           |
| `porting.request.manual_review_required` | Port-IN fell back into manual-review mode (GAP2\_NaaS\_115, 2026-05-29).                              |
| `porting.request.loa_signed`             | Port-IN LOA signed in-platform (cpaasparity2-porting-loa-workflow, 2026-05-29).                       |
| `number.port_out.requested`              | Number port-OUT lifecycle events (NaaS-005 capability-gap fix, 2026-05-29).                           |
| `number.port_out.cancelled`              | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |

### Conversation Events

| Event                         | Description                                                                                                                                                           |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `conversation.created`        | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                 |
| `conversation.disposed`       | Fired by the auto-disposition service when a conversation is automatically closed/resolved by an AI or rule-based disposition engine.                                 |
| `conversation.scored`         | Fired by the QM-scoring service when a conversation receives a quality-management score.                                                                              |
| `conversation.csat_detractor` | CSPaaS LOW\_CSAT\_AUTOMATION\_HOOK\_2026\_05\_30 — fired when a customer-facing CSAT (1..5, \< 3) or NPS (0..10, 0..6) submission lands and qualifies as a detractor. |
| `conversation.deflected`      | CSPaaS Intercom Fin / Zendesk parity gap (2026-05-30) — CRM/CDP needs to distinguish AI-resolved volume from human-resolved volume.                                   |
| `conversation.started`        | Conversation lifecycle — fired by the inbox/handoff pipeline.                                                                                                         |
| `conversation.closed`         | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                 |

### List / Segment Events

| Event             | Description                                                                                           |
| ----------------- | ----------------------------------------------------------------------------------------------------- |
| `list.created`    | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `list.deleted`    | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `segment.created` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `segment.deleted` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |

### Webhook Endpoint Events

| Event                      | Description                                                                                           |
| -------------------------- | ----------------------------------------------------------------------------------------------------- |
| `webhook_endpoint.created` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `webhook_endpoint.updated` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `webhook_endpoint.deleted` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |

### Billing Events

| Event                  | Description                                                                                           |
| ---------------------- | ----------------------------------------------------------------------------------------------------- |
| `subscription.updated` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `balance.topped_up`    | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `credits.purchased`    | Use BALANCE\_TOPPED\_UP instead **Deprecated.**                                                       |
| `balance.low`          | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `credits.low`          | Use BALANCE\_LOW instead **Deprecated.**                                                              |
| `invoice.created`      | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `payment.failed`       | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |

### Channel Failover Events

| Event              | Description                                                                                           |
| ------------------ | ----------------------------------------------------------------------------------------------------- |
| `channel.failover` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |

### Push Events

| Event            | Description                                                                                           |
| ---------------- | ----------------------------------------------------------------------------------------------------- |
| `push.delivered` | Push notification SDK ack events.                                                                     |
| `push.opened`    | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |

### Number Masking (Proxy) Events

| Event                     | Description                                                                                           |
| ------------------------- | ----------------------------------------------------------------------------------------------------- |
| `proxy.session.created`   | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `proxy.session.closed`    | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |
| `proxy.message.forwarded` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |

### WhatsApp Events

| Event                                          | Description                                                                                                                 |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `whatsapp.account.update`                      | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.account.banned`                      | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.account.restricted`                  | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.phone.quality_update`                | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.phone.name_update`                   | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.capability.update`                   | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.security.alert`                      | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.flow.status_change`                  | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.template.approved`                   | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.template.rejected`                   | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.template.quality_update`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.template.category_update`            | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.template.components_update`          | Meta auto-edits a template's components for compliance (e.g. inserts the standard opt-out hint into a MARKETING body).      |
| `whatsapp.quality.changed`                     | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.call.received`                       | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.call.connected`                      | WhatsApp Business Calling lifecycle events (Phase 2 — 2026-05-09).                                                          |
| `whatsapp.call.accepted`                       | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.call.terminated`                     | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.call.permission_granted`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.call.permission_revoked`             | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                       |
| `whatsapp.account.alert`                       | Meta-issued operational alert about the WABA (e.g. policy violation, pricing change effective date, payment method failed). |
| `whatsapp.account.review_update`               | WABA went through a Meta-side review that updated its compliance status (e.g. moved to RESTRICTED / FLAGGED).               |
| `whatsapp.business.status_update`              | Business profile status changed at Meta (verification badge, official business account flag, business status).              |
| `whatsapp.user.preferences`                    | User-level marketing preference signal.                                                                                     |
| `whatsapp.data.export_request`                 | GDPR Article 15 (data subject access request) — user invoked "Request my data" inside the conversation.                     |
| `whatsapp.data.delete_request`                 | GDPR Article 17 (right to erasure) — user invoked "Delete my data".                                                         |
| `whatsapp.account.settings_update`             | WABA-level settings changed (commerce/profile/etc.).                                                                        |
| `whatsapp.automatic_events`                    | Meta's auto-detected business events (cart abandoned, etc.).                                                                |
| `whatsapp.group.lifecycle_update`              | WA Group lifecycle (created/deleted).                                                                                       |
| `whatsapp.group.participants_update`           | WA Group participants joined/left.                                                                                          |
| `whatsapp.group.settings_update`               | WA Group renamed/description changed.                                                                                       |
| `whatsapp.group.status_update`                 | WA Group activated/archived.                                                                                                |
| `whatsapp.history`                             | Initial-connection backfill of historical messages.                                                                         |
| `whatsapp.partner_solutions`                   | Partner integration events.                                                                                                 |
| `whatsapp.payment_configuration_update`        | Payment setup state changed (WA Pay).                                                                                       |
| `whatsapp.smb.app_state_sync`                  | SMB app state sync events.                                                                                                  |
| `whatsapp.smb.message_echoes`                  | Echoes of messages sent from the SMB app (hybrid setups).                                                                   |
| `whatsapp.template.correct_category_detection` | Meta detected the template's category was wrong vs. its actual intent.                                                      |
| `whatsapp.tracking_events`                     | Per-message tracking events (link clicks, etc.).                                                                            |

### Supervisor Events

| Event                           | Description                                                                                                 |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `supervisor.takeover_requested` | Fired when a supervisor initiates a warm-handoff takeover of a live call.                                   |
| `supervisor.takeover_failed`    | Fired when a supervisor takeover attempt fails (e.g. Jambonz REST error during the leg-swap).               |
| `supervisor.takeover_completed` | Fired when the supervisor successfully takes over the call and becomes the active party.                    |
| `supervisor.takeover_cancelled` | Fired when a takeover is cancelled (call ended before handoff completed, or supervisor explicitly aborted). |

### SIP Trunk Events

| Event                      | Description                                                                                           |
| -------------------------- | ----------------------------------------------------------------------------------------------------- |
| `sip_trunk.status_changed` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context. |

### CDP Events

| Event                   | Description                                                                                                                                                                         |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cdp.event.ingested`    | CDP inbound — fired after a Segment-shaped /cdp/track or /cdp/identify payload is verified, persisted to `tenant_*.cdp_events`, and identity- resolved against `tenant_*.contacts`. |
| `cdp.identity.resolved` | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.                                                                               |

### Other

| Event                           | Description                                                                                                       |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `email.opened`                  | Email engagement events (Resend webhook surface).                                                                 |
| `email.clicked`                 | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.             |
| `video.recording.degraded`      | PARITY-RTC-R1 (2026-05-29) — video room recording QC verdict.                                                     |
| `video.room.started`            | GAP-RTC-R2 (2026-05-29) — video room + participant + recording lifecycle webhook fan-out.                         |
| `video.room.ended`              | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.             |
| `video.participant.joined`      | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.             |
| `video.participant.left`        | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.             |
| `video.recording.completed`     | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.             |
| `video.recording.failed`        | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.             |
| `ticket.deflected`              | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.             |
| `wallboard.sla_warning`         | Voice-queue wallboard SLA early-warning (CCaaS).                                                                  |
| `wfm.adherence_breach`          | WFM intraday adherence breach (CCaaS / WFM pillar, 2026-05-30).                                                   |
| `survey.csat.response_recorded` | Post-call IVR survey response recorded (CCaaS, 2026-05-30).                                                       |
| `survey.nps.response_recorded`  | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.             |
| `queue.call.queued`             | CCaaS queue-routing lifecycle webhooks (Five9 / Genesys parity — `Interaction.Routed` / `Interaction.Abandoned`). |
| `queue.call.abandoned`          | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.             |
| `queue.call.assigned`           | Platform-defined webhook event. See source comment in `packages/shared/src/constants.ts` for context.             |

***

## Message Events

### `message.created`

Fired when an outbound message is accepted and queued for delivery.

```json theme={null}
{
  "id": "evt_abc",
  "type": "message.created",
  "created_at": "2026-03-08T12:00:00Z",
  "data": {
    "message_id": "msg_abc123",
    "channel": "sms",
    "to": "+14155552671",
    "from": "+18005551234",
    "status": "queued",
    "created_at": "2026-03-08T12:00:00Z"
  }
}
```

### `message.sent`

Fired when the message is handed off to the carrier / provider.

```json theme={null}
{
  "type": "message.sent",
  "data": {
    "message_id": "msg_abc123",
    "channel": "sms",
    "to": "+14155552671",
    "status": "sent",
    "external_id": "carrier-side-id"
  }
}
```

### `message.delivered`

```json theme={null}
{
  "type": "message.delivered",
  "data": {
    "message_id": "msg_abc123",
    "status": "delivered",
    "channel": "sms",
    "timestamp": "2026-03-08T12:00:03Z"
  }
}
```

### `message.failed`

Terminal failure reported by the carrier (or a synthesised failure
covering `undelivered` / `rejected`).

```json theme={null}
{
  "type": "message.failed",
  "data": {
    "message_id": "msg_abc123",
    "status": "failed",
    "channel": "sms",
    "timestamp": "2026-03-08T12:00:05Z"
  }
}
```

### `message.read`

```json theme={null}
{
  "type": "message.read",
  "data": {
    "message_id": "msg_abc123",
    "status": "read",
    "channel": "whatsapp",
    "timestamp": "2026-03-08T12:00:10Z"
  }
}
```

### `message.received`

Inbound message from a recipient.

```json theme={null}
{
  "type": "message.received",
  "data": {
    "message_id": "msg_inb_456",
    "channel": "sms",
    "from": "+14155552671",
    "to": "+18005551234",
    "body": "What is my order status?",
    "metadata": { "raw_provider_id": "..." }
  }
}
```

***

## Contact Events

### `contact.created`

```json theme={null}
{ "type": "contact.created", "data": { "contact_id": "con_abc123" } }
```

### `contact.updated`

```json theme={null}
{ "type": "contact.updated", "data": { "contact_id": "con_abc123" } }
```

### `contact.deleted`

```json theme={null}
{ "type": "contact.deleted", "data": { "contact_id": "con_abc123" } }
```

### `contact.merged`

```json theme={null}
{ "type": "contact.merged", "data": { "contact_id": "con_abc123" } }
```

<h3 id="contact-bulk-imported">
  `contact.bulk_imported`
</h3>

Fired **once per bulk import batch** (CSV upload or `POST /v1/contacts/bulk`),
not once per row. The payload summarises the whole batch.

```json theme={null}
{
  "id": "evt_abc",
  "type": "contact.bulk_imported",
  "created_at": "2026-03-08T12:00:00Z",
  "data": {
    "imported": 480,
    "updated": 12,
    "failed": 8,
    "total": 500,
    "import_batch_id": "imb_abc123"
  }
}
```

| Field             | Type           | Description                                                                                                                                              |
| ----------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `imported`        | integer        | New contact rows created on this batch                                                                                                                   |
| `updated`         | integer        | Existing contact rows merged on this batch (upsert toggle on)                                                                                            |
| `failed`          | integer        | Rows rejected by validation / dedup / DB constraint                                                                                                      |
| `total`           | integer        | `imported + updated + failed`                                                                                                                            |
| `import_batch_id` | string \| null | Stable identifier for this batch — present when the API was able to persist the import-jobs row; `null` only on legacy in-line imports without a job row |

<Warning>
  **Delivery semantics: at-least-once.** This event rides the standard
  webhook delivery queue (BullMQ with `attempts: 10` and exponential
  backoff starting at 30s — see
  `apps/api/src/lib/webhook-queue.ts` `WEBHOOK_DELIVERY_DEFAULT_JOB_OPTIONS`).
  Transient receiver errors (5xx, timeouts) trigger automatic retries, so
  the same `contact.bulk_imported` payload can be delivered more than
  once. Orbit does **not** guarantee exactly-once delivery on any webhook.

  **Your consumer must be idempotent.** Recommended dedupe key, in
  order of preference:

  1. **Envelope `id`** — the top-level event `id` is unique per delivery
     attempt's logical event and is the canonical idempotency key for
     every Orbit webhook (`id` is stable across retries of the same
     event). Persist seen `id` values for at least 7 days (the longest
     the queue can hold a retry window: 10 attempts × 30s exponential
     ≈ 8.5h plus the dead-letter replay window).
  2. **`data.import_batch_id`** — when non-null, `import_batch_id` is
     the natural key for the underlying batch. If you write summary
     counters into your own DB, key them on `import_batch_id` so a
     replay does not double-add the totals.

  If neither key is available (`import_batch_id: null` and a malformed
  envelope), treat the delivery as a no-op observability signal and
  fetch authoritative state via `GET /v1/contacts/import-jobs`.
</Warning>

### `contact.opted_in` / `contact.opted_out`

Fired when a recipient sends a START / STOP keyword on a registered
channel.

```json theme={null}
{
  "type": "contact.opted_out",
  "data": {
    "channel": "sms",
    "phone": "+14155552671",
    "keyword": "STOP",
    "timestamp": "2026-03-08T12:05:00Z"
  }
}
```

### `contact.recertification_due`

FCC RMD annual consent recertification window opened on a contact.

```json theme={null}
{
  "type": "contact.recertification_due",
  "data": {
    "contact_id": "con_abc123",
    "consent_id": "consent_xyz",
    "channel": "sms",
    "granted_at": "2025-05-09T00:00:00Z",
    "age_days": 365,
    "phone_number": "+14155552671",
    "email": null,
    "timestamp": "2026-05-09T00:00:00Z"
  }
}
```

### `contact.segment_changed`

Predictive scorer flipped a contact's segment label (e.g.
`champion → at_risk`, `passive → engaged`). Useful for triggering
re-engagement plays from a CRM.

```json theme={null}
{
  "type": "contact.segment_changed",
  "data": {
    "contact_id": "con_abc123",
    "previous_label": "champion",
    "new_label": "at_risk",
    "churn_risk": 0.71,
    "intent_score": 0.32,
    "propensity_score": 0.18,
    "ltv_estimate_cents": 12400,
    "signals": ["sms_open_drop", "click_drop"],
    "computed_at": "2026-03-08T12:00:00Z"
  }
}
```

***

## Campaign Events

### `campaign.created` / `campaign.updated` / `campaign.deleted`

```json theme={null}
{ "type": "campaign.created", "data": { "campaign_id": "camp_abc123" } }
```

### `campaign.started`

```json theme={null}
{
  "type": "campaign.started",
  "data": { "campaign_id": "camp_abc123", "status": "running" }
}
```

### `campaign.completed`

```json theme={null}
{
  "type": "campaign.completed",
  "data": { "campaign_id": "camp_abc123", "status": "completed" }
}
```

### `campaign.paused` / `campaign.resumed`

```json theme={null}
{ "type": "campaign.paused", "data": { "campaign_id": "camp_abc123" } }
```

### `campaign.drip_step.completed`

Single drip step finished sending to its slice.

```json theme={null}
{
  "type": "campaign.drip_step.completed",
  "data": {
    "campaign_id": "camp_abc123",
    "step_index": 2,
    "sent": 480,
    "failed": 12
  }
}
```

### `campaign.drip.completed`

Entire drip campaign finished its full schedule.

```json theme={null}
{
  "type": "campaign.drip.completed",
  "data": {
    "campaign_id": "camp_abc123",
    "status": "completed",
    "summary": { "steps": 5, "sent": 2400, "failed": 60 }
  }
}
```

***

## Voice Events

### `call.initiated`

```json theme={null}
{ "type": "call.initiated", "data": { "call_id": "call_abc123" } }
```

When the call is bridged through Jambonz, the payload also carries
provider and direction context:

```json theme={null}
{
  "type": "call.initiated",
  "data": {
    "call_id": "call_abc123",
    "provider": "jambonz",
    "provider_call_sid": "CA-…",
    "direction": "inbound",
    "from": "+14155552671",
    "to": "+18005551234",
    "status": "ringing",
    "timestamp": "2026-03-08T12:00:00Z"
  }
}
```

### `call.answered`

```json theme={null}
{
  "type": "call.answered",
  "data": {
    "call_id": "call_abc123",
    "provider": "jambonz",
    "provider_call_sid": "CA-…",
    "direction": "inbound",
    "from": "+14155552671",
    "to": "+18005551234",
    "status": "in-progress",
    "timestamp": "2026-03-08T12:00:08Z"
  }
}
```

### `call.completed`

```json theme={null}
{
  "type": "call.completed",
  "data": {
    "call_id": "call_abc123",
    "provider": "jambonz",
    "provider_call_sid": "CA-…",
    "direction": "inbound",
    "from": "+14155552671",
    "to": "+18005551234",
    "status": "completed",
    "duration_seconds": 142,
    "hangup_reason": "normal_clearing",
    "sip_response_code": 200,
    "sip_reason": "OK",
    "timestamp": "2026-03-08T12:02:22Z"
  }
}
```

### `call.failed`

```json theme={null}
{
  "type": "call.failed",
  "data": {
    "call_id": "call_abc123",
    "provider": "jambonz",
    "provider_call_sid": "CA-…",
    "direction": "outbound",
    "from": "+18005551234",
    "to": "+14155559999",
    "status": "no-answer",
    "duration_seconds": 0,
    "hangup_reason": "no_user_response",
    "sip_response_code": 480,
    "sip_reason": "Temporarily Unavailable",
    "timestamp": "2026-03-08T12:00:30Z"
  }
}
```

### `call.transferred`

```json theme={null}
{
  "type": "call.transferred",
  "data": {
    "call_id": "call_abc123",
    "transferred_to": "+14155558888"
  }
}
```

### `call.dtmf_sent`

Mid-call DTMF inject through the API.

```json theme={null}
{
  "type": "call.dtmf_sent",
  "data": {
    "call_id": "call_abc123",
    "digits": "1234",
    "duration_ms": 100,
    "gap_ms": 80,
    "timestamp": "2026-03-08T12:01:30Z"
  }
}
```

### `call.recording.paused` / `call.recording.resumed`

SIPREC fork toggled mid-call.

```json theme={null}
{
  "type": "call.recording.paused",
  "data": {
    "call_id": "call_abc123",
    "recording": false,
    "timestamp": "2026-03-08T12:01:00Z"
  }
}
```

### `call.recording.ready`

```json theme={null}
{
  "type": "call.recording.ready",
  "data": {
    "call_id": "call_abc123",
    "recording_url": "gs://devotel-recordings/...",
    "duration_seconds": 142,
    "timestamp": "2026-03-08T12:06:00Z"
  }
}
```

### `call.transcription.ready`

```json theme={null}
{
  "type": "call.transcription.ready",
  "data": {
    "call_id": "call_abc123",
    "transcript_length": 4820,
    "timestamp": "2026-03-08T12:06:30Z"
  }
}
```

### `call.synthesis.ready` (legacy inline pipeline)

```json theme={null}
{
  "type": "call.synthesis.ready",
  "data": {
    "call_id": "call_abc123",
    "summary": "Customer asked about order ORD-12345…",
    "action_items": ["Send tracking link"],
    "sentiment": "neutral",
    "topics": ["order_status"],
    "timestamp": "2026-03-08T12:07:00Z"
  }
}
```

### `call.synthesized` (post-call synthesis pipeline)

Richer payload from the async synthesis scheduler. Gated on tenant
opt-in.

```json theme={null}
{
  "type": "call.synthesized",
  "data": {
    "call_id": "call_abc123",
    "direction": "inbound",
    "from": "+14155552671",
    "to": "+18005551234",
    "duration_seconds": 142,
    "ended_at": "2026-03-08T12:02:22Z",
    "synthesis": {
      "summary": "...",
      "sentiment": "neutral",
      "key_points": ["..."],
      "follow_up_actions": ["..."],
      "facts_learned": ["..."],
      "customer_intent": "order_status",
      "resolution": "resolved"
    },
    "synthesised_at": "2026-03-08T12:08:00Z"
  }
}
```

### `call.ringing`

Fires when an inbound call is detected by the SIP edge but before it is answered. Useful for "live caller is dialing in" UI updates without waiting for the post-answer `call.answered` event.

```json theme={null}
{
  "type": "call.ringing",
  "data": {
    "call_id": "call_abc123",
    "provider": "jambonz",
    "provider_call_sid": "CA-…",
    "direction": "inbound",
    "from": "+14155552671",
    "to": "+18005551234",
    "status": "ringing",
    "timestamp": "2026-03-08T12:00:01Z"
  }
}
```

**Trigger condition:** carrier sends `INVITE` to the SIP edge.
**Retry behaviour:** standard webhook retry (exponential 1m → 5m → 15m → 1h → 6h, 5 attempts max). Idempotent — multiple ring callbacks during a single call can fire if the call is being routed via multiple ring-group legs.

**Note (current implementation):** ringing is currently bundled with the `call.initiated` event for inbound calls. The standalone `call.ringing` event is emitted by the underlying carrier webhook but only forwarded to tenant subscribers when the org explicitly subscribes. If `call.ringing` is missing from your delivery, fall back to listening for `call.initiated` with `status: "ringing"`.

### `call.early_media`

Fires when the carrier begins streaming pre-answer audio — a SIP `180 Ringing` response carrying SDP. This is the moment ringback tone, IVR prompts, voicemail greetings, or answering-machine-detection (AMD) audio start playing into the bridge BEFORE the destination has formally answered (`200 OK`). Useful for IVR routing decisions, AMD branching, and accurate "Ringing…" → "Audio streaming" UX transitions on softphone clients.

```json theme={null}
{
  "type": "call.early_media",
  "data": {
    "call_id": "call_abc123",
    "call_sid": "CA-…",
    "provider": "jambonz",
    "direction": "outbound",
    "from": "+18005551234",
    "to": "+14155552671",
    "status": "early_media",
    "timestamp": "2026-03-08T12:00:02Z"
  }
}
```

**Trigger condition:** carrier sends a `180 Ringing` with an `application/sdp` body, OR a `183 Session Progress` with SDP. Distinct from `call.ringing` (which fires on `180 Ringing` WITHOUT SDP, i.e. headers-only ringback).

**Retry behaviour:** standard webhook retry (exponential 1m → 5m → 15m → 1h → 6h, 5 attempts max). The event is fire-and-forget — a subsequent `call.answered` event always follows on the same `call_id` once the destination picks up.

**Note (current implementation):** the event is published both on the tenant SSE channel (`events:tenant_<id>`) for live dashboard updates AND via signed webhooks for subscribers who opt in. The SSE channel is what powers the browser softphone's "Audio streaming" label and the `<audio>` element's autoplay-unblock call; the webhook is the durable delivery path for backend systems.

### Conference Events

Conference lifecycle events fire from the conference service in `apps/api/src/routes/voice/`. The events ride the same delivery + retry semantics as call events.

#### `conference.created`

Fires when `POST /api/v1/voice/conferences` succeeds.

```json theme={null}
{
  "type": "conference.created",
  "data": {
    "conference_id": "conf_abc123",
    "name": "Q1 Planning Call",
    "max_participants": 25,
    "record": true,
    "created_by_user_id": "usr_xxx",
    "timestamp": "2026-03-08T12:00:00Z"
  }
}
```

#### `conference.participant_joined`

Fires when a new participant successfully joins (after `200 OK` to the SIP `INVITE` for that leg).

```json theme={null}
{
  "type": "conference.participant_joined",
  "data": {
    "conference_id": "conf_abc123",
    "participant_id": "cpart_def456",
    "call_id": "call_xyz789",
    "phone_number": "+14155552671",
    "muted": false,
    "joined_at": "2026-03-08T12:01:14Z"
  }
}
```

#### `conference.participant_left`

Fires when a participant disconnects — either via `DELETE` API call, BYE from the carrier, or the conference moderator's `end-conference` action.

```json theme={null}
{
  "type": "conference.participant_left",
  "data": {
    "conference_id": "conf_abc123",
    "participant_id": "cpart_def456",
    "call_id": "call_xyz789",
    "duration_seconds": 312,
    "reason": "normal_disconnect",
    "timestamp": "2026-03-08T12:06:26Z"
  }
}
```

`reason` values: `normal_disconnect` (BYE from participant), `kicked` (DELETE via API), `conference_ended` (moderator ended), `network_failure` (RTP timeout).

#### `conference.ended`

Fires when the conference's active participant count drops to zero, or moderator hits `end-conference`. Always the LAST event for a conference id.

```json theme={null}
{
  "type": "conference.ended",
  "data": {
    "conference_id": "conf_abc123",
    "duration_seconds": 1840,
    "participant_count": 7,
    "ended_reason": "moderator_ended",
    "recording_url": "https://storage.devotel.io/conf/conf_abc123.mp3",
    "timestamp": "2026-03-08T12:30:40Z"
  }
}
```

`ended_reason` values: `moderator_ended`, `last_participant_left`, `max_duration_reached`.

### Recording Events

#### `recording.started`

Fires when `POST /api/v1/voice/calls/{id}/recording/start` (or the per-call `record:true` flag) starts a fresh recording.

```json theme={null}
{
  "type": "recording.started",
  "data": {
    "recording_id": "rec_abc123",
    "call_id": "call_abc123",
    "dual_channel": true,
    "started_at": "2026-03-08T12:00:08Z"
  }
}
```

#### `recording.completed`

Alias for `call.recording.ready` (same payload + same `recording_url`). Documented separately because the call-id may not be available for conference recordings — those carry `conference_id` instead.

```json theme={null}
{
  "type": "recording.completed",
  "data": {
    "recording_id": "rec_abc123",
    "call_id": "call_abc123",
    "duration_seconds": 142,
    "format": "mp3",
    "size_bytes": 4980000,
    "recording_url": "https://storage.devotel.io/recordings/rec_abc123.mp3",
    "url_expires_at": "2026-03-09T12:06:00Z",
    "timestamp": "2026-03-08T12:06:00Z"
  }
}
```

#### `recording.failed`

Fires when an upstream recording attempt fails (storage write failure, codec mismatch, AMD aborted the recording before any audio was captured).

```json theme={null}
{
  "type": "recording.failed",
  "data": {
    "recording_id": "rec_abc123",
    "call_id": "call_abc123",
    "reason": "storage_write_failed",
    "details": "GCS 503 — Service Unavailable",
    "timestamp": "2026-03-08T12:06:02Z"
  }
}
```

### `voicemail.received`

```json theme={null}
{
  "type": "voicemail.received",
  "data": {
    "voicemail_id": "vm_abc123",
    "call_id": "call_abc123",
    "from": "+14155552671",
    "transcript": "Hi, please call me back at noon — I had a question about…",
    "timestamp": "2026-03-08T12:05:00Z"
  }
}
```

### `voicemail.transcript_updated`

Fires when an originally-missing voicemail transcript is recovered by
the retry pipeline.

```json theme={null}
{
  "type": "voicemail.transcript_updated",
  "data": {
    "voicemail_id": "vm_abc123",
    "transcript": "Recovered transcript text…"
  }
}
```

### `recording.retention_deleted`

Fires 24h before a retention-driven GCS purge so tenants can mirror
the asset to their own archive. Payload carries a signed download URL
valid until `purge_scheduled_at`.

```json theme={null}
{
  "type": "recording.retention_deleted",
  "data": {
    "source": "call",
    "source_id": "call_abc123",
    "channel": "voice",
    "created_at": "2025-05-08T00:00:00Z",
    "gcs_uri": "gs://...",
    "download_url": "https://storage.googleapis.com/...?X-Goog-Signature=...",
    "download_url_expires_at": "2026-05-10T00:00:00Z",
    "purge_scheduled_at": "2026-05-10T00:00:00Z",
    "retention_policy": {
      "voice_days": 365,
      "sms_days": 365,
      "email_days": 365,
      "whatsapp_days": 365,
      "rcs_days": 365,
      "viber_days": 365,
      "apply_hard_delete": true
    },
    "timestamp": "2026-05-09T00:00:00Z"
  }
}
```

***

## Agent Events

### `agent.created` / `agent.updated` / `agent.deleted` / `agent.deployed`

```json theme={null}
{
  "type": "agent.created",
  "data": {
    "agent_id": "agt_abc123",
    "name": "Support Bot",
    "type": "voice"
  }
}
```

### `agent.conversation.started`

```json theme={null}
{
  "type": "agent.conversation.started",
  "data": {
    "conversation_id": "conv_001",
    "agent_id": "agt_abc123",
    "model": "claude-sonnet-4-6",
    "timestamp": "2026-03-08T12:00:00Z"
  }
}
```

### `agent.conversation.ended`

```json theme={null}
{
  "type": "agent.conversation.ended",
  "data": {
    "conversation_id": "conv_001",
    "agent_id": "agt_abc123",
    "reason": "Escalated to human agent",
    "end_status": "escalated",
    "timestamp": "2026-03-08T12:15:00Z"
  }
}
```

### `agent.handoff.requested`

Agent escalated to a human operator.

```json theme={null}
{
  "type": "agent.handoff.requested",
  "data": {
    "conversation_id": "conv_001",
    "agent_id": "agt_abc123",
    "reason": "Customer requested human agent",
    "status": "escalated"
  }
}
```

### `agent.handoff_occurred`

Agent delegated to another specialist agent through the
`transfer_to_agent` tool.

```json theme={null}
{
  "type": "agent.handoff_occurred",
  "data": {
    "handoff_id": "ho_001",
    "source_agent_id": "agt_general",
    "target_agent_id": "agt_billing",
    "conversation_id": "conv_001",
    "reason": "Billing question",
    "summary": "User asked about invoice INV-2026-…"
  }
}
```

### `agent.calendar_event.created`

Fires from the agent's `create_calendar_event` MCP tool.

```json theme={null}
{
  "type": "agent.calendar_event.created",
  "data": {
    "event_id": "cal_evt_001",
    "title": "Meeting with Jane Doe",
    "description": "Discuss enterprise plan",
    "start_time": "2026-03-09T10:00:00Z",
    "end_time": "2026-03-09T10:30:00Z",
    "attendee_email": "jane@example.com",
    "conversation_id": "conv_001"
  }
}
```

***

## Flow Events

### `flow.created` / `flow.updated` / `flow.published` / `flow.deleted`

```json theme={null}
{ "type": "flow.created", "data": { "flow_id": "flow_abc123" } }
```

### `flow.executed`

Coarse terminal signal. `status` is `completed`, `failed`, or
`timeout`.

```json theme={null}
{
  "type": "flow.executed",
  "data": {
    "flow_id": "flow_abc123",
    "execution_id": "exec_001",
    "status": "completed",
    "step_count": 8
  }
}
```

### `flow.execution.started`

```json theme={null}
{
  "type": "flow.execution.started",
  "data": {
    "flow_id": "flow_abc123",
    "execution_id": "exec_001",
    "node_count": 12,
    "timestamp": "2026-03-08T12:00:00Z"
  }
}
```

### `flow.execution.completed`

```json theme={null}
{
  "type": "flow.execution.completed",
  "data": {
    "flow_id": "flow_abc123",
    "execution_id": "exec_001",
    "step_count": 8,
    "duration_ms": 5200,
    "timestamp": "2026-03-08T12:00:05Z"
  }
}
```

### `flow.execution.failed`

```json theme={null}
{
  "type": "flow.execution.failed",
  "data": {
    "flow_id": "flow_abc123",
    "execution_id": "exec_001",
    "error": "node http_request failed: 502",
    "step_count": 3,
    "duration_ms": 1300,
    "timestamp": "2026-03-08T12:00:01Z"
  }
}
```

***

## Verification Events

The platform uses the `verification.*` prefix (not `verify.*`).

### `verification.sent`

```json theme={null}
{
  "type": "verification.sent",
  "data": {
    "verification_id": "ver_abc123",
    "channel": "sms",
    "to": "+14155552671"
  }
}
```

When a SIM-swap soft warning is detected, `sim_swap_warning: true` is
included alongside the payload above.

### `verification.approved`

```json theme={null}
{
  "type": "verification.approved",
  "data": {
    "verification_id": "ver_abc123",
    "channel": "sms",
    "to": "+14155552671"
  }
}
```

For Silent Verification (SIM-card-network-binding flow), `channel` is
`"silent"`.

### `verification.failed`

```json theme={null}
{
  "type": "verification.failed",
  "data": {
    "verification_id": "ver_abc123",
    "channel": "sms",
    "to": "+14155552671",
    "reason": "max_attempts_exceeded"
  }
}
```

When the failure is a SIM-swap block, `reason: "sim_swap_detected"`
plus `last_swap_date` are included.

***

## Number / Porting Events

### `number.purchased`

```json theme={null}
{
  "type": "number.purchased",
  "data": {
    "number_id": "num_abc123",
    "phone_number": "+14155550100"
  }
}
```

`reclaimed: true` is included when the number was re-claimed from
the parking pool.

### `number.released`

```json theme={null}
{ "type": "number.released", "data": { "number_id": "num_abc123" } }
```

### `number.ported`

```json theme={null}
{
  "type": "number.ported",
  "data": {
    "porting_id": "port_001",
    "numbers": ["+14155550100", "+14155550101"],
    "carrier": "Verizon",
    "provider": "telnyx",
    "status": "submitted"
  }
}
```

### `porting.request.cancelled`

Customer aborted an in-flight port.

```json theme={null}
{
  "type": "porting.request.cancelled",
  "data": {
    "porting_request_id": "port_001",
    "numbers": ["+14155550100"],
    "cancelled_from_status": "submitted"
  }
}
```

***

## Conversation Events

### `conversation.created`

```json theme={null}
{
  "type": "conversation.created",
  "data": {
    "conversation_id": "conv_001",
    "campaign_id": "camp_abc123",
    "agent_id": "agt_abc123",
    "contact_id": "con_xyz789",
    "recipient": "+14155552671",
    "source": "journey"
  }
}
```

***

## List / Segment Events

```json theme={null}
{ "type": "list.created", "data": { "list_id": "list_abc" } }
{ "type": "list.deleted", "data": { "list_id": "list_abc" } }
{ "type": "segment.created", "data": { "segment_id": "seg_abc" } }
{ "type": "segment.deleted", "data": { "segment_id": "seg_abc" } }
```

***

## Webhook Endpoint Events

```json theme={null}
{ "type": "webhook_endpoint.created", "data": { "endpoint_id": "wh_abc" } }
{ "type": "webhook_endpoint.updated", "data": { "endpoint_id": "wh_abc" } }
{ "type": "webhook_endpoint.deleted", "data": { "endpoint_id": "wh_abc" } }
```

***

## Billing Events

### `balance.low`

```json theme={null}
{
  "type": "balance.low",
  "data": {
    "remaining_cents": 75,
    "remaining_usd": "0.75",
    "threshold_cents": 100,
    "triggered_by": "message:msg_abc123",
    "timestamp": "2026-03-08T12:00:00Z"
  }
}
```

### `balance.topped_up`

```json theme={null}
{
  "type": "balance.topped_up",
  "data": {
    "organization_id": "org_abc",
    "amount_cents": 5000,
    "currency": "usd"
  }
}
```

### `credits.purchased` (deprecated alias of `balance.topped_up`)

Same data plus a legacy `credits` field. Prefer `balance.topped_up`
for new integrations.

***

## Channel Failover Events

### `channel.failover`

Fired when a messaging channel's primary provider failed and Orbit
automatically switched to a backup.

```json theme={null}
{
  "type": "channel.failover",
  "data": {
    "channel": "sms",
    "failed_provider": "telnyx",
    "active_provider": "jasmin",
    "error_message": "HTTP 502 from carrier",
    "message_id": "msg_abc123",
    "attempt_index": 1,
    "timestamp": "2026-03-08T12:00:00Z"
  }
}
```

***

## Push Events

### `push.delivered`

Mobile / web SDK acknowledged a push was rendered on-device.

```json theme={null}
{
  "type": "push.delivered",
  "data": {
    "id": "push_abc123",
    "device_token_id": "dt_abc",
    "at": "2026-03-08T12:00:01Z"
  }
}
```

### `push.opened`

User tapped the push and the SDK reported the open.

```json theme={null}
{
  "type": "push.opened",
  "data": {
    "id": "push_abc123",
    "device_token_id": "dt_abc",
    "at": "2026-03-08T12:01:30Z"
  }
}
```

***

## Number Masking (Proxy) Events

### `proxy.session.created`

```json theme={null}
{
  "type": "proxy.session.created",
  "data": {
    "session_id": "psess_abc",
    "proxy_number": "+14155550100",
    "participant_a": "+14155552671",
    "participant_b": "+14155558888",
    "expires_at": "2026-03-08T13:00:00Z"
  }
}
```

### `proxy.session.closed`

```json theme={null}
{
  "type": "proxy.session.closed",
  "data": {
    "session_id": "psess_abc",
    "proxy_number": "+14155550100",
    "closed_at": "2026-03-08T12:45:00Z"
  }
}
```

### `proxy.message.forwarded`

```json theme={null}
{
  "type": "proxy.message.forwarded",
  "data": {
    "session_id": "psess_abc",
    "proxy_number": "+14155550100",
    "from_participant": "+14155552671",
    "to_participant": "+14155558888",
    "channel": "sms"
  }
}
```

***

## WhatsApp Events

WhatsApp events mirror Meta WABA webhook fields. Each fires after
Orbit ingests the corresponding Meta callback and persists the
upstream change. Payloads carry the relevant `waba_id` /
`phone_number_id` so consumers can correlate to their own Meta tooling.

### WhatsApp Calling

The lifecycle events (`whatsapp.call.connected`, `_accepted`,
`_terminated`) share the same payload shape; the legacy
`whatsapp.call.received` is also dispatched on every transition for
backward-compatible consumers.

```json theme={null}
{
  "type": "whatsapp.call.connected",
  "data": {
    "waba_id": "1234567890",
    "phone_number_id": "0987654321",
    "meta_call_id": "wacid_…",
    "wa_call_log_id": "wacall_…",
    "direction": "inbound",
    "from": "+14155552671",
    "to": "+18005551234",
    "phase": "connect",
    "meta_event": "connect",
    "meta_status": null,
    "duration_seconds": null,
    "biz_opaque_callback_data": null
  }
}
```

`whatsapp.call.permission_granted`:

```json theme={null}
{
  "type": "whatsapp.call.permission_granted",
  "data": {
    "contact_id": "con_abc",
    "waba_id": "1234567890",
    "phone_number_id": "0987654321",
    "source": "inbound_call",
    "ttl_seconds": 86400,
    "meta_call_id": "wacid_…"
  }
}
```

`whatsapp.call.permission_revoked`:

```json theme={null}
{
  "type": "whatsapp.call.permission_revoked",
  "data": {
    "contact_id": "con_abc",
    "waba_id": "1234567890",
    "phone_number_id": "0987654321",
    "meta_call_id": "wacid_…"
  }
}
```

### WhatsApp Templates

Sample for `whatsapp.template.approved` (others share the same shape
with the relevant Meta payload echoed under `details`):

```json theme={null}
{
  "type": "whatsapp.template.approved",
  "data": {
    "waba_id": "1234567890",
    "template_id": "tpl_abc",
    "template_name": "appointment_reminder_v1",
    "language": "en_US",
    "details": { "...": "Meta event payload" }
  }
}
```

`whatsapp.template.rejected` includes `details.reason` with Meta's
rejection text.

### WhatsApp Account / Business / Phone

`whatsapp.account.update`, `whatsapp.account.banned`,
`whatsapp.account.restricted`, `whatsapp.account.alert`,
`whatsapp.account.review_update`, `whatsapp.account.settings_update`,
`whatsapp.business.status_update`, `whatsapp.phone.quality_update`,
`whatsapp.phone.name_update`, `whatsapp.capability.update`,
`whatsapp.security.alert`, `whatsapp.flow.status_change`,
`whatsapp.quality.changed` — all share the shape:

```json theme={null}
{
  "type": "whatsapp.account.banned",
  "data": {
    "waba_id": "1234567890",
    "details": { "...": "Meta event payload" }
  }
}
```

### WhatsApp Data Subject Requests

```json theme={null}
{
  "type": "whatsapp.data.export_request",
  "data": {
    "waba_id": "1234567890",
    "user": "+14155552671",
    "details": { "...": "Meta payload" }
  }
}
```

`whatsapp.data.delete_request` follows the same shape.

### WhatsApp v25 fields

`whatsapp.automatic_events`, `whatsapp.history`,
`whatsapp.partner_solutions`, `whatsapp.payment_configuration_update`,
`whatsapp.smb.app_state_sync`, `whatsapp.smb.message_echoes`,
`whatsapp.tracking_events`, `whatsapp.user.preferences`,
`whatsapp.group.lifecycle_update`, `whatsapp.group.participants_update`,
`whatsapp.group.settings_update`, `whatsapp.group.status_update` — each
carries the original Meta event payload under `details`:

```json theme={null}
{
  "type": "whatsapp.tracking_events",
  "data": {
    "waba_id": "1234567890",
    "details": { "...": "Meta event payload" }
  }
}
```

***

## Subscribing to Events

Register a webhook and specify which events to receive:

```bash theme={null}
curl -X POST https://orbit-api.devotel.io/api/v1/webhooks \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/orbit",
    "events": ["message.delivered", "message.failed", "call.completed"],
    "secret": "whsec_your_secret"
  }'
```

Use `"events": ["*"]` to subscribe to all event types. Subscribing to
a name not listed on this page returns a 422.

## See also

* [Webhook Events Catalog](/webhooks/events) — one-line description per event
* [Webhook Overview](/webhooks/overview) — delivery, signing, and retry semantics
* [Webhook Security](/webhooks/security) — verifying signatures
