Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

convai-webhook-guard

Verify ElevenLabs post-call webhooks before you trust them. Stdlib only.

Why

The post-call webhook is where the ground truth about a voice agent's conversation arrives: the transcript, the tool calls, the tool results. Everything downstream that matters, billing, CRM writes, call grading (grounded-check runs on exactly this data), inherits its trust from this one endpoint. An unverified webhook receiver is an open door that accepts "the customer agreed to $9,999" from anyone who can find the URL.

ElevenLabs signs every delivery:

elevenlabs-signature: t=<unix_seconds>,v0=<hex>
v0 = HMAC-SHA256(secret, "<timestamp>.<raw_body>")

This tool implements that check, verified against the official SDK source rather than guessed, with two deliberate departures:

  • Signatures are compared with hmac.compare_digest, not !=. A plain comparison leaks how many leading bytes matched through timing.
  • Timestamps too far in the future are rejected too. The reference check only rejects old ones, so a captured request with a forged far-future timestamp would stay replayable forever if the clock check is your only replay defense.

Usage

export ELEVENLABS_WEBHOOK_SECRET=...

python webhook_guard.py serve --port 8000    # reference receiver, verified events as JSONL
python webhook_guard.py sign payload.json    # forge a valid header for local testing

The sign command is the part you did not know you wanted: it produces the exact header ElevenLabs would send for a payload, so you can test your real receiver end to end with curl instead of waiting for a live call to finish.

As a library it is one function:

from webhook_guard import verify, SignatureError

try:
    event = verify(raw_body, request.headers["elevenlabs-signature"], secret)
except SignatureError:
    return 401

Pass the raw request body, byte for byte. A body that has been parsed and re-serialized will not verify, because key order and whitespace are part of the signed message. There is a test asserting exactly that failure, since it is the single most common way webhook verification goes wrong in production.

Tests: python -m unittest -v.

What it does not do

  • It authenticates the envelope, not the contents. A verified webhook proves ElevenLabs sent it, not that the agent behaved. Auditing what the agent said against what its tools returned is the other tool's job.
  • No queueing, retries, or storage. Verify, then hand the event to whatever you already trust.

MIT license.

About

Verify ElevenLabs post-call webhooks before you trust them. HMAC check with constant-time compare, plus a sign command to test your own receiver. Stdlib only.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages