Drive It Over HTTP
The TUI (terminal user interface) is a comfortable place to test an agent, but no customer is ever going to open your terminal. A real dispatcher gets reached over the wire: from a web page, a Slack message, a phone. Before we wire up any of those surfaces, it's worth seeing the thing they all sit on top of.
Here's the part that makes eve click: every eve app exposes the same HTTP session API, no matter what you build on top. The TUI, Slack, and the dashboard all act as clients. They start sessions, stream events, and send follow-ups through the same three routes.
So let's skip the surfaces for a second and talk to the dispatcher the way every surface does, with plain curl.
Outcome
You start a durable session with the dispatcher over HTTP, stream its reply as events, and send a follow-up that resumes the same conversation.
Hands-on exercise
With npx eve dev running, open a second terminal. There's nothing to write this lesson, you're learning the contract every channel speaks, so we drive it by hand.
Start a session. Send the customer's first message:
curl -X POST http://127.0.0.1:2000/eve/v1/session \
-H 'content-type: application/json' \
-d '{"message":"what does a basic tune-up cost?"}'The response hands you two things you'll reuse, and they do different jobs:
- An
x-eve-session-idresponse header. This is the stream-and-inspect handle: it names the run so you can watch it. - A
continuationTokenin the JSON body. This is the resume handle: you send it back to add the next message to this conversation.
Stream the session. Point at the stream route with the id from that header:
curl http://127.0.0.1:2000/eve/v1/session/<sessionId>/streamYou get newline-delimited JSON, one event per line: the turn starting, the lookup_service call going out, its result coming back, the assistant's text, and the turn completing. The TUI renders this raw event log as the ⚙ lines you saw earlier.
Send a follow-up. When the session is waiting for you (session.waiting), continue it with the token from the first response:
curl -X POST http://127.0.0.1:2000/eve/v1/session/<sessionId> \
-H 'content-type: application/json' \
-d '{"continuationToken":"<token>","message":"and how long does it take?"}'Same session, same history. The dispatcher already knows you're asking about the tune-up, you don't repeat yourself.
Try It
The first POST returns something like this (headers shown above the body):
x-eve-session-id: sess_8f2c1a...
{ "sessionId": "sess_8f2c1a...", "continuationToken": "ct_b91e..." }And the stream prints the turn as it happens:
{"type":"session.started"}
{"type":"turn.started"}
{"type":"actions.requested","data":{"calls":[{"name":"lookup_service","input":{"query":"tune-up"}}]}}
{"type":"action.result","data":{"result":[{"name":"Basic Tune-Up","price":"$65.00","estMinutes":60}]}}
{"type":"message.completed","data":{"finishReason":"stop"}}
{"type":"turn.completed"}
{"type":"session.waiting"}That session.waiting at the end is the agent telling you it's done with this turn and ready for the next message, the exact moment your follow-up token becomes useful. The same durable machinery will let a turn park for human approval in Section 3 and pick up days later.
Getting a 401? The dev server accepts local requests, but make sure you're hitting 127.0.0.1/localhost and not a deployed URL. A rejected continuationToken usually means it's stale, each session has exactly one active token, so always use the most recent one the API handed back.
Done-When
POST /eve/v1/sessionreturns asessionIdand acontinuationToken.- Streaming the session prints NDJSON events, including the
lookup_servicecall andsession.waiting. - A follow-up
POSTwith thecontinuationTokencontinues the same conversation without repeating context. - You can say which handle streams a run and which one resumes it.
Solution
There's no code to write here, the agent already exposed these routes the moment you ran it. The "solution" is the shape of the contract every channel is built on:
| Route | What It Does |
|---|---|
POST /eve/v1/session | Start a durable session; returns sessionId + continuationToken. |
GET /eve/v1/session/:id/stream | Stream the run as NDJSON events (reconnectable). |
POST /eve/v1/session/:id | Send a follow-up with the continuationToken. |
Hold onto this picture. In Section 4 you'll put a web dashboard and Slack in front of the dispatcher, and neither one invents a new way to talk to it. useEveAgent calls these same routes from the browser; the Slack channel calls them from a webhook.
Was this helpful?