Skip to content

REST API

The gateway's HTTP API, generated from its own OpenAPI spec — regenerate with uv run python scripts/gen_api_reference.py. Every endpoint authenticates with Authorization: Bearer <bk_… key> (mint one in the console under API keys); the base URL is https://beta.barista.sh.

Two shapes worth knowing before the list: a session that is still starting or mid-wake answers 409 with a human-readable reason — retry shortly; and WebSocket attach (/v1/sessions/{name}/attach) is documented in the CLI reference rather than here, since OpenAPI does not describe WebSockets.

Sessions

GET /v1/sessions

The tenant's sessions, each with its one-word state (bar-052). This is the canonical list — the old /v1/fleet noun is gone.

Query parameters: - meta (array of string) — metadata filter as key=value, repeatable; all pairs must match - include (string) — 'meta' to carry each row's metadata without filtering

POST /v1/sessions

Create Session

Body: - name (string, required) - template (string) - image (string) (default: busybox:latest) - digest (string) - command (array of string) - env (object) - idle_pause_s (integer) - metadata (object) - size (string)

DELETE /v1/sessions/{name}

Delete a session: destroy its instance on the node, then forget it.

deleted means the guest VM is gone — not merely that we stopped listing the session (bar-063). When the node cannot confirm the destroy, nothing is removed and this answers a retryable 503 instead of a lying 200.

Deleting a session that has no live instance (never materialised, or already reaped) succeeds: there is nothing to leak, so dropping the desired record is the whole of the delete.

GET /v1/sessions/{name}

Get Session

POST /v1/sessions/{name}/pause

Pause a running session, keeping its memory (on a memory-snapshot runtime). Blocks until the node's async pause operation settles.

POST /v1/sessions/{name}/resume

Resume a paused session (it continues from its held memory).

POST /v1/sessions/{name}/exec

Run a command in the session over Contract A Exec and return its output. The interactive (PTY) attach is the streaming variant, added next.

output_truncated is always in the response and says whether stdout/stderr are the whole of what the command produced; when it is true, output_truncation gives the per-stream byte counts and the limit that separated them.

Body: - cmd (array of string, required) - tty (boolean) (default: False) - env (object) - workdir (string) - ready_timeout_s (number) - ensure (boolean) (default: False) - template (string)

GET /v1/sessions/{name}/logs

Bounded application/serial logs for the owning tenant's session.

Bytes are base64 inside SSE JSON so arbitrary workload output cannot break event framing. Lifecycle events remain on the separate journal endpoint.

Query parameters: - tail (integer) (default: 100) - follow (boolean) (default: False)

GET /v1/sessions/{name}/events

Server-Sent-Events tail of the node's events for this session — state changes, wake-fired, ttl warnings — filtered to its instance.

DELETE /v1/sessions/{name}/publish

Unpublish Session

POST /v1/sessions/{name}/publish

Publish a session to a public URL <slug>.<public_suffix>. The slug defaults to the session name. The published endpoint is then reachable without a key (host-based ingress), waking the session on request.

Body: - slug (string)

DELETE /v1/sessions/{name}/proxy/{path}

Forward a request to the session's workload, waking it if parked.

This is the customer-visible data path — the substrate demos' kubectl port-forward + POST, but tenant-scoped and wake-on-request: a parked session is resumed transparently before the request is proxied.

GET /v1/sessions/{name}/proxy/{path}

Forward a request to the session's workload, waking it if parked.

This is the customer-visible data path — the substrate demos' kubectl port-forward + POST, but tenant-scoped and wake-on-request: a parked session is resumed transparently before the request is proxied.

PATCH /v1/sessions/{name}/proxy/{path}

Forward a request to the session's workload, waking it if parked.

This is the customer-visible data path — the substrate demos' kubectl port-forward + POST, but tenant-scoped and wake-on-request: a parked session is resumed transparently before the request is proxied.

POST /v1/sessions/{name}/proxy/{path}

Forward a request to the session's workload, waking it if parked.

This is the customer-visible data path — the substrate demos' kubectl port-forward + POST, but tenant-scoped and wake-on-request: a parked session is resumed transparently before the request is proxied.

PUT /v1/sessions/{name}/proxy/{path}

Forward a request to the session's workload, waking it if parked.

This is the customer-visible data path — the substrate demos' kubectl port-forward + POST, but tenant-scoped and wake-on-request: a parked session is resumed transparently before the request is proxied.

Templates

GET /v1/templates

List Templates

POST /v1/templates

Register Template

Body: - name (string, required) - image (string, required) - digest (string) - description (string)

GET /v1/templates/-/registries

The registries this fleet's nodes can pull from (bar-043) — what the registration gate enforces, surfaced so a caller (and the console) can see the constraint BEFORE hitting the 422. An empty list means unrestricted. Path uses the - segment so it can never collide with a template name.

DELETE /v1/templates/{name}

Delete Template

GET /v1/templates/{name}

Get Template

API keys

GET /v1/apikeys

List Keys

POST /v1/apikeys

Create Key

DELETE /v1/apikeys/{key_id}

Revoke Key

Usage

GET /v1/usage

Current Usage