Webhook Payloads
This page documents the structure of webhook payloads sent by Vocobase when events occur.Headers
Every webhook request includes these headers:Event: inbound.route
This event is sent when a partner-configured pre-answer policy is available for a Vobiz or Plivo inbound call.
Payload structure
Headers
Inbound route webhooks for this feature use feature-specific headers:Response contract
Partners return JSON with anaction value:
ANSWER_WITH_AISELECT_AGENTTRANSFERREJECT
TRANSFER, to_number must be E.164.
When action is SELECT_AGENT, agent_id must be set.
Vocobase records each resolved route decision for partner observability. Query GET /api/v2/inbound-route-decisions to inspect action, source, webhook status, webhook latency, failure reason, transfer target, and created session or phone-call IDs.
Event: call.status.updated
Sent whenever Vocobase learns that a telephony call moved to a new meaningful call status. This event is for real-time orchestration: live dashboards, partner-owned dialer queues, and concurrency release.
call.status.updated is sent for phone calls only. Browser WebRTC sessions do not have a carrier call leg and therefore do not emit this event.
Payload structure
Field reference
Call status values
Vocobase normalizes provider-specific call states into one vocabulary:Provider normalization
Partners should branch ondata.status, not on provider-specific values. Vocobase stores the raw provider value for debugging.
External queue orchestration
If you run your own dialer, usecall.status.updated to manage slots:
session.completed to release a dialer slot. session.completed is the final rich result after transcript, recording, billing, and extraction processing.
Event: session.completed
Sent when a Vocobase session has reached final post-call processing. For telephony calls, this happens after the call leg ends and the bot/session pipeline has persisted transcript, recording metadata, billing, variables, and extraction results.
Payload structure
Field reference
Data object fields
Transcript entry format
Each entry in thetranscript array has:
recording_url is a presigned URL valid for 7 days from the moment the webhook fires. Download and persist the recording on your side if you need long-term retention. If the URL expires before you can download it, call GET /calls/{call_id}/recording-url to mint a fresh one with another 7-day window.Final call status on session.completed
call.status in session.completed reflects the final known carrier state. For real-time intermediate statuses, use call.status.updated.
Call disposition values
Transferred calls
When an agent transfers a live call to a human:- The bot speaks the configured announcement (
transfer_message). - Vocobase transfers the caller to
transfer_target. - The
session.completedwebhook includes transfer metadata.
session.completed webhook fires once the bot leg ends, not when the caller eventually hangs up with the human. This means:
duration_secondsreflects only the bot leg (caller-on-with-bot time).recording_url, when present, is the bot-leg recording. The human side is not recorded.call.transferredistrue;call.transferred_atis the redirect moment;call.transfer_targetis the destination E.164.
call.transferred as the cheap discriminator if your downstream automation needs to distinguish a transferred call from a normal hangup.
Polling GET /calls/{id} vs webhook
Both the webhook and GET /api/v2/calls/{id} return the same data shape, so a partner that can’t accept inbound webhooks (or wants to reconcile dropped deliveries) can poll the GET endpoint instead.
A call can appear completed before all transcript, recording, and extraction fields are ready. The processing_complete boolean tells you when the response is final:
Recommended polling pattern
session.completed webhook will reach you before polling kicks in — polling is the fallback for partners that can’t accept inbound webhooks, or for reconciliation after a delivery failure.
For sessions created before this field shipped,
pipeline_completed_at will be null permanently. Treat null + status: completed on an older row as “final” — those rows pre-date the signal.Post-call extraction
When the agent has a Custom Analysis config defined, the platform runs an LLM extraction over the transcript after every completed call and ships the result inline in the samesession.completed webhook — no second webhook to handle. Configure extraction via the dashboard’s “Variables & Analytics” tab on the agent editor or via PUT /api/v2/agent/:id with extraction_config.
Extraction object structure
Extraction failures never block webhook delivery. The unified payload always ships with
extraction.status indicating outcome — partners that need extraction values can branch on status === 'success', partners that just need transcript + recording can ignore the field.Replay extraction against a past session
If you editextraction_config and want to backfill an existing session, call POST /api/v2/calls/{call_id}/extract with { "dry_run": false }. Optional dry_run: true returns the result without persisting. The replay uses the agent’s current config (not the config at original-call time).
Pre-call variables
Thevariables field on every webhook echoes the per-call values that were substituted into the agent’s prompt and greeting. Configure variable names via the dashboard “Variables & Analytics” tab or PUT /api/v2/agent/:id with variables: ["callee_name", "mobile_number"]. Supply per-call values via POST /api/v2/calls/start body field variables: { callee_name: "Sajal" }. Missing values render as empty strings — the platform never errors on missing variables.
Next steps
Webhook Setup
Configure webhook endpoints and verify signatures.
Error Handling
Understand retry behavior and failure handling.