HTTP API endpoints

Every public Shardflux HTTP API operation by resource: method, path, authentication, parameters and request fields, from openapi.json.

Every operation of the public HTTP API, generated from openapi.json (OpenAPI 3.1.0, API version 0.1.0). Base URL: https://api.shardflux.dev. Send a project API key on every request: Authorization: Bearer sfk_<key_id>_<secret>. Conventions (idempotency, pagination, long-running operations) are on the HTTP API page. Error responses use the ErrorBody schema; the codes are listed under Errors.

Workspace tools (exec, PTY, processes, files, git, browser) are served by the workspace’s cell at its cell_endpoint, with a token from POST /v1/workspaces/{workspace_id}/tool-tokens; they are not listed here.

Principal

The API key making the request: its organization, project and tool permissions.

GET /v1/me

The authenticated principal.

Authentication: API key

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

Organizations

The organization an API key belongs to.

GET /v1/organizations

Organizations visible to the principal.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}

Get an organization.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

Projects

The project an API key belongs to.

GET /v1/organizations/{organization_id}/projects

List projects.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/projects/{project_id}

Get a project.

Authentication: API key

Parameters

Name In Type Required Description
project_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

Workspaces

Open workspaces by key, and suspend, resume, snapshot, fork, reset or close them.

POST /v1/workspaces/open

Open a workspace by key (create on first use, reconnect or resume afterwards).

New keys resolve template to its latest published version; reopening never changes or resets the workspace (the response reports the template version actually used). 200 when the workspace is already running and ready (with cell_endpoint and a tool token); otherwise 202 with the operation to poll. A running workspace whose startup failed (startup.state failed) is not ready: the open is 202 with an open operation (input.startup_retry) that runs the failed step again. Concurrent opens of one key share one workspace and one operation. secrets (optional) binds secret names injected into every exec/PTY start: it sets the binding of a new key and replaces it on an existing key (omitted = unchanged); an unknown or unusable name is 422 details.reason secret_not_available with details.names (nothing is created or changed). The template version’s secret inputs join the binding on create and whenever secrets is given; a required one this workspace may not use is 422 input_required (details.kind secret); a bound name equal to a template env key or text input is 422 env_collision (details.name). inputs (optional): the version’s text inputs {NAME: string}; stored on create (else the declared default) and replaced on an existing key (omitted = unchanged); 422 input_unknown, input_invalid or input_required (details.names). lifetime: omitted = the version’s default (else persistent); session workspaces are discarded when the session ends (close(), idle timeout), after which the key opens a NEW workspace; reopening a live key with another lifetime is 409 lifetime_mismatch. A new workspace is layered when its version supports it and layered opens are enabled (disk_layout). Errors: 404 template/key outside scope, 402 entitlement_required, 403 quota_exceeded (details.limit), 409 operation in progress, deleted key (workspace_deleted) or lifetime_mismatch, 422 reserved_key_prefix (keys starting with sf:). Supports Idempotency-Key. Held open: with Prefer: wait=<seconds> (at most 20) an open whose outcome is an operation is held until the operation is terminal or the wait elapses; success answers 200 with the running workspace, the succeeded operation and a tool token (Preference-Applied: wait=<seconds>), anything else 202 with the fresh operation. Without Preference-Applied the server did not wait: poll the operation. mode: omitted = processful for a new key and the stored mode for an existing one; file_first creates a workspace whose state is a versioned file tree with no VM between executions: it is ready at once (200 with a tool token, observed_state running, tree_revision 0, no operation), needs a layered template version (409 layout_unsupported otherwise) and is persistent (lifetime: session or idle_policy with it are 422 not_supported_for_mode); each open of a file-first key re-resolves the size of its execution VMs from caps, the template and the plan. 422 mode_not_available while the deployment does not offer file-first workspaces; reopening a key with another mode is 409 mode_mismatch.

Authentication: API key

Parameters

Name In Type Required Description
prefer header string no RFC 7240 preference, e.g. wait=20 (held open).

Request body (application/json, required)

Field Type Required Description
key string yes Stable workspace key, unique per organization (e.g. ${customerId}/${projectId}).
template string yes Template slug; new workspaces use its latest published version.
caps object no Optional user caps; the ceiling is min(template, cap, plan). Absent fields add no restriction.
project_id string (uuid) no UUIDv7, lowercase canonical form.
agent_label string no Attribution label; one agent session per (workspace, principal, label).
tools array of "exec" or "files" or "pty" or "process" or "git" or "browser" no
secrets array of string no Secret names bound to the workspace (max 50, unique): injected as environment variables into every exec and PTY start (terminal sessions included), together with the call’s own secret_refs. Each must name a live secret this workspace may use (its project, its id, and allowed_tools including exec and pty), else 422 details.reason secret_not_available with details.names.
inputs object no Open-time inputs of the template version: {NAME: string} for its declared text inputs. A new workspace stores each given value, else the declared default; on an existing key inputs replaces them all (omitted = unchanged). Secret inputs are not passed here: they bind the stored secret of the same name. 422 input_unknown (undeclared name, details.names), input_invalid (a secret input, a non-string, or a value over 4096 bytes or with CR, LF or NUL; details.names), input_required (details {names, kind}).
lifetime WorkspaceLifetime no persistent: kept until deleted (default). session: discarded when the session ends (close(), idle timeout or draft discard;).
idle_policy string no adaptive (the learned timeout, default), never, or fixed:<seconds> (60..604800).
mode WorkspaceMode no processful (default): one VM keeps processes, memory and files between calls; it can be suspended, resumed and forked. file_first: the state is a versioned file tree (tree_revision); there is no VM between executions, each exec runs in a fresh VM and publishes the changed files as the next revision, nothing but files survives an execution. A file-first workspace is ready (running) from creation and is never suspended; suspend, resume, snapshot, fork, reset, save-as-template, volumes and idle policies are 409 not_supported_for_mode. Immutable.

Responses: 200 · 202 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/workspaces

List workspaces (API keys: their project; users: their organizations).

By default only persistent standard workspaces; lifetime and purpose (each also any) show sessions, drafts and test instances. Ended sessions are tombstones: add include_deleted=true.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
organization_id query string (uuid) no UUIDv7, lowercase canonical form.
project_id query string (uuid) no UUIDv7, lowercase canonical form.
state query string (one of 11) no Observed state filter.
desired_state query "running" or "suspended" or "deleted" no
key_prefix query string no
include_deleted query boolean no
lifetime query "persistent" or "session" or "any" no persistent (default), session or any. Key lookups pass any.
purpose query "standard" or "template_draft" or "template_test" or "any" no standard (default), template_draft, template_test or any. Key lookups pass any.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/workspaces

List an organization’s workspaces (API keys see only their project).

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
project_id query string (uuid) no UUIDv7, lowercase canonical form.
state query string (one of 11) no Observed state filter.
desired_state query "running" or "suspended" or "deleted" no
key_prefix query string no
include_deleted query boolean no
lifetime query "persistent" or "session" or "any" no persistent (default), session or any. Key lookups pass any.
purpose query "standard" or "template_draft" or "template_test" or "any" no standard (default), template_draft, template_test or any. Key lookups pass any.
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/workspaces/{workspace_id}

Get a workspace: desired/observed state, cell, template version, caps/ceilings, grants, active operation, pending reason.

Tombstoned workspaces stay readable (deleted_at set) until final cleanup.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 Workspace · 4XX ErrorBody · 5XX ErrorBody

DELETE /v1/workspaces/{workspace_id}

Delete a workspace (tombstone now, storage cleanup by the cell).

Sets desired_state=deleted and deleted_at, revokes tool access immediately (workspace revocation watermark, agent sessions revoked) and creates a delete operation for the cell. A file-first workspace’s tree revisions are deleted with the tombstone and the cell deletes its stored files. Repeating returns the same operation. The key is never reused. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/workspaces/{workspace_id}/inputs

The workspace’s text inputs.

The text inputs the workspace was opened with (the given value, else the declared default). Every exec, PTY, start command and service gets them as environment variables, above the template env and below the call’s own env. Secret inputs are bound secrets (GET …/secrets). Set on create; replaced by an open of the key with inputs. Deleted workspaces stay readable.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 WorkspaceInputs · 4XX ErrorBody · 5XX ErrorBody

PUT /v1/workspaces/{workspace_id}/idle-policy

