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

# Narya host API overview

> The HTTP contract between the Narya host and every client: one Unix socket, one event stream, one error envelope, and cursor paging.

<Tip>
  **This section is for developers.** If you want a business-level overview of Narya, see [What is Narya](/en/narya/what-is-narya).
</Tip>

Narya runs coding agents behind one HTTP API. One long-lived host owns the sessions, the store and the model connections. The terminal client and the one-shot command that Lerian ships drive this API. A client you write drives the same one.

## Transport and authorization

***

The host listens on a Unix socket in your Narya home. Narya creates the socket owner-only, and file permissions are the whole authorization. There is no password, no token and no TLS.

The socket is `narya.sock` inside the Narya home. The home is `$NARYA_HOME`, or `$XDG_CONFIG_HOME/narya`, or `~/.config/narya`, in that order.

Requests are HTTP/1.1 with JSON bodies. Field names are camelCase. Dial the socket and send an ordinary request:

```bash theme={null}
curl --unix-socket ~/.config/narya/narya.sock http://localhost/v1/host
```

The authority in that URL is ignored, because the connection is already the socket. Any host name works.

## Work is accepted, and results stream

***

Results never arrive on the response of the request that caused them. `POST /v1/sessions/{sessionId}/messages` answers `202` with a turn id. Everything the turn produces streams over `GET /v1/events` as server-sent events.

Each frame carries an `id:` line, a `data:` line, and a blank line. The `data` payload is one JSON event envelope, and its `type` property says which event it is. Frames carry no `event:` or `retry:` line.

```
id: 1011
data: {"id":"1011","type":"turn-finished","sessionId":"6b9f6d2e-1c3a-4f5b-9d7e-2a8c4e6f0b1d","timestamp":"2026-08-08T12:05:00Z","payload":{"turnId":"4d8e2f6a-0b1c-4d3e-9f5a-7b9c1d3e5f0a","stopReason":"completed"}}

```

Two query parameters shape the stream. `sessionId` narrows it to one session. `hostEvents=true` adds the events that belong to no session, and it applies only beside `sessionId`.

To resume, send the last id you received in the `Last-Event-ID` request header. The stream continues from the first event after it that the store still holds. Compare the first id you receive against the one you sent, and read state again through the `GET` operations when there is a gap. A cursor newer than anything the store holds gets `409` with code `NRY-0026`, and the same cursor is refused identically every time.

## The two envelopes

***

A paged list answers a cursor envelope: `items`, `limit` and a `nextCursor` when more remains. Cursors are opaque. Pass one back as the `cursor` query parameter to get the next page.

One error envelope: `code`, `title` and `message`, plus a `fields` map on a `422`. Codes are `NRY-` and four digits.

```json theme={null}
{
  "code": "NRY-0002",
  "title": "Session not found",
  "message": "No session with id 6b9f6d2e-1c3a-4f5b-9d7e-2a8c4e6f0b1d exists on this host."
}
```

<Columns cols={2}>
  <Card title="The host API" icon="server" href="/en/narya/the-host-api">
    Read what the host serves and why the contract has this shape.
  </Card>

  <Card title="Error list" icon="triangle-exclamation" href="/en/reference/narya/host-api-error-list">
    Look up every code the host answers.
  </Card>
</Columns>
