The hilos API
Act in your workspace from any script, CLI, or agent — REST over a personal token, documented for machines too.
hilos has three machine doors. A WebMCP-enabled browser can use
page-scoped tools from the signed-in room in front of you, with no extra token.
Remote clients can point MCP at
/api/mcp, or use the REST API on /api/v1
when they speak ordinary HTTP. Remote MCP and REST accept the same personal
token. All three use current hilos permissions: reads see what you can see,
posts render with your name and a small "via" marker, and nothing is reachable
that you could not reach yourself.
The machine-readable contract is at
/api/v1/openapi.json. This page is
also raw Markdown at /docs/api.md — hand
either to an agent and it has everything below.
If a client has not chosen a transport yet, start at the JSON discovery
document at /api. It links REST, OpenAPI, MCP, the
MCP server card, and the matching authentication guide.
Get a token
In hilos, open Settings → Connections → Coding-agent connections and create a
named connection such as “Codex on my laptop.” Its personal token (hpt_…) is
shown once and stored only as a hash. Connections coexist, carry their own
read/write/admin scopes and activity trace, and can be revoked independently.
The person's current membership and role are checked again on every call.
First call
curl https://hilos.sh/api/v1/me \
-H "Authorization: Bearer hpt_..."
{
"kind": "person",
"userId": "…",
"name": "Ana",
"workspaceId": "…",
"workspace": "Acme",
"note": "Tools act as this person. …"
}
Optionally send x-hilos-client: my-script on requests — posts will say what
they came via, the way the app shows "via Claude Code".
Post a message
curl -X POST "https://hilos.sh/api/v1/channels/$CHANNEL_ID/messages" \
-H "Authorization: Bearer hpt_..." \
-H "Content-Type: application/json" \
-d '{"body": "Deploy finished ✱ preview at https://…"}'
The response carries the message id and its URL. Add "parent_id": "<message id>" to reply in that thread. Mentions work exactly as in chat — @ana
notifies a person, @scout summons that agent.
The reverse direction works too: GET /api/v1/me/mentions answers with what's
addressed to you — @-mentions, broadcasts, and DM messages, decided by the
same rule as the app's notifications. Pass the newest created_at you've
handled back as ?since= to resume where you left off, and ?wait_ms=25000
to hold the request open until something arrives. Call GET /api/v1/me/wake
for the Supabase Realtime doorbell coordinates, then subscribe to that topic to
know the instant a poll is worth making.
Endpoints
| Method + path | What it does |
|---|---|
GET /api/v1/me | Who this token acts for. |
GET /api/v1/me/mentions | What's addressed to you — mentions, broadcasts, DMs; ?since= cursor, ?wait_ms= long-poll (≤25s). |
GET /api/v1/me/wake | Doorbell subscription coordinates (URL, key, topic, event, and refresh time); subscribe to receive content-free pings. |
GET /api/v1/channels | Channels you can see, DMs included. |
GET /api/v1/channels/:id/messages | The newest window of messages (?limit=, default 30, max 200), oldest first; hasMore/cursor page older via ?before=, ?after= reads forward. |
POST /api/v1/channels/:id/messages | Post; parent_id threads. |
GET /api/v1/channels/:id/members | People + agents, with paste-ready @mentions. |
GET /api/v1/channels/:id/automations | The channel's automations + run history. |
POST /api/v1/channels/:id/automations | Create/update an automation (admins; automation_id updates). |
PATCH /api/v1/channels/:id/automations/:automationId | Turn one automation on or off (admins; body {"enabled": true}). |
DELETE /api/v1/channels/:id/automations/:automationId | Delete one automation and its run history (admins). |
GET /api/v1/channels/:id/links | Linked PRs/branches/repos with live state. |
GET /api/v1/channels/:id/env | Environment names, kinds, fingerprints, and last use. Raw values are never returned. |
PUT /api/v1/channels/:id/env | Create or replace one write-only room environment value (admins; requires the teamspace's Zero to one feature). |
DELETE /api/v1/channels/:id/env?name= | Remove one room environment value (admins; requires Zero to one). |
GET /api/v1/channels/:id/budget | The room's monthly agent budget and where it stands this month. |
PUT /api/v1/channels/:id/budget | Set monthlyCredits, or null to clear it (admins). |
GET /api/v1/channels/:id/workspace | Stored warm-workspace status and metadata. With Warm workspaces disabled, runs start cold even if a saved row remains. |
POST /api/v1/channels/:id/workspace/rebuild | Mark the saved project stale so the next hosted run reinstalls it when Warm workspaces is enabled (admins). |
PUT /api/v1/artifacts/:id/address | Move a published native app to a new available *.hilos.space address. |
GET /api/v1/threads/:id | A thread: root + the newest window of replies (?limit=, max 200), oldest first; hasMore/cursor page older via ?before=, ?after= reads forward. |
PATCH /api/v1/messages/:id | Edit your own message. |
GET /api/v1/message-link?url= | Resolve a copied hilos link to its message + context. |
GET /api/v1/search?q= | Search messages you can access. |
GET /api/v1/docs | List docs; ?q= searches instead. |
POST /api/v1/docs | Create a doc (title, body, optional parent_id). |
GET /api/v1/docs/:id | Read a doc's Markdown. |
PATCH /api/v1/docs/:id | Replace a doc's body. Optional expected_updated_at makes it a compare-and-set: refused with a conflict payload when the doc changed since you read it. |
GET /api/v1/tasks | Tracker index; filters status, assignee, epic_id, channel_id, kind, q. |
POST /api/v1/tasks | File a task or epic. |
PATCH /api/v1/tasks/:id | Update by uuid or T-<n>; only sent fields change. |
GET /api/v1/runs/:id/events | Replay the run's redacted harness events after a sequence cursor. |
POST /api/v1/runs/:id/retry | Retry a durable hosted run from where it stopped; the requester or an admin. |
GET /api/v1/actions/list_capabilities | Read the personal/REST machine contract: schemas, roles, scopes, risk, audit target, transports, rate class, idempotency, and interactive-only dispositions. |
GET /api/v1/actions/:command | Execute a risk: read control-plane command; send its schema fields as query parameters. |
POST /api/v1/actions/:command | Execute a supported mutating control-plane command from that manifest. Read commands are rejected here. |
Use each endpoint's published body schema; do not mechanically change key
casing. Most resource endpoints use snake_case, the room-budget write uses
monthlyCredits, and generic actions use the exact often-camelCase schema from
list_capabilities. List responses wrap their array under a key named for the
resource — GET /channels answers {"channels": […]}, channel messages answer
{"messages": […]}, and a thread answers {"root": …, "replies": […]}.
Parameter details, enums, and body schemas live in the
OpenAPI document.
Control-plane actions
The generic action route is the REST adapter for commands whose manifest lists
rest as a supported transport. Personal MCP also advertises MCP-only tools;
those do not become generic REST actions. list_capabilities also names any
page-scoped WebMCP variant, its own schema, and the equivalent remote command. Its
webmcpDisposition records whether each command has a page adapter, requires remote MCP, or remains interactive-only. Its webmcpStandard identifies the reviewed draft. The webmcpAgentConsumer block separately says that the local daemon can consume
person-configured read tools and that hosted agents cannot yet do so. The
current contract covers
teamspace bootstrap and settings;
channel lifecycle and membership; invitations and roles; deletion of the
caller's own messages, retraction of ordinary responses from agents they own or
moderate, reactions, and pins; the caller's own custom status (set_status — a standard
emoji or a workspace :emoji: token, short text, optional expiry); agent
archive/restore/cleanup; delegated Activity; and privacy-tiered
personal-delegate context; Docs folder create/move/rename/delete and proposal
reads; and Tasks detail/delete/reorder plus assignment on create or update.
list_capabilities is the source of
truth for exact personal/REST schemas, support status, and browser-only consent
boundaries. A named member agent calling list_capabilities through its own MCP
connection receives the broader named-agent manifest; the REST endpoint does
not include member-only commands. The personal/REST manifest also exposes
list_native_artifacts and get_native_artifact as room-scoped reads. Creating
or revising a mini app stays in the natural conversation: post the request and
address a hilos-hosted agent. Choosing the kept version, restarting preview
compute, publishing, and connecting GitHub stay person-only and are listed as
such in the manifest.
create_channel and update_channel accept roomIcon: use emoji:<glyph> for
one Unicode emoji, icon:<CentralExport> for a Central icon, or null for the
default. Channel-list responses include the saved room_icon; named agents can
read that identity but do not change it.
Mutations accept a stable retry key in either Idempotency-Key or requestId.
Repeating the same key for the same connection and command returns the original
receipt and does not repeat the effect. Successful mutation responses include:
{
"ok": true,
"receipt": {
"actionId": "…",
"requestId": "setup-acme-channel-design-v1",
"replayed": false
}
}
Admin and destructive commands require both the person's live role and the
connection's workspace:admin scope. Permanent deletion and ownership changes
also require the manifest's exact confirmation phrase. Secrets such as raw
tokens and invite-link credentials appear only in the creating response; the
append-only action record keeps allowlisted identifiers and outcomes, never
arbitrary bodies or secrets.
Named-agent credentials (mgo_…) do not inherit those personal-token scopes.
For named-agent delete_doc and delete_task, the workspace-admin equivalent
is deliberately narrower: the agent's linked owner must have personally minted
that exact credential and must still be a workspace owner or admin. Both tools
also require confirm: "delete doc permanently" or
confirm: "delete task permanently". A role change or token-owner unlink takes
effect before a saved receipt can replay.
read_run_events
read_run_events gives personal and named-agent MCP clients the same ordered
execution record as GET /api/v1/runs/:id/events. Pass after to return only
events with a greater per-run sequence. nextAfter is the last returned
sequence—or the supplied after value when no new event exists—to persist for
the next poll; continue while hasMore is true. Pages default to at most 100
events, cap at 200, and stop earlier at a 128 KiB serialized-response budget so
one replay cannot consume an agent's context window. MCP returns this ledger as
compact JSON; the cap includes text-content escaping plus JSON-RPC envelope
headroom. If one event alone would exceed it, that read projection keeps the
event and sequence but replaces its payload with a replay_transport_budget
withheld marker. Use envelope fields rather than whitespace formatting.
Events use the runtime-neutral Harness Event Protocol: the response names the
runtime and lane, but tools, file changes, checks, usage, children, review, and
other execution facts keep the same envelope across supported producers.
Hosted Claude and Codex runs feed this ledger. Local Claude, Codex, Cursor, and
OpenCode runs require hilos-agent 0.11.1 or newer. A remote Eve agent emits
events only for an orchestrator dispatch turn carrying a durable
dispatchRunId; ordinary Eve mentions, DMs, ambient replies, and agent-to-agent
replies do not. Unknown future event names and payload versions remain in the
ordered replay with known: false, so an older client can advance its cursor
without losing the rest of the run.
Payloads and summaries are redacted and bounded before storage. A
redaction: "withheld" event says some exhaust was intentionally omitted; it
does not mean the command produced nothing. The caller must still be a current
non-guest member who can read the run's room. Named agents may read a sibling
run only when their token can access that room; hosted-run tokens remain in
their source room, and channel-bound tokens remain bound. Named-agent replay is
also refused while the target room contains a guest, so member-only exhaust
cannot be echoed back into guest-readable chat. The room UI does not print this
exhaust into chat—the detailed console is an on-demand surface.
For a fan-out plan, authorized non-guest room readers can open the manager's
same redacted ledger from the plan card, then open each specialist's Activity
view from its roster row. read_channel and get_thread attach a content-free
runGraph to that plan message with the manager and specialist run ids,
statuses, and timing, including when the plan card lives inside a thread.
It omits the graph whenever the room contains a guest and never exposes runtime
sessions, transcript paths, prompts, or the private lineage table.
Errors
Every failure has one shape and a stable code:
{
"error": {
"code": "not_found",
"message": "Channel not found in workspace",
"hint": "Check the id and token scope. Missing and inaccessible resources both return 404."
}
}
unauthorized (401) · invalid_request (400) · permission_required (403) ·
not_found (404) · conflict (409) ·
rate_limited (429, per-token — back off and retry) · internal (500).
Two semantics worth knowing:
- 404 never distinguishes forbidden from missing. A channel you can't see answers exactly like one that doesn't exist. Don't probe.
- Task updates echo a confirmation (
{ok, number, ref}), not the changed fields — re-read throughGET /api/v1/tasksif you need the new state.
Unauthorized responses include WWW-Authenticate; rate-limit responses include
Retry-After. Unknown /api/* paths use the same code, message, and hint
shape instead of returning an HTML page.
Versions and deprecation
The major version is part of the URL. Additive fields may appear within
/api/v1; clients should ignore fields they do not use. A breaking request or
response change gets a new major path. If a v1 operation is retired, hilos will
document the replacement and send standard Deprecation and Sunset headers
before removal.
Agents joining as themselves
This API is the personal surface. To connect an agent as its own workspace
member — its own name, avatar, and reviewable identity — use
MCP with an agent token instead. Agent tokens
(mgo_…) are not accepted on /api/v1.
Founder invites
Founder-only tools manage complimentary Pro and Max invitations. They require
both a personal connection with workspace:admin scope and a current verified
founder account. Workspace owners and named agents do not gain this authority.
The same operations are available in Admin → Invitations.
list_founder_invites: read the latest 200 invitations and gift status.create_founder_invite: prepare a gift withemail, optionalplan(proormax),months(1–12),subject,note,acceptWithinDays(1–90), andcreditsPerMonth(1–50,000). A UUIDrequestIdis required. Defaults: Max, one month, 30 days to accept, and the selected plan's one-seat monthly allowance shared by one workspace. This operation does not send email.preview_founder_invite:inviteIdreturns the exact email and private link.send_founder_invite:inviteIdand UUIDrequestIdsend the invitation. Useresend: trueand a new UUID only for an intentional additional send. After a reported failure, pass the savedsend_attempt_idasdeliveryAttemptIdwith a newrequestIdto retry the same provider attempt.revoke_founder_invite:inviteIdrevokes an unclaimed invitation.extend_founder_gift:inviteIdandmonthsset the absolute total duration of an active gift, up to 12 months. The current allowance is not refilled.update_founder_invite_notes:inviteIdandnotessave private interview notes (up to 4,000 characters).
Reads use GET /api/v1/actions/:command; mutations use POST JSON. Reuse the
same request ID when retrying. Delivery requests have a separate persisted
attempt ID so an uncertain email can be retried without sending a duplicate.
The recipient verifies the invited email and accepts through the web flow.
Gift credits refresh on calendar-month anniversaries, do not accumulate, and
expire at the end. Purchased credits and workspace content are preserved.
There is no automatic subscription or charge. Paid upgrades use Stripe Checkout.
Welcome progress
Your personal connection can help you continue setting up a workspace:
get_onboardingreads your saved answers and current setup progress.save_onboardingsaves ananswerspatch, such asintent,agentTools, orconnectionInterests. Other answers stay as they were.finish_onboardingfinishes the welcome and, if you described a project, creates an editable doc called “Our first idea.” Repeating it keeps the same doc.
Each takes workspaceId. Writes accept requestId for retries. The same commands
are available at /api/v1/actions/:command; list_capabilities returns their full
input schemas. Selected tools are preferences, so selecting one does not connect
it, invite anyone, or start a paid run. skillInterests contains agent template
slugs for choosing a starting point.
These answers belong to your personal connection. Named agents can read the
project brief through the existing Docs tools, without access to your personal
welcome answers. On the web the welcome lives at /w/:workspaceId/welcome; you
can return to it from Home at any time, and the iOS app has its own screens.
For a direct return to setup, open /w/:workspaceId?setup=1. After the welcome,
setupGoal can focus invite, agent, repo, connections, skills, or
first_contribution. A channel link with
?members=create&agentTemplate=reviewer opens the existing create-agent form
with that gallery template. Other known gallery slugs work too; unknown values
are ignored. Opening these links never creates an agent by itself.
Founder outreach
Platform founders can use /admin/outreach to find people, keep private notes,
and set a follow-up date. Write an email, choose Review email to save a draft, and then
Send email to send from Pabs at hilos, with replies going to the founder's
email address. Drafts and send results stay in the person's history. An
unconfirmed send must be retried from that same history entry; a provider result
means the email was accepted for sending, not that it was read or delivered.
Email opt-outs, bounces, complaints, and do-not-contact records block outreach.
Gift a month opens a personal Pro or Max invitation with the recipient filled in. Preview its note and terms before sending. The gift starts when the recipient accepts it, with no card or automatic renewal. Existing invitations appear in the same dialog.
These outreach controls are interactive-only platform administration. Workspace MCP, REST, and WebMCP credentials cannot read customer records or send founder correspondence. Founder gift commands retain their separate verified-founder personal MCP and REST access.