Set or clear the workspace idle policy (automatic suspend).

idle_policy: adaptive (the learned timeout), never, or fixed:<seconds> (60..604800); null clears it so the template default (else adaptive) applies. Work signals always win: a running command, an attached session or a keepalive keeps the workspace running. Applies from the idle loop’s next evaluation. 409 session_lifetime for session workspaces (they end after their idle timeout), 409 not_supported_for_mode for file-first workspaces (never suspended), 409 workspace_deleted. Returns the workspace.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required)

Field Type Required Description
idle_policy string or null yes

Responses: 200 Workspace · 4XX ErrorBody · 5XX ErrorBody

POST /v1/workspaces/{workspace_id}/suspend

Suspend a running workspace (durable full-state checkpoint; a session workspace is 409 session_lifetime).

Creates a durable operation executed by the cell (Phase 8); poll GET /operations/{id}. A file-first workspace is 409 not_supported_for_mode. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/workspaces/{workspace_id}/resume

Resume a suspended workspace (admitted like a start).

Creates a resume operation executed by the cell, or returns the active resume/open (concurrent wakes join one operation); 202 with it: poll GET /operations/{id}. Errors: 409 already_running or not_suspended, operation_in_progress (a suspend or another operation is active; details.active_operation_id), workspace_deleted, not_supported_for_mode (file-first); 402/403 as for open (admitted like a start). Supports Idempotency-Key. Held resume: with Prefer: wait=<seconds> (at most 20) the response is held until the operation is terminal or the wait elapses, exactly like a held open; success answers 200 with the running workspace, the succeeded operation, cell_endpoint and a tool token for agent_label/tools (minted while the restore is in flight, at the new ownership epoch), Preference-Applied: wait=<seconds>; anything else is 202 with the fresh operation. With the preference a workspace that is already running answers 200 at once (operation null, a token) instead of 409 already_running. Without Preference-Applied the server did not wait: poll the operation. tools beyond the principal’s tool permissions are 403 (nothing is created); a token the API cannot issue otherwise is tool_token: null.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.
prefer header string no RFC 7240 preference, e.g. wait=20 (held resume).

Request body (application/json, optional)

Field Type Required Description
agent_label string no Attribution label; one agent session per (workspace, principal, label).
tools array of "exec" or "files" or "pty" or "process" or "git" or "browser" no

Responses: 200 · 202 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/workspaces/{workspace_id}/snapshot

Snapshot a running or suspended workspace.

Creates a durable operation executed by the cell (Phase 8); poll GET /operations/{id}. A file-first workspace is 409 not_supported_for_mode. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required)

Field Type Required Description
label string no

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/workspaces/{workspace_id}/suspend-when-idle

Suspend the workspace if it stays idle for after_seconds from now (e.g. at the end of an agent turn).

Records a deferred suspend for the cell’s idle loop: once the workspace has been idle for after_seconds (30..3600), it is suspended (within a few seconds of activity flush grace), at not_before (= now + after_seconds) at the earliest. A tool call after the request (the next turn) or a resume cancels it for good. Other work only defers it: a command still running, an attached exec/PTY stream or a keepalive postpones the suspend until after_seconds after it ends. It applies under every idle policy (never included) and only ever shortens the policy’s wait; a policy that suspends sooner still does. Repeating replaces the pending request (the new requested_at counts); DELETE cancels it; idle.suspend_request on the workspace shows it. 202 {workspace, operation: null, suspend_request}; when a suspend is already in progress, 202 {workspace, operation: that suspend, suspend_request: null} and nothing is recorded. The suspend, when it happens, is a system suspend operation with input.reason requested_after_idle (input.requested_at, input.after_seconds). Errors: 409 session_lifetime, workspace_deleted, operation_in_progress (another lifecycle operation is active), not_running, not_supported_for_mode (file-first). Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required)

Field Type Required Description
after_seconds integer yes Seconds from now the workspace must stay idle before it is suspended (30..3600).

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

DELETE /v1/workspaces/{workspace_id}/suspend-when-idle

Cancel a pending suspend-when-idle request.

Idempotent: 200 with the workspace whether or not a request was pending, in any workspace state (idle.suspend_request is null afterwards). A suspend the request already started is not undone: it shows as the workspace’s active_operation; resume or open the workspace instead.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 Workspace · 4XX ErrorBody · 5XX ErrorBody

POST /v1/workspaces/{workspace_id}/fork

Fork a workspace into a new key (independent copy of its committed state).

Creates the target workspace (same template version and disk layout) and a fork operation on it, admitted like a start. Caps default to the source’s. lifetime is the fork’s own (default persistent): forking a session keeps its state. A file-first source is 409 not_supported_for_mode. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required)

Field Type Required Description
key string yes Stable workspace key, unique per organization (e.g. ${customerId}/${projectId}).
caps object no Optional user caps; the ceiling is min(template, cap, plan). Absent fields add no restriction.
lifetime WorkspaceLifetime no persistent: kept until deleted (default). session: discarded when the session ends (close(), idle timeout or draft discard;).

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/workspaces/{workspace_id}/close

Close a session workspace (ends the session: the workspace is deleted).

Sessions only (409 not_session for a persistent workspace; the SDK then only closes local streams). Ends the session exactly like a delete (VM stopped without a snapshot, layer and checkpoints released) with ended_reason closed; the key then opens a NEW workspace. 202 with the delete operation (input.reason session_closed). Idempotent: repeating returns the active or last delete operation. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/workspaces/{workspace_id}/reset

Reset a layered workspace to its template (wipes the workspace layer).

Keeps the key, id, template version, caps, secret bindings, volume attachments and history; wipes every change. Running: restarted on a blank layer (processes are gone, epoch + 1, old tool tokens get 409 stale_epoch). Suspended: stays suspended; the next resume boots blank. The previous checkpoint stays restorable for 7 days (result.recovery_checkpoint_id). 202 with the reset operation. Errors: 422 confirm_destructive_required, 409 legacy_disk_layout, not_resettable, operation_in_progress, not_supported_for_mode (file-first). Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required, ResetWorkspaceBody)

Field Type Required Description
confirm_destructive boolean no Must be true: reset wipes every change in the workspace layer (422 confirm_destructive_required otherwise).

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/workspaces/{workspace_id}/save-as-template

Save a layered workspace as the next version of an organization template.

Everything in the workspace becomes template content (its whole filesystem, minus the sf-scrub.v1 list, the contents of /proc, /sys, /dev, /run and /tmp, and shared-volume contents), stored as one new org layer on the workspace’s template chain. A running workspace is captured briefly (operation, layer_snapshot); a suspended one uses its current checkpoint; checkpoint_id saves a committed checkpoint instead. 202 SaveAsTemplateResponse: poll the build. Owners/admins and API keys with a tool permission (403 otherwise). Errors: 409 legacy_disk_layout, workspace_not_running, operation_in_progress, not_supported_for_mode (file-first), template_archived, 422 platform_template_slug, invalid_defaults, update_policy_not_available, too_many_acknowledged_findings, invalid_path, 403 quota_exceeded (concurrent_template_builds). Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required, SaveAsTemplateBody)

Field Type Required Description
template_slug string yes Organization template to save into (created when absent; platform slugs are refused).
display_name string no Template name when this save creates the template.
description string no The version description (default: the source version’s).
defaults object no Defaults of the new version (omitted fields: persistent lifetime, platform idle timeout, no limits).
checkpoint_id string (uuid) no A committed checkpoint of this workspace to save instead of its current state.
auto_publish boolean no
acknowledged_scan_findings array of string no Up to 200 absolute paths the credential scan may report without failing the build (recorded in the manifest).
settings TemplateSettingsInput no What a workspace of the version gets when it opens (). Omitted fields are empty (recipes do not carry settings forward).

Responses: 202 SaveAsTemplateResponse · 4XX ErrorBody · 5XX ErrorBody

GET /v1/workspaces/{workspace_id}/secrets

Secret names bound to a workspace, with per-name status (never values).

Bound secrets are injected into every exec and PTY start of the workspace together with the call’s secret_refs. status: available | not_allowed | deleted. Deleted workspaces stay readable.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

PUT /v1/workspaces/{workspace_id}/secrets

Replace the secret names bound to a workspace.

