Skip to content
Like what we’re building? Star on GitHub

Cloud REST API reference

Audience. Anyone calling iterion programmatically — a CI job, an SDK author, an operator writing curl runbooks. Every endpoint listed here exists in pkg/server/, grouped by domain.

This page is curated, not exhaustive: it covers the cloud- and team-facing surface, and leaves out the local-studio-only routes (/api/local/*, /api/files, /api/projects, /api/examples, /api/filesystem/*) along with much of the run-console read surface. A few team-facing families have their own reference instead of a table here: /api/admin/llm/* (cloud-llm-credentials.md), /api/admin/settings/usage-caps (usage-caps.md), the notification routes (notifications.md), the config-share routes (config-share.md), and /api/teams/{id}/plugin-sources* (plugins.md). For the complete inventory of the build you are actually running, use the generated spec — every route is recorded by the server's recordingMux, so it cannot drift:

bash
iterion openapi                 # OpenAPI 3.1 for this binary, offline, to stdout
curl .../api/openapi.json       # the same, from a live instance
curl .../api/routes             # just the method+pattern inventory

(The /api/v1/native, /api/v1/dispatcher and /api/v1/mcp/board CRUD sub-trees register on the same mux but bypass the route recorder — they are handed the bare ServeMux rather than the recording wrapper — so they are deliberately absent from that spec. The exception worth knowing: the forge-facing /api/v1/native/issues/* routes and the dependency graph go through the recorded path and therefore do appear.)

Authentication. Most routes accept any of:

  • Cookie: __Host-iterion_auth (access JWT) + __Host-iterion_refresh (rotation). The __Host- prefix is dropped — leaving the bare iterion_auth / iterion_refresh — when the deployment cannot meet its terms (no TLS, or an explicit cookie domain); a browser would discard the prefixed form there. Both spellings are accepted on read.
  • Bearer JWT: Authorization: Bearer <access-jwt> issued by login / refresh.
  • Bearer PAT: Authorization: Bearer iap_… — long-lived personal access token; authenticates as the issuing user with that user's role + super-admin flag (pkg/server/pat_routes.go:identityFromPAT).
  • WS query: ?t=<access-jwt> for WebSocket clients that can't set headers.

Where a route says "team member", "team admin" or "super-admin", the guard maps to canViewTeam / canManageTeam / requireSuperAdmin. Webhook delivery URLs (POST /api/webhooks/<provider>/<id>) use their own auth (token bearer or HMAC body signature) and are public to the JWT layer.

Authentication + identity

MethodPathAuthPurpose
POST/api/auth/loginpublicEmail + password login
POST/api/auth/refreshrefresh cookieRotate access JWT
POST/api/auth/logoutpublicDrop refresh session + cookies
POST/api/auth/registerpublic (when signup_mode=open or with invite)Create account
POST/api/auth/password/changepublic (legacy)First-login password rotation for pending_password_change users
POST/api/auth/password/reset/requestpublicMint + email a reset token (always 200, no enumeration)
POST/api/auth/password/reset/confirmpublicRedeem iar_…, set new password, issue fresh session
GET/api/auth/providerspublicList configured OIDC connectors + signup_mode
GET/api/auth/oidc/{provider}/startpublicStart OIDC dance
GET/api/auth/oidc/{provider}/callbackpublicOIDC redirect target
GET/api/auth/invitations/lookuppublicResolve invitation token → email + team
POST/api/auth/invitations/acceptmemberAccept an invitation while logged in
GET/api/auth/mememberCurrent user + active team identity
POST/api/auth/me/team/{team_id}memberSwitch active team
POST/api/auth/me/org/{org_id}memberSwitch active org (re-issues the JWT; validates org then team)
POST/api/me/passwordmemberSelf-service password change
POST/api/me/sessions/revoke-allmemberSign out every device

Source: pkg/server/auth_routes.go + pkg/server/password_routes.go.

Teams + members + invitations

MethodPathAuthPurpose
GET/api/teamsmemberList the caller's teams
POST/api/teamsmemberCreate a team
GET/api/teams/{id}/membersteam memberList members
PATCH/api/teams/{id}/members/{user_id}team adminChange role
DELETE/api/teams/{id}/members/{user_id}team adminRemove a member
GET/api/teams/{id}/invitationsteam adminList pending invitations
POST/api/teams/{id}/invitationsteam adminMint a token (shown once)
DELETE/api/teams/{id}/invitations/{invite_id}team adminRevoke
GET/api/orgs/{id}/usageorg memberOrg-member mirror of the admin usage view (see below)
GET/api/teams/{id}/auditteam adminTenant audit log

Organisations — self-serve (org members, teams, SSO)

The org-admin self-serve mirror of the super-admin org views (two-level tenancy, ADR-048). All routes are requireAuth; the org role is checked in-handler — read routes need org membership (canViewOrg), mutations need org admin/owner (canManageOrg). Sources: pkg/server/orgs_routes.go, pkg/server/org_sso_routes.go, pkg/server/org_sso_domain_routes.go.

MethodPathAuthPurpose
GET/api/orgs/{id}/membersorg memberList org members + roles
PATCH/api/orgs/{id}/members/{user_id}org adminChange a member's org role (member|admin|owner)
DELETE/api/orgs/{id}/members/{user_id}org adminRemove a member
GET/api/orgs/{id}/invitationsorg adminList pending org invitations
POST/api/orgs/{id}/invitationsorg adminMint an org invitation token
DELETE/api/orgs/{id}/invitations/{invite_id}org adminRevoke
GET/api/orgs/{id}/teamsorg memberList the org's teams
POST/api/orgs/{id}/teamsorg adminCreate a team in the org
GET/api/orgs/{id}/auditorg adminOrg audit log
GET/api/orgs/{id}/sso/providersorg memberList SSO providers
POST/api/orgs/{id}/sso/providersorg adminAdd an SSO provider (OIDC)
PATCH/api/orgs/{id}/sso/providers/{provider_id}org adminUpdate a provider
DELETE/api/orgs/{id}/sso/providers/{provider_id}org adminRemove a provider
POST/api/orgs/{id}/sso/providers/{provider_id}/testorg adminTest a provider's config
GET/api/orgs/{id}/sso/domainsorg memberList claimed SSO domains
POST/api/orgs/{id}/sso/domainsorg adminClaim a domain
POST/api/orgs/{id}/sso/domains/{domain_id}/verifyorg adminVerify a claimed domain
DELETE/api/orgs/{id}/sso/domains/{domain_id}org adminRelease a domain

BYOK LLM keys + generic secrets + bindings

User-scoped + team-scoped flavours share the same payload shape. Both return metadata only — the plaintext is write-only.

MethodPathAuthPurpose
GET/api/teams/{id}/api-keysteam memberList team's BYOK keys
POST/api/teams/{id}/api-keysteam adminCreate
PATCH/api/teams/{id}/api-keys/{key_id}team adminToggle default / rename
DELETE/api/teams/{id}/api-keys/{key_id}team adminDelete
GET/api/me/api-keysmemberList own user-scoped keys
POST/api/me/api-keysmemberCreate personal key
PATCH/api/me/api-keys/{key_id}memberUpdate
DELETE/api/me/api-keys/{key_id}memberDelete
GET/api/teams/{id}/secretsteam memberList team's generic secrets
POST/api/teams/{id}/secretsteam adminCreate
PATCH/api/teams/{id}/secrets/{secret_id}team adminUpdate
DELETE/api/teams/{id}/secrets/{secret_id}team adminDelete
GET/api/me/secretsmemberPersonal secrets
POST/api/me/secretsmemberCreate
PATCH/api/me/secrets/{secret_id}memberUpdate
DELETE/api/me/secrets/{secret_id}memberDelete
GET/api/teams/{id}/bots/{bot_id}/bindingsteam memberList bot bindings
POST/api/teams/{id}/bots/{bot_id}/bindingsteam adminCreate binding
PATCH/api/teams/{id}/bots/{bot_id}/bindings/{binding_id}team adminUpdate
DELETE/api/teams/{id}/bots/{bot_id}/bindings/{binding_id}team adminDelete

Sources: pkg/server/byok_routes.go, pkg/server/generic_secrets_routes.go, pkg/server/bot_bindings_routes.go. Full semantics in secrets-reference.md.

Team bot sources (cloud bot editing)

Team-authored bot bundles — the writable, tenant-scoped store the studio editor saves into (cloud pods bake the catalog read-only). Each source is a multi-file bundle (main.bot + manifest.yaml + skills/…). Edit rights = the config_editor capability, team admin, or owner (canEditBots); if the server has no bot-source store wired every route returns 501 bot editing is not enabled on this server.

MethodPathAccessPurpose
GET/api/teams/{id}/bot-sourcesbot editorList the team's bots (metadata only — file bodies omitted)
GET/api/teams/{id}/bot-sources/{slug}bot editorOne bot with its full file map
PUT/api/teams/{id}/bot-sources/{slug}bot editorCreate or replace the whole bundle ({files, version?})
PUT/api/teams/{id}/bot-sources/{slug}/files/{path...}bot editorPer-file save ({content, version?})
DELETE/api/teams/{id}/bot-sources/{slug}/files/{path...}bot editorDelete one file (never main.bot)
DELETE/api/teams/{id}/bot-sources/{slug}bot editorDelete the bot
POST/api/teams/{id}/bot-sources/{slug}/forkbot editorFork a baked catalog bot ({from}) into an editable copy

Every write compiles the bundle before it persists — a bot that fails to parse/compile is rejected 400 bot does not compile: <diagnostics>, never left to fail at launch. A non-zero version is an optimistic if-match token (409 if a concurrent editor advanced it); slug collisions are 409. Source: pkg/server/bot_sources_routes.go, store pkg/botsource/.

Forge integrations (connections, OAuth apps, repo-bots)

The team-scoped, outbound forge layer behind the studio's repo-first shell (docs/repo-scope.md): connect a forge, hold an OAuth app / GitHub App credential, and provision a set of bots onto a repo (webhook + hook

MethodPathAuthPurpose
GET/api/teams/{id}/forge/connectionsteam memberList forge connections
POST/api/teams/{id}/forge/connectionsteam adminConnect a forge (PAT / OAuth / GitHub-App install)
DELETE/api/teams/{id}/forge/connections/{conn_id}team adminRemove a connection
GET/api/teams/{id}/forge/connections/{conn_id}/healthteam memberConnection health / token probe
POST/api/teams/{id}/forge/connections/{conn_id}/refreshteam memberGitHub App only: re-probe live installation grants, persist them, and force a fresh token mint
POST/api/teams/{id}/forge/connections/{conn_id}/avatarteam adminUpload the iterion-bot avatar onto the account behind a PAT connection ({variant?, force?}); 422 on OAuth (a person), on GitHub (no API — names the App's settings page) and on a token the forge rejects (the connection is marked revoked; reconnect first), 409 needs_force on an account the forge does not flag as a bot or would not describe at all, 502 when the forge did not answer the identity read or refused the upload. See brand.md
GET/api/teams/{id}/forge/connections/{conn_id}/reposteam memberRepos visible to the connection
GET/api/teams/{id}/forge/reposteam memberTeam's forge-linked repos
POST/api/teams/{id}/forge/reposteam adminCreate a repo (opt-in RepoCreator capability)
GET/api/teams/{id}/forge/oauth-appsteam memberList per-tenant OAuth apps
POST/api/teams/{id}/forge/oauth-appsteam adminRegister an OAuth app (manual / auto / auto_from_connection)
DELETE/api/teams/{id}/forge/oauth-apps/{app_id}team adminRemove an OAuth app
POST/api/teams/{id}/forge/oauth-apps/github-manifestteam adminStart the GitHub App-manifest auto-create flow
GET/api/teams/{id}/forge/repo-botsteam memberList repo→bot provisionings (integrations)
GET/api/teams/{id}/forge/repo-bots/previewteam memberPreview what enabling a bot set subscribes to (no forge writes)
POST/api/teams/{id}/forge/repo-botsteam adminEnable bots on a repo (provision webhook + hook + secret + bindings)
PATCH/api/teams/{id}/forge/repo-bots/{integration_id}team adminSet the exact bot set (replace semantics)
DELETE/api/teams/{id}/forge/repo-bots/{integration_id}team adminDisable / deprovision (tears down webhook + hook)
PATCH/api/teams/{id}/forge/integrations/{iid}team adminUpdate an integration (incl. sync_issues_enabled)
POST/api/teams/{id}/forge/integrations/{iid}/syncteam adminRun the forge→board issue sync now (one-way, forge is source)
GET/api/teams/{id}/forge/integrations/{iid}/hooksteam memberList the webhooks on an integration

The OAuth handshake completes on public callbacks the SPA is redirected to: GET /api/forge/oauth/callback, GET /api/forge/github/app/callback, and GET /api/forge/github/app-manifest/callback.

Project-board binding (GitHub Projects v2)

One board per team (ADR-097). Binding it makes the board's Status column two-way with the native board's columns and imports Area/Mode/Priority onto cards as area:/mode:/prio: labels. Runbook: docs/github-board-sync.md.

MethodPathAuthPurpose
GET/api/teams/{id}/board-bindingteam memberThe binding, incl. the effective status map and the last sync
PUT/api/teams/{id}/board-bindingteam adminBind / re-bind (resolves the board and caches its ids)
DELETE/api/teams/{id}/board-bindingteam adminUnbind

PUT takes the board's address, never its ids — every id in the stored binding comes from reading the board with the team's own credential, so a caller cannot point a team at a board it has no rights on:

jsonc
{
  "owner": "SocialGouv",
  "number": 203,
  "owner_kind": "org",              // or "user"; default "org"
  "connection_id": "conn_123",
  "status_map": {                   // optional; default = the shipped five
    "Todo": "ready",
    "Doing": "in_progress",
    "Shipped": "done"
  },
  "sync_every_seconds": 120         // absent = default (120); 0 = off; floor 60
}

Every rejection is a 400 naming the cause: a malformed ref, a non-injective status_map (two columns on one state), an interval under the floor, a board the credential cannot resolve, or a map matching none of the board's columns (the real column names are listed in the message). GET/DELETE on an unbound team are 404, never a silent success.

Inbound webhooks

CRUD (operator-side) plus per-provider delivery URLs.

MethodPathAuthPurpose
GET/api/teams/{id}/webhooksteam memberList
POST/api/teams/{id}/webhooksteam adminCreate + mint iwh_ token (shown once)
GET/api/teams/{id}/webhooks/{webhook_id}team memberGet one
PATCH/api/teams/{id}/webhooks/{webhook_id}team adminUpdate
DELETE/api/teams/{id}/webhooks/{webhook_id}team adminDelete
POST/api/teams/{id}/webhooks/{webhook_id}/rotateteam adminRotate token + re-seal HMAC
GET/api/teams/{id}/webhooks/{webhook_id}/deliveriesteam memberLast ~100 deliveries
POST/api/webhooks/gitlab/{id}webhook tokenInbound delivery (MR + /revi)
POST/api/webhooks/github/{id}webhook HMACInbound PR delivery
POST/api/webhooks/forgejo/{id}webhook HMACInbound PR delivery (also Gitea headers)
POST/api/webhooks/generic/{id}webhook token (or HMAC opt-in)Bot-agnostic JSON delivery

Source: pkg/server/webhooks_routes.go. Full reference: webhooks.md.

OAuth-forfait (Claude / Codex)

MethodPathAuthPurpose
GET/api/me/oauth/connectionsmemberList configured forfait kinds + expiry
POST/api/me/oauth/{kind}/authorize/startmemberBegin the browser authorize handshake — the primary way a user connects
POST/api/me/oauth/{kind}/authorize/completememberFinish that handshake
POST/api/me/oauth/{kind}/credentialsmemberUpload pasted credentials.json / auth.json
POST/api/me/oauth/{kind}/refreshmemberRefresh stored access token against the IdP
PATCH/api/me/oauth/{kind}memberName the account behind the credential ({"account_label": "…"}, "" clears; ≤ 120 characters) — metadata only, the sealed credential is untouched
DELETE/api/me/oauth/{kind}memberDisconnect

authorize/complete and credentials take an optional ?account_label= query parameter to name the account at connect time. The listing exposes account_label beside fingerprint, the same string the publisher logs when it picks a credential (see cloud-llm-credentials.md).

Every route above has a team-scoped mirror at /api/teams/{id}/oauth/… (connections, {kind}/authorize/start, {kind}/authorize/complete, {kind}/credentials, {kind}/refresh, PATCH {kind}, and DELETE {kind}) for a forfait the whole team draws on rather than one operator, and a platform mirror at /api/admin/llm/oauth/… (super-admin).

Source: pkg/server/oauth_routes.go, pkg/server/oauth_team_routes.go.

Credential pool

Lending your own subscription or personal metered key to the shared pool — full model in credential-pool.md.

MethodPathAuthPurpose
GET/api/me/poolmemberYour pledges and what they have served
PUT/api/me/pool/{source}/{ref}memberCreate or update a pledge (ceilings, sharing window, bot allow-list)
DELETE/api/me/pool/{source}/{ref}memberWithdraw a pledge
GET/api/me/pool/historymemberThe runs your quota served
GET/api/teams/{id}/poolteam memberThe pool's policy and its donors
PUT/api/teams/{id}/poolteam adminSet the audience policy deciding who may draw

Source: pkg/server/credpool_routes.go.

Cloud schedules

Recurring bots, the cloud counterpart of iterion schedulescheduling.md.

MethodPathAuthPurpose
GET/api/teams/{id}/schedulesteam memberList the team's cron-scheduled bots
POST/api/teams/{id}/schedulesteam adminCreate a schedule
PATCH/api/teams/{id}/schedules/{sid}team adminUpdate one
DELETE/api/teams/{id}/schedules/{sid}team adminRemove one

Source: pkg/server/schedules_routes.go.

Triggers (event-driven runs)

The subscription registry binding (event filter) → (bot launch), gated on server_info.triggers_enabledADR-046.

MethodPathAuthPurpose
GET/api/v1/triggersmemberList subscriptions (team-scoped in cloud)
POST/api/v1/triggersmemberCreate one
GET/api/v1/triggers/{id}memberRead one
PUT/api/v1/triggers/{id}memberReplace one
DELETE/api/v1/triggers/{id}memberRemove one
POST/api/v1/triggers/emitmemberPublish a custom event onto the bus
GET/api/v1/triggers/healthmemberEvaluator + bus health
POST/api/v1/bots/{name}/triggers/from-invocationmemberGenerate a subscription from a bot manifest's invocations: block

Source: pkg/server/triggers_routes.go.

Personal access tokens (PATs)

MethodPathAuthPurpose
GET/api/me/tokensmemberList own PATs (no plaintext)
POST/api/me/tokensmemberMint a PAT (iap_… shown once)
DELETE/api/me/tokens/{token_id}member (owner) or super-adminRevoke

Source: pkg/server/pat_routes.go.

Memory + knowledge

Spaces are addressed by query params (?name=, ?visibility=, plus ?bot= for visibility=bot and ?project= for project/bot scopes).

MethodPathAuthPurpose
GET/api/memory/usagemember{used_bytes, quota_bytes} for one space
GET/api/memory/docsmemberList documents in a space (optional ?dir=)
GET/api/memory/docmemberRead a document (?path=)
PUT/api/memory/docmember (super-admin for visibility=global)Write
DELETE/api/memory/docmember (super-admin for global)Delete
GET/api/memory/exportmemberTarball export of the space
POST/api/memory/importmember (super-admin for global)Import a tarball

Source: pkg/server/memory_routes.go. Full reference: memory-and-knowledge.md.

Runs surface

Read-only views plus the launch / resume mutations the studio drives.

MethodPathAuthPurpose
GET/api/runsmember (tenant-scoped)List runs
GET/api/runs/global-activememberActive runs across the local stores on this machine — a desktop-daemon affordance walking $HOME/.iterion/**. In cloud mode it returns {"runs":[]} unconditionally: the pod's $HOME is shared infrastructure, so walking it could leak across tenants.
POST/api/runsmemberLaunch a workflow
POST/api/runs/preview-costmemberEstimate cost before launch
POST/api/runs/uploadsmemberUpload an attachment
GET/api/runs/{id}member (run tenant)Run state
GET/api/runs/{id}/eventsmemberEvent log
GET/api/runs/{id}/workflowmemberWorkflow source attached to the run
GET/api/runs/{id}/artifacts/{node}memberArtifact versions for a node
GET/api/runs/{id}/artifacts/{node}/{version}memberOne artifact
GET/api/runs/{id}/files / …/files/content / …/files/diffmemberWorking-tree views
GET/api/runs/{id}/commits etc.memberWorktree commit history
GET/api/runs/{id}/attachments/{name}memberDownload an attachment
GET/api/runs/{id}/attachments/{name}/urlmemberPre-signed S3 URL
POST/api/runs/{id}/cancelmemberCancel a running run
POST/api/runs/{id}/pausememberPause
POST/api/runs/{id}/resumememberResume (re-publishes through the queue)
POST/api/runs/{id}/forkmemberFork at a prior turn
POST/api/runs/{id}/mergememberLand the run's storage branch on a target branch. For a repo-targeted run — whose workspace is gone by the time it returns — the server materialises its own clone of the launch ref, runs the same merge pipeline, and pushes the advanced target back to the forge (never force). The merge is persisted as merged only once the forge has it; a refused push records merge_status=failed.
GET/api/runs/{id}/merge/conflictsmemberConflicting paths left by a merge attempt
POST/api/runs/{id}/merge/conflicts/resolvememberResolve one conflicting path with supplied content
POST/api/runs/{id}/merge/conflicts/resolve-with-agentmemberDelegate one conflict to the resolver agent (ITERION_CONFLICT_RESOLVER_MODEL)
POST/api/runs/{id}/merge/conflicts/finalizememberCommit the resolved merge and continue the pipeline
POST/api/runs/{id}/merge/conflicts/abortmemberAbandon the merge; the storage branch is preserved
POST/api/runs/{id}/commit-and-finalizememberCommit pending work and finalise
POST/api/runs/{id}/renamememberRename a run
GET/api/runs/{id}/childrenmemberChild (subbot) runs
GET/api/runs/{id}/review/scope / …/review/diffmemberHuman-gate review scope and its diff (review-scope.md)
GET/api/runs/{id}/session-boardmemberSession-board widgets (session-board.md)
GET/api/runs/{id}/interactions/pendingmemberUnanswered ask_user_async questions
GET/DELETE/api/runs/{id}/queue-messages, …/queue-message/{msgID}memberPending steering messages for the run
GET/api/runs/{id}/logmemberStreamed run log
GET/api/runs/{id}/previewmemberPreview proxy (SSRF-guarded)
GET/api/ws/runs/{id}/shellmember (via ?t=)Post-mortem PTY in a preserved worktree (post-mortem-shell.md)
GET/api/ws/runs/{id}member (via ?t=)Live run-console WebSocket
GET/api/v1/runs/statsmemberRolling stats (for the studio)
GET/api/v1/limits/costmemberCost-cap status
POST/api/v1/limits/cost/overridememberGrant or revoke the day's cost-cap override. Any authenticated member — the handler performs no role check and records the audit actor as operator.

Source: pkg/server/runs.go.

Super-admin (organisations + users + DLQ + audit)

MethodPathAuthPurpose
GET/api/admin/orgssuper-adminList every org
POST/api/admin/orgssuper-adminCreate org
GET/api/admin/orgs/{id}super-adminRead
PATCH/api/admin/orgs/{id}super-adminUpdate name / slug / quotas
DELETE/api/admin/orgs/{id}super-adminSchedule org deletion (reversible until it runs)
POST/api/admin/orgs/{id}/restoresuper-adminCancel a scheduled deletion
POST/api/admin/orgs/{id}/statussuper-adminSuspend / read-only / activate
GET/api/admin/orgs/{id}/usagesuper-adminUsage snapshot
GET/api/admin/orgs/{id}/teamssuper-adminList the org's teams
GET/api/admin/userssuper-adminList users (?offset=&limit= pagination; limit default 50, max 200)
PATCH/api/admin/users/{id}super-adminStatus / super-admin flag
POST/api/admin/users/{id}/reset-passwordsuper-adminForce a user's password reset
GET/api/admin/auditsuper-adminPlatform audit log (filters: action, actor, from, to, offset, limit)
GET/api/admin/dlqsuper-adminList parked messages
GET/api/admin/dlq/{seq}super-adminPeek payload
POST/api/admin/dlq/{seq}/replaysuper-adminRe-publish onto the live subject
DELETE/api/admin/dlq/{seq}super-adminDiscard
GET/api/admin/botssuper-adminList platform bot overrides (metadata + content digest)
GET/api/admin/bots/{slug}super-adminOne override incl. its file map
PUT/api/admin/bots/{slug}super-adminPush/replace an override ({files, version?}; compiled before persisting; 413 over the body cap)
DELETE/api/admin/bots/{slug}super-adminRemove the override (baked catalog serves again)
PUT/DELETE/api/admin/bots/{slug}/files/{path}super-adminSingle-file edit of an override
POST/api/admin/bots/{slug}/forksuper-adminSeed the override from the baked bundle ({from})
GET/PUT/api/admin/settings/bot-rolessuper-adminWebhook role→bot bindings (merge semantics; null clears a field)
GET/PUT/api/admin/settings/sandboxsuper-adminsandbox: auto fallback image override

Sources: pkg/server/admin_orgs_routes.go, pkg/server/admin_bots_routes.go, pkg/server/platform_settings.go, pkg/server/queue_sweeper.go.

Server info + health

MethodPathAuthPurpose
GET/api/server/infopublicMode, version, auth_required, email_enabled, per-feature enablement flags, upload limits
GET/healthzpublicLiveness — HTTP listener up
GET/readyzpublicReadiness — Mongo + NATS + S3 reachable under 1s deadline
GET/metricspublic on the metrics port (ClusterIP-only by design)Prometheus scrape

Non-obvious JSON shapes

POST /api/teams/{id}/webhooks — create response (token-once)

json
{
  "config": {
    "id": "8e2…",
    "tenant_id": "team_acme",
    "name": "GitLab MR review",
    "provider": "gitlab",
    "sign_mode": "",
    "enabled": true,
    "token_last4": "Vp3a",
    "fingerprint": "sha256:…",
    "bot_ids": ["review-pr"],
    "wildcard_bots": false,
    "project_allowlist": ["acme/*"],
    "event_allowlist": [],
    "rate_limit": { "rate": 1.0, "burst": 10 },
    "monthly_call_limit": 0,
    "launch_vars": {},
    "key_overrides": {},
    "created_by": "user_…",
    "created_at": "2026-06-11T10:11:12Z",
    "updated_at": "2026-06-11T10:11:12Z"
  },
  "token": "iwh_…"
}

The token field is the only way to recover the plaintext. The same shape comes back from the rotate endpoint.

Launch-denial envelope

Every gate refusal — REST launch, resume, webhook publication — uses the same shape (pkg/server/launch_gate.go):

jsonc
{
  "error":    "monthly_run_quota_exceeded",   // stable token
  "detail":   "monthly run quota (1000) exhausted",
  "reset_at": "2026-07-01T00:00:00Z"          // monthly quotas
}

Plus the header Retry-After: <seconds> on concurrency_cap_exceeded and launch_rate_limited. Token list and HTTP semantics in quotas-and-limits.md.

GET /api/orgs/{id}/usage (also /api/admin/orgs/{id}/usage)

See quotas-and-limits.md → Reading usage for the full orgUsageView schema. Same shape on both routes — the admin endpoint is super-admin only, the member endpoint is any org member.

POST /api/me/tokens — create PAT

Request:

json
{ "name": "github-actions", "team_id": "team_…", "expires_in_days": 90 }

Response (plaintext shown once):

json
{
  "pat":   { "id": "…", "name": "github-actions", "token_last4": "Q9k2", "expires_at": "…",  },
  "token": "iap_…"
}

expires_in_days is clamped down to ITERION_PAT_MAX_TTL when the platform sets one. team_id is optional; without it the PAT inherits the user's default team and re-checks membership at every use.