Skip to content
Vaakyo
← Blog

Webhooks for call results: signatures, retries and idempotency

Every finished call can update your CRM, order system or sheet. Here is how to receive call webhooks safely and reliably.

The Vaakyo team2 min read

  • Webhooks
  • Engineering

A voice agent is only as useful as what happens after the call. Webhooks deliver each call's outcome to your systems the moment it ends: the status, duration, transcript, summary, extracted fields and cost.

Verify the signature

Anyone can send a POST to your endpoint, so check that each request really comes from Vaakyo. Every webhook carries an X-Voxa-Signature header of the form t=<unix seconds>,v1=<hex HMAC-SHA256>. The signature is an HMAC-SHA256 of <t>.<raw request body>, keyed with your webhook secret:

import hashlib, hmac, time


def verify(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    timestamp, signature = parts.get("t", ""), parts.get("v1", "")
    if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > tolerance:
        return False  # too old: a replay
    expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

Compute it over the raw body exactly as received, before parsing JSON.

Answer fast, work later

Return a 2xx within a few seconds, then do the work in the background (a queue, a job). If your endpoint is slow or failing, Vaakyo retries, so a long-running handler risks receiving the same event again while it's still processing.

Expect duplicates

Retries mean you may receive an event more than once. Make processing idempotent: use the call id (and the event type) as a key, and skip work you've already done.

Choose the events you need

You don't need every event. For most integrations, the end-of-call event with the results is enough; add live events (call started, transfer, tool calls) only if you show them in real time somewhere.

Map results to actions

Decide in advance what each outcome does:

  • A confirmed COD order is released for shipping.
  • A booked appointment is written to the calendar and an SMS goes out.
  • A hot lead is assigned to a salesperson.
  • A failed call is retried, or flagged for a person.

Watch the delivery log

The console's webhook log shows every delivery with its response code and timing, and lets you resend one. When an integration breaks, start there.

Get started today

Talk to an expert

Tell us about your calls. We'll help you plan the agent, the numbers and the rollout for your team.

Contact sales

Start building

Build an agent and talk to it in your browser in minutes. New workspaces start with ₹250 of free credits.

Start free