Skip to content
Hoody.com

A Bot is a long-lived assistant of the Hoody Agent. It works by opening delegate sessions on containers and agents, following them, and reporting back what they did. Create a Bot (or use the default Bot, chief, which is created on first use), post a message (the reply arrives on the stream and in the log), follow it, and stop a delegate when needed.

This page is not the Hoody Bot service at /api/bot/, which controls Hoody from a chat app. Bots here run on the agent.

A Bot lives in one realm: global (not tied to a realm, its delegates see every container of the account) or a realm id. Name the realm with X-Hoody-Realm or ?realm=; omitted, the agent’s current realm. ?realm=all is accepted only on GET /bots; anywhere else it is 400 bad_request. An agent pinned to one realm refuses any other realm, and all, with 400 realm_scope_unsupported.

Guardrails are limits on the work, not instructions to the Bot. They apply to the Bot and to every delegate it opens.

The sessions a Bot opens are listed with List a Bot’s delegates and read with the sessions routes (see Sessions).

Every Bot also has a per-realm URL at /api/v1/agent/bots/{realm}/{bot}, ready to paste as the base URL of an OpenAI client (<base>/v1), an Anthropic client (<base>), or an MCP client (<base>/mcp). The compat paths under /api/v1/agent/compat/openai/v1/... and /api/v1/agent/compat/anthropic/v1/... reach the same Bots. Apps send any Authorization or x-api-key value; access is decided before the request reaches the agent.


Lists the realm’s Bots, sorted by id. The default Bot, chief, is created on first use, so the list is never empty. With ?realm=all it lists the Bots of every realm this login serves, global included, sorted by realm and then id; each row carries its realm and address. Under ?realm=all, chief is not created in a realm that has no Bots yet.

