TryVox
Getting Started

Webhooks

Receive real-time event notifications from TryVox.

Webhooks allow TryVox to send real-time HTTP notifications to your application when events occur, such as when a call is answered, ends, or when a message is delivered.

Call created
POST /calls
Ringing
ring_url
Answered
answer_url → VoxML
In progress
status_callback_url
Hangup
hangup_url → CDR

Overview

TryVox sends HTTP POST requests to your webhook URLs when events occur. Your application receives these requests, processes the event data, and responds accordingly.

Common Use Cases

  • Call control — Return VoxML instructions when a call is answered
  • Status tracking — Update your database when call status changes
  • Event logging — Log all call events for analytics and debugging
  • Error handling — Trigger alerts when calls fail

Webhook Configuration

Webhooks are configured in two ways:

1. Per-Call Webhooks

Specify webhook URLs when creating a call:

curl -X POST https://api.tryvox.io/v1/voice/accounts/$TRYVOX_AUTH_ID/calls \
  -u $TRYVOX_AUTH_ID:$TRYVOX_AUTH_TOKEN \
  -H "Content-Type: application/json" \
  -d '{
    "from": "+919876543210",
    "to": "+14155551234",
    "answer_url": "https://your-app.com/answer",
    "ring_url": "https://your-app.com/ring",
    "hangup_url": "https://your-app.com/hangup",
    "fallback_url": "https://your-app.com/fallback",
    "status_callback_url": "https://your-app.com/status",
    "webhook_secret": "replace-with-your-account-webhook-secret"
  }'

Per-call webhook fields:

  • answer_url — Called when the call is answered. Returns VoxML to control the call.
  • ring_url — Called when the destination starts ringing.
  • hangup_url — Called when the call ends, with the full CDR.
  • fallback_url — Called if answer_url cannot be fetched successfully, such as a timeout or HTTP error.
  • status_callback_url — Called for ringing, answered, and hangup transitions.
  • webhook_secret — Your per-account signing secret for this call. It is accepted write-only and is never returned by the API.

2. Application-Level Webhooks

Configure default webhook URLs for many calls at once with a Voice Application. Application-level URLs are inherited by every phone number and SIP endpoint attached to it.

Voice Applications can store the same callback URLs and signing secret as defaults for inbound calls.

Verify voice webhook signatures

Signed POST requests to answer_url, fallback_url, ring_url, hangup_url, and status_callback_url include:

X-TryVox-Timestamp: 1785320611
X-TryVox-Signature: t=1785320611,v1=<hex-hmac-sha256>

Compute HMAC-SHA256(webhook_secret, "{X-TryVox-Timestamp}.{raw-request-body}"), compare the hexadecimal digest with v1 using a constant-time comparison, and reject timestamps outside your replay window (five minutes is recommended). Always verify the raw body bytes before parsing JSON.

For account-wide subscriptions to all call.* and message.* events, use Webhook Subscriptions instead.

Webhook payloads

Voice webhook payloads depend on the configured endpoint:

  • answer_url and fallback_url receive lower-case fields and must return VoxML.
  • ring_url, hangup_url, and status_callback_url receive Voice API fields such as Event, CallUUID, and Timestamp. Lifecycle status payloads also include RequestID.
  • Account-wide Webhook Subscriptions use their own event envelope; see Webhook Subscriptions.

Example: hangup URL payload

{
  "Event": "Hangup",
  "CallUUID": "c7a34e6f-9d1b-4c8e-a5f2-3b9d7e8c1a4f",
  "RequestID": "c7a34e6f-9d1b-4c8e-a5f2-3b9d7e8c1a4f",
  "Timestamp": "2026-04-09T10:32:50.456Z",
  "From": "+919876543210",
  "To": "+14155551234",
  "Direction": "outbound",
  "Status": "completed",
  "Reason": "NORMAL_CLEARING",
  "AccountId": "AC123456",
  "SIPCallID": "74E02DF4-6AA338AB00041FD7-A56966C0",
  "StartTime": "2026-04-09T10:30:45.102Z",
  "EndTime": "2026-04-09T10:32:50.456Z",
  "Duration": 125,
  "Billsec": 120,
  "RingTime": 5,
  "Cost": 0.5,
  "Currency": "INR",
  "MOS": 4.2
}

Status is the call outcome, not a delivery acknowledgement:

StatusMeaning
completedThe far end answered; Billsec is greater than zero.
busyThe called party was busy.
no-answerRang out, or cleared before anyone picked up.
cancelledThe caller hung up first, or the call was terminated via the API.
failedRejected, unroutable, or terminated by a network fault.