Replaces the whole binding (names: [] clears it); applies from the next exec/PTY start (running processes keep their environment). Every name must be a live secret this workspace may use (its project, its id, and allowed_tools including exec and pty), else 422 details.reason secret_not_available with details.names and nothing changes. A name equal to a key of the template version’s env or one of its text inputs is 422 env_collision (details.name;). Exactly the given names are bound (the version’s secret inputs join the binding only through open). Audited when the binding changes. 409 workspace_deleted.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required)

Field Type Required Description
names array of string yes Secret names bound to the workspace (max 50, unique): injected as environment variables into every exec and PTY start (terminal sessions included), together with the call’s own secret_refs. Each must name a live secret this workspace may use (its project, its id, and allowed_tools including exec and pty), else 422 details.reason secret_not_available with details.names.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

Operations

Lifecycle operations (open, suspend, resume, fork, ...) and their progress.

GET /v1/operations/{operation_id}

Poll an asynchronous operation.

Stays readable after its workspace is tombstoned. Bounded wait: with Prefer: wait=<seconds> (at most 20) and an operation that is not terminal, the response is held until its state or state_reason changes or the wait elapses, then carries the fresh operation and Preference-Applied: wait=<seconds>. Without Preference-Applied the server did not wait: poll with backoff.

Authentication: API key

Parameters

Name In Type Required Description
operation_id path string (uuid) yes UUIDv7, lowercase canonical form.
prefer header string no RFC 7240 preference, e.g. wait=20.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/workspaces/{workspace_id}/operations

List a workspace’s operations, newest first.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
state query "queued" or "capacity_pending" or "running" or "succeeded" or "failed" or "canceled" no
kind query string (one of 15) no
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

Tool tokens

Short-lived tokens for the workspace tools (exec, PTY, files, git, browser) served at the workspace’s cell_endpoint, and agent sessions.

POST /v1/workspaces/{workspace_id}/tool-tokens

Issue a workspace tool token (ES256, <= 15 min) for the cell gateway.

Creates or reuses the agent session for (workspace, principal, agent_label) and signs a token with claims iss, aud, sub, pty, org, prj, ws, epoch, tools, sid, iat, exp, jti (verify with GET /v1/.well-known/tool-token-keys). tools must be a subset of the API key’s tool permissions (users: of their role). A suspended workspace gets a token too: the cell serves it only the reads of its disk (files read, stat, list and search, X-Served-From: disk) and answers every other call 409 workspace_not_running (wake the workspace; its resume moves the ownership epoch). 409 with the active operation when the workspace is neither running nor suspended; on 409 stale_epoch from the cell, request a new token.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required)

Field Type Required Description
agent_label string no Attribution label; one agent session per (workspace, principal, label).
tools array of "exec" or "files" or "pty" or "process" or "git" or "browser" no

Responses: 201 ToolToken · 4XX ErrorBody · 5XX ErrorBody

GET /v1/workspaces/{workspace_id}/agent-sessions

List the attributed agent sessions of a workspace.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

Volumes

Persistent volumes shared between workspaces of a project.

GET /v1/projects/{project_id}/volumes

List a project’s shared volumes (optionally with the organization’s org-shared volumes).

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
include_org_shared query boolean no Also list org-shared volumes owned by other projects of the organization (attachable here).
include_deleted query boolean no
project_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/projects/{project_id}/volumes

Create a shared volume (EFS access point created by the cell).

202 with the volume (state creating) and its volume_create operation; the volume becomes available when the cell has created its storage (poll the operation or the volume). Quotas from the plan: limit.shared_volumes_max (live volumes per organization) and limit.shared_volume_gib_max (quota_gib of one volume) -> 403 quota_exceeded (details.limit); a plan without them -> 402 entitlement_required (details.reason limits_missing). org_shared: true (owners/admins only) makes it attachable from every project of the organization. 409 name_in_use. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
project_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required)

Field Type Required Description
name string yes Unique among the project’s live volumes.
quota_gib integer yes
org_shared boolean no

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/projects/{project_id}/volumes/{volume_id}

Get a shared volume (the project’s own, or an org-shared volume of its organization).

Authentication: API key

Parameters

Name In Type Required Description
project_id path string (uuid) yes UUIDv7, lowercase canonical form.
volume_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 Volume · 4XX ErrorBody · 5XX ErrorBody

DELETE /v1/projects/{project_id}/volumes/{volume_id}

Delete a shared volume and its data (executed by the cell).

202 with the volume (state deleting) and its volume_delete operation; deleted once the cell removed the data and the access point. Refused with 409 volume_attached (details.attachments) while it is attached, unless force=true&confirm_name=<volume name>: attachments are then detached by the delete (running guests see I/O errors on the mount). Only the owning project; org-shared volumes only by owners/admins. Idempotent (a deleting/deleted volume returns its delete operation). Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
force query boolean no
confirm_name query string no
project_id path string (uuid) yes UUIDv7, lowercase canonical form.
volume_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/projects/{project_id}/volumes/{volume_id}/attachments

List a volume’s attachments (API keys: only to their project’s workspaces).

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
include_detached query boolean no
project_id path string (uuid) yes UUIDv7, lowercase canonical form.
volume_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/workspaces/{workspace_id}/volumes

List the volumes attached to a workspace.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
include_detached query boolean no
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/workspaces/{workspace_id}/volumes

Attach a shared volume to a workspace at mount_path (ro or rw).

202 with the attachment (state attaching) and its volume_attach operation; the cell mounts it in the running guest (or records it for the next start when the workspace has no VM) and reports attached. The volume must be available, of the same organization and of the workspace’s project unless org-shared (409 volume_not_shared). One attachment per (volume, workspace); mount paths may not nest (409 mount_path_conflict); at most 8 per workspace (403 quota_exceeded). Attach/detach share the workspace’s single active lifecycle operation: 409 operation_in_progress while another one runs. Re-attaching an attached volume with the same mount_path/mode returns 200 without a new operation. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required)

Field Type Required Description
volume_id string (uuid) yes UUIDv7, lowercase canonical form.
mount_path string yes Absolute guest path (e.g. /mnt/data); segments of A-Z a-z 0-9 . _ - not starting with "."; system directories (/etc, /usr, /proc, /tmp, /var, ...) and nesting with another mount are refused.
mode "ro" or "rw" no

Responses: 200 · 202 · 4XX ErrorBody · 5XX ErrorBody

DELETE /v1/workspaces/{workspace_id}/volumes/{volume_id}

Detach a shared volume from a workspace.

202 with the attachment (state detaching) and its volume_detach operation; the cell unmounts it (the guest sees I/O errors on the path afterwards, never stale writes) and reports detached. Idempotent while detaching. 404 when the volume is not attached. 409 operation_in_progress while another lifecycle operation of the workspace runs. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.
volume_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

Templates

Published templates and their versions, files, recipes and diffs.

GET /v1/organizations/{organization_id}/templates

List the templates an organization can use (platform + its own), with the version open picks.

Archived templates only with include_archived=true. Ordered by id; cursor pagination.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
include_archived query boolean no Include archived templates and versions.
owner query "platform" or "organization" no
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/templates/{slug}

Get a template by slug with its versions, compatibility, caps, installed tools and plan clamping.

The organization’s own template shadows a platform template of the same slug (like open); open_resolves_to is what open would use now. Unpublished versions appear only for owners/admins of the owning organization. 404 outside the organization.

Authentication: API key

Parameters

Name In Type Required Description
include_archived query boolean no Include archived templates and versions.
owner query "platform" or "organization" no Pick the platform template even when an organization template shadows its slug.
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/templates

List the templates an organization can use (platform + its own), with the version open picks (the API key’s organization).

Archived templates only with include_archived=true. Ordered by id; cursor pagination.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
include_archived query boolean no Include archived templates and versions.
owner query "platform" or "organization" no

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/templates/{slug}

Get a template by slug with its versions, compatibility, caps, installed tools and plan clamping (the API key’s organization).

The organization’s own template shadows a platform template of the same slug (like open); open_resolves_to is what open would use now. Unpublished versions appear only for owners/admins of the owning organization. 404 outside the organization.

Authentication: API key

Parameters

Name In Type Required Description
include_archived query boolean no Include archived templates and versions.
owner query "platform" or "organization" no Pick the platform template even when an organization template shadows its slug.
slug path string yes

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/templates/{slug}/versions/{version}/files