NameInTypeRequiredDescription
realmquerystringNoThe realm to list: global (Bots not tied to a realm), a 24-hex realm id, or all for every realm this login serves, global included. Also accepted as the X-Hoody-Realm header, except all. Omitted, the agent’s current realm.
pagequeryintegerNo1-based page number for pagination.
limitqueryintegerNoMaximum items per page (0 = no pagination).
X-Hoody-RealmheaderstringNoPer-request realm selector: global (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots?realm=global" \
-H "Authorization: Bearer <token>"

Returns one Bot. chief is created on first use. The Bot’s live progress is on its own session: follow session_id with GET /sessions/{session_id}/stream for its reply text and thinking as they are generated, its tool calls and the end of each turn (event.agent_done). GET /bots/{id}/stream carries only the finished log rows. There is no stop route for the Bot itself: to stop its running turn, POST /sessions/{session_id}/cancel. stopBotDelegate stops one of its delegates, not the Bot.

NameInTypeRequiredDescription
idpathstringYesThe bot id.
X-Hoody-RealmheaderstringNoPer-request realm selector: global (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent).
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/chief" \
-H "Authorization: Bearer <token>"

Returns the Bot’s log in order: the messages posted to it, its replies, and the delegate events it was told about. Pages by seq: pass next_since back as since while has_more is true. POST /bots/{id}/forget moves the rows to the archive.

NameInTypeRequiredDescription
idpathstringYesThe bot id.
sincequeryintegerNoReturn only rows whose seq is greater than this: the next_since of the previous page. Default 0.
limitqueryintegerNoAt most this many rows: 100 when omitted or 0, at most 500 (a larger value reads 500). Negative or non-integer = 400. These routes page by since, not by page number: ?page is 400.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header.
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/chief/log?since=0&limit=100" \
-H "Authorization: Bearer <token>"

Server-Sent Events of the Bot’s log: first a state frame (the Bot as GET /bots/{id} returns it), then the rows after since, then each new row as it is written, and a new state frame whenever the Bot changes. Each row frame’s id is the row’s seq: to resume, reconnect with the Last-Event-ID header (an EventSource sends it by itself) or ?since=<last id>. A resume cursor whose rows were moved to the archive in the meantime (POST /bots/{id}/forget or /reset), or one ahead of the log (the Bot was deleted and created again), is answered with a lagged frame (code replay_gap) before the rows the log still holds. A client that reads too slowly is caught up from the stored log, not dropped.

This stream carries finished rows only: the Bot’s reply is one bot row written when its turn ends, and a turn that ends without reply text writes no row. For a chat view that shows the reply as it is written, the Bot’s thinking, its tool calls and when a turn starts and ends, also follow the Bot’s own session: GET /sessions/{session_id}/stream, with session_id from the state frame (it changes after POST /bots/{id}/reset). Do not answer the questions on that session whose frame_request kind starts with bot.: the Bot runtime answers them.

An end frame is sent when the Bot is deleted or the server ends the stream. Heartbeat comments every 15 s. The stream counts toward the per-IP stream cap (--http-max-streams-per-ip).

NameInTypeRequiredDescription
idpathstringYesThe bot id.
sincequeryintegerNoReturn only rows whose seq is greater than this. Default 0.
Last-Event-IDheaderstringNoSSE resume cursor: the id (a non-negative integer seq) of the last frame received. It overrides ?since, and an SSE client sends it on reconnect. Another value is 400 bad_request.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header.
Terminal window
curl -N "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/chief/stream?since=0" \
-H "Authorization: Bearer <token>"

Returns the log rows moved out of the log by POST /bots/{id}/forget and /reset, oldest first. Pages by seq: pass next_since back as since while has_more is true. POST /bots/{id}/purge deletes them.

NameInTypeRequiredDescription
idpathstringYesThe bot id.
sincequeryintegerNoReturn only rows whose seq is greater than this: the next_since of the previous page. Default 0.
limitqueryintegerNoAt most this many rows: 100 when omitted or 0, at most 500 (a larger value reads 500). Negative or non-integer = 400. These routes page by since, not by page number: ?page is 400.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header.
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/chief/archive?since=0&limit=100" \
-H "Authorization: Bearer <token>"

Lists the sessions the Bot opened, open and closed, by when it opened them; state=open or state=closed lists only those. Each delegate is an ordinary session: read or attach it with the /sessions routes. The open delegates of the page also carry how soon they read a message (capability) and what they are doing (current_step), read from their sessions as the list is served. Each delegate also carries the Bot’s messages it has not read yet (queued_commands) and the last message or stop sent to it (last_command).

NameInTypeRequiredDescription
idpathstringYesThe bot id.
statequerystringNoopen or closed: list only the delegates in that state. Omitted: both.
pagequeryintegerNo1-based page number for pagination.
limitqueryintegerNoMaximum items per page (0 = no pagination).
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header.
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/chief/delegates?state=open" \
-H "Authorization: Bearer <token>"

Creates a Bot: a long-lived assistant that works by opening delegate sessions on containers and agents, following them, and reporting back what they did. Its own session is opened when the first message is posted. guardrails are limits on the work, not instructions to the Bot: they apply to the Bot and to every delegate it opens. The Bot receives them before its next message, and each delegate receives them at the top of its first prompt as limits set by the owner of the work.

NameInTypeRequiredDescription
X-Hoody-RealmheaderstringNoPer-request realm selector: global or a 24-hex realm id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header.
FieldTypeRequiredDescription
idstringNoThe Bot’s id. Omit it to have one generated. It cannot be changed later. To retry a create safely, pass an id: when the first try created the Bot, the retry answers 409 bot_exists. Pattern: ^[a-z0-9][a-z0-9_-]{0,63}$.
namestringNoDisplay name. Omitted, it is the id.
rolestringNoWhat the Bot is for, in one paragraph. Max length: 1000.
modelstringNoThe model the Bot’s session runs. Omit it for the bot agent’s own model. A model no session could start with is refused 422 model_unavailable.
guardrailsstringNoLimits that apply to the Bot and to every delegate it opens.
allowed_containersarray of stringNoContainers delegates may run on. Empty or omitted means any.
allowed_agentsarray of stringNoAgents delegates may run. Empty or omitted means any.
yolobooleanNoRun every delegate with YOLO mode on (approvals granted without asking). Default false.
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"id": "release-bot",
"name": "Release Bot",
"role": "Keeps the deploy pipeline moving.",
"guardrails": "Never push to main."
}'

Queues a message for the Bot and answers 202. When the Bot is free the message is posted within a few seconds and turn_id names the Bot turn it started; while the Bot is busy the answer comes at once with state queued, and the message is posted when the Bot’s current turn ends. Each message reaches the Bot with its own id and the time it was accepted. When the Bot’s turn ends, every message accepted before the Bot’s next post is put together goes out in that post, in order, so a correction sent while the Bot was busy is read with the message it corrects; a message accepted after that waits for the turn after. A delegate reads at its own cutoff: everything the Bot passes on to it before its next step is read together at that step. A correction the Bot passes on after the delegate already took the first message reaches it at its following step, in order; nothing already passed on is taken back. A message sent while a gate on the Bot’s own session waits for you (pending_gate on GET /bots/{id}) declines that gate, telling the Bot you sent a new message, and is posted when the Bot’s turn ends.

