> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stoutdata.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# API overview

> Base URL, authentication schemes, rate limits, and error conventions for the Stout HTTP API.

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 box list for an org is `GET https://api.stoutdata.ai/api/orgs/:orgId/boxes`.

## 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 run status), switch to the streaming (SSE / WebSocket) endpoints instead of tight polling.

## Error format

Every error response has a JSON body with at least these fields:

```json theme={null}
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "Box not found"
}
```

Validation errors add an `issues` array from Zod:

```json theme={null}
{
  "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.
