API overview and authentication
Faber exposes a small JSON API over HTTP. The contract is an OpenAPI 3.1
document, openapi/openapi.yaml in the repository, which the server also
serves. The reference on this site is generated from it.
Base URL
Section titled “Base URL”http://<host>:3000/api/v1Faber speaks plain HTTP. Put a TLS-terminating reverse proxy in front of it before it leaves the host; see Docker deployment.
Authentication
Section titled “Authentication”Every route except /health, /openapi.yaml and /openapi.json needs the API
key in the Authorization header, either as a bearer token or as the raw key:
Authorization: Bearer 3f9c…Authorization: 3f9c…A missing or wrong key gets 401 with WWW-Authenticate: Bearer and:
{ "error": "Missing or invalid API key", "code": "unauthorized" }The server is configured with API_KEY. It accepts a comma-separated list, so
keys can be rotated without downtime: deploy old,new, move clients to
new, then deploy new alone. Keys are compared in constant time.
Endpoints
Section titled “Endpoints”| Method and path | Auth | Purpose |
|---|---|---|
POST /execute | yes | Run steps in a sandbox. Execution model |
POST /file | yes | Upload a file (multipart) |
GET /file | yes | List stored files |
GET /file/{id} | yes | Download a stored file |
DELETE /file/{id} | yes | Delete a stored file |
DELETE /cache | yes | Clear the step cache namespace |
GET /info | yes | Version, architecture, limits, profiles, cache state, toolchains |
GET /metrics | yes | Prometheus metrics (text) |
GET /health | no | Liveness and readiness: 200 normally, 503 while shutting down |
GET /openapi.yaml, GET /openapi.json | no | The OpenAPI document |
Each has a page in the reference, with request and response schemas.
Request IDs
Section titled “Request IDs”Every response has an x-request-id header. The same ID is in the service’s
log line for the request. Include it when you report a problem, and log it on
the client side for failed calls; the SDKs attach it to their errors.
Errors
Section titled “Errors”Error responses have one shape, with a stable machine-readable code:
{ "error": "Execution capacity is currently exhausted", "code": "capacity_exhausted" }Errors lists every code, its status and what to do about it.
Remember that a task failing is not an API error: /execute returns 200
and reports the task’s outcome in the body.
Retries and timeouts
Section titled “Retries and timeouts”- Retry
503after theRetry-Afterheader (seconds) when present, with exponential backoff otherwise. It means no task slots were free, the instance is shutting down, or the request was cancelled. - Retry connection errors the same way.
- Do not retry
4xx. The request is wrong and will fail again. - Client timeout. A request can take up to
OVERALL_TIMEOUT_MS(30 s by default, seeGET /info) plus a few seconds. Set your HTTP timeout above that.
Re-sending an /execute request is safe: it has no side effects apart from
the step cache. Uploads are idempotent (the ID is the content hash).
Compatibility
Section titled “Compatibility”- Clients should ignore unknown fields in responses and treat unknown enum
values (for example a new
outcome, or a new errorcode) as a generic case. New fields and values may be added withinv1. - The 0.2 request format (a bare JSON array of steps) is still accepted on
/executeand answered with a bare array.
The OpenAPI document
Section titled “The OpenAPI document”curl -s http://localhost:3000/api/v1/openapi.json | jq .infoUse it to generate a client in a language without an SDK,
or to validate requests in tests. The repository’s openapi/examples/ holds
example requests and responses that are checked against the schema.