Reason carries the raw hangup cause behind that status (NORMAL_CLEARING, USER_BUSY, CALL_REJECTED, and so on). Cost, Currency, MOS and RingTime are present when TryVox has computed them for the call; they are omitted otherwise.

Delivery and retries

Each event is delivered with up to four attempts — the first, then retries after roughly 2s, 8s, and 25s.

TryVox retries on a connection failure or timeout, on any 5xx, and on 408 or 429. Any other 4xx is treated as a permanent refusal and is not retried, so return a 2xx as soon as you have accepted the event and do your processing afterwards.

Every attempt carries X-TryVox-Delivery-Attempt (1 for the first delivery) and is signed afresh, so each retry has its own X-TryVox-Timestamp and will pass a replay-window check. RequestID is stable across attempts — use it to de-duplicate, because a retry after your endpoint accepted the event but failed to respond in time will deliver the same event twice.

After the final attempt the event is discarded.

Voice Webhooks (Answer URL)

The answer_url is special — it's called when a call is answered and expects a VoxML response to control the call.

Example Request to Your Answer URL

TryVox sends:

{
  "call_uuid": "c7a34e6f-9d1b-4c8e-a5f2-3b9d7e8c1a4f",
  "account_id": "AC123456",
  "from": "+919876543210",
  "to": "+14155551234",
  "direction": "outbound"
}

Example VoxML Response

Your server responds with:

{
  "voxml_version": "1.0",
  "instructions": [
    {
      "verb": "Say",
      "text": "Hello! I am your AI assistant. How can I help you today?",
      "engine": "google",
      "language": "en-US"
    },
    {
      "verb": "Stream",
      "url": "wss://your-app.com/ai-agent",
      "track": "inbound_track"
    }
  ]
}

TryVox executes these VoxML instructions to control the call flow.

Webhook Response Requirements

Your webhook endpoint should:

  1. Respond quickly — Return a response within 15 seconds
  2. Return 200 OK — Indicate successful receipt
  3. For answer_url — Return valid VoxML JSON

Example Webhook Handler (Node.js/Express)

app.post('/answer', (req, res) => {
  const { call_uuid, from, to } = req.body;

  console.log(`Call ${call_uuid} answered from ${from} to ${to}`);

  // Return VoxML to control the call
  res.json({
    voxml_version: "1.0",
    instructions: [
      {
        verb: "Say",
        text: "Welcome to our service!",
        engine: "google",
        language: "en-US"
      }
    ]
  });
});

app.post('/status', (req, res) => {
  const { Event, CallUUID, Status } = req.body;

  console.log(`Call ${CallUUID} ${Event}: ${Status}`);

  // Update your database, trigger alerts, etc.

  res.sendStatus(200);
});

Answer URL Fallback

If the answer_url times out or returns an HTTP error, TryVox tries the fallback_url once when configured:

{
  "answer_url": "https://your-app.com/answer",
  "fallback_url": "https://your-app.com/fallback"
}

Use the fallback URL to handle errors gracefully and prevent dropped calls.

Webhook Security

Verify Webhook Source

To ensure webhooks are coming from TryVox:

  1. Verify X-TryVox-Timestamp and X-TryVox-Signature
  2. Whitelist TryVox IP ranges in your firewall
  3. Use HTTPS for all webhook URLs

Use HTTPS

Always use HTTPS webhook URLs to prevent man-in-the-middle attacks:

✅ https://your-app.com/answer
❌ http://your-app.com/answer

Testing Webhooks Locally

Use tools like ngrok to expose your local server for webhook testing:

# Start ngrok tunnel
ngrok http 3000

# Use the ngrok URL in your webhook config
https://abc123.ngrok.io/answer

Debugging Webhooks

View Webhook Logs

The TryVox dashboard shows webhook request/response logs for each call:

  1. Go to Calls in the dashboard
  2. Click on a call to view details
  3. Scroll to Webhook Logs section

Common Issues

Webhook not called:

  • Check that the URL is publicly accessible
  • Verify HTTPS is used (not HTTP)
  • Check firewall rules

Webhook times out:

  • Ensure your endpoint responds within 15 seconds
  • Move slow operations (database writes, API calls) to background jobs

Invalid VoxML:

  • Validate your VoxML JSON structure
  • Check that all required fields are included
  • Use the VoxML validator

Next Steps

On this page