> ## 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.

# REST API

> API reference for the Layercode REST API.

## Authorize Client Session

To connect a client (browser or mobile app) to a Layercode voice agent, you must first authorize the session. This is done by calling the Layercode REST API endpoint below from your backend.

**How the authorization flow works:**
When using a Layercode frontend SDK (such as `@layercode/react-sdk` or `@layercode/js-sdk`), the SDK will automatically make a POST request to the `authorizeSessionEndpoint` URL that you specify in your frontend code.

This `authorizeSessionEndpoint` should be an endpoint on **your own backend** (not Layercode's). Your backend receives this request from the frontend, then securely calls the Layercode REST API (`https://api.layercode.com/v1/agents/web/authorize_session`) using your `LAYERCODE_API_KEY`. Your backend then returns the `client_session_key` to the frontend.

<Info>
  Your Layercode API key should <b>never</b> be exposed to the frontend. Always call this endpoint from your backend, then return the <code>client\_session\_key</code> to your
  frontend.
</Info>

### Endpoint

```http theme={null}
POST https://api.layercode.com/v1/agents/web/authorize_session
```

### Headers

<ParamField header="Authorization" type="string" required>
  Bearer token using your <code>LAYERCODE\_API\_KEY</code>.
</ParamField>

<ParamField header="Content-Type" type="string" required default="application/json">
  Must be <code>application/json</code>.
</ParamField>

### Request Body

<ParamField body="agent_id" type="string" required>
  The ID of the Layercode agent the client should connect to.
</ParamField>

<ParamField body="conversation_id" type="string">
  (Optional) The conversation ID to resume an existing conversation. If not provided, a new conversation will be created.
</ParamField>

<ParamField body="config" type="object">
  (Optional) Per-session pipeline configuration override. When provided, it is stored on the session and takes precedence over the agent's saved config for that session. Use this
  to customize the config options (e.g. the TTS voice).
</ParamField>

### Response

<ResponseField name="client_session_key" type="string" required>
  The key your frontend uses to connect to the Layercode WebSocket API.
</ResponseField>

<ResponseField name="conversation_id" type="string" required>
  The unique conversation ID.
</ResponseField>

<ResponseField name="config" type="object">
  Optional configuration for this session used by the frontend SDK. When present, it can include:

  <br />

  <code>transcription.trigger</code> and VAD settings such as <code>vad.enabled</code>,{' '}
  <code>vad.gate\_audio</code>, <code>vad.buffer\_frames</code>, <code>vad.model</code>, <code>vad.positive\_speech\_threshold</code>, <code>vad.negative\_speech\_threshold</code>,{' '}
  <code>vad.redemption\_frames</code>, <code>vad.min\_speech\_frames</code>, <code>vad.pre\_speech\_pad\_frames</code>, <code>vad.frame\_samples</code>.
</ResponseField>

### Example Request

```bash theme={null}
# Example with only agent_id (creates a new session)
curl -X POST https://api.layercode.com/v1/agents/web/authorize_session \
  -H "Authorization: Bearer $LAYERCODE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "ag-123456"}'

# Example with agent_id and conversation_id (resumes an existing conversation)
curl -X POST https://api.layercode.com/v1/agents/web/authorize_session \
  -H "Authorization: Bearer $LAYERCODE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "ag-123456", "conversation_id": "lc_conv_abc123..."}'

# Example with per-session config
curl -X POST https://api.layercode.com/v1/agents/web/authorize_session \
  -H "Authorization: Bearer $LAYERCODE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "ag-123456",
    "config": {
      "type": "voice",
      "clients": {
        "browser": {
          "enabled": true
        }
      },
      "plugins": [
        { "use": "stt.deepgram", "options": { "model_id": "flux" } },
        { "use": "turn_manager", "options": { "mode": "automatic" } },
        { "use": "agent.llm", "options": { "provider": "google", "model_id": "gemini-2.5-flash-lite" } },
        { "use": "tts.rime", "options": { "model_id": "mistv2", "voice_id": "courtney" } }
      ],
      "session_webhook": {
        "url": "https://example.com/session-webhook",
        "events": ["session.start", "session.end", "session.update"],
        "custom_metadata": { "tenant_id": "t_42", "plan": "enterprise" },
        "custom_headers": { "x-tenant-id": "t_42", "x-session-origin": "mobile" }
      }
    }
  }'
```

### Example Response

```json theme={null}
{
  "client_session_key": "lc_sesskey_abc123...",
  "conversation_id": "lc_conv_abc123..."
}
```

### Error Responses

<ResponseField name="error" type="string" required>
  Error message describing the problem.
</ResponseField>

**Possible error cases:**

* `400` – Invalid or missing bearer token, invalid agent ID, missing or invalid conversation ID.
* `402` – Insufficient balance for the organization.

**Example error response:**

```json theme={null}
{
  "error": "insufficient balance"
}
```

### Example: Backend Endpoint (Next.js)

Here's how you might implement an authorization endpoint in your backend (Next.js example):

```ts Next.js app/api/authorize/route.ts [expandable] theme={null}
export const dynamic = 'force-dynamic';
import { NextResponse } from 'next/server';

export const POST = async (request: Request) => {
  // Here you could do any user authorization checks you need for your app
  const endpoint = 'https://api.layercode.com/v1/agents/web/authorize_session';
  const apiKey = process.env.LAYERCODE_API_KEY;
  if (!apiKey) {
    throw new Error('LAYERCODE_API_KEY is not set.');
  }
  const requestBody = await request.json();
  if (!requestBody || !requestBody.agent_id) {
    throw new Error('Missing agent_id in request body.');
  }
  try {
    const response = await fetch(endpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${apiKey}`
      },
      body: JSON.stringify(requestBody)
    });
    if (!response.ok) {
      const text = await response.text();
      throw new Error(text || response.statusText);
    }
    return NextResponse.json(await response.json());
  } catch (error: any) {
    console.log('Layercode authorize session response error:', error.message);
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
};
```

<Info>
  For other backend frameworks (Express, FastAPI, etc.), the logic is the same: receive a request from your frontend, call the Layercode <code>authorize\_session</code> endpoint
  with your API key, and return the <code>client\_session\_key</code> to your frontend.
</Info>

## Agents

### List Agents

```http theme={null}
GET https://api.layercode.com/v1/agents
```

<ParamField header="Authorization" type="string" required>
  Bearer token using your <code>LAYERCODE\_API\_KEY</code>.
</ParamField>

#### Response

Returns all agents.

<ResponseField name="agents" type="array" required>
  Each agent object includes <code>id</code>, <code>name</code>, <code>type</code>, <code>agent\_template\_id</code>, <code>created\_at</code>, <code>updated\_at</code>, and{' '}
  <code>assigned\_phone\_numbers</code> (array of phone number assignments with <code>phone\_number</code>, <code>twilio\_sid</code>, <code>friendly\_name</code>,{' '}
  <code>assigned\_at</code>).
</ResponseField>

#### Example

```bash theme={null}
curl -H "Authorization: Bearer $LAYERCODE_API_KEY" \
  https://api.layercode.com/v1/agents
