Authentication
Every endpoint except the health probes takes a bearer token: Authorization: Bearer <api-key>. Create a key in the customer portal under Developers. Keys are scoped to one account.
Treat them as secrets and rotate them if exposed.
Health
Liveness / readiness probes.
/livez No authLiveness probe.
Answers only "is this process running". It never consults a dependency, and that is the point: a downed database or payload key store is a readiness condition, not a reason to restart the process. Restarting cannot reach an unreachable vault — it just churns the pod and blocks the rollout that would carry the fix. Unauthenticated.
Responses
| Status | Meaning |
|---|---|
200 | The process is running. HealthOK |
/healthz No authReadiness probe.
Reports the observed health of the dependencies that gate every payload path — the database and the payload encryption key store — so a load balancer can route around a degraded instance. Use /livez for liveness. Unauthenticated.
Responses
| Status | Meaning |
|---|---|
200 | Healthy. HealthOK |
503 | A gating dependency (database or key store) is unavailable; this instance is degraded. HealthDegraded |
Jobs
Otium-native job submission and lookup.
/v1/jobs Submit a job.
Validates, persists, and acknowledges a single inference job, then returns immediately — scheduling and execution happen asynchronously. **Idempotency.** Send the `Idempotency-Key` header (or the body's `idempotency_key`, the same key; sending both with different values is a `400`) to make resubmission safe. With the header, a repeat of the same request returns the original job with the original status and `Idempotent-Replayed: true`, showing the job as it is now; the same key with a different request is a `422`. With only the body field, a repeat returns the existing job with `200`.
Parameters
| Parameter | In · type | Description |
|---|---|---|
Idempotency-Key | header · string | Makes a retried create safe. Up to 255 printable ASCII characters (a UUID is ideal), unique per request you mean to make; keys are per account and remembered for 24 hours. A repeat of the same request (same endpoint and byte-identical body) within that window returns the original response with `Idempotent-Replayed: true` and creates nothing. The same key with a different request is a `422`; while the first request is still running it is a `409` with `Retry-After`. A request that failed (any non-2xx) is not remembered, so retrying it with the same key runs it again. |
Request body SubmitJobRequest
| Field | Type | Description |
|---|---|---|
model (required) | string | What to run. An intent alias (e.g. `otium-medium`) or an exact catalog model id. Required. An alias is resolved to a concrete model server-side; an unresolvable value is rejected with 400. |
otium | OtiumIntent | Optional intent extension — declare an outcome (task, quality floor, family) rather than only a model. OpenAI-compatible (stock clients ignore it). |
tier | Tier | SLA tier. Omit to default to `remnant`. rushprioritystandardremnant |
payload | string | Small inline request body (PoC). Production payloads live in object storage. |
idempotency_key | string | Per-tenant key making resubmission safe. A repeat returns the original job. |
max_attempts | integer | Max execution attempts before dead-lettering. Non-positive values default to 3. Default: 3 |
boundary | Boundary | Locks the job to a residency boundary. Empty means unconstrained. afapaccaeueu-demenasaukus |
sensitivity | Sensitivity | Data-sensitivity class. Empty defaults to `internal` (trusted-only). confidentialinternalpublic |
max_tokens | integer | Output-token ceiling. Bounds the up-front cost estimate the prepaid gate reserves; 0 uses a default ceiling. A chat-completion body that sets neither max_tokens nor max_completion_tokens is capped at 8192 output tokens when it runs. |
Responses
| Status | Meaning |
|---|---|
200 | Idempotent replay — the existing job for this idempotency key. Job |
201 | Job created. Job |
400 | Invalid request (bad JSON, missing model, unknown tier or boundary, a malformed Idempotency-Key). NativeError |
409 | An earlier request with this `Idempotency-Key` is still running; retry after `Retry-After`. |
422 | This `Idempotency-Key` was already used with a different request (another body or endpoint). Use a new key for a new request. |
429 | Per-client-IP submit rate limit exceeded. |
503 | Database, payload key store, or catalog briefly unavailable; retry after `Retry-After`. NativeError |
/v1/jobs/{id} Get a job.
Returns a job by id. A tenant may only read its own jobs.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string (uuid) | Job id. |
Responses
| Status | Meaning |
|---|---|
200 | The job. Job |
404 | Not found, or owned by another tenant. NativeError |
Files
OpenAI-compatible Files API (batch input upload, output download).
/v1/files List files.
Parameters
| Parameter | In · type | Description |
|---|---|---|
purpose | query · string | Filter by purpose. Omit for all of the tenant's files. |
Responses
| Status | Meaning |
|---|---|
200 | A single page of files (OpenAI list envelope). FileList |
/v1/files Upload a batch input file.
Uploads a JSONL batch input file (`purpose=batch`). Each line is a `BatchRequestInput`. OpenAI-compatible. Uploads above the server limit are rejected with `413`.
Request body
Responses
| Status | Meaning |
|---|---|
200 | Uploaded file metadata. FileObject |
400 | Unsupported purpose or missing file field. OpenAIError |
413 | File exceeds the maximum upload size. OpenAIError |
/v1/files/{id} Get file metadata.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | File id (e.g. `file-<uuid>`). |
Responses
| Status | Meaning |
|---|---|
200 | File metadata. FileObject |
404 | No such file (or owned by another tenant). OpenAIError |
/v1/files/{id} Delete a file.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | File id (e.g. `file-<uuid>`). |
Responses
| Status | Meaning |
|---|---|
200 | Deletion acknowledgement. FileDeleted |
404 | No such file (or owned by another tenant). OpenAIError |
/v1/files/{id}/content Download file content.
Streams the raw JSONL content of a file.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | File id (e.g. `file-<uuid>`). |
Responses
| Status | Meaning |
|---|---|
200 | Raw JSONL content. |
404 | No such file (or owned by another tenant). OpenAIError |
/v1/uploads Start a multi-part upload of a large batch input file.
OpenAI's Uploads API, for a file too large for one `POST /v1/files` request (a request through the edge is capped at 100 MB). Create the upload with the file's exact size, add its bytes in parts of at most 64 MiB each (in any order, retrying a failed part alone), then complete it with the part ids in file order. The upload expires an hour after it is created; an expired or cancelled upload's parts are deleted. A whole upload may declare at most 8 GiB. A gzipped JSONL is accepted here as on `/v1/files`: it is recognized by its content.
Request body
| Field | Type | Description |
|---|---|---|
filename | string | |
purpose (required) | string | batch |
bytes (required) | integer (int64) | The file's exact size; complete checks the parts add up to it. |
mime_type | string |
Responses
| Status | Meaning |
|---|---|
200 | The new upload, pending. Upload |
400 | Unsupported purpose, or a size that is zero or above the limit. OpenAIError |
/v1/uploads/{id}/parts Add a part to an upload.
Adds up to 64 MiB of the file. Parts may arrive in any order and in parallel; their order in the file is the order `complete` lists them in.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Upload id (`upload_…`). |
Request body
Responses
| Status | Meaning |
|---|---|
200 | The part. UploadPart |
400 | Missing `data` field, or the upload is completed, cancelled or expired. OpenAIError |
404 | No such upload (or owned by another tenant). OpenAIError |
413 | The part is larger than 64 MiB. OpenAIError |
/v1/uploads/{id}/complete Complete an upload into a batch input file.
Joins the listed parts, in the order listed, into a file usable as a batch's `input_file_id`. The parts must belong to this upload, appear once each and add up to the size the upload was created with. Completing an upload that already completed returns it again, with the same file. `md5` is accepted and not checked.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Upload id (`upload_…`). |
Request body
| Field | Type | Description |
|---|---|---|
part_ids (required) | array of string | |
md5 | string |
Responses
| Status | Meaning |
|---|---|
200 | The completed upload, carrying its file. Upload |
400 | An unknown, foreign or repeated part, parts that do not add up to the declared size, or an upload that is cancelled or expired. OpenAIError |
404 | No such upload (or owned by another tenant). OpenAIError |
/v1/uploads/{id}/cancel Cancel an upload.
Cancels a pending upload; its parts are deleted shortly after.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Upload id (`upload_…`). |
Responses
| Status | Meaning |
|---|---|
200 | The cancelled upload. Upload |
400 | The upload is already completed or cancelled. OpenAIError |
404 | No such upload (or owned by another tenant). OpenAIError |
Batches
OpenAI-compatible Batch API.
/v1/chat/completions Not served (Otium is batch-only).
Otium has no synchronous chat endpoint: it runs work that can wait, on a deadline. This route exists only to say so with an OpenAI-shaped `404` carrying `code: batch_only`, so a gateway or SDK that tries its default path shows the caller a reason instead of a bare "not found". Send the same requests as a batch: upload a JSONL file to `/v1/files`, then create the batch at `/v1/batches`.
Responses
| Status | Meaning |
|---|---|
404 | Always. The message names the batch endpoints to use instead. OpenAIError |
/v1/batches List batches.
Parameters
| Parameter | In · type | Description |
|---|---|---|
limit | query · integer | Max batches to return. Defaults to the server's page size. |
after | query · string | The `last_id` of the previous page; the page starts with the batch after it. Page until `has_more` is `false`, as the OpenAI SDK does. |
Responses
| Status | Meaning |
|---|---|
200 | One page of batches, newest first (OpenAI list envelope). BatchList |
/v1/batches Create a batch.
Creates a batch over a previously uploaded input file. OpenAI-compatible. **Completion window → SLA tier.** `completion_window` accepts OpenAI's `24h` (and empty, treated as `24h`), the shorthands `1h` / `6h` / `7d` / `168h`, and Otium's own tier names as an extension — the flexible-deadline knob. **Data residency.** Set `metadata.boundary` (e.g. `us`, `eu`) to lock every job in the batch to a residency boundary. **Upgrades.** By default a job may run on a warm, larger model at its own product's price. Set `metadata.allow_upgrade` to `"false"` to keep this batch on the models it names, or `"true"` to allow it on an account that has upgrades switched off. **Idempotency.** Send an `Idempotency-Key` header and a repeat of the same request returns the original batch object byte for byte, with `Idempotent-Replayed: true`, instead of creating a second batch over the same file.
Parameters
| Parameter | In · type | Description |
|---|---|---|
Idempotency-Key | header · string | Makes a retried create safe. Up to 255 printable ASCII characters (a UUID is ideal), unique per request you mean to make; keys are per account and remembered for 24 hours. A repeat of the same request (same endpoint and byte-identical body) within that window returns the original response with `Idempotent-Replayed: true` and creates nothing. The same key with a different request is a `422`; while the first request is still running it is a `409` with `Retry-After`. A request that failed (any non-2xx) is not remembered, so retrying it with the same key runs it again. |
Request body CreateBatchRequest
| Field | Type | Description |
|---|---|---|
input_file_id (required) | string | Id of an uploaded file with purpose `batch`, owned by the caller. |
endpoint | string | The only endpoint supported today. /v1/chat/completionsDefault: /v1/chat/completions |
completion_window | string | OpenAI `24h` (default), the shorthands `1h` / `6h` / `7d` / `168h`, or an
Otium tier name (`rush`, `priority`, `standard`, `remnant`). Default: 24h |
metadata | map of string | Up to 16 string key/value pairs. The reserved key `boundary` locks every job in the batch to a residency boundary. A key a gateway adds on its caller's behalf (`otari_user_id`) does not count against the 16. |
Responses
| Status | Meaning |
|---|---|
200 | The created batch (status `validating`). Batch |
400 | Invalid request (bad JSON, missing input_file_id, unsupported endpoint/window, too much metadata, invalid boundary or allow_upgrade). OpenAIError |
404 | input_file_id does not exist or is not owned by the caller. OpenAIError |
409 | An earlier request with this `Idempotency-Key` is still running; retry after `Retry-After`. |
422 | This `Idempotency-Key` was already used with a different request (another body or endpoint). Use a new key for a new request. |
503 | Database briefly unavailable; retry after `Retry-After`. OpenAIError |
/v1/batches/{id} Get a batch.
The OpenAI batch, plus `waiting` while it is `in_progress`: its requests that have not started, by model, and why. `request_counts` moves only as requests finish, so `waiting` is what tells work that is held from work that is stuck. A request is `held` while the provisioner gathers enough work to share a GPU's boot or waits for a cheaper price (never past `latest_start`), `starting` while capacity is being started (a cold start takes 15-30 minutes, longer when a cloud has no capacity), `queued` behind a serving worker, or `billing_hold` on the account's funds or monthly spend cap. OpenAI clients ignore the field.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Batch id (e.g. `batch_<uuid>`). |
Responses
| Status | Meaning |
|---|---|
200 | The batch. |
404 | No such batch (or owned by another tenant). OpenAIError |
/v1/batches/{id}/cancel Cancel a batch.
Requests cancellation: the batch moves to `cancelling`, the processor stops outstanding jobs and finalizes what completed. Idempotent while already `cancelling`. Cancelling a terminal batch is a `409`.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Batch id (e.g. `batch_<uuid>`). |
Responses
| Status | Meaning |
|---|---|
200 | The batch, now `cancelling` (or unchanged if already cancelling). Batch |
404 | No such batch (or owned by another tenant). OpenAIError |
409 | The batch is in a terminal status and cannot be cancelled. OpenAIError |
Models
OpenAI-compatible model listing.
/v1/models List the models you can submit to.
The offered products plus the previews granted to your account (`preview: true`), OpenAI-compatible (`client.models.list()` works unchanged). Each `id` is what a request's `model` field names. `context_window` is the most tokens, prompt plus completion, one request may use; it is omitted when one number would not be true (a product that runs several models). Sorted by `id`; an empty catalog is `data: []`.
Responses
| Status | Meaning |
|---|---|
200 | The models. ModelList |
Workflows
Workflow graphs — publish, validate, unit-test, and read compiled plans.
/v1/workflows List workflows.
Your workflows, one entry per name, with the latest version and how many versions exist.
Responses
| Status | Meaning |
|---|---|
200 | The workflows. WorkflowList |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
503 | Workflows are not available on this deployment. NativeError |
/v1/workflows Publish a workflow version.
Validates, compiles and stores a workflow document as a new version of the workflow it names. Send the YAML as the raw body (`curl --data-binary @workflow.yaml`), or as JSON `{"document": "<yaml>"}` with `Content-Type: application/json`. Up to 1 MiB. **Idempotent.** Publishing a document identical to an existing version creates nothing: it returns that version with `200` and `created: false`, so publishing on every merge is safe. A new version is `201` with `created: true`. A document that does not compile is `422` with every finding in `diagnostics`. So is one whose `tools.endpoint` names a tool endpoint you have not registered.
Request body WorkflowDocumentEnvelope
| Field | Type | Description |
|---|---|---|
document (required) | string | The workflow document, as YAML text. |
Responses
| Status | Meaning |
|---|---|
200 | Replay. The document matches an existing version, which is returned. WorkflowCompileResult |
201 | A new version was created. WorkflowCompileResult |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
413 | The document is over 1 MiB. NativeError |
422 | The document was rejected. `diagnostics` lists every finding. WorkflowCompileResult |
503 | Workflows are not available on this deployment. NativeError |
/v1/workflows/validate Validate a workflow document without publishing it.
Compiles a document and returns the findings, and, when it compiles, its summary (critical path, durations, estimated cost) and a Mermaid diagram. Writes nothing. The body is the same as for publishing. Validation always answers `200`; read `ok` and `diagnostics` for the verdict.
Parameters
| Parameter | In · type | Description |
|---|---|---|
plan | query · boolean | `true` includes the compiled plan in the result. |
Request body WorkflowDocumentEnvelope
| Field | Type | Description |
|---|---|---|
document (required) | string | The workflow document, as YAML text. |
Responses
| Status | Meaning |
|---|---|
200 | The compile result. `created` and `version` are never set here. WorkflowCompileResult |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
413 | The document is over 1 MiB. NativeError |
/v1/workflows/test Run a workflow's unit tests.
Runs a test suite (the contents of a `*.test.yaml` file) against a workflow document, with each case's node outputs supplied by the suite instead of a model. Writes nothing and runs no inference. The same runner as `otiumctl workflow test`. A suite that runs is `200` whether or not its cases pass; the report says which. A document that does not compile, a suite that does not parse or is invalid, or a suite that does not finish within 15 seconds is `422`.
Request body WorkflowTestRequest
| Field | Type | Description |
|---|---|---|
document (required) | string | The workflow document under test, as YAML text. Up to 1 MiB. |
tests (required) | string | The test suite (a `*.test.yaml` file's contents), as YAML or JSON. Up to 1 MiB. |
run | string | Run only the cases whose name contains this. |
Responses
| Status | Meaning |
|---|---|
200 | The suite ran. WorkflowTestReport |
400 | The body is not JSON with a non-empty `document` and `tests`. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
413 | The request is too large. NativeError |
422 | The document or the suite was rejected, or the suite timed out. NativeError |
/v1/workflows/{name} List a workflow's versions.
Parameters
| Parameter | In · type | Description |
|---|---|---|
name (required) | path · string | The workflow's name, as its document declares it. |
Responses
| Status | Meaning |
|---|---|
200 | Every version of the workflow. WorkflowVersionList |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Workflows are not available on this deployment. NativeError |
/v1/workflows/{name}/{version} Get a workflow version and its document.
Parameters
| Parameter | In · type | Description |
|---|---|---|
name (required) | path · string | The workflow's name, as its document declares it. |
version (required) | path · string | A version number (1 or more), or `latest` for the newest published version. Anything else is `400`. |
Responses
| Status | Meaning |
|---|---|
200 | The version, with its document. WorkflowDetail |
400 | The version is not a positive number or `latest`. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Workflows are not available on this deployment. NativeError |
/v1/workflows/{name}/{version} Deprecate a workflow version.
Stops new runs from using the version. Nothing is deleted: existing runs reference it, and it stays readable. A purged version cannot be changed (`409`).
Parameters
| Parameter | In · type | Description |
|---|---|---|
name (required) | path · string | The workflow's name, as its document declares it. |
version (required) | path · string | A version number (1 or more), or `latest` for the newest published version. Anything else is `400`. |
Responses
| Status | Meaning |
|---|---|
200 | The version, now deprecated. WorkflowVersion |
400 | The version is not a positive number or `latest`. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
409 | The version was purged and cannot be changed. NativeError |
503 | Workflows are not available on this deployment. NativeError |
/v1/workflows/{name}/{version}/plan Get a workflow version's compiled plan.
The plan the scheduler runs from: topological order, critical path, edges, barriers, affinity and cache groups, and per-node estimates. `mermaid` and `summary` come from the document, so a purged version returns its plan without them.
Parameters
| Parameter | In · type | Description |
|---|---|---|
name (required) | path · string | The workflow's name, as its document declares it. |
version (required) | path · string | A version number (1 or more), or `latest` for the newest published version. Anything else is `400`. |
planner | query · integer | A specific planner version's plan. Omitted, the newest plan for the version. |
Responses
| Status | Meaning |
|---|---|
200 | The plan. WorkflowPlan |
400 | The version is not a positive number or `latest`. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Workflows are not available on this deployment. NativeError |
Assets
Versioned asset bundles a workflow's prompts read.
/v1/assets List asset bundles.
Your asset bundles: the versioned reference data a workflow's prompts render from. One entry per bundle, with its latest version.
Responses
| Status | Meaning |
|---|---|
200 | The bundles. AssetBundleList |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
503 | Asset bundles are not available on this deployment. NativeError |
/v1/assets Publish an asset bundle version.
Publishes a new version of a bundle. Each entry in `assets` is either a string (one value shared by every run) or an object of key to string (one value per key). Publishing content identical to the bundle's latest version creates nothing: it returns that version with `200` and `created: false`, so a CI job can republish on every run. A new version is `201`. A bundle is at most 8 MiB.
Request body AssetPublishRequest
| Field | Type | Description |
|---|---|---|
bundle (required) | string | The bundle to publish a version of. Created on first publish. |
comment | string | A note kept with the version. |
assets (required) | object | Asset name to value: a string for one value shared by every run, or an object of key to string for one value per key. |
Responses
| Status | Meaning |
|---|---|
200 | Identical to the latest version. Nothing was created. AssetPublishResult |
201 | A new version was published. AssetPublishResult |
400 | The body or a bundle name, asset or size is invalid. The message says which. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
413 | The body is over 16 MiB. NativeError |
503 | Asset bundles are not available on this deployment. NativeError |
/v1/assets/{bundle} List a bundle's versions.
Every version of one bundle, newest first. Metadata only, never content.
Parameters
| Parameter | In · type | Description |
|---|---|---|
bundle (required) | path · string | Bundle name. |
Responses
| Status | Meaning |
|---|---|
200 | The versions. AssetVersionList |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Asset bundles are not available on this deployment. NativeError |
/v1/assets/{bundle}/{version} Get a bundle version with its content.
One version's metadata and its assets. A purged version has no assets.
Parameters
| Parameter | In · type | Description |
|---|---|---|
bundle (required) | path · string | Bundle name. |
version (required) | path · integer | Version number. |
Responses
| Status | Meaning |
|---|---|
200 | The version and its content. AssetDetail |
400 | The version is not a positive integer. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Asset bundles are not available on this deployment. NativeError |
/v1/assets/{bundle}/{version} Deprecate a bundle version.
Stops new runs from pinning this version. Runs that already pinned it keep it. Its content stays; to destroy the content, purge it.
Parameters
| Parameter | In · type | Description |
|---|---|---|
bundle (required) | path · string | Bundle name. |
version (required) | path · integer | Version number. |
Responses
| Status | Meaning |
|---|---|
200 | The version, now deprecated. AssetVersion |
400 | The version is not a positive integer. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
409 | The version cannot change from its current state. NativeError |
503 | Asset bundles are not available on this deployment. NativeError |
/v1/assets/{bundle}/{version}/purge Purge a bundle version's content.
Destroys the version's content and keeps its record, so runs that used it still say which version they rendered from. Refused with `409` while a live run pins the version: wait for it to finish.
Parameters
| Parameter | In · type | Description |
|---|---|---|
bundle (required) | path · string | Bundle name. |
version (required) | path · integer | Version number. |
Responses
| Status | Meaning |
|---|---|
200 | The version, now purged. AssetVersion |
400 | The version is not a positive integer. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
409 | A live run pins this version, or it cannot change from its current state. NativeError |
503 | Asset bundles are not available on this deployment. NativeError |
Runs
Workflow execution — run sets, runs, their nodes and attempts.
/v1/run-sets List run sets.
Your run sets, oldest first. A batch that names a workflow becomes one run set with one run per input line; a continuation is a run set too (`continues_set_id`). Keyset-paged: pass the previous page's `next_cursor` as `after`.
Parameters
| Parameter | In · type | Description |
|---|---|---|
status | query · string | Comma-separated `RunStatus` values to include, e.g. `failed,partial`. An unknown value filters nothing rather than failing. |
after | query · string | The previous page's `next_cursor`. |
limit | query · integer | Page size. Above 1000 is capped; an unreadable value uses the default. |
Responses
| Status | Meaning |
|---|---|
200 | A page of run sets. RunSetList |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
503 | Workflow runs are not available on this deployment. NativeError |
/v1/run-sets/{id} Get a run set.
A run set's aggregate state: its status, how many runs finished, a live per-status count, and the queued work being held before it starts (`holds`). **Held is not stuck.** Otium may hold queued work before booting a GPU: to gather enough work to share one boot (`gathering`), or to wait for a cheaper spot price (`price`). The set still reads `running` (the work is accepted and will run) and `holds` names the nodes held, how many runs each, and the latest start, by which capacity is started regardless. **Two clocks.** `execution_budget_seconds` is the SLA bought (it stops while a run waits on you); `expires_at` is the separate wall-clock bound. They are never collapsed into one "time remaining". **Set-scope nodes.** When the workflow has `scope: set` nodes, `set_run` names the run that carries them: `{status: "pending"}` until every item has finished, then its id, status and outcome. The counts are items only; the set is `running` until the set run has finished too.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run set id. |
Responses
| Status | Meaning |
|---|---|
200 | The run set. RunSet |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Workflow runs are not available on this deployment. NativeError |
/v1/run-sets/{id}/runs List a run set's runs.
One run per input item, keyset-paged like the set listing. Items only: the set run (custom_id `$set`), which carries a workflow's set-scope nodes, is not one of them and is never listed here; read it with `GET /v1/run-sets/{id}/set`.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run set id. |
status | query · string | Comma-separated `RunStatus` values to include, e.g. `failed,partial`. An unknown value filters nothing rather than failing. |
custom_id | query · string | Only the run for this input line's `custom_id`. |
finished_after | query · string (date-time) | Only runs that finished strictly after this time (RFC 3339): what finished since the last poll. Pass the latest `finished_at` already seen less a minute, and skip run ids already handled; runs finish on several writers, so one can commit a moment after a run that finished later, and the overlap is what keeps it from being missed. |
after | query · string | The previous page's `next_cursor`. |
limit | query · integer | Page size. Above 1000 is capped; an unreadable value uses the default. |
Responses
| Status | Meaning |
|---|---|
200 | A page of runs. RunList |
400 | `finished_after` is not an RFC 3339 time. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Workflow runs are not available on this deployment. NativeError |
/v1/run-sets/{id}/set Get a run set's set run.
The run that carries the workflow's set-scope nodes, which run once per submission after every item has finished, exactly as `GET /v1/runs/{id}` returns it. Its `custom_id` is `$set`. While the items are still running the answer is `409` with their counts, so a client can poll this one URL for the result that reads across the whole submission.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run set id. |
Responses
| Status | Meaning |
|---|---|
200 | The set run. Run |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, owned by another tenant, a workflow with no set-scope nodes, or a set that ended before its items finished. NativeError |
409 | The items are still running; the set run does not exist yet. SetRunPending |
503 | Workflow runs are not available on this deployment. NativeError |
/v1/run-sets/{id}/output Download a run set's results.
JSONL, one line per run: the same lines a workflow batch writes to its output file. Any set has one, including a continuation, which an API call created and which therefore has no batch file of its own.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run set id. |
Responses
| Status | Meaning |
|---|---|
200 | The results. |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Workflow runs are not available on this deployment. NativeError |
/v1/run-sets/{id}/rerun Rerun a run set from a step.
Starts a new run set over this one's items, against a version of the same workflow, that reruns the steps in `from` and everything downstream of them and reuses this set's recorded output for every other step. Use it to measure a change to one step without buying the steps before it again: only the rerun steps are charged. Every reused step must be identical in both versions, its prompt, product, schemas, validators, condition and inputs included; if one changed, the answer is `409` naming it, so add it to `from`. A recorded skip is reused as made. Items whose content was deleted under the retention policy, or whose reused steps did not finish, are left out and counted in `excluded`. `dry_run: true` creates nothing and answers what the rerun would cover and cost. Like a batch line, a run your balance or spend cap cannot cover is created `hold`. Idempotent: the same source, version and steps return the set the first call created, with `200` and `existing: true`.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run set id. |
Request body RerunRequest
| Field | Type | Description |
|---|---|---|
version | integer | The workflow version to rerun against. 0 or absent is the latest published. |
from (required) | array of string | The steps to rerun. They and every step downstream of them run again. |
dry_run | boolean | Create nothing; answer what the rerun would cover and cost. |
Responses
| Status | Meaning |
|---|---|
200 | A dry run, or the rerun an identical earlier call created. RerunResult |
201 | The rerun was created. RerunResult |
400 | The body is not a rerun request. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
409 | Still running, an unknown step or version, or a reused step that differs between the versions. NativeError |
/v1/run-sets/{id}/continue Continue a run set.
Starts a new run set that resumes every unfinished run in this one. Nodes that already produced a valid output are carried over (`inherited_nodes`) and are not bought again; only the rest run (`rerunning_nodes`). It is a new purchase with a fresh reservation, admitted like a batch line: a run your balance or monthly spend cap cannot cover is created `hold` (`held_runs`) and starts on its own once it can. Idempotent: a repeat returns the continuation the first call created with `200` and `existing: true`. It is `409` when there is nothing to continue, when the set has not stopped yet, or when its content was deleted under the retention policy.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run set id. |
Responses
| Status | Meaning |
|---|---|
200 | Replay. The continuation an earlier call created. Continuation |
201 | The continuation was created. Continuation |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
409 | Nothing to continue, still running, or the content was deleted. NativeError |
503 | Workflow runs are not available on this deployment. NativeError |
/v1/run-sets/{id}/nodes/{key}/parked List the runs waiting at an external node.
The runs in a set currently parked at one external node, with each one's rendered input, so you can do the work and resume them in bulk. The cohort is live, not a snapshot: runs arrive at a park at different times, so an empty page now does not mean the cohort is finished, and you resume in waves.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run set id. |
key (required) | path · string | The node's key in the workflow document. |
after | query · string | The previous page's `next_cursor`. |
limit | query · integer | Page size. Out-of-range values use the default. |
Responses
| Status | Meaning |
|---|---|
200 | A page of parked runs. ParkedCohort |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Workflow runs are not available on this deployment. NativeError |
/v1/run-sets/{id}/nodes/{key}/output.jsonl Download one node's results across a set, in OpenAI batch-output format.
One node's results for every run in the set, each line a `BatchRequestOutput`, so code that already reads OpenAI batch output keeps working while you move a pipeline onto a workflow one stage at a time. An unknown node key is `404`, never an empty file.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run set id. |
key (required) | path · string | The node's key in the workflow document. |
Responses
| Status | Meaning |
|---|---|
200 | JSONL, one `BatchRequestOutput` per line. |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | No such set, or the workflow has no node with this key. NativeError |
503 | Workflow runs are not available on this deployment. NativeError |
/v1/run-sets/{id}/nodes/{key}/resume Resume parked runs in bulk.
Resumes runs parked at an external node from one JSONL body, a line per run: `{"custom_id": "...", "output": {...}}`. Each output goes through the node's validators. Safe to retry after a timeout: a line naming a run already resumed is a no-op that reports success, so re-sending the whole file is always correct. One bad line fails that line only (see `results`) and never rejects the body. Up to 32 MiB per body and 4 MiB per line.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run set id. |
key (required) | path · string | The node's key in the workflow document. |
Request body
Responses
| Status | Meaning |
|---|---|
200 | A result per line. BulkResumeResult |
400 | The body could not be read as lines (a line over 4 MiB). NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
413 | The body is over 32 MiB. NativeError |
503 | Workflow runs are not available on this deployment. NativeError |
/v1/runs/{id} Get a run.
One input item's run through the graph: each node's status, output, and, while the node waits behind a held cold start, `hold`. **Three durations.** `budget_consumed_seconds` is the SLA clock, which includes the wait for capacity; `parked_seconds` is time spent waiting on you, which the SLA clock does not count; `execution_seconds` is the time workers actually spent on the run, retries included. Compare `execution_seconds` with a plan's p95 execution.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run id. |
Responses
| Status | Meaning |
|---|---|
200 | The run. Run |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Workflow runs are not available on this deployment. NativeError |
/v1/runs/{id}/nodes/{key}/attempts List a node's attempts.
Every attempt at one node, oldest first: the model and region that served it, its output (rejected or accepted), the validator verdicts, tokens and cost, and when a worker leased it. Debug a validator here: a rejected output is visible only on its attempt.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run id. |
key (required) | path · string | The node's key in the workflow document. |
Responses
| Status | Meaning |
|---|---|
200 | The node's attempts. NodeAttempts |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Workflow runs are not available on this deployment. NativeError |
/v1/runs/{id}/cancel Cancel a run.
Stops one run: its unfinished nodes end `failed` with reason `cancelled`, jobs not yet leased are stopped, and the run ends `cancelled`. Cancelling a finished run changes nothing and returns it.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run id. |
Responses
| Status | Meaning |
|---|---|
200 | The run, after cancelling. Run |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Workflow runs are not available on this deployment. NativeError |
/v1/runs/{id}/continue Continue one run.
The single-run form of `POST /v1/run-sets/{id}/continue`, for debugging. Same idempotency and `409` rules.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run id. |
Responses
| Status | Meaning |
|---|---|
200 | Replay. The continuation an earlier call created. Continuation |
201 | The continuation was created. Continuation |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
409 | Nothing to continue, still running, or the content was deleted. NativeError |
503 | Workflow runs are not available on this deployment. NativeError |
/v1/runs/{id}/nodes/{key}/resume Resume one parked run.
Supplies an external node's output for one run. For more than a handful of runs use the set's bulk resume. A rejected output leaves the node parked, so you can send it again.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Run id. |
key (required) | path · string | The node's key in the workflow document. |
Request body ResumeRequest
| Field | Type | Description |
|---|---|---|
output (required) | object | The external node's output, checked by its validators. |
Responses
| Status | Meaning |
|---|---|
200 | Resumed. ResumeOK |
400 | The body is not `{"output": ...}`. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
409 | The node is not parked (most often, it was already resumed). NativeError |
413 | The body is over 32 MiB. NativeError |
422 | The node's validators rejected the output. The node stays parked. ResumeRejected |
503 | Workflow runs are not available on this deployment. NativeError |
Webhooks
Lifecycle notifications. A notification carries ids and counts, never content.
/v1/webhooks List webhook endpoints.
Your registered endpoints, and the events you can subscribe to. A notification carries ids, counts and a link to an authenticated listing, never a prompt or a result.
Responses
| Status | Meaning |
|---|---|
200 | The endpoints and the event vocabulary. WebhookEndpointList |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
503 | Webhooks are not available on this deployment. NativeError |
/v1/webhooks Register a webhook endpoint.
Registers an `https` URL to notify. With no `events`, it subscribes to the set-level events only (`run_set.completed`, `run_set.node_parked`); per-run events fire once per item and must be named. At most 10 endpoints per account. The response carries the signing secret. It is shown once and cannot be retrieved again; if you lose it, rotate. Each delivery is signed in the `Otium-Signature` header.
Request body WebhookEndpointRequest
| Field | Type | Description |
|---|---|---|
url | string | An https URL. Required to register. |
description | string | |
events | array of WebhookEvent | Events to subscribe to. Empty or absent on register means the set-level defaults. |
enabled | boolean |
Responses
| Status | Meaning |
|---|---|
201 | Registered. The secret is in this response only. WebhookRegistration |
400 | No URL, a URL that is not https or resolves to a private address, an unknown event, or the endpoint limit reached. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
503 | Webhooks are not available on this deployment. NativeError |
/v1/webhooks/deliveries List recent webhook deliveries.
Recent deliveries to all your endpoints, newest first: what was sent, how many tries, and what your endpoint answered. A delivery that used up its retries is kept as `dead`.
Parameters
| Parameter | In · type | Description |
|---|---|---|
limit | query · integer | How many deliveries to return. An unreadable value uses the default. |
Responses
| Status | Meaning |
|---|---|
200 | The deliveries. WebhookDeliveryList |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
503 | Webhooks are not available on this deployment. NativeError |
/v1/webhooks/{id} Get a webhook endpoint.
One endpoint, with its last success and failure. Never the secret.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Webhook endpoint id. |
Responses
| Status | Meaning |
|---|---|
200 | The endpoint. WebhookEndpoint |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Webhooks are not available on this deployment. NativeError |
/v1/webhooks/{id} Update a webhook endpoint.
Changes the URL, description, subscribed events or enabled flag. A field left out is unchanged.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Webhook endpoint id. |
Request body WebhookEndpointRequest
| Field | Type | Description |
|---|---|---|
url | string | An https URL. Required to register. |
description | string | |
events | array of WebhookEvent | Events to subscribe to. Empty or absent on register means the set-level defaults. |
enabled | boolean |
Responses
| Status | Meaning |
|---|---|
200 | The updated endpoint. WebhookEndpoint |
400 | An invalid URL or an unknown event. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Webhooks are not available on this deployment. NativeError |
/v1/webhooks/{id} Delete a webhook endpoint.
Removes the endpoint and its delivery history.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Webhook endpoint id. |
Responses
| Status | Meaning |
|---|---|
200 | Deleted. WebhookDeleted |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Webhooks are not available on this deployment. NativeError |
/v1/webhooks/{id}/rotate Rotate a webhook endpoint's signing secret.
Issues a new signing secret, shown once in this response.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Webhook endpoint id. |
Responses
| Status | Meaning |
|---|---|
200 | The endpoint and its new secret. WebhookRegistration |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Webhooks are not available on this deployment. NativeError |
/v1/webhooks/{id}/deliveries List one endpoint's recent deliveries.
As `GET /v1/webhooks/deliveries`, for one endpoint.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Webhook endpoint id. |
limit | query · integer | How many deliveries to return. An unreadable value uses the default. |
Responses
| Status | Meaning |
|---|---|
200 | The deliveries. WebhookDeliveryList |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Webhooks are not available on this deployment. NativeError |
Tools
Endpoints a workflow's tool nodes call, signed by Otium.
/v1/tools List tool endpoints.
Your registered tool endpoints: the URLs a workflow's tool nodes call, named by `tools: { endpoint }` in the workflow document.
Responses
| Status | Meaning |
|---|---|
200 | The endpoints. ToolEndpointList |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
503 | Tool endpoints are not available on this deployment. NativeError |
/v1/tools Register a tool endpoint.
Registers an `https` URL under a name a workflow can refer to. The name is lowercase letters, digits, `-` or `_`, and cannot change later. At most 20 endpoints per account. The response carries the signing secret Otium signs each call with. It is shown once and cannot be retrieved again; if you lose it, rotate.
Request body ToolEndpointRequest
| Field | Type | Description |
|---|---|---|
name | string | Lowercase letters, digits, `-` or `_`. |
url | string | An https URL. |
description | string | Up to 200 characters. |
Responses
| Status | Meaning |
|---|---|
201 | Registered. The secret is in this response only. ToolRegistration |
400 | A missing or invalid name or URL, a description over 200 characters, or the endpoint limit reached. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
409 | An endpoint with this name already exists. NativeError |
503 | Tool endpoints are not available on this deployment. NativeError |
/v1/tools/{id} Get a tool endpoint.
One endpoint. Never the secret.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Tool endpoint id. |
Responses
| Status | Meaning |
|---|---|
200 | The endpoint. ToolEndpoint |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Tool endpoints are not available on this deployment. NativeError |
/v1/tools/{id} Update a tool endpoint.
Changes the URL or description. A field left out is unchanged. The name cannot change, because published workflows refer to it; register a new endpoint instead.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Tool endpoint id. |
Request body ToolEndpointRequest
| Field | Type | Description |
|---|---|---|
name | string | Lowercase letters, digits, `-` or `_`. |
url | string | An https URL. |
description | string | Up to 200 characters. |
Responses
| Status | Meaning |
|---|---|
200 | The updated endpoint. ToolEndpoint |
400 | A name was sent, or the URL or description is invalid. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Tool endpoints are not available on this deployment. NativeError |
/v1/tools/{id} Delete a tool endpoint.
Removes the endpoint.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Tool endpoint id. |
Responses
| Status | Meaning |
|---|---|
204 | Deleted. |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Tool endpoints are not available on this deployment. NativeError |
/v1/tools/{id}/rotate Rotate a tool endpoint's signing secret.
Issues a new signing secret, shown once in this response. The old one stops working at once.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | Tool endpoint id. |
Responses
| Status | Meaning |
|---|---|
200 | The endpoint and its new secret. ToolRegistration |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | Tool endpoints are not available on this deployment. NativeError |
Account
The signed-in person's account and API keys. A CLI token only; an API key gets 403.
/v1/account Get the signed-in account.
The account the CLI token belongs to. An API key gets `403`.
Responses
| Status | Meaning |
|---|---|
200 | The account. Account |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
403 | An API key on an account route. Use a CLI token (otiumctl auth login). NativeError |
/v1/api-keys List API keys.
The account's API keys, newest first, revoked ones included. A key's secret is never returned here; `last_four` identifies it. An API key gets `403`: only a person (a CLI token) manages keys.
Responses
| Status | Meaning |
|---|---|
200 | The keys. APIKeyList |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
403 | An API key on an account route. Use a CLI token (otiumctl auth login). NativeError |
/v1/api-keys Create an API key.
Mints an API key for programs and CI. The response carries the full `secret` once: it is never stored or shown again, so save it now. An API key gets `403`.
Request body APIKeyCreateRequest
| Field | Type | Description |
|---|---|---|
name (required) | string | |
expires_days | integer | Days until the key expires. Absent, it expires in 90 days. `0` is an explicit "never expires", which you have to ask for. Existing keys keep the expiry they were made with. |
service | boolean | A key for a system rather than a person. Only an org's owners and admins may create one. |
Responses
| Status | Meaning |
|---|---|
201 | The key, with its secret. APIKeyCreated |
400 | Missing or over-long `name`, a negative `expires_days`, or an unreadable body. NativeError |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
403 | An API key on an account route. Use a CLI token (otiumctl auth login). NativeError |
503 | API keys are unavailable on this deployment. NativeError |
/v1/api-keys/{id} Revoke an API key.
Revokes one of the account's keys. Revoking twice is not an error. An API key gets `403`.
Parameters
| Parameter | In · type | Description |
|---|---|---|
id (required) | path · string | API key id. |
Responses
| Status | Meaning |
|---|---|
200 | Revoked. APIKeyRevoked |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
403 | An API key on an account route. Use a CLI token (otiumctl auth login). NativeError |
404 | Not found, or owned by another tenant. NativeError |
503 | API keys are unavailable on this deployment. NativeError |
CLI sign-in
The OAuth device grant `otiumctl auth login` runs, and token renewal.
/v1/auth/device No authStart a CLI sign-in.
Starts the OAuth device authorization grant (RFC 8628) that `otiumctl auth login` runs. Show the person `user_code` and `verification_uri`; they approve it in the portal, signed in and re-entering their password (and second factor when MFA is on). Then poll `POST /v1/auth/device/token` every `interval` seconds until `expires_in` runs out. Unauthenticated and rate-limited per client IP.
Request body DeviceStartRequest
| Field | Type | Description |
|---|---|---|
device_name | string | Shown on the approval page and the Devices list, e.g. `otiumctl on build-01`. Optional. |
Responses
| Status | Meaning |
|---|---|
200 | The sign-in was started. DeviceStart |
400 | `device_name` is over 100 characters. NativeError |
429 | Rate limit exceeded for this client IP. |
503 | CLI sign-in is unavailable, or the database is down. NativeError |
/v1/auth/device/token No authPoll for a CLI sign-in's token.
Until the person approves the sign-in, this answers `400` with an RFC 8628 error code: `authorization_pending` (keep polling), `slow_down` (poll less often), `access_denied`, `expired_token` (start again) or `invalid_grant` (unknown or already used). Once approved it returns the credentials, exactly once. Unauthenticated and rate-limited per client IP.
Request body DevicePollRequest
| Field | Type | Description |
|---|---|---|
device_code (required) | string | From `POST /v1/auth/device`. |
Responses
| Status | Meaning |
|---|---|
200 | Approved. The sign-in's credentials. TokenResponse |
400 | Not approved (yet), or no `device_code` was sent. TokenError |
429 | Rate limit exceeded for this client IP. |
503 | CLI sign-in is unavailable, or the database is down. NativeError |
/v1/auth/token/refresh No authRenew a CLI sign-in.
Exchanges a refresh token for a new access token and a new refresh token (RFC 6749 §6). Each refresh token works once: presenting one that was already used revokes the sign-in. A sign-in ends after 30 days unused or 90 days in all; any failure is `401` `invalid_grant`, and the CLI signs in again. Unauthenticated and rate-limited per client IP.
Request body TokenRefreshRequest
| Field | Type | Description |
|---|---|---|
refresh_token (required) | string |
Responses
| Status | Meaning |
|---|---|
200 | The renewed credentials. TokenResponse |
400 | No `refresh_token` was sent (`invalid_request`). TokenError |
401 | The sign-in has ended (`invalid_grant`). TokenError |
429 | Rate limit exceeded for this client IP. |
503 | CLI sign-in is unavailable, or the database is down. NativeError |
/v1/auth/token Sign this CLI token out.
Revokes the user token the request authenticated with (`otiumctl auth logout`). Other sign-ins are managed from the portal's Devices page. An API key gets `403`.
Responses
| Status | Meaning |
|---|---|
200 | Signed out. TokenRevoked |
401 | No credential, or one that is invalid, expired or revoked. NativeError |
403 | An API key on an account route. Use a CLI token (otiumctl auth login). NativeError |
Schemas
The object shapes the endpoints above accept and return.
ModelList
| Field | Type | Description |
|---|---|---|
object (required) | string | list |
data (required) | array of Model |
Model
| Field | Type | Description |
|---|---|---|
id (required) | string | The product to name in a request's `model` field. |
object (required) | string | model |
created (required) | integer | Unix seconds the product was created; 0 when unknown. |
owned_by (required) | string | |
context_window | integer | Most tokens (prompt plus completion) one request may use. |
preview | boolean | A preview granted to your account: usable by you, not offered to everyone. Omitted for an offered model. |
warm | boolean | A worker is serving this model now, so work starts without a cold start (15-30 minutes). A snapshot: idle workers are released within minutes. |
Tier
SLA tier — the completion window the caller will wait.
rushprioritystandardremnantBoundary
Data-residency boundary (never a raw cloud region). Empty means unconstrained. Coarse and fine tags coexist (e.g. a region in `eu` may also be in `eu-de`).
afapaccaeueu-demenasaukusSensitivity
Data-sensitivity class. Empty defaults to `internal` (trusted-only). Sets the minimum worker trust tier the job may run on. See docs/trust-tiers.md.
confidentialinternalpublicTrustTier
Minimum worker trust tier required to run the job, derived from its sensitivity at submit. Control-plane-assigned to workers; never self-reported.
known_providerowner_trusteduntrustedJobStatus
Position in the job lifecycle state machine.
acceptedholdqueuedscheduleddispatchedrunningsucceededfailedinterruptedexpireddead_lettercancelledBatchStatus
OpenAI batch lifecycle status.
validatingfailedin_progressfinalizingcompletedexpiredcancellingcancelledSubmitJobRequest
| Field | Type | Description |
|---|---|---|
model (required) | string | What to run. An intent alias (e.g. `otium-medium`) or an exact catalog model id. Required. An alias is resolved to a concrete model server-side; an unresolvable value is rejected with 400. |
otium | OtiumIntent | Optional intent extension — declare an outcome (task, quality floor, family) rather than only a model. OpenAI-compatible (stock clients ignore it). |
tier | Tier | SLA tier. Omit to default to `remnant`. rushprioritystandardremnant |
payload | string | Small inline request body (PoC). Production payloads live in object storage. |
idempotency_key | string | Per-tenant key making resubmission safe. A repeat returns the original job. |
max_attempts | integer | Max execution attempts before dead-lettering. Non-positive values default to 3. Default: 3 |
boundary | Boundary | Locks the job to a residency boundary. Empty means unconstrained. afapaccaeueu-demenasaukus |
sensitivity | Sensitivity | Data-sensitivity class. Empty defaults to `internal` (trusted-only). confidentialinternalpublic |
max_tokens | integer | Output-token ceiling. Bounds the up-front cost estimate the prepaid gate reserves; 0 uses a default ceiling. A chat-completion body that sets neither max_tokens nor max_completion_tokens is capped at 8192 output tokens when it runs. |
OtiumIntent
The optional `otium` selection extension: declare an outcome instead of a model. Rung 1 routes on the `model` alias alone; these fields are carried for the measured router and planner (later rungs) and do not yet change the resolved model.
| Field | Type | Description |
|---|---|---|
task | string | The task kind, e.g. extract | classify | summarize | generate | chat. |
quality | string | The quality floor — the cheapest execution that meets it, e.g. good | high | best. |
family | string | Model-family constraint — auto (default) | qwen | gemma | glm | an exact model id. |
allow_upgrade | boolean | Overrides the account's upgrade setting for this job. true lets it run on a warm, larger model at its own product's price; false keeps it on its own. Omitted takes the account setting, which is on by default. |
Job
The durable record of one unit of deferred inference work.
| Field | Type | Description |
|---|---|---|
id (required) | string (uuid) | |
idempotency_key | string | |
tenant (required) | string | |
product | string | The sellable SKU the job was submitted under (billing keys on it). Empty for pre-product jobs. |
model (required) | string | The concrete model the job runs on (dispatch/provisioning key on it). |
status (required) | JobStatus | acceptedholdqueuedscheduleddispatchedrunningsucceededfailedinterruptedexpireddead_lettercancelled |
tier (required) | Tier | rushprioritystandardremnant |
deadline (required) | string (date-time) | SLA deadline; the job expires if not completed by this time. |
boundary | Boundary | afapaccaeueu-demenasaukus |
sensitivity | Sensitivity | confidentialinternalpublic |
required_trust | TrustTier | known_providerowner_trusteduntrusted |
own_hardware_only | boolean | Whether the job runs only on the account's own workers (customer-hosted), waiting for them rather than running on Otium's capacity. Set when the job is created, from the account setting. |
allow_upgrade | boolean | Whether the job may run on a warm, larger model at its own product's price. Set when the job is created, from the request or the account setting. |
served_model | string | The model that served the job when it was upgraded onto a larger model; empty when it ran on `model`. Billing always keys on `product`. |
run_id | string | Workflow run this job is an attempt of. Empty for an ordinary job. A workflow job is scheduled, leased and executed by exactly the same path as any other; these two fields are only how a completion finds its graph node. |
node_key | string | Workflow node this job is an attempt of. Empty for an ordinary job. |
attempts (required) | integer | |
max_attempts (required) | integer | |
last_error | string | Category/summary of the last failure. Never contains payload content. |
payload | string | |
result | string | |
input_ref | string | Object-storage key for the input when not stored inline. |
result_ref | string | Object-storage key for the result when not stored inline. |
leased_by | string | Worker id holding the job while running. |
lease_expires_at | string (date-time) | |
created_at (required) | string (date-time) | |
updated_at | string (date-time) | |
queued_at | string (date-time) | |
scheduled_at | string (date-time) | |
started_at | string (date-time) | |
finished_at | string (date-time) | |
content_purged_at | string (date-time) | When the retention policy deleted this job's payload and result. Absent while the content is held. Status, token counts and cost are kept regardless. |
input_tokens | integer | |
output_tokens | integer | |
cached_tokens | integer | |
cost_usd | number | |
estimated_cost_usd | number |
FileObject
OpenAI representation of an uploaded or generated file.
| Field | Type | Description |
|---|---|---|
id (required) | string | |
object (required) | string | file |
bytes (required) | integer (int64) | |
created_at (required) | integer (int64) | Creation time, Unix seconds. |
filename (required) | string | |
purpose (required) | string | batchbatch_output |
Upload
OpenAI's Upload object.
| Field | Type | Description |
|---|---|---|
id (required) | string | |
object (required) | string | upload |
bytes (required) | integer (int64) | |
created_at (required) | integer (int64) | |
filename (required) | string | |
purpose (required) | string | |
status (required) | string | pendingcompletedcancelledexpired |
expires_at (required) | integer (int64) | |
file (required) | FileObject | The file a completed upload became; null until then. |
UploadPart
OpenAI's Upload Part object.
| Field | Type | Description |
|---|---|---|
id (required) | string | |
object (required) | string | upload.part |
created_at (required) | integer (int64) | |
upload_id (required) | string |
FileList
| Field | Type | Description |
|---|---|---|
object (required) | string | list |
data (required) | array of FileObject | |
first_id (required) | string, nullable | The first item's id; null on an empty page. |
last_id (required) | string, nullable | The last item's id, the `after` for the next page; null on an empty page. |
has_more (required) | boolean |
FileDeleted
| Field | Type | Description |
|---|---|---|
id (required) | string | |
object (required) | string | file |
deleted (required) | boolean |
CreateBatchRequest
| Field | Type | Description |
|---|---|---|
input_file_id (required) | string | Id of an uploaded file with purpose `batch`, owned by the caller. |
endpoint | string | The only endpoint supported today. /v1/chat/completionsDefault: /v1/chat/completions |
completion_window | string | OpenAI `24h` (default), the shorthands `1h` / `6h` / `7d` / `168h`, or an
Otium tier name (`rush`, `priority`, `standard`, `remnant`). Default: 24h |
metadata | map of string | Up to 16 string key/value pairs. The reserved key `boundary` locks every job in the batch to a residency boundary. A key a gateway adds on its caller's behalf (`otari_user_id`) does not count against the 16. |
Batch
OpenAI representation of a batch. Unset timestamps serialize as null.
| Field | Type | Description |
|---|---|---|
id (required) | string | |
object (required) | string | batch |
endpoint (required) | string | |
errors | BatchErrorList | |
input_file_id (required) | string | |
completion_window (required) | string | |
status (required) | BatchStatus | validatingfailedin_progressfinalizingcompletedexpiredcancellingcancelled |
output_file_id | string | |
error_file_id | string | |
created_at (required) | integer (int64) | Unix seconds. |
in_progress_at | integer (int64), nullable | |
expires_at | integer (int64), nullable | |
finalizing_at | integer (int64), nullable | |
completed_at | integer (int64), nullable | |
failed_at | integer (int64), nullable | |
expired_at | integer (int64), nullable | |
cancelling_at | integer (int64), nullable | |
cancelled_at | integer (int64), nullable | |
request_counts (required) | RequestCounts | |
metadata | map of string |
BatchList
| Field | Type | Description |
|---|---|---|
object (required) | string | list |
data (required) | array of Batch | |
first_id (required) | string, nullable | The first item's id; null on an empty page. |
last_id (required) | string, nullable | The last item's id, the `after` for the next page; null on an empty page. |
has_more (required) | boolean |
RequestCounts
Per-batch progress tally.
| Field | Type | Description |
|---|---|---|
total (required) | integer | |
completed (required) | integer | |
failed (required) | integer |
BatchErrorList
Non-fatal errors discovered during validation.
| Field | Type | Description |
|---|---|---|
object (required) | string | list |
data (required) | array of BatchError |
RunStatus
A run's (or run set's) position. `accepted`: persisted, nothing evaluated yet. `hold`: withheld until the balance covers its reservation. `running`: at least one node is live (queued work held before a cold start still reads `running`; see `holds`). `parked`: waiting on an external node, so no budget accrues. Terminal: `succeeded`, `partial` (some outputs produced, a first-class result), `failed`, `expired`, `cancelled`.
acceptedholdrunningparkedsucceededpartialfailedexpiredcancelledRunOutcome
Why a finished run ended as it did. `completed_with_skips` is a success: the graph's guards pruned the rest.
completedcompleted_with_skipsnode_failedbudget_exhausteddeadline_exceededpark_expiredcancelledNodeStatus
`blocked`: waiting on upstream nodes. `ready`: rendered and queued for a worker. `running`: a worker has it. `parked`: an external node waiting for your resume. Terminal: `succeeded`, `failed`, `skipped`. Never count `skipped` as failure; read `disposition`.
blockedreadyrunningsucceededfailedskippedparkedTerminalReason
Why a node (or attempt) stopped.
okinvalid_outputexecution_failedcapacity_unavailabletimeoutguard_falseupstream_skippedupstream_failedbudget_exhaustedpark_expiredcancelledtool_timeouttool_errortool_refusedDisposition
`ok`: produced its output. `pruned`: the graph correctly chose not to run it (a guard was false, or an upstream was pruned). `degraded`: something prevented it from running. Aggregate on this, never on `skipped`.
okpruneddegradedRunSetHold
One node's held work in a run set.
| Field | Type | Description |
|---|---|---|
node_key (required) | string | |
reason (required) | HoldReason | gatheringprice |
latest_start | string (date-time) | As on `Hold`. |
runs (required) | integer | How many of the set's runs are waiting at this node. |
RunSetSummary
| Field | Type | Description |
|---|---|---|
id (required) | string | |
workflow_id (required) | string | |
batch_id | string | The batch that created the set. Absent for a continuation. |
continues_set_id | string | The set this one continues, when it is a continuation. |
tier (required) | Tier | rushprioritystandardremnant |
status (required) | RunStatus | acceptedholdrunningparkedsucceededpartialfailedexpiredcancelled |
outcome | RunOutcome | completedcompleted_with_skipsnode_failedbudget_exhausteddeadline_exceededpark_expiredcancelled |
total (required) | integer | |
completed (required) | integer | |
failed (required) | integer | |
execution_budget_seconds (required) | integer (int64) | The SLA bought, per run. Stops while a run waits on you. |
expires_at (required) | string (date-time) | The wall-clock bound, separate from the execution budget. |
created_at (required) | string (date-time) | |
finished_at | string (date-time) |
RunSetList
| Field | Type | Description |
|---|---|---|
run_sets (required) | array of RunSetSummary | |
count (required) | integer | |
next_cursor | string | Pass as `after` for the next page. Absent on the last page. |
RunSet
| Field | Type | Description |
|---|---|---|
id (required) | string | |
workflow_id (required) | string | |
plan_id (required) | string | |
batch_id | string | |
tier (required) | Tier | rushprioritystandardremnant |
status (required) | RunStatus | acceptedholdrunningparkedsucceededpartialfailedexpiredcancelled |
outcome | RunOutcome | completedcompleted_with_skipsnode_failedbudget_exhausteddeadline_exceededpark_expiredcancelled |
execution_budget_seconds (required) | integer (int64) | The SLA bought, per run. Stops while a run waits on you. |
expires_at (required) | string (date-time) | The wall-clock bound, separate from the execution budget. |
total (required) | integer | |
completed (required) | integer | |
failed (required) | integer | |
counts (required) | map of integer | Runs per `RunStatus`, live. |
holds (required) | array of RunSetHold | Queued work held before it starts, by node. Empty when nothing is held. |
bounds_reached (required) | array of RunSetBounds | Per node, how many runs took an output that reached a `maxLength` or `maxItems` its `response_format` set. Constrained decoding stops a field at its limit, so such a field was usually cut short. Each attempt's `bounds_reached` names the field. Empty when no output reached one. |
set_run | SetRunRef | |
created_at (required) | string (date-time) | |
finished_at | string (date-time) |
RunSetBounds
One node's count of outputs that reached a size bound.
| Field | Type | Description |
|---|---|---|
node_key (required) | string | |
runs (required) | integer |
SetRunRef
The run carrying a workflow's set-scope nodes. Absent when the workflow has none; no `id` and status `pending` until every item has finished.
| Field | Type | Description |
|---|---|---|
id | string | |
status (required) | string | A `RunStatus`, or `pending` before the set run exists. |
outcome | RunOutcome | completedcompleted_with_skipsnode_failedbudget_exhausteddeadline_exceededpark_expiredcancelled |
SetRunPending
A set whose items are still running, so its set run does not exist yet.
| Field | Type | Description |
|---|---|---|
status (required) | string | Always `pending`. |
items (required) | object |
RunSummary
| Field | Type | Description |
|---|---|---|
id (required) | string | |
run_set_id (required) | string | |
custom_id | string | The input line's `custom_id`. |
status (required) | RunStatus | acceptedholdrunningparkedsucceededpartialfailedexpiredcancelled |
outcome | RunOutcome | completedcompleted_with_skipsnode_failedbudget_exhausteddeadline_exceededpark_expiredcancelled |
budget_consumed_seconds (required) | integer (int64) | |
parked_seconds (required) | integer (int64) | |
cost_usd (required) | number | |
created_at (required) | string (date-time) | |
finished_at | string (date-time) |
RunList
| Field | Type | Description |
|---|---|---|
run_set_id (required) | string | |
runs (required) | array of RunSummary | |
count (required) | integer | |
next_cursor | string | Pass as `after` for the next page. Absent on the last page. |
Run
| Field | Type | Description |
|---|---|---|
id (required) | string | |
run_set_id (required) | string | |
custom_id | string | |
status (required) | RunStatus | acceptedholdrunningparkedsucceededpartialfailedexpiredcancelled |
outcome | RunOutcome | completedcompleted_with_skipsnode_failedbudget_exhausteddeadline_exceededpark_expiredcancelled |
budget_consumed_seconds (required) | integer (int64) | The SLA clock, including the wait for capacity and excluding parked time. |
parked_seconds (required) | integer (int64) | Time spent waiting on you at external nodes. |
execution_seconds (required) | number | Time workers spent on this run: each finished attempt from lease to finish, retries included. Attempts still running add nothing yet, and an inherited node counted in the run that produced it. |
cost_usd (required) | number | |
estimated_cost_usd (required) | number | |
nodes (required) | array of RunNode | |
created_at (required) | string (date-time) | |
finished_at | string (date-time) |
RunNode
| Field | Type | Description |
|---|---|---|
node_key (required) | string | |
seq (required) | integer | The node's position in the plan. |
status (required) | NodeStatus | blockedreadyrunningsucceededfailedskippedparked |
terminal_reason | TerminalReason | okinvalid_outputexecution_failedcapacity_unavailabletimeoutguard_falseupstream_skippedupstream_failedbudget_exhaustedpark_expiredcancelledtool_timeouttool_errortool_refused |
disposition (required) | Disposition | okpruneddegraded |
output | any | The node's validated output. Downstream bindings read this. |
error | string | Why a failed node failed, as its last attempt reported it. |
rejected_output | any | The last output a validator rejected, on a node that ended `invalid_output`. Kept apart from `output` so a rejected value can never reach a downstream node. |
inherited_from_run_id | string | The earlier run that produced this output, when a continuation carried it. |
input | any | An external node's rendered park payload. |
hold | Hold | |
execution_seconds (required) | number | This node's finished attempts in this run, lease to finish, summed. |
started_at | string (date-time) | When the node became ready, so it includes the wait for a worker. |
finished_at | string (date-time) |
Verdict
A validator's result. Carries a code, a pointer and a constraint, never content.
| Field | Type | Description |
|---|---|---|
ok (required) | boolean | |
code | string | |
pointer | string | JSON pointer to the offending location, e.g. `/name`. |
expected | string | The constraint that failed, e.g. `string`. |
Attempt
| Field | Type | Description |
|---|---|---|
id (required) | string | |
attempt (required) | integer | |
policy_step (required) | integer | Which step of the node's attempt policy (model fallback) this was. |
status (required) | AttemptStatus | runningsucceededfailed |
terminal_reason | TerminalReason | okinvalid_outputexecution_failedcapacity_unavailabletimeoutguard_falseupstream_skippedupstream_failedbudget_exhaustedpark_expiredcancelledtool_timeouttool_errortool_refused |
disposition (required) | Disposition | okpruneddegraded |
from_run_id | string | Set when this attempt ran in an earlier run that a continuation carried from. |
identity (required) | AttemptIdentity | |
output | any | What this attempt produced, accepted or rejected. |
verdicts (required) | array of Verdict | The validator chain's results, in order. |
bounds_reached (required) | array of Bound | Where this attempt's output, once accepted, reached a `maxLength` or `maxItems` its `response_format` set. Empty when it reached none or was not accepted. |
input_tokens (required) | integer | |
output_tokens (required) | integer | |
cached_tokens (required) | integer | |
cost_usd (required) | number | |
started_at | string (date-time) | When the attempt was created and its job queued, not when a worker took it. |
finished_at | string (date-time) | |
leased_at | string (date-time) | When a worker took the job (its last lease, after a requeue). Absent until then. |
execution_seconds (required) | number | From the lease to the job finishing. 0 until it has. |
NodeAttempts
| Field | Type | Description |
|---|---|---|
run_id (required) | string | |
node_key (required) | string | |
status (required) | NodeStatus | blockedreadyrunningsucceededfailedskippedparked |
terminal_reason | TerminalReason | okinvalid_outputexecution_failedcapacity_unavailabletimeoutguard_falseupstream_skippedupstream_failedbudget_exhaustedpark_expiredcancelledtool_timeouttool_errortool_refused |
disposition (required) | Disposition | okpruneddegraded |
inherited_from_run_id | string | |
final_attempt_id | string | The attempt whose output became the node's. |
attempts (required) | array of Attempt | |
count (required) | integer | |
cost_usd (required) | number | The attempts' cost, summed. |
ParkedRun
| Field | Type | Description |
|---|---|---|
run_id (required) | string | |
custom_id | string | |
input | any | The external node's rendered input. |
resume_token | string | |
parked_at (required) | string (date-time) |
ParkedCohort
| Field | Type | Description |
|---|---|---|
run_set_id (required) | string | |
node_key (required) | string | |
runs (required) | array of ParkedRun | |
next_cursor | string | Pass as `after` for the next page. Absent on the last page. |
count (required) | integer |
ResumeLineResult
| Field | Type | Description |
|---|---|---|
custom_id (required) | string | |
run_id | string | |
ok (required) | boolean | |
error | string | Why this line was rejected. Other lines are unaffected. |
verdict | Verdict |
BulkResumeResult
| Field | Type | Description |
|---|---|---|
results (required) | array of ResumeLineResult | |
resumed (required) | integer | |
rejected (required) | integer |
ResumeRequest
| Field | Type | Description |
|---|---|---|
output (required) | object | The external node's output, checked by its validators. |
ResumeOK
| Field | Type | Description |
|---|---|---|
ok (required) | boolean | true |
ResumeRejected
| Field | Type | Description |
|---|---|---|
error (required) | string | |
verdict (required) | Verdict |
RerunSummary
| Field | Type | Description |
|---|---|---|
node_key (required) | string | |
reason | TerminalReason | okinvalid_outputexecution_failedcapacity_unavailabletimeoutguard_falseupstream_skippedupstream_failedbudget_exhaustedpark_expiredcancelledtool_timeouttool_errortool_refused |
runs (required) | integer |
RerunRequest
| Field | Type | Description |
|---|---|---|
version | integer | The workflow version to rerun against. 0 or absent is the latest published. |
from (required) | array of string | The steps to rerun. They and every step downstream of them run again. |
dry_run | boolean | Create nothing; answer what the rerun would cover and cost. |
RerunResult
| Field | Type | Description |
|---|---|---|
run_set_id | string | The new run set. Absent on a dry run. |
source_run_set_id (required) | string | |
existing (required) | boolean | True when an identical earlier call created this rerun. |
dry_run (required) | boolean | |
runs (required) | integer | Items the rerun covers. |
held_runs (required) | integer | Runs created `hold`, waiting on funds or the monthly spend cap. |
rerun_steps (required) | array of string | |
carried_steps (required) | array of string | Steps whose recorded output is reused, at no charge. |
excluded (required) | array of object | Source items left out, by reason. Empty when none were. |
estimated_cost_usd (required) | number | The p95 of what the rerun buys. Reused steps cost nothing. |
Continuation
| Field | Type | Description |
|---|---|---|
run_set_id (required) | string | The new set. |
source_run_set_id | string | |
existing (required) | boolean | True when a repeat call returned the continuation an earlier one created. |
runs (required) | integer | |
inherited_nodes (required) | integer | Nodes carried over with their outputs, not bought again. |
rerunning_nodes (required) | integer | |
skipped_runs (required) | integer | Source runs not continued (already succeeded, or continued before). |
held_runs (required) | integer | Continuation runs waiting on funds or the monthly spend cap. A continuation is a new purchase, admitted like a batch line on each run's reservation; a held run starts on its own once the account can cover it. |
rerun (required) | array of RerunSummary | What is being run again, by node and reason. |
AssetStatus
`published`: runs may pin it. `deprecated`: new runs may not pin it, existing ones keep it. `purged`: its content is destroyed and its record kept.
publisheddeprecatedpurgedAssetBundleSummary
| Field | Type | Description |
|---|---|---|
bundle (required) | string | |
latest_version (required) | integer | |
status (required) | AssetStatus | publisheddeprecatedpurged |
versions (required) | integer | |
bytes (required) | integer (int64) | |
updated_at | string (date-time) |
AssetBundleList
| Field | Type | Description |
|---|---|---|
bundles (required) | array of AssetBundleSummary | |
count (required) | integer |
AssetVersion
One version's metadata. Never its content.
| Field | Type | Description |
|---|---|---|
id (required) | string | |
bundle (required) | string | |
version (required) | integer | |
status (required) | AssetStatus | publisheddeprecatedpurged |
digest (required) | string | Digest of the content, so identical publishes are recognised. |
bytes (required) | integer (int64) | |
assets (required) | integer | How many assets the version supplies. |
keys (required) | integer | How many keys its keyed assets cover. |
comment | string | |
created_at (required) | string (date-time) | |
published_at | string (date-time) | |
purged_at | string (date-time) |
AssetVersionList
| Field | Type | Description |
|---|---|---|
bundle (required) | string | |
versions (required) | array of AssetVersion | |
count (required) | integer |
AssetDetail
One version's metadata and its content.
| Field | Type | Description |
|---|---|---|
id (required) | string | |
bundle (required) | string | |
version (required) | integer | |
status (required) | AssetStatus | publisheddeprecatedpurged |
digest (required) | string | |
bytes (required) | integer (int64) | |
assets (required) | object | The content, in the form it was published: a string for a shared value, an object of key to string for a keyed one. Empty once purged. |
keys (required) | integer | |
comment | string | |
created_at (required) | string (date-time) | |
published_at | string (date-time) | |
purged_at | string (date-time) |
AssetPublishRequest
| Field | Type | Description |
|---|---|---|
bundle (required) | string | The bundle to publish a version of. Created on first publish. |
comment | string | A note kept with the version. |
assets (required) | object | Asset name to value: a string for one value shared by every run, or an object of key to string for one value per key. |
AssetPublishResult
| Field | Type | Description |
|---|---|---|
created (required) | boolean | False when the content matched the latest version and nothing was created. |
version (required) | AssetVersion |
WebhookEvent
`run_set.completed` and `run_set.node_parked` fire once per run set (the default). `run_set.items_completed` fires once per run set too, when every item of a workflow with set-scope nodes has finished and its set run starts; subscribe to it by name. The `run.*` and `node.completed` events fire once per item and must be subscribed to by name. `batch.completed`, `batch.failed`, `batch.expired` and `batch.cancelled` fire once when a plain batch reaches that status (in the default subscription), named as OpenAI names them; a batch that runs a workflow fires `run_set.completed` instead.
run_set.completedrun_set.node_parkedrun_set.items_completedrun.completedrun.failedrun.partialrun.parkedrun.expirednode.completedbatch.completedbatch.failedbatch.expiredbatch.cancelledWebhookEndpoint
A registered endpoint. Never carries the signing secret.
| Field | Type | Description |
|---|---|---|
id (required) | string | |
url (required) | string | |
description | string | |
events (required) | array of WebhookEvent | |
enabled (required) | boolean | |
created_at (required) | string (date-time) | |
updated_at (required) | string (date-time) | |
last_success_at | string (date-time) | |
last_failure_at | string (date-time) | |
last_error | string | |
consecutive_failures (required) | integer |
WebhookEventInfo
| Field | Type | Description |
|---|---|---|
event (required) | WebhookEvent | run_set.completedrun_set.node_parkedrun_set.items_completedrun.completedrun.failedrun.partialrun.parkedrun.expirednode.completedbatch.completedbatch.failedbatch.expiredbatch.cancelled |
per_run (required) | boolean | True when the event fires once per item rather than once per run set. |
default (required) | boolean | True when an endpoint that names no events subscribes to it. |
WebhookEndpointList
| Field | Type | Description |
|---|---|---|
endpoints (required) | array of WebhookEndpoint | |
count (required) | integer | |
available_events (required) | array of WebhookEventInfo |
WebhookEndpointRequest
On update every field is optional, and a field left out is unchanged.
| Field | Type | Description |
|---|---|---|
url | string | An https URL. Required to register. |
description | string | |
events | array of WebhookEvent | Events to subscribe to. Empty or absent on register means the set-level defaults. |
enabled | boolean |
WebhookRegistration
| Field | Type | Description |
|---|---|---|
endpoint (required) | WebhookEndpoint | |
secret (required) | string | The signing secret. Shown here once; it cannot be retrieved later. |
secret_note (required) | string |
WebhookDeleted
| Field | Type | Description |
|---|---|---|
deleted (required) | boolean | true |
WebhookDelivery
| Field | Type | Description |
|---|---|---|
id (required) | string | |
endpoint_id (required) | string | |
event (required) | WebhookEvent | run_set.completedrun_set.node_parkedrun_set.items_completedrun.completedrun.failedrun.partialrun.parkedrun.expirednode.completedbatch.completedbatch.failedbatch.expiredbatch.cancelled |
status (required) | WebhookDeliveryStatus | pendingdelivereddead |
attempts (required) | integer | |
next_attempt_at | string (date-time) | When a pending delivery is retried next. Absent once it is final. |
last_status_code | integer | The HTTP status your endpoint last answered. |
last_error | string | |
created_at (required) | string (date-time) | |
delivered_at | string (date-time) |
WebhookDeliveryList
| Field | Type | Description |
|---|---|---|
deliveries (required) | array of WebhookDelivery | |
count (required) | integer |
ToolEndpoint
A registered tool endpoint. Never carries the signing secret.
| Field | Type | Description |
|---|---|---|
id (required) | string | |
name (required) | string | What a workflow's `tools.endpoint` names. |
url (required) | string | |
description | string | |
created_at (required) | string (date-time) | |
updated_at (required) | string (date-time) |
ToolEndpointList
| Field | Type | Description |
|---|---|---|
endpoints (required) | array of ToolEndpoint | |
count (required) | integer | |
egress_ips (required) | array of string | The addresses tool calls come from, to allow on your endpoint's firewall. Empty when none are published for your deployment. |
ToolEndpointRequest
To register, `name` and `url` are required. To update, send only `url` and/or `description`; sending `name` is refused.
| Field | Type | Description |
|---|---|---|
name | string | Lowercase letters, digits, `-` or `_`. |
url | string | An https URL. |
description | string | Up to 200 characters. |
ToolRegistration
| Field | Type | Description |
|---|---|---|
endpoint (required) | ToolEndpoint | |
secret (required) | string | The signing secret. Shown here once; it cannot be retrieved later. |
secret_note (required) | string |
DeviceStartRequest
| Field | Type | Description |
|---|---|---|
device_name | string | Shown on the approval page and the Devices list, e.g. `otiumctl on build-01`. Optional. |
DeviceStart
| Field | Type | Description |
|---|---|---|
device_code (required) | string | The CLI's secret for polling. Never show it to the person. |
user_code (required) | string | The code the person confirms in the portal. |
verification_uri (required) | string | The portal page where the person approves the sign-in. |
expires_in (required) | integer | Seconds until the codes expire. |
interval (required) | integer | Minimum seconds between polls. |
DevicePollRequest
| Field | Type | Description |
|---|---|---|
device_code (required) | string | From `POST /v1/auth/device`. |
TokenRefreshRequest
| Field | Type | Description |
|---|---|---|
refresh_token (required) | string |
TokenSignIn
A CLI sign-in, as the Devices list shows it.
| Field | Type | Description |
|---|---|---|
id (required) | string | |
name (required) | string | The device name the CLI sent. |
last_four (required) | string | The last four characters of the current access token, for display. |
created_ip (required) | string | |
created_at (required) | string (date-time) | |
last_used_at | string (date-time) | |
revoked_at | string (date-time) | |
expires_at | string (date-time) | When the sign-in ends regardless of use. |
TokenResponse
An OAuth token response (RFC 6749 §5.1).
| Field | Type | Description |
|---|---|---|
access_token (required) | string | Send as `Authorization: Bearer <access_token>`. |
token_type (required) | string | Bearer |
expires_in (required) | integer | Seconds until the access token expires. Renew it with the refresh token. |
refresh_token (required) | string | Single-use. Each renewal returns a new one. |
user_token (required) | TokenSignIn |
TokenErrorCode
invalid_requestauthorization_pendingslow_downaccess_deniedexpired_tokeninvalid_grantTokenError
An OAuth error response (RFC 8628 §3.5, RFC 6749 §5.2).
| Field | Type | Description |
|---|---|---|
error (required) | TokenErrorCode | invalid_requestauthorization_pendingslow_downaccess_deniedexpired_tokeninvalid_grant |
error_description (required) | string |
TokenRevoked
| Field | Type | Description |
|---|---|---|
revoked (required) | boolean | true |
Account
| Field | Type | Description |
|---|---|---|
tenant (required) | string | |
name (required) | string | |
email (required) | string | |
plan (required) | string | |
mfa_enabled (required) | boolean | |
created_at (required) | string (date-time) |
APIKey
An API key's metadata. The secret is never part of it.
| Field | Type | Description |
|---|---|---|
id (required) | string | |
created_by | string | The account that created the key. |
service | boolean | The key belongs to a system (a pipeline, a deployment) rather than to the person who created it, so it counts as nobody's activity and outlives them. |
name (required) | string | |
prefix (required) | string | Always `sk-otium`. |
last_four (required) | string | The last four characters of the secret. |
created_at (required) | string (date-time) | |
last_used_at | string (date-time) | |
expires_at | string (date-time) | Absent when the key never expires. |
revoked (required) | boolean |
APIKeyList
| Field | Type | Description |
|---|---|---|
keys (required) | array of APIKey | |
count (required) | integer |
APIKeyCreateRequest
| Field | Type | Description |
|---|---|---|
name (required) | string | |
expires_days | integer | Days until the key expires. Absent, it expires in 90 days. `0` is an explicit "never expires", which you have to ask for. Existing keys keep the expiry they were made with. |
service | boolean | A key for a system rather than a person. Only an org's owners and admins may create one. |
APIKeyCreated
A new key's metadata plus its secret, returned only this once.
| Field | Type | Description |
|---|---|---|
id (required) | string | |
created_by | string | |
service | boolean | |
name (required) | string | |
prefix (required) | string | |
last_four (required) | string | |
created_at (required) | string (date-time) | |
last_used_at | string (date-time) | |
expires_at | string (date-time) | |
revoked (required) | boolean | |
secret (required) | string | The full key, `sk-otium-…`. Shown once; store it now. |
APIKeyRevoked
| Field | Type | Description |
|---|---|---|
id (required) | string | |
revoked (required) | boolean | true |
WorkflowStatus
`published`: new runs may use it. `deprecated`: new runs may not; existing runs and reads are unaffected. `purged`: the document was erased; the version remains as a record.
publisheddeprecatedpurgedWorkflowSummary
| Field | Type | Description |
|---|---|---|
name (required) | string | |
description (required) | string | |
latest_version (required) | integer | |
status (required) | WorkflowStatus | publisheddeprecatedpurged |
versions (required) | integer | How many versions exist. |
updated_at | string (date-time) |
WorkflowList
| Field | Type | Description |
|---|---|---|
workflows (required) | array of WorkflowSummary | |
count (required) | integer |
WorkflowVersion
| Field | Type | Description |
|---|---|---|
id (required) | string | |
name (required) | string | |
version (required) | integer | |
status (required) | WorkflowStatus | publisheddeprecatedpurged |
digest (required) | string | The digest of the canonical document. Identical documents share it. |
description (required) | string | |
created_at (required) | string (date-time) | |
published_at | string (date-time) | |
purged_at | string (date-time) |
WorkflowVersionList
| Field | Type | Description |
|---|---|---|
name (required) | string | |
versions (required) | array of WorkflowVersion | |
count (required) | integer |
WorkflowDetail
A version and its document.
| Field | Type | Description |
|---|---|---|
id (required) | string | |
name (required) | string | |
version (required) | integer | |
status (required) | WorkflowStatus | publisheddeprecatedpurged |
digest (required) | string | |
description (required) | string | |
created_at (required) | string (date-time) | |
published_at | string (date-time) | |
purged_at | string (date-time) | |
document (required) | string | The canonical YAML. Empty once the version is purged. |
WorkflowDocumentEnvelope
The JSON form of a document upload.
| Field | Type | Description |
|---|---|---|
document (required) | string | The workflow document, as YAML text. |
WorkflowDiagnostic
One compiler finding.
| Field | Type | Description |
|---|---|---|
severity (required) | WorkflowDiagnosticSeverity | errorwarn |
code (required) | string | A stable identifier for the kind of finding. |
message (required) | string | |
node | string | The node the finding is about, if any. |
path | string | Where in the document, e.g. `tools.endpoint`. |
PlanSummary
The headline figures for a compiled document.
| Field | Type | Description |
|---|---|---|
nodes (required) | integer | |
external_nodes (required) | integer | |
tool_nodes (required) | integer | |
depth (required) | integer | The critical path's length in nodes. |
critical_path (required) | array of string | |
p50_duration_seconds (required) | number | Wall-clock critical path, parks included. |
p95_duration_seconds (required) | number | Wall-clock critical path, parks included. |
p95_execution_seconds (required) | number | The critical path with parks counted as zero. What the tier's execution budget is checked against. |
est_cost_p50_usd (required) | number | Estimated cost per run. |
est_cost_p95_usd (required) | number | Estimated cost per run. |
cost_per_10k_usd (required) | number | `est_cost_p50_usd` for 10,000 runs. |
affinity_groups (required) | integer | |
barriers (required) | integer | |
cache_groups (required) | integer | |
errors (required) | integer | |
warnings (required) | integer | |
estimate_basis (required) | PlanEstimateBasis | declaredassumed |
declared_nodes (required) | integer | Inference nodes that declared their token usage. |
inference_nodes (required) | integer | |
set | PlanSetSummary |
WorkflowCompileResult
The result of validating or publishing a document.
| Field | Type | Description |
|---|---|---|
ok (required) | boolean | The document compiled with no errors. |
created (required) | boolean | Publishing created a new version. Always false for a validate or a replay. |
name | string | The document's name, when it parsed. |
plan | Plan | |
digest | string | |
diagnostics (required) | array of WorkflowDiagnostic | |
summary | PlanSummary | |
mermaid | string | The graph as a Mermaid diagram. |
version | WorkflowVersion |
Plan
A compiled workflow version, the structure the scheduler runs from.
| Field | Type | Description |
|---|---|---|
planner_version (required) | integer | |
scopes (required) | map of PlanScope | Plans by scope. `item` always; `set` when the document has set-scope nodes. |
asset_bundle | string | The asset bundle a run pins. Absent when the graph uses none. |
assets | array of string | The asset names the graph reads. |
est_cost_p50_usd (required) | number | |
est_cost_p95_usd (required) | number | Per item. |
set_est_cost_p50_usd | number | The set scope's fixed cost, paid once per submission. Absent without a set scope. |
set_est_cost_p95_usd | number | The set scope's fixed cost, paid once per submission. Absent without a set scope. |
set_est_cost_per_item_p95_usd | number | What each item adds to the set scope's cost. Absent without a set scope. |
estimate_basis (required) | PlanEstimateBasis | declaredassumed |
declared_nodes (required) | integer | |
inference_nodes (required) | integer | |
tool_endpoint | string | The registered tool endpoint the run's tool nodes call. |
WorkflowPlan
| Field | Type | Description |
|---|---|---|
name (required) | string | |
version (required) | integer | |
planner_version (required) | integer | |
plan (required) | Plan | |
mermaid | string | The graph as a Mermaid diagram. Absent once the version is purged. |
summary | PlanSummary |
WorkflowTestRequest
| Field | Type | Description |
|---|---|---|
document (required) | string | The workflow document under test, as YAML text. Up to 1 MiB. |
tests (required) | string | The test suite (a `*.test.yaml` file's contents), as YAML or JSON. Up to 1 MiB. |
run | string | Run only the cases whose name contains this. |
WorkflowTestReport
| Field | Type | Description |
|---|---|---|
passed (required) | integer | |
failed (required) | integer | |
cases (required) | array of WorkflowTestCase |
WorkflowTestCase
| Field | Type | Description |
|---|---|---|
name (required) | string | |
pass (required) | boolean | |
failures | array of string | Each difference from what the case expected. Absent when it passed. |
run (required) | WorkflowTestObserved |
HealthOK
| Field | Type | Description |
|---|---|---|
status (required) | string | ok |
HealthDegraded
| Field | Type | Description |
|---|---|---|
status (required) | string | degraded |
database (required) | string | down |
NativeError
Native-surface error envelope (`POST /v1/jobs`, `GET /v1/jobs/{id}`).
| Field | Type | Description |
|---|---|---|
error (required) | string |
OpenAIError
OpenAI-compatible error envelope used by the Files and Batch endpoints.
| Field | Type | Description |
|---|---|---|
error (required) | object |