Wire shape
Process fields (camelCase on the wire):
Every field above is required on
process. Nullable ones (domainRef,
currentRevisionRef, accountableResponsibilityLinkRef) must be sent as
null. A ref is exactly { "id": "<uuid>", "workspaceId": "<uuid>" } — no
other keys — and every ref’s workspaceId must equal process.workspaceId.
schemaVersion must match 1.<minor>.<patch>. Timestamps are ISO 8601.
Revision fields
revision (the spec revision) is likewise strict with every field required:
Each entry in
stages[] requires all of: stageKey (lowercase identifier
matching ^[a-z][a-z0-9_-]*$), name, purpose, entryConditions (array of
JSON objects), exitConditions (array of JSON objects), responsibleLinkRefs,
requiredCapabilityRefs, optionalSkillRefs (arrays of refs),
allowedCommandTypes (array of strings), authorityClass ∈ observe
prepare gated_side_effect autonomous_side_effect, expectedDuration
(JSON object or null), and exceptionRoutes (array of JSON objects).
Each entry in handoffs[] requires all of: handoffKey (same identifier
pattern), fromStageKey, toStageKey, acceptingLinkRef (ref or null),
sla (JSON object or null), and escalation (JSON object or null).
As with process, every ref anywhere inside revision must carry the same
workspaceId as the revision itself.
A proposal that validates
contentDigest with the real sha256: digest of your revision content
before proposing anything you intend to keep.
Lifecycle
Declared states:discovered, proposed, confirmed, shadowing,
active, changing, deprecated, retired.
Transitions exposed by the REST API:
changing, deprecated, and retired remain valid state values, but REST
does not expose transitions into them. Treat active as the terminal state
reachable through this API and propose a new revision when the workflow
changes.
Operations
All routes acceptAuthorization: Bearer oxk_... or a web-app session, and
every mutation requires an Idempotency-Key header — a missing one is
400 missing_idempotency_key.
201 (or 200 when the idempotency key replays) with
{ "data": { "processId", "transition", "ledger", "aggregateVersion" }, "meta": { ... } }.
A stale expected_aggregate_version returns 409 operating_process_conflict.
Where the IDs come from
The easiest way to get a well-formed proposal is not to hand-write one:
run a discovery run and call its
propose
operation, which materializes an observed process card into a
confirmation-ready proposal.
MCP equivalents
No MCP tool writes operating processes today — this resource is REST-first. The wizard’smap command drives the discovery → propose flow over these
same endpoints.