Webhook Request Payload

Layercode sends different webhook event types to your backend. Each request body is JSON. All requests include:
  • type (string): One of message, session.start, session.end, session.update.
  • session_id (string): Connection identifier for this session. Changes each reconnect.
  • conversation_id (string): Stable conversation identifier.
Additional fields vary by event type, as described below.

message

  • text (string): Transcribed user text. | session_id (string): A unique identifier for the current session | | conversation_id (string): A unique identifier for the conversation |
  • turn_id (string): Unique ID for this turn.
  • from_phone_number (string, optional): Caller phone number if Twilio is used.
  • to_phone_number (string, optional): Agent phone number if Twilio is used.
Example:
{
  "type": "message",
  "session_id": "sess_abc123",
  "conversation_id": "conv_xyz789",
  "turn_id": "turn_xyz123",
  "text": "Hello, how are you?",
  "from_phone_number": "+14155550123",
  "to_phone_number": "+14155559876"
}

session.start

Sent when a new session begins and your agent should optionally speak first.
  • turn_id (string): Unique ID for the assistant welcome turn.
  • from_phone_number (string, optional): Caller phone number if Twilio is used.
  • to_phone_number (string, optional): Agent phone number if Twilio is used.
{
  "type": "session.start",
  "session_id": "sess_abc123",
  "conversation_id": "conv_xyz789",
  "turn_id": "turn_welcome_123",
  "from_phone_number": "+14155550123",
  "to_phone_number": "+14155559876"
}

session.update

Sent when asynchronous session data becomes available (e.g., after a recording completes).
  • recording_status (string): completed or failed.
  • recording_url (string, optional): API URL to download WAV when completed.
  • recording_duration (number, optional): Duration in seconds.
  • error_message (string, optional): Error details when failed.
  • metadata (object): Session metadata originally provided during authorization (if any).
  • from_phone_number (string, optional): Caller phone number if Twilio is used.
  • to_phone_number (string, optional): Agent phone number if Twilio is used.
{
  "type": "session.update",
  "session_id": "sess_abc123",
  "conversation_id": "conv_xyz789",
  "from_phone_number": "+14155550123",
  "to_phone_number": "+14155559876",
  "recording_status": "completed",
  "recording_url": "https://api.layercode.com/v1/agents/ag_123/sessions/sess_abc123/recording",
  "recording_duration": 42.3,
  "metadata": { "userId": "u_123" }
}

session.end

Sent when the session finishes. Includes transcript and usage metrics.
  • agent_id (string): Agent ID.
  • started_at / ended_at (string): ISO timestamps.
  • duration (number|null): Total milliseconds (if available).
  • transcription_duration_seconds (number|null)
  • tts_duration_seconds (number|null)
  • latency (number|null)
  • ip_address (string|null)
  • country_code (string|null)
  • recording_status (string): enabled or disabled (org setting for session recording).
  • transcript (array): Items of { role: 'user' | 'assistant', text: string, timestamp: number }.
  • from_phone_number (string, optional): Caller phone number if Twilio is used.
  • to_phone_number (string, optional): Agent phone number if Twilio is used.
{
  "type": "session.end",
  "session_id": "sess_abc123",
  "conversation_id": "conv_xyz789",
  "agent_id": "ag_123",
  "from_phone_number": "+14155550123",
  "to_phone_number": "+14155559876",
  "started_at": "2025-08-28T10:00:00.000Z",
  "ended_at": "2025-08-28T10:03:00.000Z",
  "duration": 180000,
  "transcription_duration_seconds": 20.1,
  "tts_duration_seconds": 19.8,
  "latency": 120,
  "ip_address": "203.0.113.10",
  "country_code": "US",
  "recording_status": "enabled",
  "transcript": [
    { "role": "user", "text": "Hello", "timestamp": 1724848800000 },
    { "role": "assistant", "text": "Hi there!", "timestamp": 1724848805000 }
  ]
}

Verifying the webhook request

To confirm that webhook requests are from Layercode you should always verify the webhook request.

Webhook SSE Response Format

Your response should be a stream of SSE events. The SSE stream format is JSON based. Each JSON message below must be sent as a separate SSE event in the format below. Each SSE event consists of a data: field, followed by a stringified JSON object and two newlines (\n\n).

Event Types

Text to speech Send any number of response.tts type events to the client containing text, which the Layercode voice agent will convert to speech and send to the client as response.audio events. The text will be processed in sentence chunks for natural speech delivery.
{
  "type": "response.tts",
  "content": "Hello this is a complete text message to speak to the user",
  "turn_id": "turn_xyz123"
}
JSON data to forward to the client Your webhook SSE can return response.data type events, which will be forwarded directly to the browser client. This is ideal for updating UI and state in the browser. If you want to pass text or json deltas instead of full objects, you can simply pass a json object like { "delta": "text delta..." } and accumulate and render the delta in the client browser.
{
  "type": "response.data",
  "content": { "json": "object" },
  "turn_id": "turn_xyz123"
}
Note: Multiple response.tts and response.data messages can be sent over a single SSE response (e.g. so the agent can say “I’m just getting your results”, do a tool call, return the results in response.data, and then speak a summary of the results). Ending the SSE response Once the webhook SSE response is ready to be closed, you must send the following final event:
{
  "type": "response.end",
  "turn_id": "turn_xyz123"
}