```

```json theme={null}
{
  "agents": [
    {
      "id": "ag-123456",
      "name": "My Agent ag-123456",
      "type": "voice",
      "agent_template_id": "tmpl_default",
      "created_at": "2024-04-01T12:00:00.000Z",
      "updated_at": "2024-04-08T16:30:16.000Z",
      "assigned_phone_numbers": [
        {
          "phone_number": "+15551234567",
          "twilio_sid": "PNxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
          "friendly_name": "Support Line",
          "assigned_at": "2024-04-02T09:21:00.000Z"
        }
      ]
    }
  ]
}
```

### Create Agent From Template

```http theme={null}
POST https://api.layercode.com/v1/agents
```

<ParamField header="Authorization" type="string" required>
  Bearer token using your <code>LAYERCODE\_API\_KEY</code>.
</ParamField>

<ParamField header="Content-Type" type="string" required default="application/json">
  Must be <code>application/json</code>.
</ParamField>

<ParamField body="template_id" type="string">
  Optional template ID to initialize the agent configuration. If omitted, the default recommended template is used.
</ParamField>

<ParamField body="name" type="string">
  Optional display name for the new agent. If omitted, Layercode assigns a default name (e.g., <code>My Agent ag-123456</code>).
</ParamField>

#### Response

Returns the newly created agent record, including configuration and webhook secret.

<ResponseField name="id" type="string" required>
  Unique identifier for the agent.
</ResponseField>

<ResponseField name="name" type="string" required>
  Human-friendly name assigned by Layercode.
</ResponseField>

<ResponseField name="type" type="string" required>
  Agent type (currently <code>voice</code>).
</ResponseField>

<ResponseField name="config" type="object" required>
  Full pipeline configuration cloned from the template.
</ResponseField>

<ResponseField name="webhook_secret" type="string" required>
  Secret used to validate incoming webhooks.
</ResponseField>

<ResponseField name="agent_template_id" type="string" required>
  ID of the template used to create the agent.
</ResponseField>

```bash theme={null}
curl -X POST https://api.layercode.com/v1/agents \
  -H "Authorization: Bearer $LAYERCODE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "template_id": "tmpl_sales", "name": "Sales Assistant" }'
