API REFERENCE
The chat stream
One request in, a stream of events out. Text arrives token by token, tool calls surface live, and write actions pause for approval.
/v1/chatRequest
Send JSON and set Accept: text/event-stream so the server streams the reply. Omit session_id (or send null) on the first turn, the server mints one and hands it back in the first event.
| Field | Type | Description |
|---|---|---|
messagerequired | string | The user turn. What the person typed. |
user_contextrequired | object | The end-user identity. In signed mode it must carry _ts and _sig. |
session_id | string | null | Continue an existing conversation. Null or omitted starts a new one. |
user_context must be signed, or the request is rejected with IDENTITY_SIGNATURE_REQUIRED. See the identity guide for the HMAC recipe.Send a message
curl -N https://eerraa.online/v1/chat \
-H "Authorization: Bearer era_your_project_key" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"message": "Where is order 1043?",
"user_context": { "id": "u_42", "name": "Sara" },
"session_id": null
}'The SSE event contract
The response is a stream of Server-Sent Events. Each event is a line of the form data: {json}, and events are separated by a blank line. Read the type field to decide what to do. The stream always ends with a literal data: [DONE].
session
First event of the stream. Carries the session id. Store it and send it back as session_id on the next turn.
data: {"type":"session","session_id":"sess_9f3a"}text
A chunk of the reply. Many of these arrive in order. Concatenate the content values to build the full message.
data: {"type":"text","content":"Order 1043 shipped "}tool_start
The agent called a tool. Use it to show live tool status. The id pairs the start with its matching result.
data: {"type":"tool_start","id":"call_1","name":"lookup_order","input":{"order_id":"1043"}}tool_end
The tool returned. Match it to its tool_start by id.
data: {"type":"tool_end","id":"call_1","name":"lookup_order","result":{"status":"shipped","eta":"2026-09-02"}}confirmation_required
A write action is paused, waiting for the user to approve it. The widget renders Approve and Cancel buttons. Show the display_name and input so the person can see what is about to happen.
data: {"type":"confirmation_required","id":"call_2","name":"issue_refund","display_name":"Issue refund","input":{"order_id":"1043","amount":"42.00"}}stats
Usage for the turn. Arrives near the end.
data: {"type":"stats","input_tokens":812,"output_tokens":140,"tools_used":1,"iterations":2}error
Something went wrong for this turn. The content is a human-readable message. A stable error code (for example BUDGET_EXCEEDED) may accompany it.
data: {"type":"error","content":"Monthly token budget reached."}done
The turn is complete. Carries a trace_id you can pass to /v1/feedback.
data: {"type":"done","trace_id":"tr_7c1d"}[DONE]
The final line. Not JSON. When you read it, stop reading and close the stream.
data: [DONE]
Choice buttons
An agent can end a reply with a fenced code block tagged choices holding a JSON array of 2 to 6 short strings. It arrives inside the text events like any other markdown. The widget strips the block and renders clickable buttons, if you build your own UI you can do the same.