List one directory of a template version’s file tree.

Entries directly inside path (default /), sorted by name bytes, keyset-paginated. The tree covers the whole filesystem (only the contents of /proc, /sys, /dev, /run and /tmp are left out). 409 file_list_unavailable (no file list) or file_list_indexing (retryable); 404 path_not_found; 422 invalid_path.

Authentication: API key

Parameters

Name In Type Required Description
path query string no Absolute path (/, /home/user, no trailing slash).
limit query integer no
cursor query string no
owner query "platform" or "organization" no Pick the platform template even when an organization template shadows its slug.
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes
version path integer yes

Responses: 200 TemplateFilePage · 4XX ErrorBody · 5XX ErrorBody

GET /v1/templates/{slug}/versions/{version}/files

List one directory of a template version’s file tree.

Entries directly inside path (default /), sorted by name bytes, keyset-paginated. The tree covers the whole filesystem (only the contents of /proc, /sys, /dev, /run and /tmp are left out). 409 file_list_unavailable (no file list) or file_list_indexing (retryable); 404 path_not_found; 422 invalid_path.

Authentication: API key

Parameters

Name In Type Required Description
path query string no Absolute path (/, /home/user, no trailing slash).
limit query integer no
cursor query string no
owner query "platform" or "organization" no Pick the platform template even when an organization template shadows its slug.
slug path string yes
version path integer yes

Responses: 200 TemplateFilePage · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/templates/{slug}/versions/{version}/files/entry

Get one entry of a template version’s file tree.

404 path_not_found; 409 file_list_unavailable / file_list_indexing; 422 invalid_path.

Authentication: API key

Parameters

Name In Type Required Description
path query string yes Absolute path (/, /home/user, no trailing slash).
owner query "platform" or "organization" no Pick the platform template even when an organization template shadows its slug.
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes
version path integer yes

Responses: 200 TemplateFileEntry · 4XX ErrorBody · 5XX ErrorBody

GET /v1/templates/{slug}/versions/{version}/files/entry

Get one entry of a template version’s file tree.

404 path_not_found; 409 file_list_unavailable / file_list_indexing; 422 invalid_path.

Authentication: API key

Parameters

Name In Type Required Description
path query string yes Absolute path (/, /home/user, no trailing slash).
owner query "platform" or "organization" no Pick the platform template even when an organization template shadows its slug.
slug path string yes
version path integer yes

Responses: 200 TemplateFileEntry · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/templates/{slug}/diff

Diff two versions of a template (path, change, before, after).

from is a version number of this template or base (the to version’s build base, which may be a platform version). Keyset-paginated by path; path_prefix narrows it (string prefix), change filters one kind. The first page (no cursor) carries summary. 409 file_list_unavailable / file_list_indexing when either version has no loaded file list.

Authentication: API key

Parameters

Name In Type Required Description
from query string yes A version number, or base.
to query integer yes
path_prefix query string no
change query "added" or "removed" or "changed" or "type_changed" or "metadata" no
limit query integer no
cursor query string no
owner query "platform" or "organization" no Pick the platform template even when an organization template shadows its slug.
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes

Responses: 200 TemplateDiffPage · 4XX ErrorBody · 5XX ErrorBody

GET /v1/templates/{slug}/diff

Diff two versions of a template (path, change, before, after).

from is a version number of this template or base (the to version’s build base, which may be a platform version). Keyset-paginated by path; path_prefix narrows it (string prefix), change filters one kind. The first page (no cursor) carries summary. 409 file_list_unavailable / file_list_indexing when either version has no loaded file list.

Authentication: API key

Parameters

Name In Type Required Description
from query string yes A version number, or base.
to query integer yes
path_prefix query string no
change query "added" or "removed" or "changed" or "type_changed" or "metadata" no
limit query integer no
cursor query string no
owner query "platform" or "organization" no Pick the platform template even when an organization template shadows its slug.
slug path string yes

Responses: 200 TemplateDiffPage · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/templates/{slug}/versions/{version}/recipe

Export the recipe and settings of a template version (request form, ready to build again).

recipe: v1 {base, dockerfile, network} or the recipe v2 document (base as <slug>@<version>, languages as {id, version}, files without size, settings as stored); building it again from the same base with the same API release, while its uploads exist, gives the same recipe_sha256. null for versions saved from a workspace or published by the platform. settings: the version’s TemplateSettings. Same visibility as the version (unpublished only for owners/admins of the owning organization).

Authentication: API key

Parameters

Name In Type Required Description
owner query "platform" or "organization" no Pick the platform template even when an organization template shadows its slug.
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes
version path integer yes

Responses: 200 TemplateVersionRecipe · 4XX ErrorBody · 5XX ErrorBody

GET /v1/templates/{slug}/versions/{version}/recipe

Export the recipe and settings of a template version (request form, ready to build again).

recipe: v1 {base, dockerfile, network} or the recipe v2 document (base as <slug>@<version>, languages as {id, version}, files without size, settings as stored); building it again from the same base with the same API release, while its uploads exist, gives the same recipe_sha256. null for versions saved from a workspace or published by the platform. settings: the version’s TemplateSettings. Same visibility as the version (unpublished only for owners/admins of the owning organization).

Authentication: API key

Parameters

Name In Type Required Description
owner query "platform" or "organization" no Pick the platform template even when an organization template shadows its slug.
slug path string yes
version path integer yes

Responses: 200 TemplateVersionRecipe · 4XX ErrorBody · 5XX ErrorBody

Template builds

Build template versions from a recipe or an uploaded context, and look up packages and languages.

GET /v1/organizations/{organization_id}/template-builds

List an organization’s template builds, newest first.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
state query string (one of 8) no
template query string no Organization template slug.
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/organizations/{organization_id}/template-builds

Request a custom template build (queued for the isolated builder).

202 with the queued build. Takes recipe v1 (a Dockerfile) or recipe v2 (: validated against the base, compiled to the builder’s steps, uploads locked). Records the canonical recipe and its SHA-256 (provenance input), pins the base version, clamps resources to the plan and assigns target_version. The cell executes it (building -> testing -> publishing -> published) and the API then registers the version (published at once unless auto_publish=false); poll GET .../template-builds/{id} until registration.state is registered (or the build failed/was canceled). builder_availability says whether a builder is running. Errors: 422 when the recipe is outside the host builder Dockerfile dialect or the slug is not a builder slug (details.reason: multi_stage_not_supported, from_not_template_base, stage_names_not_supported, from_flags_not_supported, base_mismatch, run_flags_not_supported, heredoc_not_supported, instruction_not_supported, no_build_context, env_invalid, user_invalid, too_many_steps, recipe_too_large, slug_not_supported_by_builder, platform_template_slug, reserved_template_slug, base_not_found, base_not_published, base_archived, architecture_not_supported, ...; line for line errors; recipe v2: invalid_recipe (details.field, details.detail), base_not_layered, language_unavailable, language_conflict, invalid_package, too_many_files, platform_owned_path, invalid_path, upload_required, upload_missing, upload_digest_mismatch, upload_too_large, too_many_steps, recipe_too_large, allowlist_empty, allow_hosts_without_allowlist, extra_hosts_without_auto, too_many_hosts, invalid_host, ip_literal_not_allowed, host_not_allowed, invalid_settings, services_unsupported, too_many_acknowledged_findings), 503 dependency_unavailable (uploads_not_configured), 402 entitlement_required, 403 quota_exceeded (concurrent_template_builds), 409 template_archived. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required)

Field Type Required Description
template_slug string yes Organization template to build into (created by the first build). Platform slugs and the reserved slugs new and edit are refused for new templates.
auto_publish boolean no Publish the produced version as soon as it is registered (new workspaces of the slug then use it). false: it stays unpublished until an owner/admin publishes it.
display_name string no Template name when this build creates the template.
recipe TemplateRecipeV1 or TemplateRecipeV2 yes Recipe v1 (TemplateRecipeV1: a Dockerfile, no schema field) or recipe v2 (TemplateRecipeV2, schema: "shardflux.template-recipe.v2": languages, packages, uploaded files, build steps, auto network and settings;).
description string no The version description (manifest description).
acknowledged_scan_findings array of string no Recipe v2 only: up to 200 absolute paths the credential scan may report without failing the build (recorded in the manifest).

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/template-builds/{build_id}

