Skip to main content
Webhooks let your application receive signed inbound HTTP requests from Voice.ai and expose outbound callable endpoints for agent actions.
Prerequisites: API key and an agent configured with webhook settings.

Overview

Voice.ai supports three webhook types. webhooks.events[], webhooks.inbound_call, and webhooks.tools use different contracts:
  • webhooks.events[] supports secret (write-only on create/update) and has_secret (read-only on fetch), with fan-out across enabled endpoints.
  • webhooks.inbound_call supports secret (write-only on create/update) and has_secret (read-only on fetch).
  • webhooks.tools define outbound API calls and do not use secret.
See Agent Configuration, the Web SDK guide, and the API reference for the same public contract on agent config and call-start requests. When configured, your server receives an HTTP POST request for each event with a JSON payload containing event details.

Example routes

The runnable receiver example and the verification snippets below use these canonical routes:

Event Webhooks

Configuration

Add event webhook configuration to your agent’s config.webhooks.events array:

Event configuration parameters

Each entry in webhooks.events[] supports required/optional fields: required url; optional secret, events, timeout (default 5), enabled (default true). Omit optional fields to use defaults. On update, omit webhooks.events to preserve the current list, set webhooks.events: null to clear it, or pass a full array to replace it. Within a replacement array, omitted secret values are preserved only for entries whose url exactly matches an existing endpoint, secret: null clears that endpoint’s signing secret, duplicate URLs are invalid, and events: [] means that endpoint receives all event types.

Event Payloads

All webhook events share a common structure with top-level fields and event-specific data:

call.started

Sent when a call connects and the agent is ready to interact.
data fields:
from_number and to_number are only included for SIP (phone) calls. Web calls do not have these fields.

call.completed

Sent after the call ends and all data has been processed. Includes transcript and usage information.
data fields:

call.failed

Sent when a phone call initiation attempt is blocked during validation before call.started. No call.started or call.completed event is sent for the failed attempt.
data fields:
call.failed is for owner/integrator notification. Phone callers do not receive a custom spoken failure reason in this flow.

Inbound Call Webhook

webhooks.inbound_call runs during inbound phone call initiation before the normal agent session starts. Use it to personalize a call with dynamic_variables and optional agent_overrides. dynamic_variables can be referenced by both the runtime prompt and greeting. Do not use it to route a call to a different agent. Call validation can still block the call after this webhook runs; subscribe to call.failed to receive owner/integrator notification for those blocked attempts.

Configuration

Add inbound call webhook configuration to your agent’s config.webhooks.inbound_call object:

Inbound call configuration parameters

On update, omit webhooks.inbound_call to preserve it, set webhooks.inbound_call: null to remove it, and set secret: null to clear only the signing secret.

Request payload

Voice.ai sends a POST request with the inbound call context:

Response payload

Your endpoint can return dynamic_variables and optional agent_overrides:
Omitted fields are allowed. Unused dynamic_variables are ignored by the runtime. Use agent_overrides for allowlisted call-scoped config changes such as tts_params overrides. dynamic_variables can be used in both your saved agent prompt and greeting. See the Web SDK guide for browser-side examples.

Webhook Tools

Tools are outbound API calls: Voice.ai calls your endpoint. Use auth_type/auth_token/headers (not secret - that is only for signed inbound webhooks like events and inbound_call). Use config.webhooks.tools to declare callable functions:

Tool configuration parameters

tools[] supports required/optional fields per tool: required name, description, parameters, url, method, execution_mode, auth_type; optional auth_token, headers, response, timeout (default 10). Omit optional fields to use defaults. On update, omit webhooks.tools to leave the current tool list unchanged, set webhooks.tools: null to clear all tools, or pass a new array to replace the current list.

Tool request shape

Voice.ai makes HTTP requests directly to your tool URL:
  • GET: Arguments as query parameters
  • POST/PUT/PATCH/DELETE: Arguments as JSON body
Metadata is sent in headers: X-VoiceAI-Request-Id, X-VoiceAI-Tool-Name, X-VoiceAI-Agent-Id, X-VoiceAI-Call-Id Example GET request:
Example POST request:
Recommended response (sync mode):

Tool authentication

  • auth_type: 'none': no auth headers added.
  • auth_type: 'bearer_token': sends Authorization: Bearer <auth_token>.
  • auth_type: 'api_key': sends X-API-Key: <auth_token>.
  • auth_type: 'custom_headers': sends your configured headers map.

Tool response behavior

  • execution_mode: 'sync': waits for downstream response body; non-2xx fails the tool call.
  • execution_mode: 'async': treats any 2xx as accepted and does not require a response payload.

Signed Inbound Webhook Headers

webhooks.events[] and webhooks.inbound_call requests include:

Signature Verification (Event and Inbound Call Webhooks)

webhooks.events[] and webhooks.inbound_call use secret for HMAC-SHA256. If you configure either secret, verify signatures to ensure requests are from Voice.ai. Tool webhooks use auth_type/auth_token/headers instead and do not use HMAC.

Signature Format

The signature is computed as:
Where:
  • timestamp is the value from X-Webhook-Timestamp header
  • payload is the raw JSON request body

Verification Examples

Use the same verifier for both event webhooks and inbound call webhooks. The examples below expose the same four routes listed above: one event endpoint, one inbound call endpoint, and two tool endpoints.

Retry Logic

Failed webhook deliveries are retried with exponential backoff: Retries stop after 5 attempts or on receiving a 4xx response (except 429 rate limit).
Idempotency: Your webhook handler should be idempotent. The same event may be delivered multiple times due to retries. Use call_id to deduplicate events.

Best Practices

  1. Always verify signatures in production to prevent spoofed requests
  2. Respond quickly with a 2xx status code within 5 seconds to avoid retries
  3. Process asynchronously - queue events for processing rather than blocking the response
  4. Handle duplicates - use call_id to deduplicate in case of retries
  5. Check timestamps - reject signed requests older than 5 minutes to prevent replay attacks
  6. Use HTTPS - ensure your webhook endpoint uses TLS encryption

Filtering Events

You can filter which events you receive by specifying the events array:
This configuration only receives call.completed events. Leave events empty or omit it to receive all event types, including call.failed.

Testing Webhooks

You can test your configured event webhook endpoints using the Test Events Webhook endpoint:
This sends a test event to each enabled configured webhooks.events[] endpoint and returns per-endpoint delivery results. It does not invoke webhooks.inbound_call.

Testing Tools Webhooks

You can test an individual tools webhook using the Test Tools Webhook endpoint:
This sends a sample function_call payload for the specified webhooks.tools[] entry and returns the delivery result. It does not invoke webhooks.inbound_call.

Testing Inbound Call Webhooks

You can test your configured inbound call webhook using the Test Inbound Call Webhook endpoint:
This sends a synthetic inbound-call payload with sample phone numbers to webhooks.inbound_call and validates the response before you use it in a live call. It does not place a real phone call. The test endpoint is intentionally strict:
  • dynamic_variables must be valid scalar values and may only include variables referenced by the agent’s saved prompt or greeting
  • agent_overrides must match the runtime override schema
  • returned TTS overrides are validated and normalized the same way runtime inbound-call overrides are, including voice_id -> speaker and dictionary resolution
For local development, use a tunnel service like ngrok to expose your local server:

Next Steps

  • Agent Configuration - Configure prompts, dynamic_variables, and webhook settings
  • Web SDK - Pass dynamicVariables from the browser and configure webhooks through the SDK
  • Analytics - View call history and metrics
  • API Reference - Complete API documentation