---
title: "eve"
description: "The default HTTP API for an agent, covering session routes, auth, and customization."
---

The eve channel is the framework's default HTTP API. It's what the terminal UI, [`useEveAgent`](../guides/frontend/overview), `curl`, and any SDK client talk to when they start sessions, send messages, and stream events. `eveChannel()` mounts the canonical session routes under `/eve/v1/session*`, and they are enabled by default even when `agent/channels/eve.ts` does not exist.

Reach for it when something needs HTTP access to your agent, including local tooling, a browser frontend, the terminal UI, or another API client. Most apps never write this file. Add `agent/channels/eve.ts` only to override the defaults, usually the route auth policy.

```ts title="agent/channels/eve.ts"
import { eveChannel } from "eve/channels/eve";
import { localDev, vercelOidc } from "eve/channels/auth";

export default eveChannel({
  auth: [vercelOidc(), localDev()],
});
```

## Routes

The application exposes a health route plus eve channel routes that inspect the agent, create sessions, send follow-ups, cancel turns, and stream events:

- `GET /eve/v1/health`
- `GET /eve/v1/info`
- `POST /eve/v1/session` (start a session)
- `POST /eve/v1/session/:sessionId` (send a follow-up)
- `POST /eve/v1/session/:sessionId/cancel` (cancel the in-flight turn)
- `GET /eve/v1/session/:sessionId/stream` (stream events, NDJSON)

Start a session with a minimal body. The response returns `sessionId` and the `continuationToken` you reuse for follow-ups:

```bash
curl -X POST https://<deployment>/eve/v1/session \
  -H "Content-Type: application/json" \
  -d '{"message":"What is the weather in Paris?"}'
# {"continuationToken":"eve:7f3c...","ok":true,"sessionId":"ses_01h..."}
```

Stream that session's events as newline-delimited JSON (`application/x-ndjson; charset=utf-8`), one event object per line:

```bash
curl -N https://<deployment>/eve/v1/session/ses_01h.../stream
# {"type":"turn.started",...}
# {"type":"message.appended","data":{"messageDelta":"It is ",...}}
# {"type":"message.completed",...}
```

Cancel a session's in-flight turn with an empty body, or scope the cancel to the turn you observed by passing the `turnId` stamped on that turn's stream events:

```bash
curl -X POST https://<deployment>/eve/v1/session/ses_01h.../cancel
# {"ok":true,"sessionId":"ses_01h...","status":"accepted"}
```

Cancellation is asynchronous: `"accepted"` means a cancellation hook accepted the request. Confirm the effective outcome on the stream as `turn.cancelled` followed by `session.waiting` — never as a failure. Active local and remote subagents are cancelled recursively before the parent settles; their own streams carry their cancellation boundaries, and cancelled work does not emit `subagent.completed` on the parent. Content emitted before the cancel stays on the event stream, while durable model history keeps only content that had already settled. The session accepts the next message normally. When there is no resumable cancellation target (including an unknown session, a settled turn, or a duplicate cancel), the route responds with `"no_active_turn"` — also a success, so a stop button can fire and forget. A `turnId` naming any other turn is accepted and consumed as a no-op, so a guarded cancel racing a turn boundary cannot stop a turn the caller never saw.

See [Sessions, runs & streaming](../concepts/sessions-runs-and-streaming) for the full request and stream flow, including the complete event set.

## CORS

The eve channel leaves CORS untouched by default. Pass `cors: true` to enable
permissive browser CORS with preflight handling, or pass an options object to
narrow origins, methods, and headers. Route auth still runs on the actual
session requests.

Enable or narrow CORS only when browser clients call the channel directly:

```ts title="agent/channels/eve.ts"
import { eveChannel } from "eve/channels/eve";
import { localDev, vercelOidc } from "eve/channels/auth";

export default eveChannel({
  auth: [vercelOidc(), localDev()],
  cors: {
    origin: "https://app.example.com",
    methods: ["GET", "POST"],
    allowedHeaders: ["authorization", "content-type"],
  },
});
```

## Authentication

The `auth` option decides who can call `/eve/v1/info` and the session routes. The built-in helpers cover development and trusted infrastructure:

- `localDev()` accepts requests during local development.
- `vercelOidc()` lets the local CLI reach a deployed agent, and lets other internal deployments from your team call it.

Neither admits browser users or external clients in production. For a public app, wire the channel to your own auth (Clerk, Auth.js, your own OIDC/JWT verification, an API-key verifier, or any custom `AuthFn`). Vercel OIDC is optional; use it only when Vercel-issued deployment tokens are part of your trust model.

`eve init` scaffolds an `agent/channels/eve.ts` with a production placeholder so you replace it before going live. The generated channel checks Vercel OIDC before falling back to localhost access, and includes `placeholderAuth()`, which returns a setup-focused 401 in production until you swap it for real auth. Delete the file and eve falls back to `[vercelOidc(), localDev()]`, which still does not admit browser users in production.

For the full auth model and helper list, see [Auth & route protection](../guides/auth-and-route-protection).

## Customization

Use `onMessage` to add request-specific context before the agent sees the user message, and `events` to observe stream events from sessions this channel created:

```ts title="agent/channels/eve.ts"
import { eveChannel, defaultEveAuth } from "eve/channels/eve";
import { localDev, vercelOidc } from "eve/channels/auth";

export default eveChannel({
  auth: [vercelOidc(), localDev()],
  onMessage(ctx, message) {
    const callerId = ctx.eve.caller?.principalId ?? "anonymous";
    return {
      auth: defaultEveAuth(ctx),
      context: [`HTTP caller ${callerId} sent: ${message}`],
    };
  },
  events: {
    "message.completed"(eventData, channel, ctx) {
      console.log("eve response completed", {
        continuationToken: channel.continuationToken,
        sessionId: ctx.session.id,
      });
    },
  },
});
```

## Clients

The browser side of this API lives in the [Frontend](../guides/frontend/overview) docs, where `useEveAgent` drives the eve channel from React UI.

For scripts, server-to-server calls, evals, tests, and custom clients, use the [TypeScript SDK](../guides/client/overview). It wraps the session routes, continuation token, stream cursor, and reconnect loop.

## What to read next

- [Frontend](../guides/frontend/overview): drive the eve channel from browser UI with `useEveAgent`
- [TypeScript SDK](../guides/client/overview): call the eve channel from TypeScript
- [Auth & route protection](../guides/auth-and-route-protection): the route auth policy
- [Sessions, runs & streaming](../concepts/sessions-runs-and-streaming): the routes this channel exposes