Get a template build: state, timestamps, bounds, provenance, results, failure, log tail and builder availability.

Bounded wait: with Prefer: wait=<seconds> (at most 20) and a build that is not settled (settled = failed, canceled, legacy succeeded, or published with registration registered/failed), the response is held until state or registration.state changes or the wait elapses, then carries the fresh build and Preference-Applied: wait=<seconds>. Without Preference-Applied the server did not wait: poll with backoff.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
build_id path string (uuid) yes UUIDv7, lowercase canonical form.
prefer header string no RFC 7240 preference, e.g. wait=20.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/organizations/{organization_id}/template-builds/{build_id}/cancel

Cancel a template build.

queued -> canceled (200); building/testing/publishing -> cancellation requested (202; honoured until the artifact upload starts, so a build in publishing may still end published); canceled -> unchanged (200); published/succeeded/failed -> 409 build_finished. API keys may cancel only builds they requested.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
build_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 202 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/template-builds/{build_id}/log-url

Get a short-lived download URL for the full build log.

Presigned S3 GET of builds/<build_id>.log (served as an attachment build-<id>.log, text/plain), valid until expires_at (at most 15 minutes). Same access as reading the build. 404 not_found with details.reason log_not_available (no full log recorded for this build, e.g. still running) or log_expired (past its retention); 503 dependency_unavailable when this deployment has no build-log bucket. Audited; never cached.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
build_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/organizations/{organization_id}/template-uploads

Request an upload of a recipe build input (a file, or a folder as an uncompressed tar), by content.

200 {upload, put: null} when the organization already has these bytes (a pending upload is checked in the bucket first). 201 with a presigned S3 PUT otherwise (valid 900 s): send the bytes with every header of put.headers (x-amz-checksum-sha256 and content-length are signed, so S3 refuses other bytes), then reference sha256:<hex> in the recipe’s build.files. Idempotent by content (no Idempotency-Key needed). Errors: 422 upload_too_large (details.limit upload_bytes_max: at most 5 GiB), 422 upload_digest_mismatch (the same sha256 is available with another size), 503 dependency_unavailable (uploads_not_configured). Owners/admins and API keys with a tool permission.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required, TemplateUploadRequest)

Field Type Required Description
sha256 string yes Lower-case hex SHA-256 of the bytes.
size integer yes Bytes, at most 5368709120 (5 GiB; more is 422 upload_too_large).
kind "file" or "tar" yes file, or tar (an uncompressed ustar/pax archive of a folder). Recorded for display; the recipe entry decides.

Responses: 200 TemplateUploadResponse · 201 TemplateUploadResponse · 4XX ErrorBody · 5XX ErrorBody

POST /v1/template-uploads

Request an upload of a recipe build input (a file, or a folder as an uncompressed tar), by content (the API key’s organization).

200 {upload, put: null} when the organization already has these bytes (a pending upload is checked in the bucket first). 201 with a presigned S3 PUT otherwise (valid 900 s): send the bytes with every header of put.headers (x-amz-checksum-sha256 and content-length are signed, so S3 refuses other bytes), then reference sha256:<hex> in the recipe’s build.files. Idempotent by content (no Idempotency-Key needed). Errors: 422 upload_too_large (details.limit upload_bytes_max: at most 5 GiB), 422 upload_digest_mismatch (the same sha256 is available with another size), 503 dependency_unavailable (uploads_not_configured). Owners/admins and API keys with a tool permission.

Authentication: API key

Request body (application/json, required, TemplateUploadRequest)

Field Type Required Description
sha256 string yes Lower-case hex SHA-256 of the bytes.
size integer yes Bytes, at most 5368709120 (5 GiB; more is 422 upload_too_large).
kind "file" or "tar" yes file, or tar (an uncompressed ustar/pax archive of a folder). Recorded for display; the recipe entry decides.

Responses: 200 TemplateUploadResponse · 201 TemplateUploadResponse · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/template-packages

Search apt, pip or npm packages for a recipe.

apt: the base’s package index (409 package_index_unavailable when the base has none); pip: the daily PyPI name list (names only; 409 package_index_unavailable before its first refresh); npm: the registry search. Upstreams are bounded (503 dependency_unavailable, retryable, when they do not answer within 2.5 s) and each organization may make 120 lookups a minute (429 rate_limited). Owners/admins and API keys with a tool permission.

Authentication: API key

Parameters

Name In Type Required Description
ecosystem query "apt" or "pip" or "npm" yes
q query string yes
base query string no <slug>@<version> (apt: the base whose apt index is searched).
limit query integer no
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 TemplatePackagePage · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/template-packages/{ecosystem}/{name}

Get one apt, pip or npm package: latest version, summary and versions.

404 not_found (package_not_found). apt needs base=<slug>@<version>. Same limits as the search.

Authentication: API key

Parameters

Name In Type Required Description
base query string no <slug>@<version> (apt: the base whose apt index is searched).
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
ecosystem path "apt" or "pip" or "npm" yes
name path string yes

Responses: 200 TemplatePackage · 4XX ErrorBody · 5XX ErrorBody

GET /v1/template-packages

Search apt, pip or npm packages for a recipe (the API key’s organization).

apt: the base’s package index (409 package_index_unavailable when the base has none); pip: the daily PyPI name list (names only; 409 package_index_unavailable before its first refresh); npm: the registry search. Upstreams are bounded (503 dependency_unavailable, retryable, when they do not answer within 2.5 s) and each organization may make 120 lookups a minute (429 rate_limited). Owners/admins and API keys with a tool permission.

Authentication: API key

Parameters

Name In Type Required Description
ecosystem query "apt" or "pip" or "npm" yes
q query string yes
base query string no <slug>@<version> (apt: the base whose apt index is searched).
limit query integer no

Responses: 200 TemplatePackagePage · 4XX ErrorBody · 5XX ErrorBody

GET /v1/template-packages/{ecosystem}/{name}

Get one apt, pip or npm package: latest version, summary and versions (the API key’s organization).

404 not_found (package_not_found). apt needs base=<slug>@<version>. Same limits as the search.

Authentication: API key

Parameters

Name In Type Required Description
base query string no <slug>@<version> (apt: the base whose apt index is searched).
ecosystem path "apt" or "pip" or "npm" yes
name path string yes

Responses: 200 TemplatePackage · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/template-languages

The recipe languages a base offers: version, default, whether the base already has it, and the hosts its install needs.

The language table read for the chain’s platform base of base, resolved as a build resolves recipe.base (422 validation_failed with details.field "base" and the build’s reasons: base_not_found, base_archived, base_not_published, architecture_not_supported). included: the base already has that version (python-node-browser: python and node), so the build installs nothing for it. A version the base has another version of is left out (a build would refuse it with language_conflict). Owners/admins and API keys with a tool permission.

Authentication: API key

Parameters

Name In Type Required Description
base query string yes <slug>@<version> (apt: the base whose apt index is searched).
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 TemplateLanguages · 4XX ErrorBody · 5XX ErrorBody

GET /v1/template-languages

The recipe languages a base offers: version, default, whether the base already has it, and the hosts its install needs (the API key’s organization).

The language table read for the chain’s platform base of base, resolved as a build resolves recipe.base (422 validation_failed with details.field "base" and the build’s reasons: base_not_found, base_archived, base_not_published, architecture_not_supported). included: the base already has that version (python-node-browser: python and node), so the build installs nothing for it. A version the base has another version of is left out (a build would refuse it with language_conflict). Owners/admins and API keys with a tool permission.

Authentication: API key

Parameters

Name In Type Required Description
base query string yes <slug>@<version> (apt: the base whose apt index is searched).

Responses: 200 TemplateLanguages · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/template-builder-availability

Whether a template builder is running (heartbeat within 60 s).

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

Template drafts

Draft templates: iterate on states and test instances, then publish a version.

GET /v1/organizations/{organization_id}/templates/{slug}/draft

Get the template’s draft.

404 draft_not_found when the template has no live draft.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes

Responses: 200 TemplateDraft · 4XX ErrorBody · 5XX ErrorBody

POST /v1/organizations/{organization_id}/templates/{slug}/draft

Create the template’s draft (a layered workspace on the draft base).

