# HTTP API reference

> Stable /eve/v1 routes (health, info, session create/continue/stream, OAuth callbacks), request/response shapes, NDJSON event vocabulary, and dev-only runtime-artifact and schedule-dispatch endpoints.

- Repository: vercel/eve
- GitHub: https://github.com/vercel/eve
- Human docs: https://grok-wiki.com/public/docs/vercel-eve-759e1d74a10f
- Complete Markdown: https://grok-wiki.com/public/docs/vercel-eve-759e1d74a10f/llms-full.txt

## Source Files

- `packages/eve/src/protocol/routes.ts`
- `docs/concepts/sessions-runs-and-streaming.md`
- `packages/eve/src/internal/nitro/routes/health.ts`
- `packages/eve/src/internal/nitro/routes/info.ts`
- `packages/eve/src/internal/nitro/routes/agent-info/build-agent-info-response.ts`
- `packages/eve/src/internal/nitro/routes/dev-runtime-artifacts.ts`

---

---
title: HTTP API reference
description: Stable /eve/v1 routes (health, info, session create/continue/stream, OAuth callbacks), request/response shapes, NDJSON event vocabulary, and dev-only runtime-artifact and schedule-dispatch endpoints.
---

Every Eve deployment exposes a stable HTTP surface under `/eve/v1`. Framework-owned routes handle health checks, agent inspection, session lifecycle, OAuth redirects, and (during local development) runtime-artifact and schedule-dispatch controls. Session create, continue, and stream routes are registered by the default `eveChannel` in `agent/channels/eve.ts`; their auth policy is whatever you configure on that channel.

## Route map

All stable routes share the prefix `/eve/v1`. Dev-only routes mount only when Nitro runs in dev mode (`eve dev`); production builds never register them.

| Method | Path | Auth | Availability |
| --- | --- | --- | --- |
| `GET` | `/eve/v1/health` | None | Always |
| `GET` | `/eve/v1/info` | `localDev()` then `vercelOidc()` | Always |
| `POST` | `/eve/v1/session` | `eveChannel` auth chain | Always |
| `POST` | `/eve/v1/session/:sessionId` | `eveChannel` auth chain | Always |
| `GET` | `/eve/v1/session/:sessionId/stream` | `eveChannel` auth chain | Always |
| `GET` or `POST` | `/eve/v1/connections/:name/callback/:token` | None (token is the capability) | Always |
| `POST` | `/eve/v1/callback/:token` | None (token is the capability) | Always |
| `GET` | `/eve/v1/dev/runtime-artifacts` | None | Dev only |
| `POST` | `/eve/v1/dev/runtime-artifacts/rebuild` | None | Dev only |
| `POST` | `/eve/v1/dev/schedules/:scheduleId` | None | Dev only |

Authored channels (`defineChannel`, Slack, Discord, and others) register additional routes outside this table. This page covers only the framework-owned `/eve/v1` surface.

## Authentication

Routes fall into three auth classes:

1. **Always public** — `GET /eve/v1/health`, OAuth/callback routes, and all dev-only routes. Callback routes are intentionally unauthenticated: the unguessable `:token` segment is the capability that authorizes resuming parked workflow work.
2. **Default inspection auth** — `GET /eve/v1/info` walks `[localDev(), vercelOidc()]`. Loopback requests succeed locally; deployed Vercel targets require a valid OIDC bearer.
3. **Channel-configured auth** — Session routes run the `auth` array you pass to `eveChannel`. `routeAuth` walks the array in order; the first strategy returning a `SessionAuthContext` wins. Skipped entries (`null`/`undefined`) continue to the next. Exhaustion returns `401`. Include `none()` last to accept anonymous traffic.

Scaffolded apps typically ship `[localDev(), vercelOidc(), placeholderAuth()]`. Replace `placeholderAuth()` before serving real users. See [Auth and deployment](/auth-and-deployment) for strategy helpers and production patterns.

## Two handles

Session HTTP uses two distinct identifiers:

- **`continuationToken`** — Resume handle for sending follow-up messages or HITL responses. Required on `POST /eve/v1/session/:sessionId`. One active continuation per session; stale tokens are rejected.
- **`sessionId`** — Stream-and-inspect handle for attaching to the NDJSON event feed. Returned in JSON and the `x-eve-session-id` response header.

