> For the complete documentation index, see [llms.txt](https://docs.ojin.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ojin.ai/apps/overview/api-reference.md).

# Session API Reference

> Start agent sessions programmatically. The widget uses this API automatically — call it directly for custom integrations.

## Base URL

```
https://{region}.agents.ojin.ai
```

The `agents.ojin.ai` domain uses geoproximity routing to direct requests to the nearest regional endpoint.

## Start a Session

### `POST /v1/public/agents/connect`

Start a new session for a given agent. Returns connection details for joining the WebRTC room.

### Request

**Headers:**

| Header         | Required | Description        |
| -------------- | -------- | ------------------ |
| `Content-Type` | Yes      | `application/json` |

**Body:**

```json
{
  "agent_id": "your-agent-id",
  "client_user_ref": "optional-user-identifier"
}
```

| Field             | Type   | Required | Description                                                                                                     |
| ----------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------- |
| `agent_id`        | string | Yes      | The ID of the agent to start a session with                                                                     |
| `client_user_ref` | string | No       | An opaque identifier for your end user. Appears in call history for analytics and tracking. Max 256 characters. |

### Response (200 OK)

```json
{
  "session_id": "550e8400-e29b-41d4-a716-446655440000",
  "room_url": "https://example.daily.co/room-name",
  "token": "eyJhbGciOiJIUzI1NiIs..."
}
```

| Field        | Type   | Description                               |
| ------------ | ------ | ----------------------------------------- |
| `session_id` | string | Unique identifier for this session        |
| `room_url`   | string | WebRTC room URL to connect to             |
| `token`      | string | Authentication token for joining the room |

Use `room_url` and `token` to connect to the WebRTC room from your client. If you're building a web application, you can use the [Daily JavaScript SDK](https://docs.daily.co/reference/daily-js) to join the room.

### Error Responses

All errors return a JSON body with `error_code` and `message`:

```json
{
  "error_code": "agent_unpublished",
  "message": "Agent exists but is currently unpublished"
}
```

For `concurrency_limit` errors, the response includes an additional `retry_after_seconds` field indicating how long to wait before retrying:

```json
{
  "error_code": "concurrency_limit",
  "message": "Max concurrency reached",
  "retry_after_seconds": 5
}
```

| Error Code             | HTTP Status | Description                                                      |
| ---------------------- | ----------- | ---------------------------------------------------------------- |
| `agent_not_found`      | 404         | Agent ID does not exist or is not visible to the caller          |
| `agent_unpublished`    | 403         | Agent exists but status is unpublished                           |
| `auth_failed`          | 403         | Hostname allowlist validation failed                             |
| `concurrency_limit`    | 429         | Max concurrency reached. Response includes `retry_after_seconds` |
| `room_creation_failed` | 502         | WebRTC room could not be created                                 |
| `orchestrator_error`   | 502         | Agent orchestrator is unreachable or returned an error           |
| `internal_error`       | 500         | Unexpected server error                                          |

### Authentication

Currently, the public Session API uses **hostname allowlist** authentication. When a browser request arrives, the server checks the `Origin` header against the domains configured on the agent:

* If the origin matches an allowed hostname, the request proceeds
* If no hostnames are configured, all requests are rejected (agent is private)
* If `*` is configured, all origins are accepted

No API key or token is needed from the client side when using hostname allowlist.

{% hint style="info" %}
Server-side calls without a browser `Origin` header only work for agents configured with `*` in their allowed hostnames. Production server-to-server authentication is planned separately.
{% endhint %}

## Cancel a Session by Room

### `POST /v1/public/agents/connect/{room}`

Cancel an active public session after a room has been allocated. This is mainly used by browser clients during unload, tab-hide, or abort cleanup.

`{room}` is the Daily room name from the `room_url` returned by `POST /v1/public/agents/connect`.

### Cancel Response (200 OK)

```json
{
  "released": 1
}
```

| Field      | Type   | Description                                                                         |
| ---------- | ------ | ----------------------------------------------------------------------------------- |
| `released` | number | Number of active sessions released. `0` means the room was already gone or unknown. |

## Examples

### curl

```bash
# Works only for wildcard/demo agents because curl does not attach a browser Origin.
curl -X POST https://eu-central-1.agents.ojin.ai/v1/public/agents/connect \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "your-agent-id"}'
```

### Python

```python
import requests

# Works only for wildcard/demo agents because server-side HTTP clients do not
# attach a browser Origin.
response = requests.post(
    "https://eu-central-1.agents.ojin.ai/v1/public/agents/connect",
    json={"agent_id": "your-agent-id"}
)

data = response.json()
print(f"Session: {data['session_id']}")
print(f"Room: {data['room_url']}")
```

### JavaScript

```javascript
const response = await fetch(
    "https://eu-central-1.agents.ojin.ai/v1/public/agents/connect",
    {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ agent_id: "your-agent-id" })
    }
);

const { session_id, room_url, token } = await response.json();
```

### JavaScript cleanup

```javascript
const room = new URL(room_url).pathname.split("/").filter(Boolean).pop();

if (room) {
  navigator.sendBeacon(
    `https://eu-central-1.agents.ojin.ai/v1/public/agents/connect/${encodeURIComponent(room)}`,
    ""
  );
}
```

## Connecting to the Room

After receiving the `room_url` and `token` from the Session API, connect to the WebRTC room using the [Daily JavaScript SDK](https://docs.daily.co/reference/daily-js):

```bash
npm install @daily-co/daily-js
```

```javascript
import DailyIframe from '@daily-co/daily-js';

// Create a call frame (attaches to DOM automatically)
const callFrame = DailyIframe.createFrame();

// Join the room with the token from the Session API
await callFrame.join({ url: room_url, token: token });

// The agent's audio and video tracks are now available
callFrame.on('track-started', (event) => {
    if (event.participant && !event.participant.local) {
        // Remote participant = the agent
        // event.track contains the audio or video MediaStreamTrack
    }
});
```

{% hint style="info" %}
This is only needed for custom integrations. If you're using the [widget](/apps/overview/widget-integration.md), it handles the room connection automatically.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ojin.ai/apps/overview/api-reference.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
