Skip to main content
Call Event Hooks are outbound HTTP webhooks that fire at specific points in a call’s lifecycle. When a call starts or ends, the platform sends a POST request with a JSON payload to every URL registered on that Assistant or Agent. Use them to trigger workflows, sync conversation data, send transcripts to your CRM, or any other external integration.

Hook types

TypeFires when
call_startedThe call is connected and audio has begun
call_concludedThe call has ended — includes the full conversation transcript, summaries, and call recording

Delivery

Request format

Webhooks are delivered as HTTP POST requests with Content-Type: application/json. Fields whose value is null are omitted from the payload.

Retry behaviour

The platform guarantees at-least-once delivery. If your endpoint returns an HTTP error status or does not respond within 30 seconds, the delivery is retried automatically.
AttemptBackoff before next retry
11 minute
22 minutes
34 minutes
48 minutes
516 minutes
Doubles each time, capped at 24 hours
20Final attempt — permanently marked FAILED
After 20 failed attempts no further retries occur.

Delivery states

StatusMeaning
PENDINGAwaiting delivery or scheduled for a retry
SUCCEEDEDDelivered successfully (2xx response received)
FAILEDAll 20 attempts exhausted without success

Idempotency

Because deliveries are retried, your endpoint may receive the same event more than once. Use the callId field as an idempotency key on your side.

Payload reference

Shared fields

Every event payload contains these top-level fields.
FieldTypeDescription
typestringThe event type: call_started or call_concluded
callIdstringUUID that uniquely identifies this call
transportobject | nullInformation about how the call was connected

Transport object

FieldTypePresent when
typestringAlways — "sip" or "websocket"
calledNumberstringSIP only — the number that was dialled
callingNumberstringSIP only — the caller’s number
{
  "type": "sip",
  "calledNumber": "+4930123456",
  "callingNumber": "+4917612345678"
}
{
  "type": "websocket"
}

call_started

Fired immediately when the call is connected. Fields
FieldTypeDescription
typestring"call_started"
callIdstringUUID of the call
startedAtnumber | nullCall start time — Unix timestamp in milliseconds
transportobject | nullTransport info
Example payload
{
  "type": "call_started",
  "callId": "550e8400-e29b-41d4-a716-446655440000",
  "startedAt": 1740571200000,
  "transport": {
    "type": "sip",
    "calledNumber": "+4930123456",
    "callingNumber": "+4917612345678"
  }
}

call_concluded

Fired after the call ends. Contains the complete conversation history, LLM-generated summaries, and an optional call recording. Fields
FieldTypeDescription
typestring"call_concluded"
callIdstringUUID of the call
startedAtnumber | nullCall start time — Unix timestamp in milliseconds
endedAtnumber | nullCall end time — Unix timestamp in milliseconds
shortSummarystring | nullShort LLM-generated summary of the call
summarystring | nullFull LLM-generated summary of the call
callRecordingstring | nullBase64-encoded audio recording of the entire call
transportobject | nullTransport info
messagesarrayOrdered conversation history
Example payload
{
  "type": "call_concluded",
  "callId": "550e8400-e29b-41d4-a716-446655440000",
  "startedAt": 1740571200000,
  "endedAt": 1740571500000,
  "shortSummary": "Customer enquired about the Pro plan pricing.",
  "summary": "The customer called to ask about the pricing of the Pro subscription plan. The assistant explained the monthly and annual pricing options and offered to send a follow-up email with a detailed comparison.",
  "callRecording": "<base64-encoded-audio>",
  "transport": {
    "type": "sip",
    "calledNumber": "+4930123456",
    "callingNumber": "+4917612345678"
  },
  "messages": [
    {
      "type": "text",
      "role": "ASSISTANT",
      "timestamp": 1740571201000,
      "text": "Hello! How can I help you today?"
    },
    {
      "type": "text",
      "role": "USER",
      "timestamp": 1740571210000,
      "text": "Hi, I'd like to know about your Pro plan pricing."
    },
    {
      "type": "tool_call",
      "role": "TOOL_CALL",
      "timestamp": 1740571215000,
      "callId": "tool-abc-123",
      "toolName": "get_pricing",
      "parameters": {
        "plan": "pro"
      }
    },
    {
      "type": "tool_result",
      "role": "TOOL_CALL_RESULT",
      "timestamp": 1740571216000,
      "callId": "tool-abc-123",
      "toolName": "get_pricing",
      "text": "{\"monthly\": 49, \"annual\": 39}"
    },
    {
      "type": "text",
      "role": "ASSISTANT",
      "timestamp": 1740571220000,
      "text": "The Pro plan is $49 per month, or $39 per month on an annual subscription."
    }
  ]
}

Messages

