If a request has
X-Signature-Type, use it to pick the scheme. If it doesn’t, it’s a simple webhook: use RSA.
Simple webhooks: RSA-SHA256
Callers signs the exact JSON body of each simple webhook with its private key (RSA, PKCS #1 v1.5 padding, SHA-256) and sends the base64 signature inX-Signature. You verify it with the public key.
Callers public key
Save this key in your application, for example ascallers-public-key.pem:
public-key.pem
Verify an RSA signature
cryptography package (pip install cryptography).
Custom webhooks and HTTP actions: HMAC-SHA256
Custom webhooks created with Create Custom Webhook, and HTTP actions your agents run before, during, or after conversations, are signed with a secret that belongs to your account. Each request includes:X-Signature: the lowercase hex HMAC-SHA256 of the request body, keyed with your secret.X-Signature-Type: HMAC.
Get your HMAC secret
1
Open settings
Open Settings → General in the dashboard.
2
Reveal the secret
In Webhook Signature, click Show HMAC Secret and copy the value.
3
Store it securely
Save it as a secret in your server’s environment (for example,
CALLERS_HMAC_SECRET). Never put it in client-side code.What is signed
The signature covers the request body after variables are filled in:Verify an HMAC signature
Compute the HMAC of the raw body with your secret and compare it toX-Signature with a constant-time comparison.
Use RSA instead of HMAC
In the custom webhook or HTTP action editor, turn on Sign with RSA-SHA256. Requests are then signed with the Callers private key,X-Signature-Type is RSA, and you verify them with the public key exactly like simple webhooks. Use this when you don’t want to manage a shared secret.
Text and Email agent webhooks
Signature verification is supported for Voice agent simple webhooks and for custom webhooks and HTTP actions. To authenticate webhooks from Text and Email agents, use a custom webhook (signed with your HMAC secret), or add a secret header in advanced mode and check it on your server.Unsigned requests
Webhooks in the agent’s Advanced mode (and advanced webhooks created through the API) aren’t signed. Protect them with a secret of your own: add a header such asAuthorization: Bearer <random token> in the webhook and reject requests without it. Combine with the Callers IP allowlist.
Best practices
- Verify before parsing or processing, and reject failures with
401. - Use constant-time comparison (
crypto.timingSafeEqual,hmac.compare_digest) for HMAC. - Keep the HMAC secret out of source control. If it leaks, contact support.
- Deduplicate on the call
idpluswebhookEvent, since retries resend the same signed body. - Use HTTPS only. Callers requires it for simple webhooks.
Troubleshooting
Every signature fails
Every signature fails
You’re probably verifying a re-serialized body. In Express, use
express.raw() (not express.json()) on the webhook route; in Flask, use request.get_data(); in Django, request.body. Also check you’re using the right scheme: simple webhooks are RSA, custom webhooks default to HMAC.HMAC fails only for JSON or Form Data custom webhooks
HMAC fails only for JSON or Form Data custom webhooks
The signature is computed over the compact JSON of the body Callers built (no extra spaces). If a proxy or framework reformatted the body before your code saw it, verify against compact JSON instead:
JSON.stringify(JSON.parse(raw)) in Node.js, or json.dumps(json.loads(raw), separators=(",", ":"), ensure_ascii=False) in Python.HMAC fails but RSA works (or the reverse)
HMAC fails but RSA works (or the reverse)
Read
X-Signature-Type. HMAC signatures are hex; RSA signatures are base64.HMAC fails for a subaccount's agent
HMAC fails for a subaccount's agent
Use the secret from that subaccount’s settings, not the parent account’s.
The secret isn't shown in Settings
The secret isn't shown in Settings
Email to have a webhook secret set up for your account.
Related
Webhooks overview
Delivery, retries, IP allowlist.
Advanced webhooks
Custom requests and signing options.
Actions
HTTP actions that use the same signatures.
Security and privacy
Account-level security settings.