Sthora
Reference

API

Every route, who may call it, and the conventions the whole surface follows.

Conventions

  • There is no global route prefix, and no path segment names an audience. One top-level segment per resource; sub-resources nest under their parent's item path.
  • Because the path no longer signals who may call it, a route's protection is readable only from its decorators. The global guard authenticates by default; each handler opts out or gates up explicitly.
  • Operator-only capability is a decorator on the handler, never a separate /admin path.
  • Lifecycle verbs are explicit routes (/start, /stop, /restart), never one :action segment — a mistyped sub-resource cannot be swallowed by a catch-all.
  • Responses are enveloped, and validation errors return a structured field-error map.

Authentication

Two principals resolve to the same AuthenticatedSession shape:

A session cookieIssued by sign-in, or by accepting an invitation
An API tokenst_-prefixed, resolved by the same global guard

No route has a parallel authorization path.

Documentation route

/docs on the API serves the OpenAPI document — in development and test only.

Routes

Public

PathNotes
GET /health
GET /setup-status, POST /setup/setup refuses with 409 once one user exists
POST /signupGated on SIGNUP_ENABLED. When off, 404 — indistinguishable from a route that was never built
POST /invitations/acceptThe one unauthenticated route that creates a user
POST /webhooks/:providergithub, gitlab, bitbucket, generic. HMAC-verified, with its own tighter rate limit. The only public route that can start work
POST /auth/two-factor/verifyTakes the sign-in challenge

Sign-in and password reset request/confirm under /auth/* are public; the rest of /auth/* requires a session.

Authentication and users

PathGuard
/auth/*Mixed, declared per handler. Sign-out, password change, session read, session list, and session revoke require a session
/auth/two-factor, /auth/two-factor/confirmSession; enrolling or disabling re-authenticates with the password
/users, /users/:id/sessionsSession to list; OWNER/ADMIN to list or revoke another member's sessions

Organizations

PathGuard
GET /organizations/:id, GET /organizations/:id/members, GET /organizations/:id/invitationsSession, organization-scoped
Rename, member role change, member removal, invite, cancel invitationOWNER

Projects and applications

PathGuard
/projects, /projects/:id/environmentsSession, organization-scoped
/applications, /applications/:idSession, organization-scoped
/applications/:id/start, /stop, /restartThree explicit routes
/applications/:id/domains, /domains/:domainId/verify
/applications/:id/variablesGET returns keys and value lengths only
/applications/:id/volumes
/applications/:id/git-source, /git-source/deploy-key, /git-source/webhook-secretGET /git-source returns the deploy key's public half and never the private one
/applications/:id/metrics, /applications/:id/containers

Deployments

PathNotes
POST /deploymentsmultipart/form-data — the only non-JSON request body in the API
GET /deployments, GET /deployments/:id
GET /deployments/:id/logsThe archived log
GET /deployments/:id/liveServer-Sent Events, carrying the session cookie
POST /deployments/:id/rollback

Servers

PathNotes
GET /servers, GET /servers/:id
GET /servers/:id/sample, /metrics, /containers
GET /servers/:id/liveServer-Sent Events
POST /servers, POST /servers/:id/agent-tokenThe issued agent token appears in these two responses and nothing else
DELETE /servers/:idRefuses while anything is deployed to the server

Ingress, Git credentials, services

PathNotes
GET /proxyRead-only ingress and certificate state for one server, named by an optional serverId query
/git-credentials, /git-credentials/:id/repositoriesGitHub App installations and the repository picker
/services, /services/:id
/services/:id/start, /stop, /restart
/services/:id/connectionThe only route that discloses generated credentials. Writes an audit row
/services/:id/backups

Alerts, tokens, billing, audit

PathNotes
/alerts, /alerts/summary, /alerts/:id/resolve/summary is three counts for the shell badge
/notification-channels, /notification-channels/:idPOST returns a webhook signing secret once
/api-tokens, /api-tokens/:idPOST returns the issued token once. DELETE revokes rather than deletes
/plans, /subscriptionSession. PUT /subscription is operator-gated by decorator
/audit-logsSession and an operator role

Why PUT /subscription is operator-gated

With the manual billing provider, a plan change is a grant. A member who could grant themselves the largest plan would make every limit decorative.

Not an HTTP route

/agent/connect is a WebSocket upgrade, authenticated during the handshake by the x-agent-token header and never by a user session. A rejected agent gets a 401 and no socket. It is a transport channel rather than a REST resource — the one documented exception to resource naming.

Origins and cookies

A self-hosted deployment serves the dashboard and the API on one origin, so session cookies stay same-origin and CORS_ALLOWED_ORIGINS can stay empty. Split-origin (cloud) deployments list the dashboard's origin there, and in AUTH_TRUSTED_ORIGINS for CSRF.

On this page