Epho provides two submission modes. They differ only in how the client waits; both create the same chat and turn records and use the same worker-backed launch process.
Synchronous streaming
POST /api/v1/chat returns text/event-stream and keeps the request open while
the turn runs.
Frame types:
| Type | Purpose |
|---|---|
chat | Sent first with chat_id and turn_id |
event | Wraps one persisted lifecycle or agent event |
done | Sent last with status, output, error, and artifacts |
data: {"type":"chat","chat_id":"01K...","turn_id":"01K..."}
data: {"type":"event","event":{"type":"status","phase":"starting","message":"Starting the agent…"}}
data: {"type":"done","status":"completed","output":"Done.","error":null,"artifacts":[]}
Epho also emits SSE keepalive comments during quiet periods so intermediaries do not close the connection.
Set cancel_on_disconnect to stop the turn if this streaming client disappears:
{
"prompt": "Run the full integration suite.",
"harness": "codex",
"model": "gpt-5.5",
"provider_api_key": "sk-proj-...",
"cancel_on_disconnect": true
}
It defaults to false, allowing the worker to finish and persist the result
after a dropped connection.
Asynchronous execution
POST /api/v1/chat/async queues the turn and returns 202 with its identifiers.
Use this mode for background jobs, automation, and any caller that should not
hold an HTTP connection.
{
"chat_id": "01K...",
"turn_id": "01K..."
}
Reconnectable streaming
Subscribe after an asynchronous submission—or reconnect after losing a stream:
curl -N https://app.epho.io/api/v1/chat/$CHAT_ID/events/subscribe \
-H "Authorization: Bearer $EPHO_API_KEY"
The subscription:
- emits the chat and latest turn identifiers;
- replays persisted events from earlier turns;
- live-tails the newest turn;
- closes with a
doneframe.
Reading persisted state
Use the chat-level endpoints to read the whole conversation:
GET /api/v1/chat/{chat_id}/events
GET /api/v1/chat/{chat_id}/response
Use the turn-level endpoints when your application already has a turn_id:
GET /api/v1/chat/{chat_id}/turns/{turn_id}/events
GET /api/v1/chat/{chat_id}/turns/{turn_id}/response
An in-flight response has status: "processing" and output: null.
Stopping a run
curl -X POST \
https://app.epho.io/api/v1/chat/$CHAT_ID/turns/$TURN_ID/stop \
-H "Authorization: Bearer $EPHO_API_KEY"
The endpoint returns 202 immediately. The worker marks the turn canceled
and tears down its sandbox.