Documentation Index
Fetch the complete documentation index at: https://orbit-docs.devotel.io/llms.txt
Use this file to discover all available pages before exploring further.
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.
Event Envelope
Every webhook delivery wraps the event in a standard envelope:
{
"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.
Message Events
message.created
Fired when an outbound message is accepted and queued for delivery.
{
"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.
{
"type": "message.sent",
"data": {
"message_id": "msg_abc123",
"channel": "sms",
"to": "+14155552671",
"status": "sent",
"external_id": "carrier-side-id"
}
}
message.delivered
{
"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).
{
"type": "message.failed",
"data": {
"message_id": "msg_abc123",
"status": "failed",
"channel": "sms",
"timestamp": "2026-03-08T12:00:05Z"
}
}
message.read
{
"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.
{
"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": "..." }
}
}
{ "type": "contact.created", "data": { "contact_id": "con_abc123" } }
{ "type": "contact.updated", "data": { "contact_id": "con_abc123" } }
{ "type": "contact.deleted", "data": { "contact_id": "con_abc123" } }
{ "type": "contact.merged", "data": { "contact_id": "con_abc123" } }
Fired when a recipient sends a START / STOP keyword on a registered
channel.
{
"type": "contact.opted_out",
"data": {
"channel": "sms",
"phone": "+14155552671",
"keyword": "STOP",
"timestamp": "2026-03-08T12:05:00Z"
}
}
FCC RMD annual consent recertification window opened on a contact.
{
"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"
}
}
Predictive scorer flipped a contact’s segment label (e.g.
champion → at_risk, passive → engaged). Useful for triggering
re-engagement plays from a CRM.
{
"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
{ "type": "campaign.created", "data": { "campaign_id": "camp_abc123" } }
campaign.started
{
"type": "campaign.started",
"data": { "campaign_id": "camp_abc123", "status": "running" }
}
campaign.completed
{
"type": "campaign.completed",
"data": { "campaign_id": "camp_abc123", "status": "completed" }
}
campaign.paused / campaign.resumed
{ "type": "campaign.paused", "data": { "campaign_id": "camp_abc123" } }
campaign.drip_step.completed
Single drip step finished sending to its slice.
{
"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.
{
"type": "campaign.drip.completed",
"data": {
"campaign_id": "camp_abc123",
"status": "completed",
"summary": { "steps": 5, "sent": 2400, "failed": 60 }
}
}
Voice Events
call.initiated
{ "type": "call.initiated", "data": { "call_id": "call_abc123" } }
When the call is bridged through Jambonz, the payload also carries
provider and direction context:
{
"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
{
"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
{
"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
{
"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
{
"type": "call.transferred",
"data": {
"call_id": "call_abc123",
"transferred_to": "+14155558888"
}
}
call.dtmf_sent
Mid-call DTMF inject through the API.
{
"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.
{
"type": "call.recording.paused",
"data": {
"call_id": "call_abc123",
"recording": false,
"timestamp": "2026-03-08T12:01:00Z"
}
}
call.recording.ready
{
"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
{
"type": "call.transcription.ready",
"data": {
"call_id": "call_abc123",
"transcript_length": 4820,
"timestamp": "2026-03-08T12:06:30Z"
}
}
call.synthesis.ready (legacy inline pipeline)
{
"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.
{
"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.
{
"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".
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 /v1/voice/conferences succeeds.
{
"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).
{
"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.
{
"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.
{
"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 /v1/voice/calls/{id}/recording/start (or the per-call record:true flag) starts a fresh recording.
{
"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.
{
"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).
{
"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
{
"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.
{
"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.
{
"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
{
"type": "agent.created",
"data": {
"agent_id": "agt_abc123",
"name": "Support Bot",
"type": "voice"
}
}
agent.conversation.started
{
"type": "agent.conversation.started",
"data": {
"conversation_id": "conv_001",
"agent_id": "agt_abc123",
"model": "gpt-4o",
"timestamp": "2026-03-08T12:00:00Z"
}
}
agent.conversation.ended
{
"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.
{
"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.
{
"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.
{
"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
{ "type": "flow.created", "data": { "flow_id": "flow_abc123" } }
flow.executed
Coarse terminal signal. status is completed, failed, or
timeout.
{
"type": "flow.executed",
"data": {
"flow_id": "flow_abc123",
"execution_id": "exec_001",
"status": "completed",
"step_count": 8
}
}
flow.execution.started
{
"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
{
"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
{
"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
{
"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
{
"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
{
"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
{
"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
{ "type": "number.released", "data": { "number_id": "num_abc123" } }
number.ported
{
"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.
{
"type": "porting.request.cancelled",
"data": {
"porting_request_id": "port_001",
"numbers": ["+14155550100"],
"cancelled_from_status": "submitted"
}
}
Conversation Events
conversation.created
{
"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
{ "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
{ "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
{
"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
{
"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.
subscription.updated
{
"type": "subscription.updated",
"data": {
"organization_id": "org_abc",
"action": "change_plan"
}
}
action is one of cancel, reactivate, change_plan.
Channel Failover Events
channel.failover
Fired when a messaging channel’s primary provider failed and Orbit
automatically switched to a backup.
{
"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.
{
"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.
{
"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
{
"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
{
"type": "proxy.session.closed",
"data": {
"session_id": "psess_abc",
"proxy_number": "+14155550100",
"closed_at": "2026-03-08T12:45:00Z"
}
}
proxy.message.forwarded
{
"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.
{
"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:
{
"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:
{
"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):
{
"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:
{
"type": "whatsapp.account.banned",
"data": {
"waba_id": "1234567890",
"details": { "...": "Meta event payload" }
}
}
WhatsApp Data Subject Requests
{
"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:
{
"type": "whatsapp.tracking_events",
"data": {
"waba_id": "1234567890",
"details": { "...": "Meta event payload" }
}
}
Subscribing to Events
Register a webhook and specify which events to receive:
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