The Bot’s reply arrives on GET /bots/{id}/stream and in GET /bots/{id}/log. Only a turn started from a posted message may approve or answer a delegate’s gate; a turn started from a delegate event cannot.

With an Idempotency-Key, a retry with the same key and text returns the same message_id and the message’s current state, and queues nothing again; the same key with a different text is refused 422. A key is remembered while its message is queued and for at least 24 hours after the message was accepted. At most 4096 keys are remembered at once: a new keyed message beyond that is refused 429 and nothing is queued. Follow the message by message_id: its user row in the log carries it, and the bot row with the reply follows once its turn ends. A 503 means the message was not queued: send it again.

NameInTypeRequiredDescription
idpathstringYesThe bot id.
Idempotency-KeyheaderstringNoOpaque retry key (1 to 255 printable ASCII, no whitespace). A retry with the same key and text returns the same message_id and the message’s current state, and queues nothing again; the same key with a different text is 422. A key is remembered while its message is queued and for at least 24 hours after it was accepted.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header.
FieldTypeRequiredDescription
textstringYesThe message (at most 64 KiB).
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/chief/messages" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: bot-req-2026-10-08-001" \
-d '{
"text": "What is the status of the release?"
}'

Changes the fields the body names. name and role are announced to the Bot before its next message. id, uid, realm, created, created_at and created_by never change: a body that names one is refused 400 field_immutable and nothing changes. yolo applies at once to every open delegate. allowed_containers and allowed_agents apply to the next delegate the Bot opens. model applies to the Bot’s next session: the running session keeps its model until POST /bots/{id}/reset starts a new one. Guardrails are changed with PUT /bots/{id}/guardrails.

NameInTypeRequiredDescription
idpathstringYesThe bot id.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header.
FieldTypeRequiredDescription
namestringNoDisplay name.
rolestringNoWhat the Bot is for, in one paragraph. Empty clears it. Max length: 1000.
modelstringNoThe model of the Bot’s next session, started by POST /bots/{id}/reset; the running session keeps its model. Empty for the bot agent’s own model. A model no session could start with is refused 422 model_unavailable and nothing changes.
allowed_containersarray of stringNoContainers delegates may run on. Empty means any.
allowed_agentsarray of stringNoAgents delegates may run. Empty means any.
yolobooleanNoYOLO mode for every delegate.
Terminal window
curl -X PATCH "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/chief" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"name": "Chief",
"role": "Keeps the web app's releases moving."
}'

Replaces the Bot’s guardrails: limits on the work that apply to the Bot and to every delegate it opens, not instructions to the Bot. The Bot receives the new text, each line marked [guardrails updated], before its next message (an empty text is announced as none). Delegates opened from then on receive it at the top of their first prompt as limits set by the owner of the work; open delegates keep the limits they were given.

NameInTypeRequiredDescription
idpathstringYesThe bot id.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header.
FieldTypeRequiredDescription
guardrailsstringYesThe new limits; empty clears them.
Terminal window
curl -X PUT "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/chief/guardrails" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"guardrails": "Never push to main."
}'

Moves the log to the archive and clears the Bot session’s conversation (posted as /clear when the Bot is free). The Bot keeps its settings and its delegates, and receives its guardrails again before the next message.

NameInTypeRequiredDescription
idpathstringYesThe bot id.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header.
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/chief/forget" \
-H "Authorization: Bearer <token>"

Moves the log to the archive and starts a new session for the Bot (with its current model). Its delegates stay its own; messages not yet posted are posted to the new session. The old session is not closed.

NameInTypeRequiredDescription
idpathstringYesThe bot id.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header.
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/chief/reset" \
-H "Authorization: Bearer <token>"

Deletes the rows forget and reset moved to the archive. The log is not touched.

NameInTypeRequiredDescription
idpathstringYesThe bot id.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header.
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/chief/purge" \
-H "Authorization: Bearer <token>"

POST /api/v1/agent/bots/{id}/delegates/{sid}/stop

Section titled “POST /api/v1/agent/bots/{id}/delegates/{sid}/stop”

