Skip to content

Every /v1 route

HTTP API

Send human sessions as cookies or workspace keys as Authorization: Bearer hk_live_….

Error shape{"error":{"code","message"}}
Method Path Authorization Purpose
POST /v1/workspaces human session Create an organization and its first workspace
GET /v1/vaults user or key List visible workspaces; deleted=1 lists deleted
POST /v1/vaults human session Create a workspace; body: name
PATCH /v1/vaults/:vaultId human owner Rename a workspace; body: name
DELETE /v1/vaults/:vaultId human owner Delete a workspace; data destroyed after 30 days
POST /v1/vaults/:vaultId/restore human org owner Restore a deleted workspace within 30 days
GET /v1/vaults/:vaultId/workspace viewer+ Workspace identity, index state, capabilities
POST /v1/vaults/:vaultId/corpus/query viewer+ Search the code index; body names an operation
POST /v1/vaults/:vaultId/corpus/refresh editor+ Re-index one repository or all of them
GET /v1/vaults/:vaultId/repositories viewer+ Indexed repositories, plan limit, GitHub state
PUT /v1/vaults/:vaultId/repositories editor+ Choose the repositories to index
GET /v1/vaults/:vaultId/github/repositories editor+ Repositories the GitHub installation grants
GET /v1/vaults/:vaultId/sandboxes viewer+ Cloud sandboxes this workspace has run
PUT /v1/vaults/:vaultId/sandboxes/:id agent+ Report one sandbox event; body: kind, event
GET /v1/organizations/:orgId/github org owner GitHub connection state for an organization
POST /v1/organizations/:orgId/github/install org owner Start the GitHub App installation
POST /v1/organizations/:orgId/github org owner Finish installation; body: installationId, state, code
DELETE /v1/organizations/:orgId/github org owner Disconnect GitHub and drop its selections
POST /v1/webhooks/github-app GitHub signature Push and installation events
GET /v1/vaults/:vaultId/models viewer+ Hosted model catalog
POST /v1/vaults/:vaultId/models/chat/completions viewer+ Hosted chat completion, streaming or not
GET /v1/billing user or key Plan, limits, and usage
GET /v1/billing/plan user or key Org plan only (lightweight)
POST /v1/billing/checkout org owner Create checkout; body: plan
GET /v1/billing/checkout/:checkoutId org owner Verify a Polar checkout return
POST /v1/billing/change-plan org owner Change a paid plan; body: plan
POST /v1/billing/keep-plan billing owner Remove the scheduled plan change
POST /v1/billing/transfer-owner billing owner Transfer billing; body: targetMemberId
POST /v1/billing/cancel org owner Cancel at period end (grace period retained)
POST /v1/billing/reactivate org owner Undo a pending cancellation
POST /v1/billing/portal org owner Open the customer billing portal
POST /v1/billing/webhook Polar signature Billing webhook
GET /v1/vaults/:vaultId/keys human owner List keys
POST /v1/vaults/:vaultId/keys human owner Mint key
DELETE /v1/vaults/:vaultId/keys/:id human owner Revoke key
GET /v1/vaults/:vaultId/grants owner List grants
POST /v1/vaults/:vaultId/grants human owner Grant a member access to a workspace
DELETE /v1/vaults/:vaultId/grants/:principalId human owner Revoke a grant
GET /v1/organizations/:orgId/members member Members, pending invitations, signed-in Macs
POST /v1/organizations/:orgId/invitations owner or admin Invite a person; body: email, role
DELETE /v1/organizations/:orgId/invitations/:id owner or admin Cancel a pending invitation
DELETE /v1/organizations/:orgId/devices/:keyId member (own) or admin Sign a device out
POST /v1/connect none (rate limited) Start device sign-in; returns a user code
POST /v1/connect/poll device code Poll until approved; returns the minted key
DELETE /v1/connect/device device key Sign this device out
GET /v1/connect/requests/:userCode human session Read a pending device request
POST /v1/connect/requests/:userCode/approve human session Approve a device and mint its key
POST /v1/connect/requests/:userCode/deny human session Deny a device request

GET /v1/vaults/:vaultId/workspace describes the workspace a key or session can reach: managementUrl, organizationId, workspaceName, corpusId, corpusName, plan, and role, plus:

  • capabilities{semantic, structuralSearch, repositoryFilters}. semantic is false on Hobby.
  • index — the CocoIndex index: the number of repositories in it, file and chunk counts where the index reports them, lastSuccessAt, and embeddingVersion.

Clients use it to decide what to offer before they search: a workspace without semantic should be shown pattern search only.

POST /v1/vaults/:vaultId/corpus/query takes {"organizationId":"…","operation":"…","arguments":{…}}. The organization must be the one the credential belongs to; anything else answers 404 not_found. The body is capped at 16 KiB.

