Webhooks

Post-conversation webhook

This webhook is triggered automatically after each conversation completes if you have the setting turned on in agent configurations. Configure your webhook URL and secret in the Telvana dashboard under Settings > Webhooks.

Webhook URL Priority:

Webhook URLs can be configured at both the agent level and the workspace level. When a conversation completes, Telvana will send the webhook to the agent's webhook URL if one is configured. If no agent webhook URL is set, the workspace webhook URL will be used instead. This allows you to have a default webhook endpoint for your workspace while still being able to override it for specific agents.

Complete Implementation Example:

For a full working example with signature verification, error handling, and best practices, see our example repository: https://github.com/telvana-ai/post-conversation-webhook-example

Security:

All webhook requests from Telvana include an X-Webhook-Signature header containing an HMAC SHA-256 signature of the request body. You should verify this signature to ensure the request came from Telvana.

Signature Verification Steps:

  1. Extract the X-Webhook-Signature header from the request
  2. Compute HMAC SHA-256 of the raw request body using your webhook secret
  3. Compare the computed signature with the header value
  4. Reject requests with invalid or missing signatures

Example Verification (Node.js):

const crypto = require('crypto');

// Get the signature from headers
const receivedSignature = req.headers['x-webhook-signature'];

// Compute expected signature using raw body
const expectedSignature = crypto
.createHmac('sha256', YOUR_WEBHOOK_SECRET)
.update(rawRequestBody)
.digest('hex');

// Verify signatures match
if (receivedSignature !== expectedSignature) {
return res.status(401).json({ error: 'Invalid signature' });
}

Example Verification (Python):

import hmac
import hashlib

# Get the signature from headers
received_signature = request.headers.get('X-Webhook-Signature')

# Compute expected signature using raw body
expected_signature = hmac.new(
  YOUR_WEBHOOK_SECRET.encode('utf-8'),
  request.body,
  hashlib.sha256
).hexdigest()

# Verify signatures match
if received_signature != expected_signature:
  return {'error': 'Invalid signature'}, 401

Important Notes:

  • Always use the raw request body for signature verification (before JSON parsing)
  • Store your webhook secret securely (environment variables, secrets manager)
postWebhookpostConversation

Payload

conversationIdstring required

Unique identifier for the conversation

dateInitiatedstring date-time required

When the conversation started (ISO timestamp)

agentIdstring required

ID of the AI agent that handled the call

workspaceIdstring required

ID of the workspace/organization

transcriptstring required

Full text transcript of the conversation (empty string for failed calls)

direction'INBOUND' | 'OUTBOUND' required

Direction of call: OUTBOUND (Calling a Human) or INBOUND (Incoming Call from Human)

costnumber required

Cost in cents (0 for failed calls)

agentPhoneNumberstring required

The phone number used by the AI agent

humanPhoneNumberstring required

The customer's phone number

durationnumber required

Call duration in seconds (0 for failed calls)

summarystring required

AI-generated summary of the conversation (empty string for failed calls)

sentiment'POSITIVE' | 'NEUTRAL' | 'NEGATIVE' | 'N_A' required

Sentiment classification of the conversation. N_A indicates no sentiment is available (e.g., the call failed to connect and no human was reached).

dispositionstring required

Call outcome (e.g., COMPLETED, FAILED, VOICEMAIL). For failed calls this is "FAILED".

tagsstring[] required

Zero or more tags that apply to this conversation (built-in and custom)

variablesobject required

Key-value pairs passed during call initiation

Response

Webhook received successfully. Your endpoint should return 200 OK to acknowledge receipt.

Changes

Webhooks have no change history: a webhook is keyed by its event name rather than a path and method, so no recorded change can name it.