Stops the delegate’s work at once, whatever the Bot is doing: its running turn, its background tasks, workflow runs and shells end, its loops pause, and messages from the Bot it has not read yet are dropped. With close true its session is then closed. It stops a delegate, never the Bot: to stop the Bot’s own running turn, POST /sessions/{session_id}/cancel on the Bot’s session_id (GET /bots/{id}). Answers 200 once the work is stopped, or 202 when the session is still stopping it after a few seconds (it finishes without you; GET /bots/{id}/delegates shows the outcome in last_command). The Bot learns of it from the delegate’s report.

With an Idempotency-Key, sending the same stop again returns its outcome and stops nothing twice; the same key with a different close is 422. A 503 means the stop was not sent yet: send it again with the same key.

NameInTypeRequiredDescription
idpathstringYesThe bot id.
sidpathstringYesThe delegate id.
Idempotency-KeyheaderstringNoOpaque retry key (1 to 255 printable ASCII, no whitespace). The same stop sent again with the same key returns its outcome; the same key with a different close is 422.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header.
FieldTypeRequiredDescription
closebooleanNoAlso close the delegate’s session for good. Default false.
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/chief/delegates/9a1be4c07d2f4c11/stop" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: stop-2026-10-08-001" \
-d '{
"close": true
}'

Deletes the Bot and its log and archive. First, best effort and for at most a few seconds: every open delegate that is working or waiting on an approval is stopped, an approval the stop did not reach is declined, and auto-approve is turned off on the delegates the Bot turned it on for. Its session and its delegates are not closed: they stay listed under GET /sessions, a person can continue them, and they end like any idle session. Deleting chief removes it; the next use creates a new one.

NameInTypeRequiredDescription
idpathstringYesThe bot id.
X-Hoody-RealmheaderstringNoPer-request realm selector. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header.
Terminal window
curl -X DELETE "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/chief" \
-H "Authorization: Bearer <token>"

Every Bot has a per-realm URL ready to paste as the base URL of an OpenAI client, an Anthropic client, or an MCP client. realm is global or a 24-hex realm id; the short form …/bots/{bot}/… uses the agent’s current realm instead, and a Bot whose id is global or 24 hex is reached by the long form only. GET /bots/{id} lists a Bot’s URLs under urls. The path is read forgivingly: repeated slashes, a trailing slash, a missing or doubled /v1, and a whole …/chat/completions or …/messages URL pasted as the base all reach the same Bot. The Authorization and x-api-key headers are ignored: apps may send any value, and access is decided before the request reaches the agent.

The MCP server is stateless: it sends no event stream and keeps no session. POST each request, end the session with a DELETE that the server answers 405 (Allow: POST). A GET of /mcp with Accept: text/event-stream answers 405 (Allow: POST).

Only the last message is read, and it must be a user message with text only (an image, audio or file part is refused 400). A side request an app makes on the model (a conversation title, a summary, follow-up suggestions, tags, or an autocompletion: recognised by its system prompt or task text, or by a max_tokens of 64 or less) is not posted: the Bot’s model answers it in one completion, outside the Bot’s history. System prompts, client tools, sampling settings and max_tokens are otherwise ignored, and a tool_choice that forces a tool is refused 400. With stream: true the body becomes a Server-Sent Events stream of the same reply.

A request sent again with the same messages within 2 minutes, while its answer was never delivered in full, gets that answer without posting again. An Idempotency-Key header names the message instead: the same key always gets the same answer. A non-streamed request waits up to 100 seconds for the reply; a streamed one sends keepalives and waits up to 10 minutes. The Bot is one conversation shared by every app that talks to it.

A GET of the Bot URL answers a short text page that starts with This is the URL of Bot <name> (bot:<realm>/<id>) and says what to paste where. Model doors (/v1/models) return the one-model list in the client format. A GET of /mcp with Accept: text/event-stream answers 405 (Allow: POST).

NameInTypeRequiredDescription
realmpathstringYesThe realm.
botpathstringYesThe bot.
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/global/chief" \
-H "Authorization: Bearer <token>"

GET /api/v1/agent/bots/{realm}/{bot}/{door}

Section titled “GET /api/v1/agent/bots/{realm}/{bot}/{door}”

A GET of a Bot door returns the help page (text/plain) on the base URL, chat URL, and an unknown door; returns the one-model list (application/json) on a model door; and answers 405 (Allow: POST) on /mcp with Accept: text/event-stream. An unknown door returns 404.