Opens the organization template’s single live draft (key sf:draft:<slug>:<8 hex>, purpose template_draft, persistent, layered) on base (default: the latest published version; required when the template has none, which creates the organization template named display_name, default the slug). 202 with the open operation and the draft. Errors: 409 template_not_layered (the base is not layered-capable, or layered opens are off), 409 draft_exists (details.workspace_id), 403 template_dev_mode_role, 422 platform_template_slug / reserved_template_slug (new, edit) / base_required. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes

Request body (application/json, required, CreateDraftBody)

Field Type Required Description
base string no <slug>@<version>: a published, layered-capable version (default: the template’s latest published version; required when the template has none, which creates the organization template).
project_id string (uuid) no UUIDv7, lowercase canonical form.
display_name string no Template name when this draft creates the organization template (default: the slug).
caps object no
agent_label string no
tools array of "exec" or "files" or "pty" or "process" or "git" or "browser" no
inputs object no Open-time inputs of the template version: {NAME: string} for its declared text inputs. A new workspace stores each given value, else the declared default; on an existing key inputs replaces them all (omitted = unchanged). Secret inputs are not passed here: they bind the stored secret of the same name. 422 input_unknown (undeclared name, details.names), input_invalid (a secret input, a non-string, or a value over 4096 bytes or with CR, LF or NUL; details.names), input_required (details {names, kind}).

Responses: 200 · 202 · 4XX ErrorBody · 5XX ErrorBody

DELETE /v1/organizations/{organization_id}/templates/{slug}/draft

Discard the draft (delete it and end its live test instances).

Deletes the draft (operation delete, input.reason draft_discarded) and ends each live test instance (ended_reason draft_discarded). 202 with the draft’s delete operation. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/templates/{slug}/draft

Get the template’s draft.

404 draft_not_found when the template has no live draft.

Authentication: API key

Parameters

Name In Type Required Description
slug path string yes

Responses: 200 TemplateDraft · 4XX ErrorBody · 5XX ErrorBody

POST /v1/templates/{slug}/draft

Create the template’s draft (a layered workspace on the draft base).

Opens the organization template’s single live draft (key sf:draft:<slug>:<8 hex>, purpose template_draft, persistent, layered) on base (default: the latest published version; required when the template has none, which creates the organization template named display_name, default the slug). 202 with the open operation and the draft. Errors: 409 template_not_layered (the base is not layered-capable, or layered opens are off), 409 draft_exists (details.workspace_id), 403 template_dev_mode_role, 422 platform_template_slug / reserved_template_slug (new, edit) / base_required. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
slug path string yes

Request body (application/json, required, CreateDraftBody)

Field Type Required Description
base string no <slug>@<version>: a published, layered-capable version (default: the template’s latest published version; required when the template has none, which creates the organization template).
project_id string (uuid) no UUIDv7, lowercase canonical form.
display_name string no Template name when this draft creates the organization template (default: the slug).
caps object no
agent_label string no
tools array of "exec" or "files" or "pty" or "process" or "git" or "browser" no
inputs object no Open-time inputs of the template version: {NAME: string} for its declared text inputs. A new workspace stores each given value, else the declared default; on an existing key inputs replaces them all (omitted = unchanged). Secret inputs are not passed here: they bind the stored secret of the same name. 422 input_unknown (undeclared name, details.names), input_invalid (a secret input, a non-string, or a value over 4096 bytes or with CR, LF or NUL; details.names), input_required (details {names, kind}).

Responses: 200 · 202 · 4XX ErrorBody · 5XX ErrorBody

DELETE /v1/templates/{slug}/draft

Discard the draft (delete it and end its live test instances).

Deletes the draft (operation delete, input.reason draft_discarded) and ends each live test instance (ended_reason draft_discarded). 202 with the draft’s delete operation. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
slug path string yes

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/templates/{slug}/draft/states

List the draft’s states, newest first.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/organizations/{organization_id}/templates/{slug}/draft/states

Capture a draft state (disk-only layer_snapshot of the running draft).

202 with the layer_snapshot operation; its result carries checkpoint_id. A suspended draft is 409 workspace_not_running (its current checkpoint already serves as a state). Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes

Request body (application/json, required)

Field Type Required Description
label string no

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/templates/{slug}/draft/states

List the draft’s states, newest first.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
slug path string yes

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/templates/{slug}/draft/states

Capture a draft state (disk-only layer_snapshot of the running draft).

202 with the layer_snapshot operation; its result carries checkpoint_id. A suspended draft is 409 workspace_not_running (its current checkpoint already serves as a state). Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
slug path string yes

Request body (application/json, required)

Field Type Required Description
label string no

Responses: 202 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/templates/{slug}/draft/test-instances

List the draft’s test instances.

Live instances; include_ended=true adds ended ones (tombstones with ended_reason). API keys see only their own project’s instances.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
include_ended query boolean no
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/organizations/{organization_id}/templates/{slug}/draft/test-instances

Open a test instance of a draft state (a disposable session workspace).

Opens a layered session workspace (purpose template_test) on the draft base whose layer is a copy of the draft state; its own writes never reach the draft. Without state_id the running draft is captured first (the instance’s open depends on that layer_snapshot; origin.checkpoint_id is filled when the cell places it); a suspended draft’s current checkpoint is used instead. The instance ends on close(), idle or draft discard. 202 OpenResponse. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes

Request body (application/json, required, CreateTestInstanceBody)

Field Type Required Description
state_id string (uuid) no A draft state (GET …/draft/states). Omitted: a fresh capture of the running draft (its current checkpoint when suspended).
key string no Workspace key (default sf:test:<slug>:<8 hex>); keys starting with sf: are reserved.
caps object no
agent_label string no
tools array of "exec" or "files" or "pty" or "process" or "git" or "browser" no
inputs object no Open-time inputs of the template version: {NAME: string} for its declared text inputs. A new workspace stores each given value, else the declared default; on an existing key inputs replaces them all (omitted = unchanged). Secret inputs are not passed here: they bind the stored secret of the same name. 422 input_unknown (undeclared name, details.names), input_invalid (a secret input, a non-string, or a value over 4096 bytes or with CR, LF or NUL; details.names), input_required (details {names, kind}).

Responses: 200 · 202 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/templates/{slug}/draft/test-instances

List the draft’s test instances.

Live instances; include_ended=true adds ended ones (tombstones with ended_reason). API keys see only their own project’s instances.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
include_ended query boolean no
slug path string yes

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/templates/{slug}/draft/test-instances

Open a test instance of a draft state (a disposable session workspace).

Opens a layered session workspace (purpose template_test) on the draft base whose layer is a copy of the draft state; its own writes never reach the draft. Without state_id the running draft is captured first (the instance’s open depends on that layer_snapshot; origin.checkpoint_id is filled when the cell places it); a suspended draft’s current checkpoint is used instead. The instance ends on close(), idle or draft discard. 202 OpenResponse. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
slug path string yes

Request body (application/json, required, CreateTestInstanceBody)

Field Type Required Description
state_id string (uuid) no A draft state (GET …/draft/states). Omitted: a fresh capture of the running draft (its current checkpoint when suspended).
key string no Workspace key (default sf:test:<slug>:<8 hex>); keys starting with sf: are reserved.
caps object no
agent_label string no
tools array of "exec" or "files" or "pty" or "process" or "git" or "browser" no
inputs object no Open-time inputs of the template version: {NAME: string} for its declared text inputs. A new workspace stores each given value, else the declared default; on an existing key inputs replaces them all (omitted = unchanged). Secret inputs are not passed here: they bind the stored secret of the same name. 422 input_unknown (undeclared name, details.names), input_invalid (a secret input, a non-string, or a value over 4096 bytes or with CR, LF or NUL; details.names), input_required (details {names, kind}).

Responses: 200 · 202 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/organizations/{organization_id}/templates/{slug}/draft/publish

Publish the draft as the template’s next version (save-as-template from the draft).

Builds one new org layer holding every change since the draft base, from state_id or the draft’s current state (a fresh capture when running). settings (TemplateSettingsInput): each given field replaces that field of the draft base’s settings, each absent one is carried forward (settings.defaults and defaults together: 422 invalid_settings). Refused with 409 draft_stale (details latest_version, draft_base_version) when the template has a version newer than the draft base that this draft did not produce, and 409 build_in_progress while a build from another source is unfinished. 202 SaveAsTemplateResponse. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes

Request body (application/json, required, PublishDraftBody)

