Events
What arrives at a webhook endpoint or on the event stream. How-to: Receive webhooks.
Generated from /openapi/v1.json; interactive version: API reference.
Endpoints
Section titled “Endpoints”| method | path | what it does | success |
|---|---|---|---|
GET | /v1/events | Stream or poll workspace events | 200 |
What each event promises, in the v2 format. Receiving, verifying and replaying events: Receive webhooks. The legacy format: Events, 2026-10-01 format.
Every event
Section titled “Every event”- Written once, delivered at least once. Each change is logged as one
event, with one id. A delivery can repeat (a retry after a timeout, or our
side retrying after a lost answer), so drop repeats by the envelope
id, which is also thewebhook-idheader. - Deliveries run concurrently and retries come later, so events can arrive
out of order. Order by
seq(higher is newer): an event whoseseqis lower than one you already applied for the same object is older news. The/v1/eventsstream is always inseqorder. metadataonmessage.sent,message.status_updated,call.*andcampaign.*is what you passed when you sent the message, placed the call or created the campaign (nullwhen there was none). It, the ids beside each<thing>_id, andconversation_idon an SMS status are looked up when the delivery is first sent; one isnullwhen its row is gone.- New event types and new fields may be added: answer 2xx to a
typeyou do not handle, and ignore fields you do not know. POST /v1/webhooks/{id}/testsends itswebhook.testsample in the endpoint’s format (a v2 sample has"seq": 0and an id startingevt_test_). It is never stored, retried or counted as a failure.- The
/v1/eventsstream never skips a frame: during a long database job on our side it pauses rather than jumping ahead, and goes on when the job ends. Use webhooks when you need real-time delivery. campaign.resumed’sprevious_reasonis the reason of the pause it ended, ornullwhen that is not known.
Messages
Section titled “Messages”message.receivedcovers SMS and WhatsApp: branch onchannel(smsorwhatsapp).message.sentcovers SMS only: AI-agent, human and API sends, andbodyis the text actually sent (after formatting), not the draft. Automated rating requests and campaign texts are not announced withmessage.sent; an API send withconversation: "none"hasconversation_idnull.- A split reply that went out as two texts is one
message.sent:message_idis the first part,message_idsevery part in order, and each part gets its ownmessage.status_updated, keyed by its ownmessage_id.message_id: nullwithmessage_ids: []means no text reached the carrier queue. A multi-part reply is announced once, when every part is handed over. - A reply the carrier never confirmed has no
message.sent; its status events say so. One confirmed only later gets itsmessage.sentwithin about 10 minutes of that. - For an AI agent’s or a teammate’s reply, the status events can come
before its
message.sent(even on the ordered stream). For an API send,message.sentalways comes first. message.received’skeyword(opt_out,opt_in,help) says the platform already applied it;campaign_idnames the campaign a reply was attributed to. Itsmessage_idis the conversation message’s id:GET /v1/messages/{id}does not read inbound texts.- A WhatsApp
message.receivedis a message the person sent: text, a button tap, a list or button reply, a location, or a file with or without a caption.bodyis their own words (a tap’s button label; empty for a file with no caption), and a tap’squick_reply.payloadis the button’s payload. A WhatsApp STOP or START the platform applied haskeywordopt_outoropt_in, as on SMS (WhatsApp has no HELP keyword). A reaction, a message only the WhatsApp Business App can show, your own replies from the Business App and chat history imported from it raise nomessage.received. message.status_updatedcarries the samestatuswordGET /v1/messages/{id}answers. Branch onchannelfirst.- An SMS status event is silent while a text is
sending: the first one is usuallysent, thendelivered,undelivered,failedorunconfirmed, and a send can go straight todelivered,failedorskipped. Early events can showsegments: null. - WhatsApp status events come as Meta reports each step:
sent,delivered,read,failed; a repeated status makes no second event. Areadevent also has thesent_atanddelivered_atMeta reported. SMSread_atis alwaysnull. - Campaign messages’ status events reach only endpoints and streams that
name
message.status_updated:"*"leaves them out. - For SMS, an event lost to a crash between storing a text (or its status)
and logging the event is logged later by a sweep, within about 10 minutes,
with the same content. A queued inbound text can have its events up to 30
seconds late. WhatsApp events have no such repair:
GET /v1/messages/{id}always has a status, andGET /v1/conversations/{id}/messagesevery message the person sent.
Inbound pictures (MMS)
Section titled “Inbound pictures (MMS)”A picture or video someone texts you is downloaded and stored in your
workspace; the provider’s own URL is never passed on. Each file is in
message.received’s media as { "url", "content_type", "size" }, where
url is https://api.omniocto.com/v1/media/{id}: call it with your API key
for a signed download link valid for 1 hour. A file we could not fetch is
not listed but counted in media_failed, so a picture-only MMS that failed
arrives as media: [] with media_failed: 1. Vonage numbers do not pass
media on: the message arrives with a placeholder line in body.
- A call gets exactly one terminal event,
call.completed(answered, voicemail, no answer or busy) orcall.failed(a system or carrier failure). After it, the call’sstatusandoutcomenever change, andoutcomeis nevernull. call.ringingandcall.answeredcome before it, once each, when the call was seen to ring and to be answered. An inbound call has nocall.ringing; a call nobody answered has nocall.answered.call.ringingis sent at most once and not written again if lost.- A call that stops reporting is closed as
call.failedwith outcomeunknownanddisconnect_reasonsettle_sweep_idle, normally within 20 minutes, up to 2 hours when the liveness signal is unavailable. An inbound call is not classified: its outcome isunknown. - In
seq, a call’s events come in that order (an event written again after a loss can come later); deliveries can still arrive out of order. answered_at,disconnect_reasonandoccurred_atare in events only. A campaign’s calls reach only endpoints and streams that name the call types. Calls placed from the dashboard’s Try Voice have no events.
Campaigns
Section titled “Campaigns”- Every channel announces
campaign.started,campaign.paused,campaign.resumed,campaign.completedandcampaign.canceled;campaign.waitingandcampaign.window_openedare SMS only. An event fires whoever made the change: your API call, a teammate, Octo, or the platform (a pause when credits run out). statusis the campaign’s status right after the change.campaign.startedcomes first,queuedorrunning; the move torunninghas no event. A run whose audience turns out empty sendscampaign.started, thencampaign.completed. Treatcampaign.completedandcampaign.canceledas final.- Treat the events as a prompt, not a ledger. In rare races a change is
announced twice, and very rarely one is missing. Act on the
statusin each payload, and readGET /v1/campaigns/{id}, which is always the truth. - For an SMS campaign, an event that could not be written when the campaign
changed is written later, once, usually 10 to 15 minutes after. Its
*_atis the time it was written, and a latecampaign.resumedhasprevious_reason: null. - For a WhatsApp or voice campaign,
campaign.completedandcampaign.canceledare written exactly once: one event id per campaign, never a second one. One that could not be written when the campaign ended is written later, usually 5 to 10 minutes after, with its*_atthe time it was written. Its other events (started,paused,resumed) have no such repair. To wait for a campaign to finish, pollGET /v1/events?wait=25&campaign=<id>&types=campaign.completed,campaign.canceled,campaign.paused. campaign.paused’sreasonisoperator(someone paused it, your ownPOST /v1/campaigns/{id}/pauseincluded),spend_cap,out_of_credits,daily_cap(the carrier’s daily limit;resumes_atsays when it goes on, after midnight Pacific time),circuit_breaker(too many recent texts failed),campaign_blocking_error(the carrier is refusing the number),trial_check_unavailable,trial_campaign_needs_card,needs_revieworengine_error.messagesays the same in one sentence, ready to show.resumes_atisnullfor every other reason.campaign.completed’scountsare counted when it completed: a text still being handed to the carrier then counts asfailed, andGET /v1/campaigns/{id}shows its later state.billed_creditsis the SMS texts’ cost,nullfor WhatsApp and voice.campaign.canceled:in_flightcounts messages already handed over (they may still arrive),not_yet_sentthe recipients nothing was sent to. Discarding a draft that never started sends no event.campaign.waitingis not a pause:statusstaysqueuedorrunningand the campaign goes on by itself.resumes_atis when the hours next start (nullwhen none fall in the next 8 days).campaign.window_openedfollows once per wait, unless a pause or cancel ended it. Sending hours are checked once a minute, so both can be up to a minute late.
Poll and Monitor
Section titled “Poll and Monitor”GET /v1/events?wait=<0..25> (poll mode) answers one EventPage. A loop:
call once without after to get a next_cursor from now (do it before you
start the campaign you will wait for: an event still being written at that
instant counts as before now), then call with
after=<next_cursor> each time, whether or not events came; has_more: true
means call again at once. At most 5 polls per key (20 per workspace) may wait
at once (429 too_many_waits); wait=0 never counts, and a wait=25 loop
makes about 2 requests a minute of the route’s 60. From an MCP client the
wait_for_events tool is this call (API tools).
In Claude Code, Monitor can watch the stream in the background and report
each event line; take $CURSOR from one poll first, or the stream replays
7 days:
curl -sN "https://api.omniocto.com/v1/events?api_version=v2&after=$CURSOR&campaign=ca-0000000002&types=campaign.completed,campaign.paused" \ -H "Authorization: Bearer $OMNI_OCTO_API_KEY" | grep --line-buffered '^event: 'GET /v1/events
Section titled “GET /v1/events”Stream or poll workspace events.
Poll mode (?wait=0..25): one JSON page (EventPage, the /v1 list shape) of the events after after, answered as soon as there is one or after wait seconds with data: []. Without after (or Last-Event-ID) it starts from now: the first call returns next_cursor and only events written after it. Pass next_cursor back as after, whether or not events came; has_more: true means call again at once. At most 5 waiting polls per key and 20 per workspace (429 too_many_waits); wait=0 never counts. Stream mode (no wait): a long-lived text/event-stream of workspace events. First replays durable events after the resume cursor (?after=<seq> or the Last-Event-ID header), then tails live events. Each SSE frame’s id: is a monotonic cursor and event: is the event type; the data: payload is the event envelope. About every 15 s an event: ping frame arrives with empty data and no id:: skip it. Two other frames are not envelopes and have no id: either: replay_truncated (a cursor older than the log) and error (the key’s owner lost the owner or admin role; data is the /v1 error body with code: insufficient_role, and the stream then ends). With ?api_version=v2, an event that could not be rendered as v2 is an event: render_error frame with the event’s seq as id: and data { event_id, type, seq } plus the event’s message_id, send_id, call_id, campaign_id and conversation_id when it has them: read that resource, or replay the event without api_version (?after=<seq-1>&types=<type>). ?after= wins over Last-Event-ID when both are sent. ?campaign= (both modes) keeps only the events whose data.campaign_id is that campaign; without types, a campaign’s per-recipient message.status_updated and call.* events are still left out, as with "*". Owners and admins only: a key whose owner has the Agent role in the workspace gets 403 insufficient_role (the feed carries every event of the workspace, message text included).
Parameters
| name | in | type | description |
|---|---|---|---|
after | query | integer ≥ 0 | Resume cursor: stream events with a seq greater than this (a frame’s id:). A whole number of 0 or more; anything else is 400 invalid_cursor. |
types | query | string | Comma-separated event types to filter to (e.g. turn.completed,run.completed). An unknown type returns 400. |
campaign | query | string | A campaign’s ca-… id or UUID: only events whose payload names it (data.campaign_id). Without types, its texts’ status events and its calls’ events are left out: name message.status_updated, call.completed or call.failed in types to get them. No such campaign in this workspace: 404 not_found. |
wait | query | integer 0–25 | Poll mode: answer one JSON page instead of a stream, waiting up to this many seconds (0 to 25) for the first event. 0 answers at once. |
limit | query | integer 1–200; default 100 | Poll mode only: the most events one page carries (1 to 200, default 100). Without wait it is 400 invalid_request. |
api_version | query | string2026-10-01, v2; default 2026-10-01 | The payload version of the frames: 2026-10-01 (WorkspaceEvent, the default) or v2 (WorkspaceEventV2, the body a v2 webhook endpoint receives). Anything else returns 400. |
Last-Event-ID | header | string | Standard SSE resume header — an alternative to ?after. |
Answers 200 with EventPage; 200 (text/event-stream) with WorkspaceEvent or WorkspaceEventV2. Errors use the error envelope.
Objects
Section titled “Objects”EventPage
Section titled “EventPage”One page of the event log (poll mode). data holds the events after the cursor, oldest first, each the same envelope a stream frame carries.
| field | type | description |
|---|---|---|
object | string, required always list | |
data | array of map of string to any, required | Events in seq order, each the envelope a stream frame carries: WorkspaceEvent (2026-10-01, the default) or, with ?api_version=v2, WorkspaceEventV2. The Octo-Event-Version header names which. |
has_more | boolean, required | true when the page stopped at limit with more events ready: call again at once with next_cursor. |
next_cursor | string, required | A seq (as a string). Pass it as after on the next call, whether or not this page had events: it also moves past events your filters skipped. Always a safe resume point, for a poll or a stream. |
replay_truncated | object or null, required | null, or { after, oldest_retained_seq, retention_days } when after is older than the 7-day log: the events between them are gone. |
replay_truncated.after | integer | |
replay_truncated.oldest_retained_seq | integer | |
replay_truncated.retention_days | integer | |
render_errors | array of map of string to any, required | api_version=v2 only: events that could not be rendered as v2, each { event_id, type, seq } plus the ids it had (message_id, send_id, call_id, campaign_id, conversation_id). Read the resource, or poll ?after=<seq-1>&types=<type> without api_version for the 2026-10-01 body. Empty otherwise. |
Example: see Receive webhooks.
Envelope (every event)
Section titled “Envelope (every event)”These are the v2 fields, what an endpoint on api_version: "v2" receives. The event stream sends them with ?api_version=v2; by default it, and endpoints on 2026-10-01, send the 2026-10-01 format. Every event carries these fields; type names the event and data differs per type, below.
| field | type | description |
|---|---|---|
id | string, required | |
object | string, required always event | |
api_version | string, required always v2 | |
livemode | boolean, required | |
workspace_id | string, required | |
created_at | string, required | |
seq | integer, required | Its exact limits differ by event type (a test event’s is 0). |
type | string, required | The event type: one of the sections below. |
conversation.created
Section titled “conversation.created”| field | type | description |
|---|---|---|
data | object, required | |
data.conversation_id | string, required | |
data.channel | string, required | |
data.contact_id | string |
turn.completed
Section titled “turn.completed”| field | type | description |
|---|---|---|
data | object, required | |
data.conversation_id | string, required | |
data.surface | string, required | |
data.reply_preview | string, required | |
data.finish_reason | string, required | |
data.model | string, required |
confirmation.requested
Section titled “confirmation.requested”| field | type | description |
|---|---|---|
data | object, required | |
data.action_id | string, required | |
data.action_code | string, required | |
data.summary | string, required | |
data.conversation_id | string |
confirmation.resolved
Section titled “confirmation.resolved”| field | type | description |
|---|---|---|
data | object, required | |
data.action_id | string, required | |
data.action_code | string, required | |
data.resolution | string, requiredapproved, rejected, expired, superseded |
spend.recorded
Section titled “spend.recorded”| field | type | description |
|---|---|---|
data | object, required | |
data.amount_credits | number, required | |
data.category | string, required | |
data.conversation_id | string | |
data.balance_credits | number |
run.completed
Section titled “run.completed”| field | type | description |
|---|---|---|
data | object, required | |
data.run_id | string, required | |
data.workflow_id | string, required | |
data.status | string, required |
message.received
Section titled “message.received”| field | type | description |
|---|---|---|
data | object, required | |
data.message_id | string, required | The conversation message’s id. GET /v1/messages/{id} does not read inbound texts. |
data.channel | string, requiredsms, whatsapp | The message’s channel. |
data.conversation_id | string, required | The conversation the message landed in. |
data.contact_id | string or null, required | The sender’s contact; null when none matched. |
data.from | string, required | Who sent it: a phone number in E.164, on SMS or on WhatsApp. |
data.to | string or null, required | Your number that received it, in E.164; null when it is not known. |
data.body | string, required | The person’s own words: the SMS text, or a WhatsApp message’s text, caption or tapped button’s label. Empty when they sent only a file. |
data.media | array of objects, required | |
data.media[].url | string, required | |
data.media[].content_type | string, required | |
data.media[].size | integer or null, required | |
data.media_failed | integer, required ≥ 0 | How many attachments could not be stored. |
data.received_at | string, required | When it arrived (ISO 8601). |
data.campaign_id | string or null, required | The campaign a reply was attributed to: its UUID. |
data.campaign_short_id | string or null, required | The same campaign’s ca-… id. |
data.channel_id | string or null, required | The channel’s ch-… id. |
data.channel_uuid | string, required | The same channel’s UUID (channel_uuids in GET /v1/senders). |
data.sender_id | string or null, required | The number’s GET /v1/senders id: pn-…, or a WhatsApp-only number’s ch-…. |
data.keyword | string or null, requiredopt_out, opt_in, help | A STOP, START or HELP keyword, already handled; null for any other text. On WhatsApp only opt_out or opt_in (there is no HELP keyword). |
data.quick_reply | object or null, required | A WhatsApp button tap; null for anything typed, and always null on SMS. |
data.quick_reply.payload | string, required | The tapped button’s payload: a template quick-reply button’s payload, or an interactive reply’s id. |
message.sent
Section titled “message.sent”| field | type | description |
|---|---|---|
data | object, required | |
data.message_id | string or null, required | The GET /v1/messages/{id} id of the first (or only) part; null when no part reached the carrier queue. |
data.message_ids | array of string, required | Every part of a split reply, in order; each gets its own message.status_updated. |
data.channel | string, required always sms | Always sms. |
data.conversation_id | string or null, required | The conversation it was added to, if any. |
data.author | string, requiredai_agent, human, api | Who wrote it: an AI agent, a person, or an API send. |
data.agent_id | string or null, required | The agent’s ag-… id; null unless an AI agent wrote it. |
data.agent_uuid | string or null, required | The same agent’s UUID. |
data.from | string or null, required | The sending number, in E.164. |
data.to | string, required | The recipient, in E.164. |
data.channel_id | string or null, required | The sending channel’s ch-… id. |
data.channel_uuid | string or null, required | The same channel’s UUID. |
data.sender_id | string or null, required | The number’s GET /v1/senders id. |
data.body | string, required | The whole text, every part together. |
data.sent_at | string, required | When it was handed to the carrier (ISO 8601). |
data.metadata | map of string to string or null, required | The metadata you passed on the send, call or campaign create; null when none. |
message.status_updated
Section titled “message.status_updated”| field | type | description |
|---|---|---|
data | object, required | |
data.message_id | string, required | The GET /v1/messages/{id} id: an SMS part’s, or the WhatsApp message’s. |
data.channel | string, requiredsms, whatsapp | The message’s channel. |
data.status | string, requiredqueued, sending, sent, delivered, read, undelivered, failed, skipped, unconfirmed | The new status, the status of GET /v1/messages/{id}. |
data.from | string or null, required | The sending number, in E.164. |
data.to | string, required | The recipient, in E.164. |
data.conversation_id | string or null, required | The conversation the message is in, if any. |
data.campaign_id | string or null, required | The sending campaign’s UUID; null for a single send. |
data.campaign_short_id | string or null, required | The same campaign’s ca-… id. |
data.sender_id | string or null, required | The number’s GET /v1/senders id. |
data.segments | integer or null, required | SMS only; null on WhatsApp, and on early SMS events. |
data.billed_credits | number or null, required | SMS only; null on WhatsApp. |
data.error | object or null, required | Why it failed, the error of GET /v1/messages/{id}; null otherwise. |
data.error.code | string or null, required | |
data.error.category | string, required | |
data.error.message | string, required | |
data.error.action | string or null, required | |
data.template | object or null, required | WhatsApp only: the template sent; null on SMS. |
data.template.id | string, required | |
data.template.name | string, required | |
data.template.language | string, required | |
data.sent_at | string or null, required | When it was sent, if it was. |
data.delivered_at | string or null, required | When it was delivered, if it was. |
data.read_at | string or null, required | WhatsApp: when it was read, if it was. |
data.updated_at | string or null, required | When the status last changed. |
data.metadata | map of string to string or null, required | The metadata you passed on the send, call or campaign create; null when none. |
campaign.started
Section titled “campaign.started”| field | type | description |
|---|---|---|
data | object, required | |
data.campaign_id | string, required | The campaign’s UUID, its id on GET /v1/campaigns/{id}. |
data.campaign_short_id | string or null, required | The campaign’s ca-… id. |
data.name | string, required | The campaign’s name. |
data.channel | string, requiredsms, whatsapp, voice | The campaign’s channel. |
data.status | string, requireddraft, queued, running, paused, completed, failed, canceled | Its status after this change. |
data.started_at | string, required | When it started. |
data.metadata | map of string to string or null, required | The metadata you passed on the send, call or campaign create; null when none. |
campaign.paused
Section titled “campaign.paused”| field | type | description |
|---|---|---|
data | object, required | |
data.campaign_id | string, required | The campaign’s UUID, its id on GET /v1/campaigns/{id}. |
data.campaign_short_id | string or null, required | The campaign’s ca-… id. |
data.name | string, required | The campaign’s name. |
data.channel | string, requiredsms, whatsapp, voice | The campaign’s channel. |
data.status | string, requireddraft, queued, running, paused, completed, failed, canceled | Its status after this change. |
data.reason | string, requiredoperator, spend_cap, out_of_credits, daily_cap, circuit_breaker, campaign_blocking_error, trial_check_unavailable, trial_campaign_needs_card, needs_review, engine_error | Why it paused; operator when a person paused it. |
data.message | string, required | The reason in plain words, to show as it is. |
data.paused_at | string, required | When it paused. |
data.resumes_at | string or null, required | When it resumes by itself, if it will; null otherwise. |
data.metadata | map of string to string or null, required | The metadata you passed on the send, call or campaign create; null when none. |
campaign.resumed
Section titled “campaign.resumed”| field | type | description |
|---|---|---|
data | object, required | |
data.campaign_id | string, required | The campaign’s UUID, its id on GET /v1/campaigns/{id}. |
data.campaign_short_id | string or null, required | The campaign’s ca-… id. |
data.name | string, required | The campaign’s name. |
data.channel | string, requiredsms, whatsapp, voice | The campaign’s channel. |
data.status | string, requireddraft, queued, running, paused, completed, failed, canceled | Its status after this change. |
data.resumed_at | string, required | When it resumed. |
data.previous_reason | string or null, requiredoperator, spend_cap, out_of_credits, daily_cap, circuit_breaker, campaign_blocking_error, trial_check_unavailable, trial_campaign_needs_card, needs_review, engine_error | Why it had paused. |
data.metadata | map of string to string or null, required | The metadata you passed on the send, call or campaign create; null when none. |
campaign.completed
Section titled “campaign.completed”| field | type | description |
|---|---|---|
data | object, required | |
data.campaign_id | string, required | The campaign’s UUID, its id on GET /v1/campaigns/{id}. |
data.campaign_short_id | string or null, required | The campaign’s ca-… id. |
data.name | string, required | The campaign’s name. |
data.channel | string, requiredsms, whatsapp, voice | The campaign’s channel. |
data.status | string, requireddraft, queued, running, paused, completed, failed, canceled | Its status after this change. |
data.completed_at | string, required | When it completed. |
data.counts | object, required | The final counts, as GET /v1/campaigns/{id} answers them. |
data.counts.recipients | integer, required ≥ 0 | |
data.counts.pending | integer, required ≥ 0 | |
data.counts.sent | integer, required ≥ 0 | |
data.counts.delivered | integer, required ≥ 0 | |
data.counts.failed | integer, required ≥ 0 | |
data.counts.skipped | integer, required ≥ 0 | |
data.counts.replied | integer or null, required ≥ 0 | |
data.counts.opted_out | integer or null, required ≥ 0 | |
data.billed_credits | number or null, required | Credits the campaign cost in all; null when not known. |
data.metadata | map of string to string or null, required | The metadata you passed on the send, call or campaign create; null when none. |
campaign.canceled
Section titled “campaign.canceled”| field | type | description |
|---|---|---|
data | object, required | |
data.campaign_id | string, required | The campaign’s UUID, its id on GET /v1/campaigns/{id}. |
data.campaign_short_id | string or null, required | The campaign’s ca-… id. |
data.name | string, required | The campaign’s name. |
data.channel | string, requiredsms, whatsapp, voice | The campaign’s channel. |
data.status | string, requireddraft, queued, running, paused, completed, failed, canceled | Its status after this change. |
data.canceled_at | string, required | When it was canceled. |
data.in_flight | integer or null, required ≥ 0 | Sends or calls already under way when it was canceled. |
data.not_yet_sent | integer or null, required ≥ 0 | Recipients that will not be reached. |
data.metadata | map of string to string or null, required | The metadata you passed on the send, call or campaign create; null when none. |
campaign.waiting
Section titled “campaign.waiting”| field | type | description |
|---|---|---|
data | object, required | |
data.campaign_id | string, required | The campaign’s UUID, its id on GET /v1/campaigns/{id}. |
data.campaign_short_id | string or null, required | The campaign’s ca-… id. |
data.name | string, required | The campaign’s name. |
data.channel | string, requiredsms, whatsapp, voice | The campaign’s channel. |
data.status | string, requireddraft, queued, running, paused, completed, failed, canceled | Its status after this change. |
data.reason | string, required always send_window | Outside its sending hours or days. |
data.waiting_at | string, required | When it started waiting. |
data.resumes_at | string or null, required | When its next window opens. |
data.tz | string, required | The schedule’s IANA time zone. |
data.metadata | map of string to string or null, required | The metadata you passed on the send, call or campaign create; null when none. |
campaign.window_opened
Section titled “campaign.window_opened”| field | type | description |
|---|---|---|
data | object, required | |
data.campaign_id | string, required | The campaign’s UUID, its id on GET /v1/campaigns/{id}. |
data.campaign_short_id | string or null, required | The campaign’s ca-… id. |
data.name | string, required | The campaign’s name. |
data.channel | string, requiredsms, whatsapp, voice | The campaign’s channel. |
data.status | string, requireddraft, queued, running, paused, completed, failed, canceled | Its status after this change. |
data.opened_at | string, required | When the window opened. |
data.tz | string, required | The schedule’s IANA time zone. |
data.metadata | map of string to string or null, required | The metadata you passed on the send, call or campaign create; null when none. |
meta_response.completed
Section titled “meta_response.completed”| field | type | description |
|---|---|---|
data | object, required | |
data.response_id | string, required | |
data.conversation_id | string, required | |
data.status | string, requiredcompleted, failed | |
data.error | object or null, required | |
data.error.type | string, required | |
data.error.code | string or null, required | |
data.error.message | string, required |
meta_chat.updated
Section titled “meta_chat.updated”| field | type | description |
|---|---|---|
data | object, required | |
data.conversation_id | string, required | |
data.surface | string, required | |
data.title | string, required | |
data.preview | string, required | |
data.message_count | integer, required ≥ 0 |
call.ringing
Section titled “call.ringing”| field | type | description |
|---|---|---|
data | object, required | |
data.call_id | string, required | The call’s UUID, its id on GET /v1/calls/{id}. |
data.call_short_id | string or null, required | The call’s cv-… id. |
data.channel | string, required always voice | Always voice. |
data.conversation_id | string, required | The call’s conversation (its transcript). |
data.direction | string or null, requiredinbound, outbound | Who called whom. |
data.from | string or null, required | The calling number, in E.164. |
data.to | string or null, required | The called number, in E.164. |
data.agent_id | string or null, required | The agent’s ag-… id. |
data.agent_uuid | string or null, required | The same agent’s UUID. |
data.campaign_id | string or null, required | The placing campaign’s UUID; null for a single call. |
data.campaign_short_id | string or null, required | The same campaign’s ca-… id. |
data.status | string, requiredqueued, ringing, in_progress, completed, voicemail, no_answer, busy, failed | The call’s status after this event. |
data.occurred_at | string, required | When this happened (ISO 8601). |
data.metadata | map of string to string or null, required | The metadata you passed on the send, call or campaign create; null when none. |
call.answered
Section titled “call.answered”| field | type | description |
|---|---|---|
data | object, required | |
data.call_id | string, required | The call’s UUID, its id on GET /v1/calls/{id}. |
data.call_short_id | string or null, required | The call’s cv-… id. |
data.channel | string, required always voice | Always voice. |
data.conversation_id | string, required | The call’s conversation (its transcript). |
data.direction | string or null, requiredinbound, outbound | Who called whom. |
data.from | string or null, required | The calling number, in E.164. |
data.to | string or null, required | The called number, in E.164. |
data.agent_id | string or null, required | The agent’s ag-… id. |
data.agent_uuid | string or null, required | The same agent’s UUID. |
data.campaign_id | string or null, required | The placing campaign’s UUID; null for a single call. |
data.campaign_short_id | string or null, required | The same campaign’s ca-… id. |
data.status | string, requiredqueued, ringing, in_progress, completed, voicemail, no_answer, busy, failed | The call’s status after this event. |
data.occurred_at | string, required | When this happened (ISO 8601). |
data.answered_at | string, required | When it was answered. |
data.metadata | map of string to string or null, required | The metadata you passed on the send, call or campaign create; null when none. |
call.completed
Section titled “call.completed”| field | type | description |
|---|---|---|
data | object, required | |
data.call_id | string, required | The call’s UUID, its id on GET /v1/calls/{id}. |
data.call_short_id | string or null, required | The call’s cv-… id. |
data.channel | string, required always voice | Always voice. |
data.conversation_id | string, required | The call’s conversation (its transcript). |
data.direction | string or null, requiredinbound, outbound | Who called whom. |
data.from | string or null, required | The calling number, in E.164. |
data.to | string or null, required | The called number, in E.164. |
data.agent_id | string or null, required | The agent’s ag-… id. |
data.agent_uuid | string or null, required | The same agent’s UUID. |
data.campaign_id | string or null, required | The placing campaign’s UUID; null for a single call. |
data.campaign_short_id | string or null, required | The same campaign’s ca-… id. |
data.status | string, requiredcompleted, voicemail, no_answer, busy | |
data.occurred_at | string, required | When this happened (ISO 8601). |
data.answered_at | string or null, required | When it was answered; null if never. |
data.outcome | string, requiredvalid_pickup, answered_human, invalid_pickup, callback_requested, do_not_call, wrong_person, hung_up_early, voicemail, ivr_system, no_answer, busy, disconnected, unreachable, failed, unknown, completed, delivered, pending | How it ended (never null; unknown when unclassified). |
data.duration_sec | integer, required ≥ 0 | Talk time in whole seconds. |
data.ended_at | string, required | When it ended. |
data.disconnect_reason | string or null, required | Who or what hung up, when known. |
data.metadata | map of string to string or null, required | The metadata you passed on the send, call or campaign create; null when none. |
call.failed
Section titled “call.failed”| field | type | description |
|---|---|---|
data | object, required | |
data.call_id | string, required | The call’s UUID, its id on GET /v1/calls/{id}. |
data.call_short_id | string or null, required | The call’s cv-… id. |
data.channel | string, required always voice | Always voice. |
data.conversation_id | string, required | The call’s conversation (its transcript). |
data.direction | string or null, requiredinbound, outbound | Who called whom. |
data.from | string or null, required | The calling number, in E.164. |
data.to | string or null, required | The called number, in E.164. |
data.agent_id | string or null, required | The agent’s ag-… id. |
data.agent_uuid | string or null, required | The same agent’s UUID. |
data.campaign_id | string or null, required | The placing campaign’s UUID; null for a single call. |
data.campaign_short_id | string or null, required | The same campaign’s ca-… id. |
data.status | string, required always failed | |
data.occurred_at | string, required | When this happened (ISO 8601). |
data.answered_at | string or null, required | When it was answered; null if never. |
data.outcome | string, requiredvalid_pickup, answered_human, invalid_pickup, callback_requested, do_not_call, wrong_person, hung_up_early, voicemail, ivr_system, no_answer, busy, disconnected, unreachable, failed, unknown, completed, delivered, pending | How it ended (never null; unknown when unclassified). |
data.duration_sec | integer, required ≥ 0 | Talk time in whole seconds. |
data.ended_at | string, required | When it ended. |
data.disconnect_reason | string or null, required | Who or what hung up, when known. |
data.metadata | map of string to string or null, required | The metadata you passed on the send, call or campaign create; null when none. |
webhook.test
Section titled “webhook.test”| field | type | description |
|---|---|---|
data | object, required | |
data.webhook_id | string, required | |
data.message | string, required |