NameInTypeRequiredDescription
realmpathstringYesThe realm.
botpathstringYesThe bot.
doorpathstringYesThe door.
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/global/chief/v1/models" \
-H "Authorization: Bearer <token>"

Posts the last user message of the body to the Bot. The body uses the OpenAI, Anthropic, or MCP client format. With stream: true the answer is a Server-Sent Events stream; otherwise a JSON body. A POST of /mcp is an MCP request. The Authorization and x-api-key headers are ignored: apps may send any value, and access is decided before the request reaches the agent.

NameInTypeRequiredDescription
realmpathstringYesThe realm.
botpathstringYesThe bot.
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/global/chief/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-H "Idempotency-Key: req-2026-10-08-001" \
-d '{
"model": "bot:global/chief",
"messages": [
{ "role": "user", "content": "What is the status of the release?" }
]
}'

POST /api/v1/agent/bots/{realm}/{bot}/{door}

Section titled “POST /api/v1/agent/bots/{realm}/{bot}/{door}”

Posts the last user message of the body to the Bot through the named door. With stream: true the answer is a Server-Sent Events stream; otherwise a JSON body in the client format of the door. A POST of /mcp is an MCP request. The Authorization and x-api-key headers are ignored: apps may send any value, and access is decided before the request reaches the agent.

NameInTypeRequiredDescription
realmpathstringYesThe realm.
botpathstringYesThe bot.
doorpathstringYesThe door.
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/global/chief/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-H "Idempotency-Key: req-2026-10-08-002" \
-d '{
"model": "bot:global/chief",
"messages": [
{ "role": "user", "content": "What is the status of the release?" }
]
}'

The MCP server is stateless and has no session to end, so a DELETE of /mcp or the base URL answers 405 (Allow: POST). A DELETE of any other door is 404. The 200 response is documented for completeness but is not actually returned in practice.

NameInTypeRequiredDescription
realmpathstringYesThe realm.
botpathstringYesThe bot.
Terminal window
curl -X DELETE "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/global/chief/mcp" \
-H "Authorization: Bearer <token>"

DELETE /api/v1/agent/bots/{realm}/{bot}/{door}

Section titled “DELETE /api/v1/agent/bots/{realm}/{bot}/{door}”

The MCP server is stateless and has no session to end, so a DELETE of /mcp or the base URL answers 405 (Allow: POST). A DELETE of any other door is 404. The 200 response is documented for completeness but is not actually returned in practice.

NameInTypeRequiredDescription
realmpathstringYesThe realm.
botpathstringYesThe bot.
doorpathstringYesThe door.
Terminal window
curl -X DELETE "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/bots/global/chief/mcp" \
-H "Authorization: Bearer <token>"

The compat paths under /api/v1/agent/compat/anthropic/v1/... reach the same Bots as the Bot URL. Each Bot is a model whose id is its address, bot:<realm>/<id> (for example bot:global/chief); a bare Bot id names a Bot of the realm X-Hoody-Realm names, else of the agent’s current realm. The Authorization and x-api-key headers are ignored: apps may send any value, and access is decided before the request reaches the agent. Errors use this format’s own error body, not the agent’s. The path is read forgivingly: repeated slashes, a trailing slash, a missing or doubled /v1, and a whole …/chat/completions or …/messages URL pasted as the base all reach the same route.

GET /api/v1/agent/compat/anthropic/v1/models

Section titled “GET /api/v1/agent/compat/anthropic/v1/models”

Lists every Bot of every realm this login serves (an agent pinned to one realm: that realm’s Bots), in the Anthropic-compatible model list shape.