The messages array contains every turn of the conversation in chronological order. Each element has a type discriminator field. Shared message fields
FieldTypeDescription
typestringMessage type: text, audio, tool_call, or tool_result
rolestringWho produced this message
timestampnumberUnix timestamp in milliseconds
Role values
RoleDescription
USERSpeech input from the human caller
ASSISTANTResponse generated by the AI assistant
SYSTEMAn internal system-level message
TOOL_CALLA tool invocation initiated by the LLM
TOOL_CALL_RESULTThe result returned by a tool
UNKNOWNRole could not be determined
Message types
Represents a spoken utterance transcribed to text — from the caller (USER) or the assistant (ASSISTANT).
FieldTypeDescription
typestring"text"
rolestringUSER, ASSISTANT, SYSTEM, or UNKNOWN
timestampnumberUnix timestamp in milliseconds
textstringTranscribed or generated text content
{
  "type": "text",
  "role": "USER",
  "timestamp": 1740571210000,
  "text": "Hi, I'd like to know about your Pro plan pricing."
}
Represents a message that exists only as raw audio with no transcription available.
FieldTypeDescription
typestring"audio"
rolestringUSER, ASSISTANT, SYSTEM, or UNKNOWN
timestampnumberUnix timestamp in milliseconds
audiostringBase64-encoded raw audio data
{
  "type": "audio",
  "role": "USER",
  "timestamp": 1740571210000,
  "audio": "<base64-encoded-audio>"
}
Recorded when the LLM decides to invoke a tool during the conversation.
FieldTypeDescription
typestring"tool_call"
rolestringAlways "TOOL_CALL"
timestampnumberUnix timestamp in milliseconds
callIdstringCorrelates this call with its result
toolNamestringThe name of the tool that was invoked
parametersobjectThe arguments passed to the tool by the LLM
{
  "type": "tool_call",
  "role": "TOOL_CALL",
  "timestamp": 1740571215000,
  "callId": "tool-abc-123",
  "toolName": "get_pricing",
  "parameters": {
    "plan": "pro"
  }
}
Recorded when a tool returns its result back to the LLM.
FieldTypeDescription
typestring"tool_result"
rolestringAlways "TOOL_CALL_RESULT"
timestampnumberUnix timestamp in milliseconds
callIdstringMatches the callId of the originating tool call
toolNamestringThe name of the tool that produced the result
textstringThe tool’s return value as a plain string
{
  "type": "tool_result",
  "role": "TOOL_CALL_RESULT",
  "timestamp": 1740571216000,
  "callId": "tool-abc-123",
  "toolName": "get_pricing",
  "text": "{\"monthly\": 49, \"annual\": 39}"
}

Configuration

Call Event Hooks are configured per Assistant or Agent — they are not a standalone resource.

Dashboard

  1. Open the Assistant or Agent you want to configure.
  2. Navigate to the Event Hooks section.
  3. Click Add Hook (Hinzufügen), select the hook type, and enter your target URL.
  4. Save. The hook is now active for all future calls on that Assistant or Agent.
To update a hook, edit the URL in place and save. To remove a hook, delete it from the list and save.

REST API

Hooks are managed through the Assistant and Agent endpoints. The examples below use the Assistant path — the Agent path follows the exact same structure.
/api/v1/vendors/{vendorId}/organizations/{organizationId}/assistants
/api/v1/vendors/{vendorId}/organizations/{organizationId}/agents
Retrieve the full Assistant configuration including its hooks.
GET /api/v1/vendors/{vendorId}/organizations/{organizationId}/assistants/{assistantId}
The callEventHooks array in the response:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Support Assistant",
  "callEventHooks": [
    {
      "id": "b00bface-1337-badd-cafe-d00df00dcafe",
      "type": "call_started",
      "parameters": {
        "url": "https://your-server.com/hooks/call-started"
      }
    },
    {
      "id": "deadbeef-cafe-babe-feed-faceabadb001",
      "type": "call_concluded",
      "parameters": {
        "url": "https://your-server.com/hooks/call-concluded"
      }
    }
  ]
}
Each hook object:
FieldTypeDescription
idstringUUID of the hook instance
typestring"call_started" or "call_concluded"
parameters.urlstringThe target URL for this hook
Include callEventHooks in the request body when creating an Assistant. Omit the id — it is assigned by the platform.
POST /api/v1/vendors/{vendorId}/organizations/{organizationId}/assistants
Content-Type: application/json
{
  "name": "Support Assistant",
  "callEventHooks": [
    {
      "type": "call_started",
      "parameters": {
        "url": "https://your-server.com/hooks/call-started"
      }
    },
    {
      "type": "call_concluded",
      "parameters": {
        "url": "https://your-server.com/hooks/call-concluded"
      }
    }
  ]
}
Returns the full Assistant object including the assigned hook id values.
The PUT endpoint replaces the entire callEventHooks array. The behaviour depends on whether id is included for each hook:
ScenarioWhat to do
Update an existing hook’s URLInclude the hook’s id with the new url
Add a new hookOmit the id field
Remove a hookLeave it out of the array
PUT /api/v1/vendors/{vendorId}/organizations/{organizationId}/assistants/{assistantId}
Content-Type: application/json
{
  "name": "Support Assistant",
  "callEventHooks": [
    {
      "id": "b00bface-1337-badd-cafe-d00df00dcafe",
      "type": "call_started",
      "parameters": {
        "url": "https://your-updated-server.com/hooks/call-started"
      }
    },
    {
      "type": "call_concluded",
      "parameters": {
        "url": "https://your-server.com/hooks/call-concluded"
      }
    }
  ]
}
In this example:
  • The call_started hook with the given id is updated with the new URL.
  • The call_concluded entry has no id, so a new hook is created.
  • Any previously existing hooks not listed are removed.
Returns 200 OK with an empty success body.
The same operations apply to Agents at /api/v1/vendors/{vendorId}/organizations/{organizationId}/agents/{agentId}. The request and response shapes for callEventHooks are identical.