REST APIMenu de la documentation

Developers

REST API

Call a Harmona agent from your own backend: create an agent API key, stream replies over server-sent events, keep per-user history and handle errors.

La documentation existe en anglais et en turc, comme l'interface de Harmona. Cette page est affichée en anglais.

Any agent can answer over HTTPS. An API key belongs to one agent, so requests never name the agent. You identify your own end users with your own IDs, and each of them gets a conversation that persists between calls. API access is included on Individual, Business and Enterprise plans.

Turn on API access and create a key

  1. 1Open the agent in Studio → Agents and open its Output Channels.
  2. 2Turn on API Access.
  3. 3Under API Keys, select Create Key and name it, for example "Production".
  4. 4Copy the key. It starts with hapi_ and is shown only once.
API Access is off for every new agent. Turn it on for each agent you want to call; the other agents stay unreachable over the API.

Only organization admins can create keys. Keys created in the app don't expire. Use one key per environment or app, so you can revoke one without touching the others.

Attention

Harmona stores only the key's prefix, so a lost key can't be shown again; delete it and create a new one. Deleting a key revokes it immediately, and every integration that uses it stops working at once.

Authentication and base URL

Send the key as a bearer token on every request. On Harmona Cloud the base URL is https://api.harmona.ai; on private cloud or on-premises, use your own deployment's API address. Every endpoint is under /b2c/v1.

Authorization: Bearer hapi_your_key

Danger

Keep the key on your server, never in browser JavaScript or a mobile app. Anyone who has it can talk to the agent, read what its connections hold, and run up usage billed to your workspace. If a key leaks, delete it right away.

Endpoints

POST/b2c/v1/chat

Sends a turn and streams the agent's reply.

GET/b2c/v1/chat/rooms

Lists an end user's conversations, newest first.

GET/b2c/v1/chat/messages

Returns a conversation's history.

GET/b2c/v1/chat/handoff

Returns a conversation as plain text, for handing it to a person.

GET/b2c/v1/widget-config

Returns the Web SDK settings configured in Harmona.

Send a message

FieldRequiredDescription
external_user_idYesYour ID for the end user, up to 255 characters. The same value always returns to the same user's conversations.
messagesYesThe turn, as a list of objects with role (user or assistant) and content. The last message must come from the user. You can put a greeting you showed earlier before it, as an assistant message.
room_idNoContinue a specific conversation. Without it, the user's most recently active conversation continues; the first call creates it.
room_nameNoA name for the conversation when it is created.
curl -N https://api.harmona.ai/b2c/v1/chat \
  -H "Authorization: Bearer hapi_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "external_user_id": "customer-4821",
    "messages": [{ "role": "user", "content": "Where is my order?" }]
  }'

Reading the stream

The reply is a text/event-stream. Each frame is a line that starts with data: followed by JSON, and the stream ends with data: [DONE]. The frames are agent run events. The reply you show arrives in events named on_chain_stream, in data.chunk:

  • type: printable carries reply text in content. Skip chunks where is_thinking is true.
  • type: tool carries a structured result in artifact, with artifact.type and artifact.data, such as product cards or suggested next questions.
  • You can ignore every other event.

A reply looks like this, with each event shortened:

data: {"event": "on_chain_stream", "data": {"chunk": {"type": "printable", "content": "Your order left "}}, ...}
data: {"event": "on_chain_stream", "data": {"chunk": {"type": "printable", "content": "our warehouse today."}}, ...}
data: [DONE]

If the agent fails mid-reply, the stream sends a short apology as printable text, then an error event with data.error and data.error_code, then [DONE]. The code is rate_limit_exceeded when the model provider is busy (try again shortly) and internal_error otherwise.

A minimal reader in Node.js 18 or later:

const res = await fetch("https://api.harmona.ai/b2c/v1/chat", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.HARMONA_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    external_user_id: "customer-4821",
    messages: [{ role: "user", content: "Where is my order?" }],
  }),
});
if (!res.ok) throw new Error(`Harmona ${res.status}: ${await res.text()}`);

const decoder = new TextDecoder();
let buffer = "";
for await (const bytes of res.body) {
  buffer += decoder.decode(bytes, { stream: true });
  const frames = buffer.split("\n\n");
  buffer = frames.pop();
  for (const frame of frames) {
    const payload = frame.replace(/^data: /, "");
    if (payload === "[DONE]") continue;
    const evt = JSON.parse(payload);
    const chunk = evt.data?.chunk;
    if (evt.event === "on_chain_stream" && chunk?.type === "printable" && !chunk.is_thinking) {
      process.stdout.write(chunk.content);
    }
    if (evt.event === "error") console.error(evt.data.error_code);
  }
}

Conversations and history

  • GET /chat/rooms?external_user_id=… returns each conversation's room_id, room_name, created_at and updated_at.
  • GET /chat/messages?external_user_id=… returns the history. Add room_id for a specific conversation, limit (1–200, default 50) and offset for paging.
  • GET /chat/handoff?external_user_id=… returns agent_name and messages, a flat list of role (human or ai) and content. Tool steps are left out, so you can pass it straight to a support agent.

Errors

Error responses are JSON with a detail message. Most also carry an error_code. Branch on the code, not on the message: the message is in English and may change.

{
  "detail": "…",
  "error_code": "usage_limit_exceeded"
}
Statuserror_codeMeaning
400validation_errorThe body is invalid, for example the last message isn't from the user.
401noneThe key is missing, wrong, expired or deleted, or API access is turned off for the agent.
402usage_limit_exceededThe workspace has used its credits or reached its usage threshold.
402subscription_past_dueA card payment failed and is still open. It is retried automatically on day 1, 3 and 7.
402subscription_inactiveThe subscription is suspended or canceled.
402trial_expiredThe workspace's free trial has ended.
404room_not_foundThe room_id doesn't exist or belongs to another agent.
409noneThe agent can't chat right now. Check its model and instructions.
503noneA temporary problem. Retry.

Handling 402 errors

Don't retry a 402 automatically: it won't succeed until someone acts. Show your users a neutral message and alert your own team. The workspace Owner resolves it by buying credits, raising the threshold or settling the subscription; see Plans and credits.

Mis à jour 2026-09-24