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.

POST/v1/chat

Request

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.

FieldTypeDescription
messagerequiredstringThe user turn. What the person typed.
user_contextrequiredobjectThe end-user identity. In signed mode it must carry _ts and _sig.
session_idstring | nullContinue an existing conversation. Null or omitted starts a new one.
In signed identity mode the 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

bash
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.

text
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.

text
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.

text
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.

text
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.

text
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.

text
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.

text
data: {"type":"error","content":"Monthly token budget reached."}

done

The turn is complete. Carries a trace_id you can pass to /v1/feedback.

text
data: {"type":"done","trace_id":"tr_7c1d"}

[DONE]

The final line. Not JSON. When you read it, stop reading and close the stream.

text
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.