For the full delivery contract (ordering, reconnect, subagent child streams), see [Sessions and streaming](/sessions-and-streaming).

---

:::endpoint GET /eve/v1/health
Liveness probe for load balancers and uptime monitors. Always public.
:::

<RequestExample>

```bash
curl http://127.0.0.1:3000/eve/v1/health
```

</RequestExample>

<ResponseExample>

```json
{
  "ok": true,
  "status": "ready",
  "workflowId": "<workflow-entry-id>"
}
```

</ResponseExample>

<ResponseField name="ok" type="boolean">
Always `true` when the handler responds.
</ResponseField>

<ResponseField name="status" type="string">
Runtime readiness label. Currently `"ready"`.
</ResponseField>

<ResponseField name="workflowId" type="string">
The workflow entry reference id for the running agent.
</ResponseField>

---

:::endpoint GET /eve/v1/info
JSON inspection snapshot of the compiled agent: model, instructions, tools, skills, channels, schedules, subagents, sandbox, connections, hooks, workflow, workspace metadata, and discovery diagnostics.
:::

Auth matches the default Eve channel: loopback in local dev, Vercel OIDC in deployed targets. Response is never cached (`cache-control: no-store`).

<RequestExample>

```bash
curl http://127.0.0.1:3000/eve/v1/info
```

</RequestExample>

The top-level payload uses `kind: "eve-agent-info"` and `version: 1`. Key sections:

<ResponseField name="agent" type="object">
Name, description, model (`id`, `contextWindowTokens`, `providerOptions`, `routing`, `endpoint`), `outputSchema`, and source paths (`agentRoot`, `appRoot`).
</ResponseField>

<ResponseField name="tools" type="object">
`authored`, `framework`, `available`, `disabledFramework`, `dynamic` resolvers, and `reserved` tool names.
</ResponseField>

<ResponseField name="capabilities.devRoutes" type="boolean">
`true` in development mode, `false` in production. Indicates whether dev-only `/eve/v1/dev/*` routes are mounted.
</ResponseField>

<ResponseField name="diagnostics" type="object">
`discoveryErrors` and `discoveryWarnings` counts from agent discovery.
</ResponseField>

`eve info` and `eve build` surface the same discovery data offline. Use this route to inspect a *running* deployment.

---

:::endpoint POST /eve/v1/session
Create a new durable session and enqueue the first turn.
:::

Runs `routeAuth`, parses the JSON body, optionally checks upload policy for file attachments, then dispatches to the runtime. Returns immediately with handles; stream progress arrives on the message stream route.

<ParamField body="message" type="string | UserContent[]" required>
Plain text or an array of `text` / `file` parts. File parts require `mediaType` and `data` (base64, data URL, or HTTP URL). Framework-internal ref schemes (`eve-url:`, `eve-sandbox:`, `eve-attachment:`) are rejected.
</ParamField>

<ParamField body="clientContext" type="string | string[] | object">
One-turn client/page context. Strings and arrays are prefixed `Client context:\n` and injected as user context. Objects are JSON-stringified first.
</ParamField>

<ParamField body="outputSchema" type="object">
Optional JSON Schema object for a structured turn result. When set, the finalized payload appears on `result.completed` in the stream.
</ParamField>

<ParamField body="mode" type="'conversation' | 'task'">
Session mode. Defaults to `"conversation"` (enables `requestInput` for HITL). `"task"` runs without interactive input requests.
</ParamField>

<ParamField body="callback" type="object">
Optional remote subagent callback descriptor for `defineRemoteAgent` flows. Requires `callId`, `subagentName`, `token`, and `url` (absolute URL pointing at `POST /eve/v1/callback/:token` with matching token).
</ParamField>

<RequestExample>

```bash
curl -X POST http://127.0.0.1:3000/eve/v1/session \
  -H 'content-type: application/json' \
  -d '{"message":"Summarize the latest forecast."}'
```

</RequestExample>

<ResponseExample>

```json
{
  "ok": true,
  "sessionId": "sess_…",
  "continuationToken": "…"
}
```

</ResponseExample>