Field Type Required Description
state_id string (uuid) no UUIDv7, lowercase canonical form.
description string no
defaults object no Defaults of the new version (omitted fields: persistent lifetime, platform idle timeout, no limits).
settings TemplateSettingsInput no What a workspace of the version gets when it opens (). Omitted fields are empty (recipes do not carry settings forward).
auto_publish boolean no
acknowledged_scan_findings array of string no Up to 200 absolute paths the credential scan may report without failing the build (recorded in the manifest).

Responses: 202 SaveAsTemplateResponse · 4XX ErrorBody · 5XX ErrorBody

POST /v1/templates/{slug}/draft/publish

Publish the draft as the template’s next version (save-as-template from the draft).

Builds one new org layer holding every change since the draft base, from state_id or the draft’s current state (a fresh capture when running). settings (TemplateSettingsInput): each given field replaces that field of the draft base’s settings, each absent one is carried forward (settings.defaults and defaults together: 422 invalid_settings). Refused with 409 draft_stale (details latest_version, draft_base_version) when the template has a version newer than the draft base that this draft did not produce, and 409 build_in_progress while a build from another source is unfinished. 202 SaveAsTemplateResponse. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
slug path string yes

Request body (application/json, required, PublishDraftBody)

Field Type Required Description
state_id string (uuid) no UUIDv7, lowercase canonical form.
description string no
defaults object no Defaults of the new version (omitted fields: persistent lifetime, platform idle timeout, no limits).
settings TemplateSettingsInput no What a workspace of the version gets when it opens (). Omitted fields are empty (recipes do not carry settings forward).
auto_publish boolean no
acknowledged_scan_findings array of string no Up to 200 absolute paths the credential scan may report without failing the build (recorded in the manifest).

Responses: 202 SaveAsTemplateResponse · 4XX ErrorBody · 5XX ErrorBody

POST /v1/organizations/{organization_id}/templates/{slug}/versions/{version}/test-instances

Open a test instance of a template version, published or not.

Opens a layered session workspace (purpose template_test) on that version of the organization’s template: registered and not archived, published or not. It is a fresh workspace (a create startup run) with origin {kind: template_version, template_id, version}; it ends on close() or idle. inputs as for open (422 input_unknown, input_invalid, input_required). 202 OpenResponse (200 when an existing key is running and ready). Errors: 403 template_dev_mode_role (owners, admins and API keys with a tool permission only), 404 version_not_found, 409 template_not_layered, template_archived, 422 reserved_key_prefix. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.
slug path string yes
version path integer yes

Request body (application/json, required, CreateVersionTestInstanceBody)

Field Type Required Description
key string no Workspace key (default sf:test:<slug>:<8 hex>); caller keys starting with sf: are reserved.
caps object no
agent_label string no
tools array of "exec" or "files" or "pty" or "process" or "git" or "browser" no
inputs object no Open-time inputs of the template version: {NAME: string} for its declared text inputs. A new workspace stores each given value, else the declared default; on an existing key inputs replaces them all (omitted = unchanged). Secret inputs are not passed here: they bind the stored secret of the same name. 422 input_unknown (undeclared name, details.names), input_invalid (a secret input, a non-string, or a value over 4096 bytes or with CR, LF or NUL; details.names), input_required (details {names, kind}).
project_id string (uuid) no UUIDv7, lowercase canonical form.

Responses: 200 · 202 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/templates/{slug}/versions/{version}/test-instances

Open a test instance of a template version, published or not.

Opens a layered session workspace (purpose template_test) on that version of the organization’s template: registered and not archived, published or not. It is a fresh workspace (a create startup run) with origin {kind: template_version, template_id, version}; it ends on close() or idle. inputs as for open (422 input_unknown, input_invalid, input_required). 202 OpenResponse (200 when an existing key is running and ready). Errors: 403 template_dev_mode_role (owners, admins and API keys with a tool permission only), 404 version_not_found, 409 template_not_layered, template_archived, 422 reserved_key_prefix. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
slug path string yes
version path integer yes

Request body (application/json, required, CreateVersionTestInstanceBody)

Field Type Required Description
key string no Workspace key (default sf:test:<slug>:<8 hex>); caller keys starting with sf: are reserved.
caps object no
agent_label string no
tools array of "exec" or "files" or "pty" or "process" or "git" or "browser" no
inputs object no Open-time inputs of the template version: {NAME: string} for its declared text inputs. A new workspace stores each given value, else the declared default; on an existing key inputs replaces them all (omitted = unchanged). Secret inputs are not passed here: they bind the stored secret of the same name. 422 input_unknown (undeclared name, details.names), input_invalid (a secret input, a non-string, or a value over 4096 bytes or with CR, LF or NUL; details.names), input_required (details {names, kind}).
project_id string (uuid) no UUIDv7, lowercase canonical form.

Responses: 200 · 202 · 4XX ErrorBody · 5XX ErrorBody

Secrets

Project secrets, their versions, and the secrets bound to a workspace.

GET /v1/projects/{project_id}/secrets

List a project’s secrets (metadata only).

Project-scoped secrets only; organization secrets are listed under the organization.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
include_deleted query boolean no
project_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/projects/{project_id}/secrets

Create a project secret (owner/admin, or an API key of this project).

The value is encrypted (KMS envelope) and never returned. allowed_tools defaults to [exec, pty]. 409 when the name exists in this project. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
project_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required)

Field Type Required Description
name string yes Environment-variable-safe name, unique per scope (SHARDFLUX_ prefix reserved).
description string no
value string yes UTF-8 text, at most 65536 bytes, no NUL characters. Write-only: never returned by any management API.
allowed_workspace_ids array of string (uuid) or null no Default null (any workspace of the project).
allowed_tools array of "exec" or "files" or "pty" or "process" or "git" or "browser" no

Responses: 201 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/secrets/{secret_id}

Get secret metadata (never the value).

Deleted secrets stay readable (deleted_at set).

Authentication: API key

Parameters

Name In Type Required Description
secret_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

PATCH /v1/secrets/{secret_id}

Update a secret’s description or usage permissions.

Takes effect for the next session start that resolves it. Names are immutable (delete and recreate).

Authentication: API key

Parameters

Name In Type Required Description
secret_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required)

Field Type Required Description
description string no
allowed_project_ids array of string (uuid) or null no
allowed_workspace_ids array of string (uuid) or null no
allowed_tools array of "exec" or "files" or "pty" or "process" or "git" or "browser" no

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

DELETE /v1/secrets/{secret_id}

Delete a secret (tombstone; erases every stored value; resolution stops immediately).

Any session start after this returns it as denied. The name becomes reusable. The name is removed from every workspace binding that referred to this secret (same transaction, one audit event per workspace). Values already injected into running processes cannot be recalled. Repeating returns 204.

Authentication: API key

Parameters

Name In Type Required Description
secret_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 204 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/secrets/{secret_id}/versions

List a secret’s versions, newest first (metadata only).

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
secret_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

POST /v1/secrets/{secret_id}/versions

Rotate: store a new value as the next version.

The new version is used from the next session start; every older version’s value is erased in the same transaction (metadata kept). Values already injected into running processes are not recalled. Supports Idempotency-Key.

Authentication: API key

Parameters

Name In Type Required Description
secret_id path string (uuid) yes UUIDv7, lowercase canonical form.

Request body (application/json, required)

Field Type Required Description
value string yes UTF-8 text, at most 65536 bytes, no NUL characters. Write-only: never returned by any management API.

Responses: 201 · 4XX ErrorBody · 5XX ErrorBody

Egress policy

Outbound network policy of a project or a workspace.

GET /v1/projects/{project_id}/egress-policy

Get a project’s egress policy (default for its workspaces).

version (also the ETag) is the value to send as If-Match. Without a project policy the effective policy is the platform default (allow_all).

Authentication: API key

Parameters

Name In Type Required Description
project_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

PUT /v1/projects/{project_id}/egress-policy

Replace a project’s egress policy (creates a new immutable version).

mode allow_all | allowlist | deny_all; rules/cidrs only with allowlist. Hosts: exact FQDN or *. single-label wildcard (IDNA-normalized, lower-case); IP literals and localhost-like names are rejected. Ports 1-65535 (default [443]); protocols tcp only. cidrs: public ranges only. Optional If-Match: <version> (409 conflict with details.reason version_mismatch). Owner/admin or an API key of this project with tool permissions.

