Skip to main content
This page is the technical reference for VoiceInfra webhook events — covering the full payload schema, request headers, signature verification, and delivery behaviour. If you are looking for instructions on how to configure your webhook endpoint and view delivery logs, see the Webhooks Setup Guide.

Delivery

VoiceInfra delivers webhook events by sending an HTTP POST request to the URL you configure in your dashboard. Events fire when a call ends (hang up), regardless of the call outcome.
PropertyValue
MethodPOST
Content-Typeapplication/json
TriggerCall completion (hang up)
TimeoutYour endpoint must respond with 200 within the configured window
RetriesFailed deliveries are automatically retried
Respond to webhook requests with HTTP 200 as quickly as possible. Move any time-consuming processing (database writes, third-party API calls) to a background job to avoid timeouts that trigger unnecessary retries.

Request headers

Every webhook delivery includes the following HTTP headers:
HeaderDescription
Content-Typeapplication/json
X-VoiceInfra-SignatureHMAC-SHA256 signature of the raw request body, used to verify authenticity
X-VoiceInfra-EventEvent type — currently always call.completed

Payload schema

call_id
string
Unique identifier for the call. Use this to correlate the webhook event with the call_id returned when you initiated the call via POST /calls/outbound.
event
string
Event type. Currently always call.completed.
from_number
string
The caller’s phone number in E.164 format.
to_number
string
The called phone number in E.164 format.
agent_id
string
The ID of the AI agent that handled the call.
duration_seconds
integer
Total call duration in seconds, from answer to hang-up.
start_time
string
ISO 8601 timestamp for when the call started.
end_time
string
ISO 8601 timestamp for when the call ended.
call_outcome
string
One of answered, voicemail, or failed.
recording_url
string
URL to the call recording audio file. The file is available for download shortly after the call ends.
transcript
string
Full conversation transcript with speaker labels (for example, Agent: and Caller:).
summary
string
AI-generated summary of the call — a concise description of what was discussed and any outcomes reached.
extracted_data
object
Key data points extracted by the AI during the call. The fields present in this object vary based on your agent’s configuration. For example, a lead qualification agent might extract {"lead_score": 8, "interested": true}.

Example payload

call.completed payload
{
  "call_id": "call_01HXYZ123456",
  "event": "call.completed",
  "from_number": "+14155550100",
  "to_number": "+18005551234",
  "agent_id": "agent_abc123",
  "duration_seconds": 147,
  "start_time": "2025-01-15T14:23:00Z",
  "end_time": "2025-01-15T14:25:27Z",
  "call_outcome": "answered",
  "recording_url": "https://recordings.voiceinfra.ai/call_01HXYZ123456.mp3",
  "transcript": "Agent: Hi Sarah, this is calling to confirm your appointment...\nCaller: Yes, that works for me.",
  "summary": "Customer confirmed appointment for January 15 at 2pm. No changes requested.",
  "extracted_data": {
    "appointment_confirmed": true,
    "customer_name": "Sarah Chen"
  }
}

Signature verification

VoiceInfra signs every webhook payload with HMAC-SHA256 using the webhook secret you set in your dashboard. The signature is included in the X-VoiceInfra-Signature header as a hex-encoded string. To verify a webhook:
  1. Read the raw request body as bytes (before any JSON parsing).
  2. Compute HMAC-SHA256(raw_body, your_webhook_secret) and hex-encode the result.
  3. Compare your computed digest to the value in X-VoiceInfra-Signature using a constant-time comparison to prevent timing attacks.
  4. Reject the request with 401 if the signatures do not match.
Always verify the signature before processing a webhook payload. Without verification, your endpoint could process forged or tampered requests from a third party.
Python
import hmac
import hashlib

def verify_voiceinfra_webhook(payload: bytes, signature: str, secret: str) -> bool:
    """Verify the HMAC-SHA256 signature of a VoiceInfra webhook."""
    expected_sig = hmac.new(
        secret.encode('utf-8'),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected_sig, signature)

# Flask example:
# @app.route('/webhook', methods=['POST'])
# def handle_webhook():
#     signature = request.headers.get('X-VoiceInfra-Signature', '')
#     if not verify_voiceinfra_webhook(request.data, signature, WEBHOOK_SECRET):
#         return '', 401
#     payload = request.get_json()
#     # process payload
#     return '', 200
Node.js
const crypto = require('crypto');

function verifyVoiceInfraWebhook(payload, signature, secret) {
  const expectedSig = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expectedSig),
    Buffer.from(signature)
  );
}

// Express example:
// app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
//   const sig = req.headers['x-voiceinfra-signature'];
//   if (!verifyVoiceInfraWebhook(req.body, sig, process.env.WEBHOOK_SECRET)) {
//     return res.status(401).send('Invalid signature');
//   }
//   const payload = JSON.parse(req.body);
//   res.status(200).send('OK');
// });
Use express.raw() (not express.json()) as your body parser middleware so that the raw bytes are available for signature verification before the body is parsed as JSON.

Responding to webhooks

Your endpoint must return HTTP 200 to acknowledge receipt. VoiceInfra considers any other status code — including 2xx codes other than 200 — as a failed delivery and will retry. Do heavy processing asynchronously. Push the payload onto a queue (for example, SQS, BullMQ, or Celery) and return 200 immediately. This keeps your response time well within the timeout window and prevents retries caused by slow downstream operations.

Delivery logs

View the full history of webhook deliveries in your VoiceInfra dashboard at Settings → Webhooks → Delivery Logs. For each delivery you can see:
  • Timestamp — when the delivery was attempted
  • Event type — the X-VoiceInfra-Event value sent
  • HTTP status code — the status code your endpoint returned
  • Response time — how long your endpoint took to respond
  • Request and response payloads — the full JSON body sent and the response body returned
Use the delivery logs to diagnose failed deliveries, confirm that signature verification is working correctly, and replay specific events during development.