| Status | Meaning |
| --- | --- |
| `202` | Session created and turn enqueued |
| `400` | Invalid JSON, missing `message`, bad attachment, or upload policy violation (`413` too large, `415` bad media type) |
| `401` / `403` | Auth walk failed |
| `204` | `onMessage` returned `null` — message accepted but not dispatched |
| `500` | `onMessage` handler threw |

<ResponseField name="continuationToken" type="string">
Opaque resume token for follow-up requests. Store it client-side.
</ResponseField>

<ResponseField name="sessionId" type="string">
Durable session id. Also returned in the `x-eve-session-id` header.
</ResponseField>

Default upload policy: 25 MB per attachment, all media types. Configure via `eveChannel({ uploadPolicy })`.

---

:::endpoint POST /eve/v1/session/:sessionId
Continue an existing session with a follow-up message, HITL responses, or both.
:::

<ParamField path="sessionId" type="string" required>
The durable session id from create or prior continue responses.
</ParamField>

<ParamField body="continuationToken" type="string" required>
Current resume token. Stale or missing tokens are rejected.
</ParamField>

<ParamField body="message" type="string | UserContent[]">
Follow-up user message. Optional when `inputResponses` is provided.
</ParamField>

<ParamField body="inputResponses" type="InputResponse[]">
Non-empty array of HITL responses. Each entry requires `requestId`; include `optionId` and/or `text` as appropriate.
</ParamField>

<ParamField body="clientContext" type="string | string[] | object">
Same semantics as session create.
</ParamField>

<ParamField body="outputSchema" type="object">
Per-turn structured output schema override.
</ParamField>

At least one of `message` or `inputResponses` must be non-empty.

<RequestExample>

```bash
curl -X POST http://127.0.0.1:3000/eve/v1/session/<sessionId> \
  -H 'content-type: application/json' \
  -d '{"continuationToken":"<token>","message":"Now send the short version."}'
```

</RequestExample>

<ResponseExample>

```json
{
  "ok": true,
  "sessionId": "<sessionId>"
}
```

</ResponseExample>

Returns `200` on success. The continuation token does not rotate in the response body — keep using the token you already hold until the channel emits a new one through stream events. Wait for `session.waiting` before sending another message for deterministic ordering.

---

:::endpoint GET /eve/v1/session/:sessionId/stream
Replay or live-attach to a session's NDJSON event feed.
:::

<ParamField path="sessionId" type="string" required>
Session to stream.
</ParamField>

<ParamField query="startIndex" type="integer">
Non-negative event index for reconnect or rewind. Omit to stream from the latest live position.
</ParamField>

<RequestExample>

```bash
curl http://127.0.0.1:3000/eve/v1/session/<sessionId>/stream
```

</RequestExample>

<ResponseExample>

```text
{"type":"session.started","data":{},"meta":{"at":"2026-06-16T12:00:00.000Z"}}
{"type":"turn.started","data":{"sequence":0,"turnId":"turn_…"},"meta":{"at":"…"}}
{"type":"message.received","data":{"message":"…","sequence":1,"turnId":"turn_…"},"meta":{"at":"…"}}
```

</ResponseExample>

### Stream headers

| Header | Value |
| --- | --- |
| `content-type` | `application/x-ndjson; charset=utf-8` |
| `x-eve-stream-format` | `ndjson` |
| `x-eve-stream-version` | `15` |
| `x-eve-session-id` | Session id |
| `cache-control` | `no-store, no-transform` |
| `x-accel-buffering` | `no` |

Each line is one JSON object. Persisted events include `meta.at` (ISO timestamp). The stream is durable and fully replayable.

### Turn boundary events

Stop reading (or reconnect with an updated `startIndex`) when you see:

- `session.waiting` — parked, ready for the next user message
- `session.completed` — terminal success
- `session.failed` — terminal failure

## NDJSON event vocabulary

Events are typed by the `type` field. Most carry `data.sequence`, `data.turnId`, and often `data.stepIndex` for ordering within a turn.

### Session and turn lifecycle