```

### Get Agent Details

```http theme={null}
GET https://api.layercode.com/v1/agents/{agent_id}
```

<ParamField header="Authorization" type="string" required>
  Bearer token using your <code>LAYERCODE\_API\_KEY</code>.
</ParamField>

<ParamField pathParam="agent_id" type="string" required>
  The ID of the agent.
</ParamField>

#### Response

Returns the agent.

<ResponseField name="id" type="string" required>
  Agent ID.
</ResponseField>

<ResponseField name="name" type="string" required>
  Agent display name.
</ResponseField>

<ResponseField name="config" type="object" required>
  Current pipeline configuration.
</ResponseField>

<ResponseField name="assigned_phone_numbers" type="array">
  Array of phone number assignments for this agent.
</ResponseField>

```bash theme={null}
curl -H "Authorization: Bearer $LAYERCODE_API_KEY" \
  https://api.layercode.com/v1/agents/ag-123456
```

### Update Agent Configuration

```http theme={null}
POST https://api.layercode.com/v1/agents/{agent_id}
```

<ParamField header="Authorization" type="string" required>
  Bearer token using your <code>LAYERCODE\_API\_KEY</code>.
</ParamField>

<ParamField header="Content-Type" type="string" required default="application/json">
  Must be <code>application/json</code>.
</ParamField>

<ParamField pathParam="agent_id" type="string" required>
  The ID of the agent to update.
</ParamField>

<ParamField body="webhook_url" type="string">
  URL for production webhooks. When provided, <code>agent.llm</code> is swapped for <code>agent.webhook</code> (disabling <code>demo\_mode</code> and routing traffic to your
  backend).
</ParamField>

<ParamField body="name" type="string">
  Optional display name to set for this agent. If omitted, the name remains unchanged.
</ParamField>

<ParamField body="name" type="string">
  Optional display name to set for this agent. If omitted, the name remains unchanged.
</ParamField>

#### Response

Returns the updated agent record with the new configuration.

```bash theme={null}
curl -X POST https://api.layercode.com/v1/agents/ag-123456 \
  -H "Authorization: Bearer $LAYERCODE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://example.com/layercode-webhook"
  }'
```

## Sessions

### Get Session Details

```http theme={null}
GET https://api.layercode.com/v1/agents/{agent_id}/sessions/{session_id}
```

<ParamField header="Authorization" type="string" required>
  Bearer token using your <code>LAYERCODE\_API\_KEY</code>.
</ParamField>

<ParamField pathParam="agent_id" type="string" required>
  The ID of the agent.
</ParamField>

<ParamField pathParam="session_id" type="string" required>
  The connection ID for the session. This is the unique connection identifier for a given session.
</ParamField>

#### Response

Returns JSON with details about the session, transcript, and recording status.

<ResponseField name="session_id" type="string" required>
  Connection ID for the session.
</ResponseField>

<ResponseField name="agent_id" type="string" required>
  ID of the agent.
</ResponseField>

<ResponseField name="started_at" type="string">
  ISO timestamp when the connection started.
</ResponseField>

<ResponseField name="ended_at" type="string">
  ISO timestamp when the connection ended (if ended).
</ResponseField>

<ResponseField name="duration_ms" type="number">
  Total connection duration in milliseconds.
</ResponseField>

<ResponseField name="metadata" type="object">
  Custom metadata associated with the session.
</ResponseField>

<ResponseField name="from_phone_number" type="string">
  Caller phone number (Twilio), if applicable.
</ResponseField>

<ResponseField name="from_phone_country" type="string">
  Caller country code (Twilio), if applicable.
</ResponseField>

<ResponseField name="to_phone_number" type="string">
  Agent phone number (Twilio), if applicable.
</ResponseField>

<ResponseField name="to_phone_country" type="string">
  Agent phone number country code (Twilio), if applicable.
</ResponseField>

<ResponseField name="ip_address" type="string">
  IP address of the connection.
</ResponseField>

<ResponseField name="country_code" type="string">
  Country code derived from IP address when available.
</ResponseField>

<ResponseField name="transcription_duration_seconds" type="number">
  Total seconds of user speech.
</ResponseField>

<ResponseField name="tts_duration_seconds" type="number">
  Total seconds of generated speech.
</ResponseField>

<ResponseField name="latency_ms" type="number">
  Processing latency in milliseconds.
</ResponseField>

<ResponseField name="transcript" type="array">
  Array of transcript entries. Each entry includes: <code>timestamp</code>, <code>user\_message</code>, <code>assistant\_message</code>, <code>latency\_ms</code>.
</ResponseField>

<ResponseField name="recording_status" type="string">
  One of <code>not\_available</code>, <code>in\_progress</code>, <code>completed</code>.
</ResponseField>

<ResponseField name="recording_url" type="string">
  If <code>recording\_status</code> is <code>completed</code>, a URL to download the WAV recording for this session connection.
</ResponseField>

#### Example

```bash theme={null}
curl -H "Authorization: Bearer $LAYERCODE_API_KEY" \
  https://api.layercode.com/v1/agents/ag-123456/sessions/lc_conn_abc123
