Send Session Data to Your System via Webhook
When a voice session ends, Spokiva sends all of that session's data — the recording, the transcript, the conversation context, and usage details — as a single JSON payload to a URL you choose.
How it works
- After a session completes, Spokiva fires an HTTP
POSTto the webhook URL you configure on the workflow. - The payload is a JSON object containing the full session record: recording URLs, transcript URL, gathered context, usage, and more.
- Delivery is durable: transient failures (network errors, server 5xx, timeouts) are retried with backoff up to a configured limit.
- Each delivery carries a stable
X-Spokiva-Delivery-Idheader so your system can deduplicate retried deliveries.
What the payload contains
| Field | Description |
|---|---|
| event | Always "session_completed". |
| workflow_run_id | The unique id of this session run. |
| workflow_id | The id of the workflow (voice agent). |
| workflow_name | The name of the workflow. |
| call_time | When the session ran (ISO 8601). |
| call_disposition | How the session ended (e.g. user_hangup). |
| call_id | The provider call id. |
| call_status | The session status. |
| caller_name / caller_type | Caller info, if captured. |
| extracted_variables | Structured data extracted from the conversation. |
| initial_context | Visitor context passed in at the start (page URL, etc.). |
| gathered_context | Everything gathered during the conversation. |
| usage_info | Usage stats: LLM tokens, TTS/STT counts, duration. |
| annotations | QA / integration annotations, if any. |
| recording_url | The full session recording (downloadable). |
| transcript_url | The full transcript (downloadable). |
| user_recording_url | The caller's audio track. |
| bot_recording_url | The agent's audio track. |
recording_url, transcript_url, user_recording_url, and bot_recording_url are temporary signed download links. Fetch them promptly (within minutes) — they expire.Configuring the webhook
- Log in to admin.spokiva.in .
- Open the workflow (voice agent).
- Find the Webhook node (named "Session Completion Webhook").
- Set the Endpoint URL to your server's receiving endpoint, and keep HTTP Method as
POST. - Save and publish the workflow.
No code is needed on the widget side — the webhook fires automatically when a session ends.
Headers & retries
| Header | Description |
|---|---|
| X-Spokiva-Delivery-Id | Stable id for this delivery. Same value on retries. |
| X-Spokiva-Workflow-Run-Id | The session run id. |
| X-Spokiva-Delivery-Attempt | Which attempt this is (1, 2, 3, ...). |
Respond with HTTP 2xx to confirm receipt. Transient failures are retried with exponential backoff on statuses 408 425 429 500 502 503 504 plus connection/DNS/timeout errors. Most other 4xx are not retried. Default limit is 5 attempts, backoff capped at 10 minutes. Because retries happen, make your handler idempotent using X-Spokiva-Delivery-Id.
Example payload
{
"event": "session_completed",
"workflow_run_id": "1306",
"workflow_id": "36",
"workflow_name": "Support Agent",
"call_time": "2026-09-18T11:35:57.711649+00:00",
"call_disposition": "user_hangup",
"call_id": "06b43b50-6882-486d-b22f-8c301bd7734c",
"call_status": "user_hangup",
"caller_name": "",
"caller_type": "driver",
"extracted_variables": "{\"caller_name\": null}",
"initial_context": "{\"source\": \"widget\", \"page_url\": \"https://client-site.com\"}",
"gathered_context": "{\"call_id\": \"06b43b50-...\", \"call_disposition\": \"user_hangup\"}",
"usage_info": "{\"llm\": {\"OpenAILLMService#21|||gpt-4.1\": {\"prompt_tokens\": 3761}}, \"call_duration_seconds\": 50}",
"annotations": "{}",
"recording_url": "https://call.neptuneinfotech.com/api/v1/public/download/workflow/abc123/recording",
"transcript_url": "https://call.neptuneinfotech.com/api/v1/public/download/workflow/abc123/transcript",
"user_recording_url": "https://call.neptuneinfotech.com/api/v1/public/download/workflow/abc123/user_recording",
"bot_recording_url": "https://call.neptuneinfotech.com/api/v1/public/download/workflow/abc123/bot_recording"
}The nested objects (initial_context, gathered_context, usage_info, annotations) are delivered as JSON strings — parse with JSON.parse.
Example receiver (Node.js)
const http = require('http');
http.createServer((req, res) => {
if (req.method === 'POST') {
let body = '';
req.on('data', (c) => body += c);
req.on('end', () => {
const deliveryId = req.headers['x-spokiva-delivery-id'];
console.log('delivery', deliveryId, 'payload', body);
// TODO: store deliveryId to deduplicate; process the payload.
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ ok: true }));
});
} else {
res.writeHead(200); res.end();
}
}).listen(9000, () => console.log('webhook receiver on :9000'));Support
For help, contact your Spokiva representative or reach out through the Neptune Infotech team. Include the workflow name and the session run id.
