# 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 %}

## 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();
```

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

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

The question should be specific, self-contained, and written in natural language.
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.
