Appearance
API Reference
Base URL: https://api.echomode.io/v1
All endpoints return JSON unless noted (e.g. POST /chats/{chat_id}/messages/stream uses Server-Sent Events).
POST /chats/{chat_id}/messages/stream emits meta, then delta events carrying reply text, then one done
event. The done event includes context, describing how much of the model's window the
request used:
{"type": "done", "context": {"used": 2088, "limit": 128000, "compacted": true}}
used is the prompt tokens the provider counted, limit is the model's context window,
and compacted is true once older turns in the chat have been folded into a summary.
limit is null when the window is unknown, and clients must then hide any usage
indicator rather than assume a size. An error event carries the same detail and code
pair as a JSON error response. Authenticated endpoints require a Bearer token in the Authorization header.
Authentication
EchoMode uses JWT bearer tokens with refresh-token rotation. Obtain tokens via login or SSO, then pass the access token on every request:
Authorization: Bearer <access_token>
When the access token expires, exchange the refresh token for a new pair via POST /auth/refresh.
Versioning
The API is versioned in the path. Every endpoint below is reachable at
https://api.echomode.io/v1/<path> — the base URL above already includes it,
so paths in this reference are written relative to it.
Build clients to tolerate additions: new endpoints, new optional request fields,
and new response fields can appear under v1. Ignore response fields you do not
recognize rather than failing on them.
One surface sits outside the version prefix:
| Path | Why |
|---|---|
/hooks/workflows/* |
Webhook ingress — the URLs are stored in your systems |
Error format
Errors carry a detail field. For everything except 422 it is a string you can
surface directly:
{
"detail": "Human-readable error message"
}
Some errors also carry a machine-readable code. Switch on it rather than matching the
prose, which is free to change:
{
"detail": "this message does not fit the model's context window. Remove an attached file or narrow the Knowledge Base selection, then send again",
"code": "context_overflow"
}
code |
Returned by | Meaning |
|---|---|---|
context_overflow |
POST /chats/{chat_id}/messages, POST /chats/{chat_id}/messages/stream |
The request still exceeds the model's context window after older turns were summarised. Remove an attachment or narrow the Knowledge Base selection. |
| Status | Meaning |
|---|---|
| 400 | Validation or domain error |
| 401 | Missing or expired token |
| 403 | Insufficient permissions |
| 404 | Resource not found |
| 409 | Conflict (duplicate email, etc.) |
| 413 | Payload too large (avatar > 5 MB), or a chat request that does not fit the model's context window (code: "context_overflow") |
| 422 | Request body failed schema validation — detail is a list, see below |
| 429 | Rate limited |
Unknown fields in a request
Request bodies reject fields they do not declare. A misspelled key is refused with
422 rather than accepted and ignored, so a mistyped field surfaces as an error
instead of a silent no-op.
On a 422 the detail field is a list of problems, one entry per field.
loc locates the field, and type is extra_forbidden for an undeclared one:
{
"detail": [
{
"type": "extra_forbidden",
"loc": ["body", "visibilty"],
"msg": "Extra inputs are not permitted",
"input": "personal"
}
]
}
Read loc last-element-first to find the offending key — here visibilty, a
misspelling of visibility. The same list carries ordinary validation failures
(missing required fields, wrong types), so handling it once covers both.
Responses work the opposite way: ignore response fields you do not recognize — new
ones can appear (see Versioning above).
Pagination
List endpoints use two pagination styles:
Keyset pagination (chats, logs): pass the next_cursor value from the response as the cursor query parameter.
Offset pagination (documents, job audit): use limit/offset query parameters.
Enums & constants
Accepted values for each enum field appear on that field in the reference below.
The ones here need more than a list: what the values mean, and how they move.
Visibility
Controls who can access a resource (agents, chats, documents, folders).
| Value | Scope |
|---|---|
personal |
Only the creator can access |
team_level |
Accessible to members of the specified teams (requires team_ids) |
org_level |
Accessible to all organization members |
universal |
Read-only built-in resources (cannot be created via API) |
Echo state
The alignment state machine that tracks whether conversations stay on-topic.
| Value | Meaning |
|---|---|
stable |
Conversation is on-topic |
mildDrift |
Slight topic drift detected |
moderateDrift |
Significant topic drift |
severeDrift |
Conversation has drifted far off-topic |
assistantRefusal |
The assistant refused to respond |
Transitions flow: stable → mildDrift → moderateDrift → severeDrift. On-topic messages move the state back toward stable. assistantRefusal is set independently when a refusal is detected.
Organization tier
| Value | Description |
|---|---|
free |
Free tier (default for new self-serve organizations) |
pro |
Pro tier |
max |
Max tier |
Transition reason
Returned inside Echo events arrays to explain why the alignment state changed.
| Value | Meaning |
|---|---|
no change |
Score stayed within current state bounds |
scored below bound of stable |
Score dropped below the stable threshold |
scored below bound of mild drift |
Score dropped below the mild-drift threshold |
scored below bound of moderate drift |
Score dropped below the moderate-drift threshold |
scored above bound of mild drift |
Score rose above the mild-drift threshold (recovering) |
scored above bound of moderate drift |
Score rose above the moderate-drift threshold (recovering) |
scored above bound of severe drift |
Score rose above the severe-drift threshold (recovering) |
user exceeded off topic streak |
Consecutive off-topic rounds hit the streak threshold |
user exceeded on topic streak |
Consecutive on-topic rounds hit the recovery threshold |
assistant refusal detected |
The assistant refused to respond |
assistant refusal cleared |
A normal response followed a prior refusal |