Headless AI agent API

The OctaDezx headless Agent API: POST /agent/start and /agent/reply return the agent's checked reply, status, handoff and actions, with Server-Sent Events streaming. Available at version 0.1.

Status: available (v0.1). The OctaDezx Agent API puts the support agent behind your own UI. Your server sends the customer's message to POST /agent/start or POST /agent/reply with an API key and gets back the agent's final, checked reply, a status of answered, needs_input or handed_off, a handoff reason when a person takes over, and the actions the turn filed, such as an order or a refund request. Send Accept: text/event-stream to receive the turn as Server-Sent Events. The Agent API is live at https://api.octadezx.com/v1, version 0.1.

Start a conversation

All requests use an API key, Authorization: Bearer odx_... or x-api-key, from your server only. The user object is trusted because it comes from your server: the conversation is bound to user.id and the email and phone are linked to that contact, so the user can ask about their own orders and bookings.

FieldNotes
message1 to 4000 characters.
userOptional. id (1 to 255), email, phone, name, attributes.
conversationIdOptional. Continue an existing conversation. A conversation bound to a different user returns 409 conversation_user_mismatch.
metadataOptional JSON object, at most 4 KB, stored on the conversation.

Request

curl -X POST "$BASE/agent/start" \
  -H "Authorization: Bearer $OCTADEZX_API_KEY" -H "Content-Type: application/json" \
  -d '{"message":"Where is my order 1001?","user":{"id":"u_123","email":"jo@example.com"},"metadata":{"page":"/orders"}}'

Response

{
  "conversationId": "6f1c...",
  "status": "answered",
  "reply": "Order 1001 shipped yesterday with Pathao, tracking PTH123.",
  "user": { "id": "u_123" },
  "messageAccepted": true
}

Continue and read it

Reading returns state (open, handed_off, resolved), the raw status, handoff, the verified user (verifiedBy api_key or user_hash), and up to 500 messages with role user, assistant, agent (a teammate) or system.

Reply

curl -X POST "$BASE/agent/reply" -H "Authorization: Bearer $OCTADEZX_API_KEY" -H "Content-Type: application/json" \
  -d '{"conversationId":"6f1c...","message":"Can I change the address?"}'

Read

curl "$BASE/agent/conversations/6f1c..." -H "Authorization: Bearer $OCTADEZX_API_KEY"

Statuses

statusMeaningWhat to do
answeredThe agent replied.Show reply.
needs_inputThe final reply ends by asking the customer something, such as an order number. This is a reading of the reply text.Show reply and wait for the answer.
handed_offThe agent escalated, or a person already has the conversation. handoff.reason says why.Tell the customer a person will reply. Read later replies or subscribe to conversation.handed_off.

Actions

When a turn files something, actions lists it, read from the database rather than from the reply. Refund requests are requests for a person to decide; no money moves.

actions

"actions": [
  { "type": "order.created", "id": "...", "status": "pending", "totalAmount": 2450 },
  { "type": "appointment.requested", "id": "...", "status": "requested", "service": "Fitting", "startsAt": "2026-11-05T10:00:00Z" },
  { "type": "refund.requested", "id": "...", "status": "requested", "amountCents": 4999, "currency": "USD" }
]

Streaming with Server-Sent Events

Send Accept: text/event-stream to /agent/start or /agent/reply. The stream sends a status event with state thinking at once, then the final status, then the reply in delta chunks, then done with the full turn. Keep-alive comments arrive every 15 seconds.

Unverified text is never streamed. OctaDezx checks every reply before a customer sees it, against the catalogue, the brand safety rules and the multi-step inquiry's verified facts, so the stream waits for the checked reply and then sends it in chunks. You get an immediate thinking signal and a progressive render, not a faster first word.

EventDataWhen
status{ state, conversationId }First with state thinking, then once with the final status.
delta{ text }The reply in chunks. Concatenated, they equal done.reply.
doneThe full turnLast event.
error{ error, code, httpStatus, conversationId?, messageAccepted? }Instead of deltas and done, when the turn fails after the stream started.

Event stream

event: status
data: {"state":"thinking","conversationId":"6f1c..."}

event: delta
data: {"text":"Yes, the Brown Boot comes in 42. "}

event: delta
data: {"text":"Would you like the brown or the black?"}

event: done
data: {"conversationId":"6f1c...","status":"needs_input","reply":"Yes, the Brown Boot comes in 42. Would you like the brown or the black?","messageAccepted":true}

Reliability

  • A turn is not idempotent. Do not blindly retry a failed start or reply. When the error carries messageAccepted, read the conversation first.
  • transcriptSaved: false means the reply was generated but could not be confirmed in the transcript. Show it, do not resend.
  • Turns wait for the full checked reply, typically a few seconds. Use a 60 second client timeout, or stream.
  • The response does not list knowledge sources yet. A sources field will be added when the reply pipeline exposes them, and will never be guessed.

Install

@octadezx/sdk (available, v0.1.0, MIT license)

Server SDK for Node.js 20 and newer: Agent API with streaming, signed user tokens, webhook verification and devices.

npm install @octadezx/sdk

@octadezx/sdk on npm

Questions or a larger rollout? Contact us (kevin@octadezx.com).

Frequently asked questions

Keep reading

OctaDezx home · Pricing · Blog · Start free trial