Call2Me
Developers

Webhooks: real-time call events to your endpoint

Receive call.started, call.ended, call.transcript and call.error events as they happen — with retries, signatures, and the patterns that survive production.

Updated May 6, 2026

Webhooks are the way to react to call events without polling. The platform posts JSON to your URL, you do the work, you reply with 2xx.

Setup

Set the webhook URL on the agent:

curl -X PATCH https://api.call2me.app/v1/agents/agent_abc123 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"webhook_url": "https://your-server.com/webhooks/call2me"}'

Or in the dashboard: Agents → Edit → Webhooks.

Event types

EventWhen it firesUse it for
call.startedAudio session opensMark the call as live in your CRM
call.transcriptEach completed utteranceLive transcript UI, sentiment scoring
call.endedCall finishes (any reason)Save the recording URL, run extraction
call.errorSomething failed mid-callAlert ops, surface to the user
call.transferAgent transferred to a humanUpdate queue state

Payload shape

Every event has the same envelope:

{
  "type": "call.ended",
  "call_id": "call_xyz789",
  "agent_id": "agent_abc123",
  "timestamp": "2026-05-06T14:23:11Z",
  "data": {
    "duration_ms": 134000,
    "status": "completed",
    "transcript_url": "https://api.call2me.app/v1/calls/call_xyz789/transcript",
    "recording_url": "https://api.call2me.app/v1/calls/call_xyz789/recording.mp3"
  }
}

Event-specific fields go inside data. The envelope (type, call_id, agent_id, timestamp) is stable.

Verifying the signature

Each request carries X-Call2Me-Signature: sha256=<hex>. Compute the expected signature on the raw body using your webhook secret (visible in the dashboard once at create time):

import hmac, hashlib

def verify(body: bytes, header: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
    received = header.replace("sha256=", "")
    return hmac.compare_digest(expected, received)

Always use a constant-time comparison (hmac.compare_digest in Python, crypto.timingSafeEqual in Node).

Retry behavior

If your endpoint returns 5xx or times out (>10s), the platform retries with exponential backoff:

  • 1m, 5m, 30m, 2h, 6h, 24h

After 24h of failures the event lands in the dead-letter queue. You can view and replay from Settings → Webhooks → Failed.

4xx responses are NOT retried — they signal a permanent rejection.

Idempotency

Each event has a stable event_id field. Webhooks may be delivered more than once (rare, but possible during retries that succeeded after a network blip). Dedupe on event_id:

if not redis.set(f"event:{event_id}", "1", nx=True, ex=86400):
    return  # already processed

What's next

Frequently asked

Q.How do I configure a webhook URL?

Set webhook_url on the agent via PATCH /v1/agents/{id}. Or, in the dashboard: Agents → Edit → Webhooks tab.

Q.What events does Call2Me send?

call.started, call.ended, call.transcript (per utterance), call.error, and call.transfer. Each event includes a call_id you can use to correlate.

Q.What if my server is down when an event fires?

Webhooks retry on 5xx and timeouts with exponential backoff for up to ~24 hours. Persistent failures land in the dead-letter queue you can replay from the dashboard.

Q.How do I verify the request really came from Call2Me?

Each webhook request carries an HMAC signature in the X-Call2Me-Signature header. Compute SHA-256 over the raw body using your webhook secret and compare in constant time.

ShareX / TwitterLinkedIn

Ready to ship?

Spin up your first agent in 5 minutes — $10 free credit.

Start free