```

### Download Session Recording

```http theme={null}
GET https://api.layercode.com/v1/agents/{agent_id}/sessions/{session_id}/recording
```

<ParamField header="Authorization" type="string" required>
  Bearer token using your <code>LAYERCODE\_API\_KEY</code>.
</ParamField>

<ParamField pathParam="agent_id" type="string" required>
  The ID of the agent.
</ParamField>

<ParamField pathParam="session_id" type="string" required>
  The connection ID for the session.
</ParamField>

Returns a WAV audio file if available.

```bash theme={null}
curl -L -H "Authorization: Bearer $LAYERCODE_API_KEY" \
  -o session.wav \
  https://api.layercode.com/v1/agents/ag-123456/sessions/lc_conn_abc123/recording
```

<Note>
  Recordings are generated after a session completes. If a recording is still processing, the details endpoint will return <code>recording\_status: "in\_progress"</code>.
</Note>

<Check>
  Once your frontend receives the <code>client\_session\_key</code>, it can connect to the Layercode WebSocket API to start streaming audio.
</Check>

## Calls

### Initiate Outbound Call

```http theme={null}
POST https://api.layercode.com/v1/agents/ag-123456/calls/initiate_outbound
```

<ParamField body="from_phone_number" type="string" required>
  The phone number assigned to your Layercode Agent that will make the call.
</ParamField>

<Note>Remember: the from\_phone\_number must be a number already assigned to your Laycode Agent in the dashboard.</Note>

<ParamField body="to_phone_number" type="string" required>
  The phone number to call (e.g., your mobile number for testing).
</ParamField>

#### Response

<ResponseField name="conversation_id" type="string" required>
  The unique conversation ID.
</ResponseField>

<Note>A Session (associated with the returned conversation\_id) will be created shortly after once Twilio initiates the call)</Note>

#### Example Request

```bash theme={null}
  curl -X POST https://api.layercode.com/v1/agents/ag-123456/calls/initiate_outbound \
  -H 'Authorization: Bearer $LAYERCODE_API_KEY' \
  -H 'Content-Type: application/json' \
  -D '{
      "from_phone_number": "NUMBER_ASSIGNED_TO_YOUR_AGENT",
      "to_phone_number": "PHONE_NUMBER_TO_CALL"
  }'
```

#### Example Response

```json theme={null}
{
  "conversation_id": "lc_conv_abc123..."
}
```

#### Error Responses

<ResponseField name="error" type="string" required>
  Error message describing the problem.
</ResponseField>

**Possible error cases:**

* `400` – Invalid or missing bearer token, missing or request body, invalid from\_phone\_number (i.e. not assigned to the agent specified in the url).
* `429` – Account session concurrency limit reached.
* `402` – Insufficient balance for the organization.

## Twilio Voice

### TwiML Webhook

Use this endpoint as the Voice webhook in your Twilio phone number configuration. Layercode validates the incoming request, authorizes a session, and returns TwiML that connects the call to your agent's WebSocket stream.

```http theme={null}
POST https://api.layercode.com/v1/agents/twilio/twiml
```

<ParamField header="X-Twilio-Signature" type="string">
  Signature supplied by Twilio for request verification. Required when you have stored Twilio credentials in Layercode.
</ParamField>

<ParamField body="Direction" type="string" required>
  Call direction reported by Twilio (e.g., <code>inbound</code> or <code>outbound-api</code>).
</ParamField>

<ParamField body="From" type="string" required>
  Caller phone number.
</ParamField>

<ParamField body="FromCountry" type="string">
  Caller country code supplied by Twilio.
</ParamField>

<ParamField body="To" type="string" required>
  Phone number assigned to your agent.
</ParamField>

<ParamField body="ToCountry" type="string">
  Destination country code supplied by Twilio.
</ParamField>

#### Response

Returns TwiML that streams the call to the Layercode Twilio WebSocket endpoint.

```xml theme={null}
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Connect>
    <Stream url="wss://twilio.layercode.com/v1/agents/twilio/websocket/{client_session_key}" />
  </Connect>
</Response>
```

<Info>The response Streaming URL is generated dynamically for each request. Do not cache or reuse the client session key.</Info>
