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 POST to 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-Id header so your system can deduplicate retried deliveries.

What the payload contains

FieldDescription
eventAlways "session_completed".
workflow_run_idThe unique id of this session run.
workflow_idThe id of the workflow (voice agent).
workflow_nameThe name of the workflow.
call_timeWhen the session ran (ISO 8601).
call_dispositionHow the session ended (e.g. user_hangup).
call_idThe provider call id.
call_statusThe session status.
caller_name / caller_typeCaller info, if captured.
extracted_variablesStructured data extracted from the conversation.
initial_contextVisitor context passed in at the start (page URL, etc.).
gathered_contextEverything gathered during the conversation.
usage_infoUsage stats: LLM tokens, TTS/STT counts, duration.
annotationsQA / integration annotations, if any.
recording_urlThe full session recording (downloadable).
transcript_urlThe full transcript (downloadable).
user_recording_urlThe caller's audio track.
bot_recording_urlThe agent's audio track.
Note: 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

  1. Log in to admin.spokiva.in .
  2. Open the workflow (voice agent).
  3. Find the Webhook node (named "Session Completion Webhook").
  4. Set the Endpoint URL to your server's receiving endpoint, and keep HTTP Method as POST.
  5. Save and publish the workflow.

No code is needed on the widget side — the webhook fires automatically when a session ends.

Headers & retries

HeaderDescription
X-Spokiva-Delivery-IdStable id for this delivery. Same value on retries.
X-Spokiva-Workflow-Run-IdThe session run id.
X-Spokiva-Delivery-AttemptWhich 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.