Skip to main content
Every webhook body has a type field whose value is one of the event types on this page. When you subscribe to an endpoint, the events array must contain the event types you want (or be empty to subscribe to everything). Events fall into two classes:
  • Blocking events expect your server to return configuration that ThunderPhone uses to continue the call. Your server has about two seconds to respond. Only call.incoming is blocking.
  • Non-blocking events are fire-and-forget notifications. Respond with any 2xx; if we don’t see one, we retry with exponential backoff for up to 24 hours.

Call events

telephony.incoming

Sent when an inbound call reaches one of your phone numbers. Blocking — your response shapes the call.
For backward compatibility, the blocking payload ThunderPhone delivers for inbound phone calls is also known as call.incoming in the single-URL legacy webhook. See call.incoming for the full request / response schema.

telephony.complete

Sent when an inbound or outbound telephony call ends. Non-blocking. Includes the full transcript, recording URL, billing summary, and latency metrics. See call.complete.

telephony.tool

Sent when a telephony call invokes a function tool. Non-blocking. Includes the tool name, arguments, and response (or error). Primarily used for audit trails; most apps do not need to subscribe.

web.incoming

The widget / mic-session equivalent of telephony.incoming. Blocking when the publishable key is in mode="webhook" — your response shapes the web session’s agent.

web.complete

The widget / mic-session equivalent of telephony.complete. Non-blocking. Same payload shape as call.complete with direction: "widget" or direction: "mic".

web.tool

The widget / mic-session equivalent of telephony.tool.

Quality events

call.graded

Sent when an AI grading run completes for a call. Non-blocking. Example payload:
{
  "type": "call.graded",
  "data": {
    "call_id": 987654321,
    "grade": {
      "score": 0.92,
      "call_outcome": "successful",
      "summary": "Caller asked about their policy and got a full answer…",
      "detected_issues": [],
      "status": "completed",
      "created_at": "2026-04-20T18:25:11.002Z"
    }
  }
}

issue.reported

Sent when an issue report is filed — either by a user from the dashboard or automatically by call grading. Non-blocking. Example payload:
{
  "type": "issue.reported",
  "data": {
    "call_id": 987654321,
    "issue_report": {
      "id": 4321,
      "severity": "warning",
      "status": "open",
      "title": "Agent paused too long",
      "description": "Five-second silence before responding to the main question.",
      "source": "grading",
      "created_at": "2026-04-20T18:25:11.002Z"
    }
  }
}

Test call events

test-call.completed

Sent when a test-call run finishes (or fails). Non-blocking. Useful for wiring batch CI runs into your chat/notifications systems. Example payload:
{
  "type": "test-call.completed",
  "data": {
    "test_call_run": {
      "id": 7110,
      "target_type": "agent",
      "target_id": 12,
      "status": "completed",
      "call_id": 987654321,
      "error_message": "",
      "completed_at": "2026-04-20T18:25:04.822Z"
    }
  }
}

Deprecated aliases

The single-URL legacy webhook uses a slightly different taxonomy for backward compatibility:
Endpoint-system typeLegacy type
telephony.incomingcall.incoming
telephony.completecall.complete
If you’ve been using the legacy names you don’t need to change anything — the two names refer to the same payload.

call.incoming

The blocking inbound-call payload you must respond to.

call.complete

Post-call transcript and metrics.

Webhook endpoints

Subscribe a URL to a subset of these events.

Function Tools

How telephony.tool / web.tool events are generated.