| Event | Meaning |
| --- | --- |
| `session.started` | Durable session created. `data.runtime` may include agent id, model id, Eve version, and build metadata. Child subagent sessions include `data.invocation`. |
| `turn.started` | New turn began (`data.turnId`, `data.sequence`). |
| `message.received` | Inbound user message accepted (`data.message` is a text summary for multimodal input). |
| `turn.completed` | Turn finished successfully. |
| `turn.failed` | Turn failed (`data.code`, `data.message`, optional `data.details`). |
| `session.waiting` | Parked with `data.wait: "next-user-message"`. |
| `session.completed` | Terminal session success. |
| `session.failed` | Terminal session failure (`data.code`, `data.message`, `data.sessionId`). |

### Model steps

| Event | Meaning |
| --- | --- |
| `step.started` | Model call began. |
| `step.completed` | Model call finished (`data.finishReason`, optional `data.usage` token counts). |
| `step.failed` | Model call failed (`data.code`, `data.message`). |

`finishReason` values: `stop`, `tool-calls`, `length`, `content-filter`, `error`, `other`. `tool-calls` is the only non-terminal assistant step in the default harness.

### Assistant output

| Event | Meaning |
| --- | --- |
| `message.appended` | Text delta (`data.messageDelta`, cumulative `data.messageSoFar`). |
| `message.completed` | Finalized text block (`data.message`, `data.finishReason`). May fire multiple times per turn. |
| `reasoning.appended` | Reasoning delta (`data.reasoningDelta`, `data.reasoningSoFar`). |
| `reasoning.completed` | Finalized reasoning block. |
| `result.completed` | Structured output when `outputSchema` was requested (`data.result`). |

### Tools and human input

| Event | Meaning |
| --- | --- |
| `actions.requested` | Model requested tool calls (`data.actions`). |
| `action.result` | Tool result (`data.result`, `data.status`: `"completed"` \| `"failed"`, optional `data.error`). |
| `input.requested` | Run paused for HITL approval or `ask_question` (`data.requests`). |

Each `InputRequest` includes `requestId`, `prompt`, optional `options` (`id`, `label`, `description`, `style`), `display` hint (`confirmation` \| `select` \| `text`), and the underlying `action`.

### Subagents

