Skip to main content
Everything the Stout dashboard does is a call to the Stout HTTP API. The dashboard is a convenience; if you’d rather automate, script, or embed Stout into your own tools, every capability is reachable programmatically.

Base URL

Production: https://api.stoutdata.ai All endpoints are prefixed with /api/. For example, the job list for an org is GET https://api.stoutdata.ai/api/orgs/:orgId/jobs.

Authentication

There are two primary schemes:

User Bearer tokens

Users authenticate with JWT access tokens in the Authorization header:
Authorization: Bearer eyJhbGciOi...
Access tokens expire after 15 minutes. Refresh tokens expire after 7 days and are rotated on every use — if a refresh token is used twice, all sessions for that user are revoked as a security precaution. To obtain tokens, POST to /api/auth/login with email and password, or complete the SSO flow.

Box API keys

Boxes authenticate with a static API key in a custom header:
X-API-Key: stout_<64 hex chars>
Keys are generated by the control plane during the install-stout flow and stored on the box at /etc/lager/control_plane.json. Stout stores an HMAC-SHA256 hash of each key keyed by a server-side pepper, so a database leak alone can’t yield working keys. (Older rows may still be bare SHA-256 and are transparently upgraded on next use.) A lost key cannot be recovered, only rotated by re-running install-stout.

Rate limits

  • 100 requests per minute per IP across all endpoints.
  • Auth endpoints (/api/auth/login, /api/auth/register, /api/auth/refresh) have stricter per-route limits on top of the global cap.
  • Backed by Redis in production so limits apply across control-plane replicas.
  • Exceeding the limit returns 429 Too Many Requests with a Retry-After header.
If you’re hitting limits legitimately (e.g. polling for job completion), switch to server-sent events or webhooks instead.

Error format

Every error response has a JSON body with at least these fields:
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Box not found"
}
Validation errors add an issues array from Zod:
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Validation failed",
  "issues": [
    { "path": ["body", "name"], "message": "Required" }
  ]
}
Unique-constraint violations return 409 Conflict with a message identifying which field clashed.

Conventions

  • IDs — all resources use UUIDs.
  • Timestamps — ISO 8601 with time zone offsets (e.g. 2026-04-21T14:32:11.000Z).
  • Pagination — list endpoints accept ?page=<n>&limit=<n> and return { items, total, page, limit }. Default limit 20, max 100.
  • Correlation IDs — every response includes an x-request-id header. Include it when reporting bugs so Stout support can find your request in the logs.

Coming soon

A per-endpoint reference — request/response shapes for every route — is in the works. Until then, the control-plane source at stout/services/control-plane/src/routes/ is authoritative, and the dashboard’s network panel is the quickest way to see a worked example of any endpoint.