Operation Arguments Answer
corpus_status none {indexed, repositories, plan, limits, refresh, refreshedAt, embeddingVersion}. Read from stored state; it never wakes the index.
list_repositories none {repositories} — each with its name and indexed commit.
grep_code pattern, optional path, language, repository {results, truncated}. Structural match against the syntax tree.
search_code query, optional limit, repository, language, path {results} ranked by meaning.
ask_code query {answer: null, grounding, note} — the passages to read. The answer itself is not written.

query and a question cap at 4,000 characters, pattern at 2,000, path at 400 characters and may not start with / or contain .., repository at 200, language at 100, and limit runs from 1 to 50.

Each result carries repository, path, line, endLine, score, excerpt, and the headSha it was read at; search_code results also carry language.

Refusals:

  • 403 plan_refusedsearch_code and ask_code on Hobby: “Semantic search is included with Pro and Team.”
  • 409 no_repositoriesgrep_code, search_code, and ask_code before any repository is chosen. corpus_status answers {indexed:false, repositories:[], plan, limits} with 200, and list_repositories answers {"repositories":[]}.
  • 503 index_unavailable or 503 index_warming with Retry-After — the index did not answer, or is coming back from rest. Retry; corpus_status keeps answering.

An owner connects GitHub from the browser: POST /v1/organizations/:orgId/github/install returns the GitHub App installation URL with a signed state, and GitHub’s callback is completed by POST /v1/organizations/:orgId/github with the installation id, that state, and GitHub’s user-authorization code. DELETE on the same path disconnects the installation.

GET /v1/vaults/:vaultId/github/repositories lists what the installation grants, marking those already selected. PUT /v1/vaults/:vaultId/repositories takes the full set to index — {"repositories":[{"repository":"owner/name","branch":"main"}]} — and is the whole selection, so a repository left out is deselected and its mirror and index entries are removed. A repository the installation does not grant answers 404 repository_not_granted; more repositories than the plan indexes answers 403 plan_limit; no GitHub connection answers 409 github_not_connected.

Each selection reports repository, branch, status (mirroring, refreshing, fresh, stale, or failed), indexedSha, latestSha, stale, indexedAt, files, chunks, and error.

POST /v1/vaults/:vaultId/corpus/refresh re-indexes everything, or the one repository named in {"repository":"owner/name"}. A refresh already running answers 409 refresh_in_progress, and a second request within the refresh floor answers 429 rate_limited with Retry-After.

POST /v1/webhooks/github-app receives GitHub’s push and installation events under the App’s webhook signature. A push to an indexed branch marks that repository stale and, on Team, starts the refresh.

GET /v1/vaults/:vaultId/sandboxes answers {"sandboxes":[…],"live":n}: the fifty most recently active runs, each with id, kind (task or triage), state, startedBy, deviceName, startedAt, lastActiveAt, endedAt and checkpoints. state is running, stopped or deleted as stored, and asleep for a run that has been silent for thirty minutes; live counts only the running ones.

PUT /v1/vaults/:vaultId/sandboxes/:id is how the helios-sandbox Worker records what it ran: body {"kind":"task"|"triage","event":"started"|"active"|"checkpointed"|"stopped"|"deleted"}, answered 204. Who ran it is read from the credential and never from the body. An event other than started for an unknown id creates the record too.

A device signs itself in rather than holding a pasted key. POST /v1/connect with {deviceName, client} returns {deviceCode, userCode, verificationUrl, expiresAt, interval}; the person opens the verification URL, and GET/approve/deny on /v1/connect/requests/:userCode are the browser’s half. The device polls POST /v1/connect/poll at the returned interval until the answer is {status:"approved", baseUrl, organizationId, corpusId, key, workspaceName, corpusName, plan, role}. Codes expire, and a spent code cannot be polled twice. DELETE /v1/connect/device revokes the device’s own key; an owner or admin can sign out any device with DELETE /v1/organizations/:orgId/devices/:keyId.

GET /v1/vaults/:vaultId/models returns the model catalog, and POST /v1/vaults/:vaultId/models/chat/completions is an OpenAI-shaped chat completion, streaming when stream is true. The spend-shaped fields are set here, not by the caller: the output cap comes from the catalog entry, n must be 1, and the paying organization is the one the key belongs to. An unset upstream answers 503.

Plan Workspaces Repositories indexed Refresh Search by meaning Requests/min Requests/month
Hobby 1 1 on request no 30 50,000
Pro 5 5 on push yes 120 500,000
Team 25 every granted repository on push yes 300 2,000,000

Every /v1 request draws from two org-scoped meters: a per-minute burst bucket and a monthly ceiling by UTC calendar month. Responses carry X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset for the burst bucket, plus X-Quota-Limit and X-Quota-Remaining for the monthly ceiling.

Exceeding either meter returns 429 with a Retry-After header. The scope field in the body names the meter that denied the call: burst clears within the minute; monthly clears at the start of the next UTC month, so do not retry monthly denials in a loop. Device sign-in is limited by address rather than by organization, and refuses the start when the limiter cannot answer.