| Event | Meaning |
| --- | --- |
| `subagent.called` | Child workflow session started (`data.childSessionId` — attach to that session's stream). |
| `subagent.started` | Inline subagent execution began. |
| `subagent.event` | Wraps a child stream event under `data.event` (inline subagents). |
| `subagent.completed` | Inline subagent finished (`data.output`). |

Delegated workflow subagents publish progress on their own child-session stream. The parent only signals attachment via `subagent.called`.

### Connections and compaction

| Event | Meaning |
| --- | --- |
| `authorization.required` | Connection needs OAuth (`data.name`, `data.description`, `data.authorization` challenge with optional `url`, `userCode`, `expiresAt`, `instructions`, `displayName`). |
| `authorization.completed` | Authorization resolved (`data.outcome`: `authorized` \| `declined` \| `failed` \| `timed-out`). |
| `compaction.requested` | Context compaction began (`data.modelId`, `data.usageInputTokens`). |
| `compaction.completed` | Compaction checkpoint written. |

---

:::endpoint GET|POST /eve/v1/connections/:name/callback/:token
OAuth IdP redirect target for in-turn connection authorization.
:::

`:name` is the path-derived connection name. `:token` is the workflow hook token minted when authorization starts. The handler projects query (and form-post body) params into an `authorizationCallback` payload, calls `resumeHook(token, …)`, and returns an HTML "Authorization complete" page.

No Eve credentials are required — the token is the unguessable capability. Returns `404` when no matching authorization is pending.

---

:::endpoint POST /eve/v1/callback/:token
Terminal callback for remote subagent sessions.
:::

Used by `defineRemoteAgent` when the framework POSTs completion results back to the parent agent. Body shape:

<ParamField body="callId" type="string" required>
Subagent call identifier.
</ParamField>

<ParamField body="subagentName" type="string" required>
Remote subagent name.
</ParamField>

<ParamField body="kind" type="'session.completed' | 'session.failed'" required>
Outcome kind.
</ParamField>

<ParamField body="output" type="string">
Required for `session.completed`.
</ParamField>

<ParamField body="error" type="JsonValue">
Error payload for `session.failed`.
</ParamField>

Returns `202` with `{ "ok": true }` on success, `404` when the callback is not pending.

---

## Dev-only routes

Mounted only during `eve dev`. `GET /eve/v1/info` reports `capabilities.devRoutes: true` when they are available.

:::endpoint GET /eve/v1/dev/runtime-artifacts
Returns the current dev runtime artifact revision token.
:::

Clients poll this to detect HMR rebuilds. When the revision changes, start new sessions against the fresh snapshot; in-flight sessions keep their original artifact binding.

<ResponseExample>

```json
{
  "revision": "<opaque-revision-id>"
}
```

</ResponseExample>

---

:::endpoint POST /eve/v1/dev/runtime-artifacts/rebuild
Flushes queued runtime artifact rebuilds, then returns the current revision (same shape as `GET`).
:::

---

:::endpoint POST /eve/v1/dev/schedules/:scheduleId
Dispatch one authored schedule exactly once without waiting for cron.
:::

`:scheduleId` is the filesystem-derived schedule name (e.g. `agent/schedules/heartbeat.ts` → `"heartbeat"`). URL-encode reserved characters.

<RequestExample>

```bash
curl -X POST http://127.0.0.1:3000/eve/v1/dev/schedules/heartbeat
```

</RequestExample>

<ResponseExample>

```json
{
  "scheduleId": "heartbeat",
  "sessionIds": ["sess_1", "sess_2"]
}
```

</ResponseExample>

Subscribe to `GET /eve/v1/session/:sessionId/stream` for each returned `sessionId`. Returns `404` with `availableScheduleIds` when the schedule name is unknown.

## Error responses

Most routes return JSON errors with `ok: false` and an `error` string. Common status codes:

| Status | Typical cause |
| --- | --- |
| `400` | Malformed body, missing required fields, invalid `startIndex` |
| `401` / `403` | Auth walk failed or forbidden |
| `404` | Unknown session, schedule, or expired callback token |
| `413` / `415` | Attachment exceeds size cap or violates media-type policy |
| `500` | Handler threw (`errorId` may be present for support correlation) |

## Client integration

`eve/client` wraps these routes with typed `Client` and `ClientSession` helpers, automatic stream reconnection, and continuation-token management. Framework plugins (`eve/next`, `eve/nuxt`, `eve/sveltekit`) can proxy same-origin. Prefer the client SDK over hand-rolling POST + NDJSON loops for scripts, tests, and custom UIs.

<Steps>
<Step title="Create and stream a session">

```bash
# 1. Create
RESP=$(curl -s -X POST http://127.0.0.1:3000/eve/v1/session \
  -H 'content-type: application/json' \
  -d '{"message":"Hello"}')
SESSION_ID=$(echo "$RESP" | jq -r .sessionId)
TOKEN=$(echo "$RESP" | jq -r .continuationToken)

# 2. Stream until session.waiting
curl -N "http://127.0.0.1:3000/eve/v1/session/$SESSION_ID/stream"
```

</Step>
<Step title="Send a follow-up">

Wait for `session.waiting`, then continue:

```bash
curl -X POST "http://127.0.0.1:3000/eve/v1/session/$SESSION_ID" \
  -H 'content-type: application/json' \
  -d "{\"continuationToken\":\"$TOKEN\",\"message\":\"Shorter version, please.\"}"
```

</Step>
<Step title="Reconnect after disconnect">

```bash
curl -N "http://127.0.0.1:3000/eve/v1/session/$SESSION_ID/stream?startIndex=42"
```

</Step>
</Steps>

## Related pages

<CardGroup>
<Card title="Sessions and streaming" href="/sessions-and-streaming">
Continuation tokens, stream reconnect, subagent child-session attachment, and delivery ordering.
</Card>
<Card title="Client integration" href="/client-integration">
`eve/client`, streaming reducers, and React/Vue/Svelte hooks.
</Card>
<Card title="Auth and deployment" href="/auth-and-deployment">
Route auth strategies, env vars, and production deployment verification.
</Card>
<Card title="Connections" href="/connections">
OAuth flows, connection callbacks, and `authorization.required` stream events.
</Card>
<Card title="Subagents and schedules" href="/subagents-and-schedules">
Local and remote subagents, cron schedules, and dev schedule dispatch.
</Card>
<Card title="Quickstart" href="/quickstart">
End-to-end flow from `eve init` through first HTTP session.
</Card>
</CardGroup>
