Skip to content

Events

Download .md

What arrives at a webhook endpoint or on the event stream. How-to: Receive webhooks.

Generated from /openapi/v1.json; interactive version: API reference.

methodpathwhat it doessuccess
GET/v1/eventsStream or poll workspace events200

What each event promises, in the v2 format. Receiving, verifying and replaying events: Receive webhooks. The legacy format: Events, 2026-10-01 format.

  • 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 the webhook-id header.
  • Deliveries run concurrently and retries come later, so events can arrive out of order. Order by seq (higher is newer): an event whose seq is lower than one you already applied for the same object is older news. The /v1/events stream is always in seq order.
  • metadata on message.sent, message.status_updated, call.* and campaign.* is what you passed when you sent the message, placed the call or created the campaign (null when there was none). It, the ids beside each <thing>_id, and conversation_id on an SMS status are looked up when the delivery is first sent; one is null when its row is gone.
  • New event types and new fields may be added: answer 2xx to a type you do not handle, and ignore fields you do not know.
  • POST /v1/webhooks/{id}/test sends its webhook.test sample in the endpoint’s format (a v2 sample has "seq": 0 and an id starting evt_test_). It is never stored, retried or counted as a failure.
  • The /v1/events stream 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’s previous_reason is the reason of the pause it ended, or null when that is not known.
  • message.received covers SMS and WhatsApp: branch on channel (sms or whatsapp). message.sent covers SMS only: AI-agent, human and API sends, and body is the text actually sent (after formatting), not the draft. Automated rating requests and campaign texts are not announced with message.sent; an API send with conversation: "none" has conversation_id null.
  • A split reply that went out as two texts is one message.sent: message_id is the first part, message_ids every part in order, and each part gets its own message.status_updated, keyed by its own message_id. message_id: null with message_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 its message.sent within 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.sent always comes first.
  • message.received’s keyword (opt_out, opt_in, help) says the platform already applied it; campaign_id names the campaign a reply was attributed to. Its message_id is the conversation message’s id: GET /v1/messages/{id} does not read inbound texts.
  • A WhatsApp message.received is a message the person sent: text, a button tap, a list or button reply, a location, or a file with or without a caption. body is their own words (a tap’s button label; empty for a file with no caption), and a tap’s quick_reply.payload is the button’s payload. A WhatsApp STOP or START the platform applied has keyword opt_out or opt_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 no message.received.
  • message.status_updated carries the same status word GET /v1/messages/{id} answers. Branch on channel first.
  • An SMS status event is silent while a text is sending: the first one is usually sent, then delivered, undelivered, failed or unconfirmed, and a send can go straight to delivered, failed or skipped. Early events can show segments: null.
  • WhatsApp status events come as Meta reports each step: sent, delivered, read, failed; a repeated status makes no second event. A read event also has the sent_at and delivered_at Meta reported. SMS read_at is always null.
  • 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, and GET /v1/conversations/{id}/messages every message the person sent.

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) or call.failed (a system or carrier failure). After it, the call’s status and outcome never change, and outcome is never null.
  • call.ringing and call.answered come before it, once each, when the call was seen to ring and to be answered. An inbound call has no call.ringing; a call nobody answered has no call.answered. call.ringing is sent at most once and not written again if lost.
  • A call that stops reporting is closed as call.failed with outcome unknown and disconnect_reason settle_sweep_idle, normally within 20 minutes, up to 2 hours when the liveness signal is unavailable. An inbound call is not classified: its outcome is unknown.
  • 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_reason and occurred_at are 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.
  • Every channel announces campaign.started, campaign.paused, campaign.resumed, campaign.completed and campaign.canceled; campaign.waiting and campaign.window_opened are SMS only. An event fires whoever made the change: your API call, a teammate, Octo, or the platform (a pause when credits run out).
  • status is the campaign’s status right after the change. campaign.started comes first, queued or running; the move to running has no event. A run whose audience turns out empty sends campaign.started, then campaign.completed. Treat campaign.completed and campaign.canceled as 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 status in each payload, and read GET /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 *_at is the time it was written, and a late campaign.resumed has previous_reason: null.
  • For a WhatsApp or voice campaign, campaign.completed and campaign.canceled are 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 *_at the time it was written. Its other events (started, paused, resumed) have no such repair. To wait for a campaign to finish, poll GET /v1/events?wait=25&campaign=<id>&types=campaign.completed,campaign.canceled,campaign.paused.
  • campaign.paused’s reason is operator (someone paused it, your own POST /v1/campaigns/{id}/pause included), spend_cap, out_of_credits, daily_cap (the carrier’s daily limit; resumes_at says 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_review or engine_error. message says the same in one sentence, ready to show. resumes_at is null for every other reason.
  • campaign.completed’s counts are counted when it completed: a text still being handed to the carrier then counts as failed, and GET /v1/campaigns/{id} shows its later state. billed_credits is the SMS texts’ cost, null for WhatsApp and voice.
  • campaign.canceled: in_flight counts messages already handed over (they may still arrive), not_yet_sent the recipients nothing was sent to. Discarding a draft that never started sends no event.
  • campaign.waiting is not a pause: status stays queued or running and the campaign goes on by itself. resumes_at is when the hours next start (null when none fall in the next 8 days). campaign.window_opened follows 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.

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:

Terminal window
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: '

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

nameintypedescription
afterqueryinteger
≥ 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.
typesquerystringComma-separated event types to filter to (e.g. turn.completed,run.completed). An unknown type returns 400.
campaignquerystringA 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.
waitqueryinteger
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.
limitqueryinteger
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_versionquerystring
2026-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-IDheaderstringStandard SSE resume header — an alternative to ?after.

Answers 200 with EventPage; 200 (text/event-stream) with WorkspaceEvent or WorkspaceEventV2. Errors use the error envelope.

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.

fieldtypedescription
objectstring, required
always list
dataarray of map of string to any, requiredEvents 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_moreboolean, requiredtrue when the page stopped at limit with more events ready: call again at once with next_cursor.
next_cursorstring, requiredA 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_truncatedobject or null, requirednull, or { after, oldest_retained_seq, retention_days } when after is older than the 7-day log: the events between them are gone.
replay_truncated.afterinteger
replay_truncated.oldest_retained_seqinteger
replay_truncated.retention_daysinteger
render_errorsarray of map of string to any, requiredapi_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.

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.

fieldtypedescription
idstring, required
objectstring, required
always event
api_versionstring, required
always v2
livemodeboolean, required
workspace_idstring, required
created_atstring, required
seqinteger, requiredIts exact limits differ by event type (a test event’s is 0).
typestring, requiredThe event type: one of the sections below.
fieldtypedescription
dataobject, required
data.conversation_idstring, required
data.channelstring, required
data.contact_idstring
fieldtypedescription
dataobject, required
data.conversation_idstring, required
data.surfacestring, required
data.reply_previewstring, required
data.finish_reasonstring, required
data.modelstring, required
fieldtypedescription
dataobject, required
data.action_idstring, required
data.action_codestring, required
data.summarystring, required
data.conversation_idstring
fieldtypedescription
dataobject, required
data.action_idstring, required
data.action_codestring, required
data.resolutionstring, required
approved, rejected, expired, superseded
fieldtypedescription
dataobject, required
data.amount_creditsnumber, required
data.categorystring, required
data.conversation_idstring
data.balance_creditsnumber
fieldtypedescription
dataobject, required
data.run_idstring, required
data.workflow_idstring, required
data.statusstring, required
fieldtypedescription
dataobject, required
data.message_idstring, requiredThe conversation message’s id. GET /v1/messages/{id} does not read inbound texts.
data.channelstring, required
sms, whatsapp
The message’s channel.
data.conversation_idstring, requiredThe conversation the message landed in.
data.contact_idstring or null, requiredThe sender’s contact; null when none matched.
data.fromstring, requiredWho sent it: a phone number in E.164, on SMS or on WhatsApp.
data.tostring or null, requiredYour number that received it, in E.164; null when it is not known.
data.bodystring, requiredThe 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.mediaarray of objects, required
data.media[].urlstring, required
data.media[].content_typestring, required
data.media[].sizeinteger or null, required
data.media_failedinteger, required
≥ 0
How many attachments could not be stored.
data.received_atstring, requiredWhen it arrived (ISO 8601).
data.campaign_idstring or null, requiredThe campaign a reply was attributed to: its UUID.
data.campaign_short_idstring or null, requiredThe same campaign’s ca-… id.
data.channel_idstring or null, requiredThe channel’s ch-… id.
data.channel_uuidstring, requiredThe same channel’s UUID (channel_uuids in GET /v1/senders).
data.sender_idstring or null, requiredThe number’s GET /v1/senders id: pn-…, or a WhatsApp-only number’s ch-….
data.keywordstring or null, required
opt_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_replyobject or null, requiredA WhatsApp button tap; null for anything typed, and always null on SMS.
data.quick_reply.payloadstring, requiredThe tapped button’s payload: a template quick-reply button’s payload, or an interactive reply’s id.
fieldtypedescription
dataobject, required
data.message_idstring or null, requiredThe GET /v1/messages/{id} id of the first (or only) part; null when no part reached the carrier queue.
data.message_idsarray of string, requiredEvery part of a split reply, in order; each gets its own message.status_updated.
data.channelstring, required
always sms
Always sms.
data.conversation_idstring or null, requiredThe conversation it was added to, if any.
data.authorstring, required
ai_agent, human, api
Who wrote it: an AI agent, a person, or an API send.
data.agent_idstring or null, requiredThe agent’s ag-… id; null unless an AI agent wrote it.
data.agent_uuidstring or null, requiredThe same agent’s UUID.
data.fromstring or null, requiredThe sending number, in E.164.
data.tostring, requiredThe recipient, in E.164.
data.channel_idstring or null, requiredThe sending channel’s ch-… id.
data.channel_uuidstring or null, requiredThe same channel’s UUID.
data.sender_idstring or null, requiredThe number’s GET /v1/senders id.
data.bodystring, requiredThe whole text, every part together.
data.sent_atstring, requiredWhen it was handed to the carrier (ISO 8601).
data.metadatamap of string to string or null, requiredThe metadata you passed on the send, call or campaign create; null when none.
fieldtypedescription
dataobject, required
data.message_idstring, requiredThe GET /v1/messages/{id} id: an SMS part’s, or the WhatsApp message’s.
data.channelstring, required
sms, whatsapp
The message’s channel.
data.statusstring, required
queued, sending, sent, delivered, read, undelivered, failed, skipped, unconfirmed
The new status, the status of GET /v1/messages/{id}.
data.fromstring or null, requiredThe sending number, in E.164.
data.tostring, requiredThe recipient, in E.164.
data.conversation_idstring or null, requiredThe conversation the message is in, if any.
data.campaign_idstring or null, requiredThe sending campaign’s UUID; null for a single send.
data.campaign_short_idstring or null, requiredThe same campaign’s ca-… id.
data.sender_idstring or null, requiredThe number’s GET /v1/senders id.
data.segmentsinteger or null, requiredSMS only; null on WhatsApp, and on early SMS events.
data.billed_creditsnumber or null, requiredSMS only; null on WhatsApp.
data.errorobject or null, requiredWhy it failed, the error of GET /v1/messages/{id}; null otherwise.
data.error.codestring or null, required
data.error.categorystring, required
data.error.messagestring, required
data.error.actionstring or null, required
data.templateobject or null, requiredWhatsApp only: the template sent; null on SMS.
data.template.idstring, required
data.template.namestring, required
data.template.languagestring, required
data.sent_atstring or null, requiredWhen it was sent, if it was.
data.delivered_atstring or null, requiredWhen it was delivered, if it was.
data.read_atstring or null, requiredWhatsApp: when it was read, if it was.
data.updated_atstring or null, requiredWhen the status last changed.
data.metadatamap of string to string or null, requiredThe metadata you passed on the send, call or campaign create; null when none.
fieldtypedescription
dataobject, required
data.campaign_idstring, requiredThe campaign’s UUID, its id on GET /v1/campaigns/{id}.
data.campaign_short_idstring or null, requiredThe campaign’s ca-… id.
data.namestring, requiredThe campaign’s name.
data.channelstring, required
sms, whatsapp, voice
The campaign’s channel.
data.statusstring, required
draft, queued, running, paused, completed, failed, canceled
Its status after this change.
data.started_atstring, requiredWhen it started.
data.metadatamap of string to string or null, requiredThe metadata you passed on the send, call or campaign create; null when none.
fieldtypedescription
dataobject, required
data.campaign_idstring, requiredThe campaign’s UUID, its id on GET /v1/campaigns/{id}.
data.campaign_short_idstring or null, requiredThe campaign’s ca-… id.
data.namestring, requiredThe campaign’s name.
data.channelstring, required
sms, whatsapp, voice
The campaign’s channel.
data.statusstring, required
draft, queued, running, paused, completed, failed, canceled
Its status after this change.
data.reasonstring, required
operator, 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.messagestring, requiredThe reason in plain words, to show as it is.
data.paused_atstring, requiredWhen it paused.
data.resumes_atstring or null, requiredWhen it resumes by itself, if it will; null otherwise.
data.metadatamap of string to string or null, requiredThe metadata you passed on the send, call or campaign create; null when none.
fieldtypedescription
dataobject, required
data.campaign_idstring, requiredThe campaign’s UUID, its id on GET /v1/campaigns/{id}.
data.campaign_short_idstring or null, requiredThe campaign’s ca-… id.
data.namestring, requiredThe campaign’s name.
data.channelstring, required
sms, whatsapp, voice
The campaign’s channel.
data.statusstring, required
draft, queued, running, paused, completed, failed, canceled
Its status after this change.
data.resumed_atstring, requiredWhen it resumed.
data.previous_reasonstring or null, required
operator, 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.metadatamap of string to string or null, requiredThe metadata you passed on the send, call or campaign create; null when none.
fieldtypedescription
dataobject, required
data.campaign_idstring, requiredThe campaign’s UUID, its id on GET /v1/campaigns/{id}.
data.campaign_short_idstring or null, requiredThe campaign’s ca-… id.
data.namestring, requiredThe campaign’s name.
data.channelstring, required
sms, whatsapp, voice
The campaign’s channel.
data.statusstring, required
draft, queued, running, paused, completed, failed, canceled
Its status after this change.
data.completed_atstring, requiredWhen it completed.
data.countsobject, requiredThe final counts, as GET /v1/campaigns/{id} answers them.
data.counts.recipientsinteger, required
≥ 0
data.counts.pendinginteger, required
≥ 0
data.counts.sentinteger, required
≥ 0
data.counts.deliveredinteger, required
≥ 0
data.counts.failedinteger, required
≥ 0
data.counts.skippedinteger, required
≥ 0
data.counts.repliedinteger or null, required
≥ 0
data.counts.opted_outinteger or null, required
≥ 0
data.billed_creditsnumber or null, requiredCredits the campaign cost in all; null when not known.
data.metadatamap of string to string or null, requiredThe metadata you passed on the send, call or campaign create; null when none.
fieldtypedescription
dataobject, required
data.campaign_idstring, requiredThe campaign’s UUID, its id on GET /v1/campaigns/{id}.
data.campaign_short_idstring or null, requiredThe campaign’s ca-… id.
data.namestring, requiredThe campaign’s name.
data.channelstring, required
sms, whatsapp, voice
The campaign’s channel.
data.statusstring, required
draft, queued, running, paused, completed, failed, canceled
Its status after this change.
data.canceled_atstring, requiredWhen it was canceled.
data.in_flightinteger or null, required
≥ 0
Sends or calls already under way when it was canceled.
data.not_yet_sentinteger or null, required
≥ 0
Recipients that will not be reached.
data.metadatamap of string to string or null, requiredThe metadata you passed on the send, call or campaign create; null when none.
fieldtypedescription
dataobject, required
data.campaign_idstring, requiredThe campaign’s UUID, its id on GET /v1/campaigns/{id}.
data.campaign_short_idstring or null, requiredThe campaign’s ca-… id.
data.namestring, requiredThe campaign’s name.
data.channelstring, required
sms, whatsapp, voice
The campaign’s channel.
data.statusstring, required
draft, queued, running, paused, completed, failed, canceled
Its status after this change.
data.reasonstring, required
always send_window
Outside its sending hours or days.
data.waiting_atstring, requiredWhen it started waiting.
data.resumes_atstring or null, requiredWhen its next window opens.
data.tzstring, requiredThe schedule’s IANA time zone.
data.metadatamap of string to string or null, requiredThe metadata you passed on the send, call or campaign create; null when none.
fieldtypedescription
dataobject, required
data.campaign_idstring, requiredThe campaign’s UUID, its id on GET /v1/campaigns/{id}.
data.campaign_short_idstring or null, requiredThe campaign’s ca-… id.
data.namestring, requiredThe campaign’s name.
data.channelstring, required
sms, whatsapp, voice
The campaign’s channel.
data.statusstring, required
draft, queued, running, paused, completed, failed, canceled
Its status after this change.
data.opened_atstring, requiredWhen the window opened.
data.tzstring, requiredThe schedule’s IANA time zone.
data.metadatamap of string to string or null, requiredThe metadata you passed on the send, call or campaign create; null when none.
fieldtypedescription
dataobject, required
data.response_idstring, required
data.conversation_idstring, required
data.statusstring, required
completed, failed
data.errorobject or null, required
data.error.typestring, required
data.error.codestring or null, required
data.error.messagestring, required
fieldtypedescription
dataobject, required
data.conversation_idstring, required
data.surfacestring, required
data.titlestring, required
data.previewstring, required
data.message_countinteger, required
≥ 0
fieldtypedescription
dataobject, required
data.call_idstring, requiredThe call’s UUID, its id on GET /v1/calls/{id}.
data.call_short_idstring or null, requiredThe call’s cv-… id.
data.channelstring, required
always voice
Always voice.
data.conversation_idstring, requiredThe call’s conversation (its transcript).
data.directionstring or null, required
inbound, outbound
Who called whom.
data.fromstring or null, requiredThe calling number, in E.164.
data.tostring or null, requiredThe called number, in E.164.
data.agent_idstring or null, requiredThe agent’s ag-… id.
data.agent_uuidstring or null, requiredThe same agent’s UUID.
data.campaign_idstring or null, requiredThe placing campaign’s UUID; null for a single call.
data.campaign_short_idstring or null, requiredThe same campaign’s ca-… id.
data.statusstring, required
queued, ringing, in_progress, completed, voicemail, no_answer, busy, failed
The call’s status after this event.
data.occurred_atstring, requiredWhen this happened (ISO 8601).
data.metadatamap of string to string or null, requiredThe metadata you passed on the send, call or campaign create; null when none.
fieldtypedescription
dataobject, required
data.call_idstring, requiredThe call’s UUID, its id on GET /v1/calls/{id}.
data.call_short_idstring or null, requiredThe call’s cv-… id.
data.channelstring, required
always voice
Always voice.
data.conversation_idstring, requiredThe call’s conversation (its transcript).
data.directionstring or null, required
inbound, outbound
Who called whom.
data.fromstring or null, requiredThe calling number, in E.164.
data.tostring or null, requiredThe called number, in E.164.
data.agent_idstring or null, requiredThe agent’s ag-… id.
data.agent_uuidstring or null, requiredThe same agent’s UUID.
data.campaign_idstring or null, requiredThe placing campaign’s UUID; null for a single call.
data.campaign_short_idstring or null, requiredThe same campaign’s ca-… id.
data.statusstring, required
queued, ringing, in_progress, completed, voicemail, no_answer, busy, failed
The call’s status after this event.
data.occurred_atstring, requiredWhen this happened (ISO 8601).
data.answered_atstring, requiredWhen it was answered.
data.metadatamap of string to string or null, requiredThe metadata you passed on the send, call or campaign create; null when none.
fieldtypedescription
dataobject, required
data.call_idstring, requiredThe call’s UUID, its id on GET /v1/calls/{id}.
data.call_short_idstring or null, requiredThe call’s cv-… id.
data.channelstring, required
always voice
Always voice.
data.conversation_idstring, requiredThe call’s conversation (its transcript).
data.directionstring or null, required
inbound, outbound
Who called whom.
data.fromstring or null, requiredThe calling number, in E.164.
data.tostring or null, requiredThe called number, in E.164.
data.agent_idstring or null, requiredThe agent’s ag-… id.
data.agent_uuidstring or null, requiredThe same agent’s UUID.
data.campaign_idstring or null, requiredThe placing campaign’s UUID; null for a single call.
data.campaign_short_idstring or null, requiredThe same campaign’s ca-… id.
data.statusstring, required
completed, voicemail, no_answer, busy
data.occurred_atstring, requiredWhen this happened (ISO 8601).
data.answered_atstring or null, requiredWhen it was answered; null if never.
data.outcomestring, required
valid_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_secinteger, required
≥ 0
Talk time in whole seconds.
data.ended_atstring, requiredWhen it ended.
data.disconnect_reasonstring or null, requiredWho or what hung up, when known.
data.metadatamap of string to string or null, requiredThe metadata you passed on the send, call or campaign create; null when none.
fieldtypedescription
dataobject, required
data.call_idstring, requiredThe call’s UUID, its id on GET /v1/calls/{id}.
data.call_short_idstring or null, requiredThe call’s cv-… id.
data.channelstring, required
always voice
Always voice.
data.conversation_idstring, requiredThe call’s conversation (its transcript).
data.directionstring or null, required
inbound, outbound
Who called whom.
data.fromstring or null, requiredThe calling number, in E.164.
data.tostring or null, requiredThe called number, in E.164.
data.agent_idstring or null, requiredThe agent’s ag-… id.
data.agent_uuidstring or null, requiredThe same agent’s UUID.
data.campaign_idstring or null, requiredThe placing campaign’s UUID; null for a single call.
data.campaign_short_idstring or null, requiredThe same campaign’s ca-… id.
data.statusstring, required
always failed
data.occurred_atstring, requiredWhen this happened (ISO 8601).
data.answered_atstring or null, requiredWhen it was answered; null if never.
data.outcomestring, required
valid_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_secinteger, required
≥ 0
Talk time in whole seconds.
data.ended_atstring, requiredWhen it ended.
data.disconnect_reasonstring or null, requiredWho or what hung up, when known.
data.metadatamap of string to string or null, requiredThe metadata you passed on the send, call or campaign create; null when none.
fieldtypedescription
dataobject, required
data.webhook_idstring, required
data.messagestring, required