--- title: "API Overview" description: "Introduction to the Fabro REST API" --- The Fabro API is **under active development** and may be subject to change. Endpoints, request/response formats, and authentication mechanisms may evolve as the project matures. The Fabro API is a REST API for managing workflow runs, interactive sessions, and related resources. All requests and responses use JSON. ## Base URL The versioned API is served by `fabro server start`, which defaults to: ``` http://localhost:3000/api/v1 ``` The base URL is configurable via `settings.toml`: ```toml title="settings.toml" [server.api] url = "https://fabro.example.com/api/v1" ``` ## Authentication The API supports two authentication strategies, configured in `settings.toml`: ```toml title="settings.toml" [server.auth.api.jwt] enabled = true ``` ### JWT (Bearer Token) Send an Ed25519-signed JWT in the `Authorization` header: ``` Authorization: Bearer ``` The token must include these claims: | Claim | Description | |-------|-------------| | `iss` | Issuer — must be `fabro-web` | | `iat` | Issued-at timestamp (Unix seconds) | | `exp` | Expiration timestamp (Unix seconds) | | `sub` | Subject — a URL identifying the user (e.g. `https://github.com/username`) | The username is extracted from the last path segment of the `sub` claim and checked against the `allowed_usernames` list in the web auth config. Set the verification key via the `FABRO_JWT_PUBLIC_KEY` environment variable (PEM format or base64-encoded PEM). ### mTLS (Mutual TLS) With mTLS, the client authenticates using a TLS client certificate. Configure the strategy and shared listener TLS: ```toml title="settings.toml" [server.auth.api.mtls] enabled = true [server.listen] type = "tcp" address = "0.0.0.0:3000" [server.listen.tls] cert = "~/.fabro/certs/server.crt" key = "~/.fabro/certs/server.key" ca = "~/.fabro/certs/ca.crt" ``` The Common Name (CN) from the client certificate identifies the user. ### Multiple Strategies You can enable both strategies. They are tried in order — the first successful match wins: ```toml title="settings.toml" [server.auth.api.jwt] enabled = true [server.auth.api.mtls] enabled = true ``` ## Errors ### Error Shape All error responses share a consistent JSON structure: ```json { "errors": [ { "status": "404", "title": "Not Found", "detail": "Run abc123 not found." } ] } ``` Each entry in the `errors` array contains: | Field | Type | Description | |-------|------|-------------| | `status` | `string` | The HTTP status code as a string | | `title` | `string` | The canonical reason phrase for the status code | | `detail` | `string` | A human-readable explanation of the error | ### HTTP Status Codes | Status | Meaning | When It Occurs | |--------|---------|----------------| | `400 Bad Request` | The request body or parameters are invalid | Missing required fields, malformed JSON | | `401 Unauthorized` | Authentication is missing or invalid | No token, expired token, invalid certificate | | `403 Forbidden` | The authenticated user lacks access | Username not in the allowed list | | `404 Not Found` | The requested resource does not exist | Unknown run ID, unknown workflow name | | `409 Conflict` | The resource is in a conflicting state | Answering a question on a run that isn't running yet | | `410 Gone` | The resource is no longer available | SSE event stream has closed | | `501 Not Implemented` | The endpoint exists but is not yet implemented | Placeholder routes | | `502 Bad Gateway` | An upstream dependency failed | Graphviz `dot` not installed or returned an error | ## Pagination List endpoints that return large collections use offset-based pagination. Pass pagination parameters as query strings: | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `page[limit]` | `integer` | `20` | Maximum number of items to return (clamped to 1–100) | | `page[offset]` | `integer` | `0` | Number of items to skip | Paginated responses include a `meta` object alongside the `data` array: ```json { "data": [...], "meta": { "has_more": true } } ``` When `has_more` is `true`, increment the offset by the limit to fetch the next page. ## Versioning The Fabro API is versioned under `/api/v1`. All versioned endpoints, including the OpenAPI document, live under that prefix. Future breaking changes can be introduced under a new versioned prefix while preserving existing clients. ## Discovery The root endpoint (`GET /`) returns discovery URLs. The health endpoint (`GET /health`) can be used for liveness checks. The OpenAPI spec is available at `GET /api/v1/openapi.json`.