Skip to content

Agents and assistants over the API

An application talks to an agent through the assistant that publishes it. The assistant’s chat endpoint takes the assistant’s own key, needs no sign-in, streams its answer, and runs the agent with its knowledge, tools, skills, collaborators and approvals. This page documents that endpoint, and the separate endpoint builders use to run an agent from a script.

You want to Endpoint Credential
Put an agent in front of your customers or staff, from your own application or site POST /api/v1/public/assistants/<slug>/chat The assistant’s key, from its share link
Run an agent from a script while you build or test it POST /api/v1/tenants/<tenant-id>/agents/<agent-id>/run A builder’s sign-in token

Both are on the console host, not the gateway.

An Admin creates an assistant’s share link when it is published, or later with Get share link. The link has this shape:

https://<your-console-host>/a/<slug>#k=<access-key>

The part after #k= is the assistant’s key. It is shown once and stored nowhere, so copy it then. It can call only that assistant’s model, only for that assistant, in that tenant; the tenant’s budgets and guardrails apply, and every turn is metered against the tenant’s first project. Creating a new link revokes the previous key. See Publish and share.

POST https://<your-console-host>/api/v1/public/assistants/<slug>/chat
Content-Type: application/json
x-api-key: <access-key>
Field Required Notes
message Yes The person’s message, at most 4,000 characters.
threadId No Leave it out to start a conversation; send the one you received to continue it.
endUserRef No Your opaque handle for the person. See The person’s reference.
apiKey No The key, if you cannot send the x-api-key header.
curl -N -s https://<your-console-host>/api/v1/public/assistants/<slug>/chat \
-H "x-api-key: $ASSISTANT_KEY" \
-H 'content-type: application/json' \
-d '{"message":"How do I file a claim?","endUserRef":"cust-4821"}'
import json, os, requests
resp = requests.post(
"https://<your-console-host>/api/v1/public/assistants/<slug>/chat",
headers={"x-api-key": os.environ["ASSISTANT_KEY"]},
json={"message": "How do I file a claim?", "endUserRef": "cust-4821"},
stream=True,
timeout=200,
)
resp.raise_for_status()
for line in resp.iter_lines(decode_unicode=True):
if not line or not line.startswith("data: "):
continue
frame = json.loads(line[len("data: "):])
if "delta" in frame:
print(frame["delta"], end="", flush=True)
elif frame.get("done"):
print("\n", frame.get("usage"))
thread_id = frame.get("threadId")

The answer is a stream of server-sent events. Each event is one line, data: <json>, and the JSON is one of these frames, in this order:

Frame Meaning
{"threadId": "..."} The conversation this turn belongs to. Keep it to continue.
{"sources": [...]} The passages the answer is grounded on, when the agent has knowledge.
{"step": {...}, "index": n} A step the agent took, such as a tool call, when the assistant runs its agent with tools.
{"delta": "..."} The next piece of the answer.
{"done": true, "usage": {...}, ...} The end of the turn, with promptTokens, completionTokens and totalTokens.
{"error": "...", "detail": "..."} The turn failed; detail says why.

When the agent asks for a tool that waits for a person, the done frame also carries "waiting": true and the pending approvals. The answer arrives once an Admin or Reviewer decides; read the conversation back to get it.

GET https://<your-console-host>/api/v1/public/assistants/<slug>/threads/<thread-id>
x-api-key: <access-key>

The response is the conversation with its messages. Use it after a turn that was waiting for an approval, or to restore a conversation in your interface.

A conversation is erasable by person only if it was stored with a reference to that person. Send endUserRef on the first turn of each conversation: the opaque handle your application already uses for the person, such as a customer number. It must not be personal data: no @, at most 200 characters; otherwise the turn is refused with 400 bad_end_user_ref.

If you send none, Olympusx AI issues a reference for the conversation and returns it in the X-Olympus-Visitor-Ref response header. Keep it with the conversation: it is what Govern › Erasure needs to find it.

On the share link, the same handle goes in the fragment as u:

https://<your-console-host>/a/<slug>#k=<access-key>&u=<your-handle-for-this-person>

See Erasure.

Public assistant chat is limited per tenant, across all its assistants and links: 60 requests a minute by default, unless the tenant has a rate limit of its own. Over it, a turn is refused with HTTP 429, the OpenAI error object with code request_rate_exceeded, and a Retry-After header in seconds. Your platform administrator can change the default. See Limits.

Status error or code Cause
400 message_required, message_too_long, bad_end_user_ref, bad_json The request body.
401 key_required, invalid_key, key_expired, key_disabled The key is missing, wrong, expired or was replaced by a new link.
403 key_not_for_assistant, wrong_tenant The key belongs to another assistant or tenant.
403 model_not_granted, guardrails_blocked The tenant lost the model, or the policy blocked the message.
404 not_found No assistant with that slug, or it is disabled.
429 budget_exceeded, request_rate_exceeded A budget is spent, or the rate limit is reached.

Builders and Admins can run an agent from a script, with their own sign-in token, the same way Preview does. It is meant for testing and automation by the people who build agents, not for application traffic: a person’s token expires within minutes and carries their role.

curl -s -X POST https://<your-console-host>/api/v1/tenants/<tenant-id>/agents/<agent-id>/run \
-H "Authorization: Bearer $TOKEN" \
-H 'content-type: application/json' \
-d '{"message":"Which claims are waiting on documents?","maxToolCalls":10}'
Field Notes
message Required.
sessionId Continue a conversation with this agent; leave out to start one.
stream true for server-sent events, as with Accept: text/event-stream.
maxToolCalls, maxModelCalls, maxTokens Ceilings for this run. Left out, the agent’s own ceilings apply, or the defaults of 20, 25 and 200,000.

The response holds runId, sessionId, outcome (ok, ceiling, failed or needs_approval), answer, toolCalls, modelCalls, tokens, sources, steps, elapsedMs, and for a held call, pending with each approval’s id, tool and expiresAt. A run lasts at most 5 minutes. The request body is at most 1 MiB. Every run appears in Operate › Runs.