> ## Documentation Index
> Fetch the complete documentation index at: https://docs.layercode.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook SSE API

> Webhook SSE API

## 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`, `data`, `session.start`, `session.end`, `session.update`.
* `session_id` (string): Connection identifier for this session. Changes each reconnect.
* `conversation_id` (string): Stable conversation identifier.
* `custom_metadata` (object, optional): Custom metadata supplied via the pipeline configuration (or per-session override). See [custom metadata and headers how-to](/how-tos/custom-webhook-metadata-and-headers).

In addition, when you set `session_webhook.custom_headers` in the pipeline config (or a per-session override), Layercode appends those headers to every webhook request. See [custom metadata and headers how-to](/how-tos/custom-webhook-metadata-and-headers).

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:**

```json theme={null}
{
  "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"
}
```

***

### **data**

Sent when your client emits `client.response.data` to pass structured JSON without interrupting speech.

* `data` (object): The arbitrary JSON payload sent by the client.
* `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 the current 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.

The response to this event type should be a **regular JSON HTTP response** (not an SSE stream).

See also: [Send JSON data from the client](/how-tos/send-json-data).

**Example:**

```json theme={null}
{
  "type": "data",
  "session_id": "sess_abc123",
  "conversation_id": "conv_xyz789",
  "turn_id": "turn_xyz123",
  "data": {
    "action": "confirm_order",
    "orderId": "ORD-12345",
    "timestamp": 1724848800000
  }
}
```

***

### **session.start**

Sent when a new session begins and your agent should optionally speak first.

* `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 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.

**Example:**

```json theme={null}
{
  "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).

* `session_id` (string): A unique identifier for the current session.
* `conversation_id` (string): A unique identifier for the conversation.
* `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.

**Example:**

```json theme={null}
{
  "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.

* `session_id` (string): A unique identifier for the current session.
* `conversation_id` (string): A unique identifier for the conversation.
* `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.

**Example:**

```json theme={null}
{
  "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 }
  ]
}
```

***

## Webhook Response Events

When Layercode calls your webhook, your handler typically streams back Server-Sent Events (SSE) so the assistant can speak or update the UI. The following event types are recognized.

Note: For `response.data`, you may either include it in an SSE stream, or when responding to the incoming `data` webhook event type, return it as a regular JSON HTTP response (non‑SSE). All other webhook events should return SSE events.

### **response.tts**

Send spoken content for the assistant turn. Layercode converts the provided text to speech and streams it to the user.

```json theme={null}
{ "type": "response.tts", "content": "Let me check that for you.", "turn_id": "turn_xyz123" }
```

### **response.data**

Deliver JSON payloads to the frontend without speaking. Useful for updating dashboards or sending structured data.

```json theme={null}
{ "type": "response.data", "content": { "status": "looking-up-order" }, "turn_id": "turn_xyz123" }
```

JSON (non‑SSE) response example (when responding to the incoming `data` webhook event). See docs page: [Send JSON data from the client](/how-tos/send-json-data).

```json theme={null}
{ "type": "response.data", "content": { "status": "received", "echo": { "orderId": "ORD-12345" } }, "turn_id": "turn_xyz123" }
```

### **response.end**

Signal that the assistant has finished generating its reply for the current turn. Always emit this once the turn is complete unless you are issuing a `response.hangup`.

```json theme={null}
{ "type": "response.end", "turn_id": "turn_xyz123" }
```

### **response.hangup**

Request that Layercode end the session after finishing playback of the current assistant audio. Provide a farewell in the **required** `content` field. You do **not** need to send a separate `response.end`; Layercode will flush remaining audio and end the session automatically.

```json theme={null}
{
  "type": "response.hangup",
  "content": "Thank you for calling. Goodbye!",
  "turn_id": "turn_xyz123"
}
```