NameInTypeRequiredDescription
X-Hoody-RealmheaderstringNoPer-request realm selector: global (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global (not tied to a realm) or a 24-hex realm id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/compat/anthropic/v1/models" \
-H "x-api-key: <token>"

GET /api/v1/agent/compat/anthropic/v1/models/{model}

Section titled “GET /api/v1/agent/compat/anthropic/v1/models/{model}”

Reads the Bot named model in the Anthropic-compatible model shape. An unknown Bot, or a realm this login does not serve, answers 404.

NameInTypeRequiredDescription
modelpathstringYesThe model.
X-Hoody-RealmheaderstringNoPer-request realm selector: global (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global (not tied to a realm) or a 24-hex realm id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/compat/anthropic/v1/models/bot:global/chief" \
-H "x-api-key: <token>"

POST /api/v1/agent/compat/anthropic/v1/messages

Section titled “POST /api/v1/agent/compat/anthropic/v1/messages”

Posts the last user message to the Bot the model names and answers with the Bot’s reply, in the Anthropic Messages shape: JSON, or Server-Sent Events when the body sets stream to true. With stream true, the body carries the message_start through message_stop events instead of a JSON message.

NameInTypeRequiredDescription
X-Hoody-RealmheaderstringNoPer-request realm selector: global (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global (not tied to a realm) or a 24-hex realm id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/compat/anthropic/v1/messages" \
-H "Content-Type: application/json" \
-H "anthropic-version: 2023-06-01" \
-H "x-api-key: <token>" \
-H "Idempotency-Key: req-2026-10-08-003" \
-d '{
"model": "bot:global/chief",
"max_tokens": 1024,
"messages": [
{ "role": "user", "content": "What is the status of the release?" }
]
}'

The compat paths under /api/v1/agent/compat/openai/v1/... reach the same Bots as the Bot URL. Each Bot is a model whose id is its address, bot:<realm>/<id> (for example bot:global/chief); a bare Bot id names a Bot of the realm X-Hoody-Realm names, else of the agent’s current realm. The Authorization and x-api-key headers are ignored: apps may send any value, and access is decided before the request reaches the agent. Errors use this format’s own error body, not the agent’s. The path is read forgivingly: repeated slashes, a trailing slash, a missing or doubled /v1, and a whole …/chat/completions or …/messages URL pasted as the base all reach the same route.

Lists every Bot of every realm this login serves (an agent pinned to one realm: that realm’s Bots), in the OpenAI-compatible model list shape.

NameInTypeRequiredDescription
X-Hoody-RealmheaderstringNoPer-request realm selector: global (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global (not tied to a realm) or a 24-hex realm id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/compat/openai/v1/models" \
-H "Authorization: Bearer <token>"

GET /api/v1/agent/compat/openai/v1/models/{model}

Section titled “GET /api/v1/agent/compat/openai/v1/models/{model}”

Reads the Bot named model in the OpenAI-compatible model shape. An unknown Bot, or a realm this login does not serve, answers 404.

NameInTypeRequiredDescription
modelpathstringYesThe model.
X-Hoody-RealmheaderstringNoPer-request realm selector: global (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global (not tied to a realm) or a 24-hex realm id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/compat/openai/v1/models/bot:global/chief" \
-H "Authorization: Bearer <token>"

POST /api/v1/agent/compat/openai/v1/chat/completions

Section titled “POST /api/v1/agent/compat/openai/v1/chat/completions”

Posts the last user message to the Bot the model names and answers with the Bot’s reply, in the OpenAI chat completions shape: JSON, or Server-Sent Events when the body sets stream to true. With stream true, the body carries the chat.completion.chunk events ending in [DONE] instead of a JSON completion.

NameInTypeRequiredDescription
X-Hoody-RealmheaderstringNoPer-request realm selector: global (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global (not tied to a realm) or a 24-hex realm id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/compat/openai/v1/chat/completions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-H "Idempotency-Key: req-2026-10-08-004" \
-d '{
"model": "bot:global/chief",
"messages": [
{ "role": "user", "content": "What is the status of the release?" }
]
}'

POST /api/v1/agent/compat/openai/v1/responses

Section titled “POST /api/v1/agent/compat/openai/v1/responses”

Posts the last user message of input (a string, or a list of messages) to the Bot the model names and answers with the Bot’s reply in the OpenAI Responses shape: JSON, or Server-Sent Events when the body sets stream to true. Nothing is stored: previous_response_id and store are ignored. With stream true, the body carries the response.created through response.completed events instead of a JSON response.

NameInTypeRequiredDescription
X-Hoody-RealmheaderstringNoPer-request realm selector: global (not tied to a realm) or a 24-hex realm id (also accepted as ?realm=). On a session route it names the realm the session is looked up in: a session in another realm, or in a realm this login does not serve, is 404 not_found. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
realmquerystringNoPer-request realm selector, the in:query alias of the X-Hoody-Realm header (read only when the header is absent): global (not tied to a realm) or a 24-hex realm id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes, and for any other realm on an agent pinned to one realm.
Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/compat/openai/v1/responses" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-H "Idempotency-Key: req-2026-10-08-005" \
-d '{
"model": "bot:global/chief",
"input": "What is the status of the release?"
}'