Skip to main content

Response Envelope

Every REST response carries a top-level status, whatever else it carries. On success it is success, and the endpoint’s own fields sit beside it:
An endpoint with nothing to report answers with the status alone — {"status": "success"} — which is why no endpoint on this API ever returns a bare {}. Each endpoint page documents only its own fields; status is always there and is not repeated in those tables. Failures use the same envelope with two more keys:
error is a stable machine-readable code — key off it, not off message, which is prose and may be reworded. Each page lists the codes its endpoint can return. One endpoint sets status itself rather than inheriting it: Check Definition answers 200 with "status": "failure" when a workflow fails validation, because the verdict is the payload. The HTTP status still describes the request, not the verdict.
Two surfaces are deliberately outside this envelope. The WebSocket API is JSON-RPC 2.0 and answers with result or error. Binary transfers — ONNX model download — put the file in the body and move the envelope into the X-Response-Body header.

Pagination

Nothing on this API paginates through the query string. A cursor is a field in the JSON request body, or the listing has none at all. There are four shapes, and which one you are in is a property of the endpoint, not of the response — the last two are indistinguishable from the payload. The lists below are the only way to tell them apart.

Two rules wherever a cursor exists

Omit the cursor on the first call — never send null. Cursors are typed as strings, so "cursor": null is rejected with invalid_request_body. Leaving the key out is what asks for the first page. A short page does not mean you are finished, and neither does an empty one. limit bounds the rows read, not the rows returned: access filtering runs after the page is fetched, so a page can come back short — or completely empty — with more results waiting behind it. Only a null cursor means exhausted. Loop on the cursor, never on the page size.

Opaque cursor

Send cursor and limit. The cursor is opaque — it wraps different underlying tokens depending on the store behind the listing — so pass it back byte for byte; a modified one is rejected with invalid_cursor. Used by the workflow session listings: list_session_objects, list_session_thread_items, list_session_graph_elements, list_session_graph_neighbors, list_session_events and list_execution_events. Each command’s own page documents its default and maximum limit; a value above the maximum is an error, not silently reduced.

Record cursor

The request and response names differ. Read last_session_id from the response and send it back as start_session_id. limit is not accepted — the page size is fixed at 10 — and supplying it fails the request. Results are newest-first and the order cannot be changed. Used by list_sessions and list_executions on the workflow engine, and list_schedules and list_executions on the scheduler engine. Unlike an opaque cursor this token is a real record id, which the server re-reads to resume from. If that record has been deleted between two pages, resumption fails as a server error rather than a client one.

Complete listings

These page internally, so no cursor genuinely means the whole set:
  • GET /api-keys/target/:target/:target_id
  • GET /credentials/target/:target/:target_id
  • GET /users/target/:target/:target_id
  • the query_session_graph command, which is bounded by explicit caps and refuses with graph_traversal_limit_exceeded rather than returning a partial graph

Unpaginated listings

These accept no cursor and return a single page of roughly 1 MB. Beyond that the response is silently incomplete — no cursor, no count, no flag, nothing distinguishing a truncated listing from a complete one.
  • the list_definitions command
  • GET /orgs/:id/blobs
  • GET /blobs/:org_id/:blob_id/revisions
  • GET /users/:id/orgs
  • GET /members/target/:target/:target_id
  • GET /blobs/:org_id/:blob_id/metadata/:alias
  • GET /revisions/:id/metadata/:alias
Where one of these also filters — list_definitions by category, blobs and organizations by visibility — the filter is applied after the page budget is spent. Such a listing can come back empty while matching records exist past the boundary, so an empty result is not proof of absence.

Identifiers

Most API resources support two types of identifiers in path parameters: Either form can be used wherever a path parameter accepts a resource ID (e.g. {user_id}, {org_id}).

The “me” Alias

User endpoints accept the special value me as the {user_id} path parameter. It resolves to the authenticated user’s ID before any authorization checks are applied.
The me alias works with both bearer token and API key authentication.

Permissions

Access to user resources depends on whether the caller is the target user (self) or a different user (other). See each endpoint’s documentation for details.