Authentication: API key

Parameters

Name In Type Required Description
project_id path string (uuid) yes UUIDv7, lowercase canonical form.
if-match header string no

Request body (application/json, required)

Field Type Required Description
mode "allow_all" or "allowlist" or "deny_all" yes
rules array of object no allowlist only; at most 256.
cidrs array of string no allowlist only; public ranges; at most 64.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/projects/{project_id}/egress-policy/versions

Version history of a project’s egress policy, newest first.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
project_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/workspaces/{workspace_id}/egress-policy

Effective egress policy of a workspace and its enforcement state.

effective = workspace override > project policy > platform default (allow_all). enforcement.state is not_enforced until the cell/host acknowledges the current effective policy for the workspace’s current ownership epoch, then pending | enforced | failed. version (ETag) is the override history version for If-Match. template_egress: the template version’s egress ceiling (, null = none); effective_policy: what the host enforces, effective intersected with that ceiling.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

PUT /v1/workspaces/{workspace_id}/egress-policy

Set a workspace override of the egress policy (new immutable version).

Same body and validation as the project policy. Optional If-Match. 409 conflict (details.reason workspace_deleted) for deleted workspaces. 422 egress_widening (details {template_egress, outside: [hosts] | ["cidrs"] | ["allow_all"]}) when the workspace’s template egress ceiling would narrow the policy.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.
if-match header string no

Request body (application/json, required)

Field Type Required Description
mode "allow_all" or "allowlist" or "deny_all" yes
rules array of object no allowlist only; at most 256.
cidrs array of string no allowlist only; public ranges; at most 64.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

DELETE /v1/workspaces/{workspace_id}/egress-policy

Remove the workspace override (fall back to the project policy).

Records a cleared version. 204 without a new version when there is no active override. Optional If-Match.

Authentication: API key

Parameters

Name In Type Required Description
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.
if-match header string no

Responses: 204 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/workspaces/{workspace_id}/egress-policy/versions

Version history of a workspace’s egress override (including cleared versions), newest first.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

Usage and spend

Metered usage, estimates, grants and spend of an organization or a workspace.

GET /v1/organizations/{organization_id}/usage/summary

Current-period usage, included allowances and cap state of an organization.

Totals come from the usage ledger (hourly, finalized after the lateness window); measurement.measured_through says how far usage is complete. Billable units are whole units (floor per workspace-hour); allowance usage counts billable units. allowance_exhausted true means new opens/resumes answer 402 allowance_exhausted with exhausted_reason as details.reason. spend_cap is opt-in overage this period: while it is on, a CPU-hours or RAM GiB-hours allowance past included is in cap state overage (starts admitted, usage past it charged) until the spend cap is reached.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/usage

Usage time series (hour or day buckets) from the ledger.

Defaults to the current period at day granularity; hour granularity covers at most 31 days, day at most 400. workspace_id / volume_id (mutually exclusive) narrow it to one workspace or one shared volume (meter volume_storage_gib_seconds). API keys see only their own project.

Authentication: API key

Parameters

Name In Type Required Description
from query string (date-time) no RFC 3339 UTC timestamp with Z.
to query string (date-time) no RFC 3339 UTC timestamp with Z.
granularity query "hour" or "day" no
meter query "cpu_seconds" or "memory_gib_seconds" or "storage_gib_seconds" or "egress_bytes" or "ingress_bytes" or "volume_storage_gib_seconds" no
workspace_id query string (uuid) no UUIDv7, lowercase canonical form.
volume_id query string (uuid) no UUIDv7, lowercase canonical form.
project_id query string (uuid) no UUIDv7, lowercase canonical form.
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/workspaces/{workspace_id}/usage

Usage of one workspace (time series and totals).

Authentication: API key

Parameters

Name In Type Required Description
from query string (date-time) no RFC 3339 UTC timestamp with Z.
to query string (date-time) no RFC 3339 UTC timestamp with Z.
granularity query "hour" or "day" no
meter query "cpu_seconds" or "memory_gib_seconds" or "storage_gib_seconds" or "egress_bytes" or "ingress_bytes" or "volume_storage_gib_seconds" no
workspace_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/usage/estimate

Period cost estimate: subscription fee, usage charges and projected allowance use.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/grants

Quotas, per-workspace ceilings/reservations/grants and compute budget leases.

Ceiling = min(template, user cap, plan cap). Reservations are organization-level (pending starts count). Leases are the compute budgets granted to the cell (<= 15 min). API keys see only their own project’s workspaces.

Authentication: API key

Parameters

Name In Type Required Description
limit query integer no
cursor query string no
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/spend

Spend policy, charges this period, cap state and enforcement (leases, overshoot bound).

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/spend-policy

Usage alert thresholds and opt-in overage with its spend cap.

Alert thresholds, and whether overage is available, on, off or paused, with the spend cap, its bounds and the rates. Overage is off by default; owners and billing members change it with the PUT (the console on /api/v1, or a CLI session on /v1; project API keys are refused).

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

Entitlements

The limits and features the organization’s plan grants.

GET /v1/organizations/{organization_id}/entitlements

Resolved plan limits, allowances and policies of an organization.

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

Billing

The plan catalog and the organization’s subscription.

GET /v1/billing/catalog

The active plan catalog (the same versioned catalog admission enforces).

Public, cacheable. Prices are in minor units; purchasable plans can be bought with POST .../organizations/{id}/billing/checkout-sessions (a browser or CLI session; shard billing upgrade <plan>).

Authentication: None (public)

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

GET /v1/organizations/{organization_id}/billing/subscription

Subscription, billing state and effective plan of an organization.

Owner/billing members (browser) or any API key of the organization (read-only). billing_state: free (no paid subscription), active, canceling (ends at period end, then free limits), grace (payment overdue, workspaces unaffected), restricted (grace ended: new opens/resumes answer 402 entitlement_required).

Authentication: API key

Parameters

Name In Type Required Description
organization_id path string (uuid) yes UUIDv7, lowercase canonical form.

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

Client versions

The latest and the oldest supported version of every Shardflux client package.

GET /v1/client-versions

Latest and minimum supported version of every Shardflux client.

Unauthenticated, Cache-Control: public, max-age=3600. Clients compare their own version: below minimum_supported they are unsupported, below latest outdated. They check at most once a day (the CLI) or once per process (the SDKs), in the background, and never fail because of it.

Authentication: None (public)

Responses: 200 · 4XX ErrorBody · 5XX ErrorBody

Feedback

Send product feedback straight to the Shardflux team: what failed, confused you or is missing.

POST /v1/feedback

Send product feedback to the Shardflux team.

Delivered by email to the Shardflux team. Any valid project API key may send (no tool permission needed); the key's organization and project are recorded, so organization_id is rejected (422). A CLI session (sfu_) may send too, with an optional organization_id of the user's. Coding agents: send feedback whenever something fails, is confusing or missing, and include context (agent, client, workspace, request_id and error_code of the error response, command). Rate limited per sender (10 per 10 minutes, 50 per day) and per organization (200 per day): 429 rate_limited with a retry-after header and details.retry_after_seconds. The same message from the same sender within 24 hours is a duplicate: 200 with the original id and duplicate: true (it still counts against the rate limits). The body is limited to 32 KiB (413).

Authentication: API key

Request body (application/json, required)

Field Type Required Description
message string yes The feedback, 1-8000 characters after trimming surrounding whitespace (must contain a non-whitespace character). Control characters other than newline and tab are stripped; API keys, bearer tokens, JWTs, AWS access key ids and private key blocks are redacted before it is stored or emailed.
category "bug" or "confusing" or "missing" or "idea" or "praise" or "other" no Default other. bug: something failed or behaved wrongly; confusing: an error, doc, name or output was unclear or misleading; missing: a capability, option or template you needed does not exist; idea: a suggestion or improvement; praise: something worked well; other: anything else.
organization_id string (uuid) no Sessions (browser, or a CLI session on /v1): the organization the user is looking at, one they belong to (404 otherwise). Refused (422) with a project API key, whose organization is used.
context object no Optional, every field optional. Control characters are stripped and anything shaped like a secret is redacted before storing.

Responses: 200 · 201 · 4XX ErrorBody · 5XX ErrorBody

View this page as Markdown