Docs

#API reference

Generated from the live API’s OpenAPI spec. Every field below is enforced by the route’s zod schema, so this reference cannot drift. All requests are authenticated with Authorization: Bearer <api-key>. Base URL: https://api.ratifia.com.

Try requests interactively in the API explorer, or grab the machine-readable /openapi.json for Postman / Insomnia / codegen. It carries the full nested schemas (e.g. the policy defaults and decision context shapes) that the tables below summarize.

#Approvers

#POST /v1/approvers/

Register an approver

Admin-initiated registration. Creates a person with declared channels/methods; email/inbox are auto-verified, the rest land pending until the approver self-verifies. Idempotent per (org, email).

Request body:

FieldTypeRequiredDescription
emailstringyes
namestringno
clerkUserIdstringno
channelsobject[]no
methodsobject[]no

#GET /v1/approvers/

List approvers

All approver identities for the org, with channel + method verification state.

#GET /v1/approvers/{id}

Get an approver

Parameters:

ParamInRequiredType
idpathyesstring

#POST /v1/approvers/{id}/verify

Verify an approver capability

Self-serve completion: mark a declared channel or surface verified (or failed), persisting the proven endpoint/ref. Real per-channel proof (OTP, Slack lookup, DocuSign mapping) plugs in here.

Parameters:

ParamInRequiredType
idpathyesstring

Request body:

FieldTypeRequiredDescription
channelemail | slack | discord | phone | sms | webhookno
surfaceinbox | slack | discord | docusign | email | apino
endpointstringno
resolvedRefstringno
statusverified | failedno

#POST /v1/approvers/{id}/disable

Disable an approver

Soft-disable. The approver stops binding any surface and is never routed a decision. Policies naming them still resolve, but report as unsatisfiable, returned in warnings. Reversible via /enable. Idempotent.

Parameters:

ParamInRequiredType
idpathyesstring

#POST /v1/approvers/{id}/enable

Re-enable a disabled approver

Clears the disable. Registration deliberately does not do this, because bringing someone back is an explicit act. Idempotent.

Parameters:

ParamInRequiredType
idpathyesstring

#Decisions

#GET /v1/decisions/

List decisions (reviewer inbox)

List decisions for the org, newest first. Filter by status and assignee email for the reviewer inbox.

Parameters:

ParamInRequiredType
statusquerynoPENDING | APPROVED | REJECTED | EXPIRED | CANCELLED
assigneequerynostring
workflowRefquerynostring
limitquerynointeger
offsetquerynointeger

#GET /v1/decisions/workflows

Distinct workflows for the inbox filter

Parameters:

ParamInRequiredType
assigneequerynostring

#GET /v1/decisions/{id}

Get a decision with its quorum tally

Parameters:

ParamInRequiredType
idpathyesstring

#POST /v1/decisions/{id}/evidence

Attach immutable evidence to a decision

Append material the decision is being made ON — a Slack thread, an email, a policy doc. Append-only: evidence is never edited or deleted, and can only be attached while the decision is PENDING. Once it resolves the set is sealed, so what you see is exactly what the approver could see. Re-attaching identical content is a no-op.

Parameters:

ParamInRequiredType
idpathyesstring

Request body:

FieldTypeRequiredDescription
kindslack_thread | email | document | link | noteyes
titlestringno
sourceSystemstringno
sourceUrlstringno
sourceRefobjectno
bodystringno
bodyFormattext | markdownno
payloadobjectno
capturedAtstringno

#GET /v1/decisions/{id}/evidence

List a decision’s evidence, oldest first

Parameters:

ParamInRequiredType
idpathyesstring

#PUT /v1/decisions/{id}/output

Save the reviewer’s refined draft (conversational refinement)

Persist an edited version of a refinable decision’s proposed output. On approve, the engine resumes with the refined draft (refinedOutput ?? proposedOutput). Only allowed while the decision is PENDING and carries a proposedOutput.

Parameters:

ParamInRequiredType
idpathyesstring

Request body:

FieldTypeRequiredDescription
titlestringno
formattext | markdownno
contentstringyes

#POST /v1/decisions/{id}/refine

Refine the draft with the org’s own model (BYO)

Apply the reviewer’s feedback to the current draft using the org’s configured LLM (Settings → Refine with AI). Returns the revised draft and appends the turn to the refinement log. Does not commit: the reviewer saves via PUT /output, then approves.

Parameters:

ParamInRequiredType
idpathyesstring

Request body:

FieldTypeRequiredDescription
feedbackstringyes

#POST /v1/decisions/{id}/decide

Approve or reject a decision

Record a vote. Under quorum the decision resolves only when the approval/rejection threshold is met; reject-wins by default. On resolution Ratifia fires the engine resume event.

Parameters:

ParamInRequiredType
idpathyesstring

Request body:

FieldTypeRequiredDescription
decisionapprove | rejectyes
notestringno
responseValueone ofno

#Directory

#GET /v1/directory/actor

Resolve an internal actor id to a display label

Parameters:

ParamInRequiredType
refqueryyesstring

#Notifications

#GET /v1/contact-methods/

Get my contact methods

#PUT /v1/contact-methods/

Update my contact methods

Request body:

FieldTypeRequiredDescription
emailstringno
smsstringno
slackstringno
pushEnabledbooleanno

#POST /v1/push-devices/

Register this device for push

Idempotent on (user, token), so it is safe to call on every launch. The client should do exactly that, because push tokens rotate on reinstall and restore. Re-registering a revoked device reactivates it.

Request body:

FieldTypeRequiredDescription
tokenstringyes
platformios | androidyes
deviceNamestringno

#GET /v1/push-devices/

List my registered devices

#DELETE /v1/push-devices/{id}

Revoke one of my devices

Soft-revoke. Call on sign-out, otherwise the next person to sign in on that handset keeps receiving the previous user’s notifications.

Parameters:

ParamInRequiredType
idpathyesstring

#Policies

#GET /v1/policies/

List approval policies

All approval policies for the org, each with its usage: pending decisions under it and when it was last used (FN-256).

#POST /v1/policies/

Create (or upsert) an approval policy

Create an org-scoped approval policy: who approves (approver group + quorum) and the surface the verdict is recorded on. Idempotent upsert keyed by (org, key). key is the immutable slug code references; name and description are editable labels. A body with only name is read as key = name. Rejects unsatisfiable policies with 422.

Request body:

FieldTypeRequiredDescription
namestringno
descriptionstringno
defaultsobjectno
keystringno

#GET /v1/policies/{key}

Get an approval policy by key

Parameters:

ParamInRequiredType
keypathyesstring

#PUT /v1/policies/{key}

Update an approval policy

Replace an existing policy’s defaults, and optionally its name and description. The key never changes: to use a different key, create a new policy. 404 if it does not exist. Rejects unsatisfiable policies with 422.

Parameters:

ParamInRequiredType
keypathyesstring

Request body:

FieldTypeRequiredDescription
namestringno
descriptionstringno
defaultsobjectno

#DELETE /v1/policies/{key}

Delete an approval policy

Refused with 409 policy_in_use while the policy has pending decisions or was used in the last 30 days, because code likely still references its key and would start failing with unknown_policy. Pass force=true to delete anyway; the override is audited.

Parameters:

ParamInRequiredType
forcequerynotrue | false
keypathyesstring

#Runs

#POST /v1/runs/

Trigger a workflow run

Fire the external engine event for a registered workflow. Ratifia seeds no run/step rows; the engine owns execution and Ratifia tracks the decisions requested on the run.

Request body:

FieldTypeRequiredDescription
workflowIdstringyes
inputobjectno
idempotencyKeystringno
timeoutSecintegerno

#Worker

#POST /v1/worker/register

Register (upsert) a workflow definition

SDK/worker self-registration. Idempotent upsert keyed by workflow id for the API key’s org.

Request body:

FieldTypeRequiredDescription
idstringyes
namestringno
versionintegerno
enginebundled | inngest | temporal | triggerno
stepsobject[]yes

#POST /v1/worker/decisions

Open a HITL decision (decision-first model)

Called by an engine adapter (e.g. flowplane.awaitApproval) to request a human decision for an external-engine run. The policy gate may resolve "not required", in which case approvalNeeded=false and no decision is created.

Request body:

FieldTypeRequiredDescription
enginebundled | inngest | temporal | trigger | mcp | apino
externalRunIdstringyes
stepRefstringyes
workflowRefstringno
assigneeEmailstringno
policystringno
requiredbooleanno
contextobjectno
proposedOutputobjectno
responseSpecone ofno
docusignobjectno
timeoutSecintegerno
exclusivebooleanno
factsHashstringno

#GET /v1/worker/decisions

List decisions (API-key scope): the agent's inbox

Parameters:

ParamInRequiredType
statusquerynoPENDING | APPROVED | REJECTED | EXPIRED | CANCELLED
limitquerynointeger

#GET /v1/worker/decisions/{id}

Get a decision status (API-key scope): poll a park-and-resume verdict

Parameters:

ParamInRequiredType
idpathyesstring

#GET /v1/worker/decisions/{id}/verify

Verify an approval before acting on it (API-key scope)

Read-only check that a decision authorizes an action right now: APPROVED, facts hash matches, optional workflow/step match, and not already consumed. Always returns 200 with valid and, when invalid, a reason: not_found, not_approved, facts_mismatch, workflow_mismatch, step_mismatch, or consumed. Use consume to spend the approval.

Parameters:

ParamInRequiredType
factsHashquerynostring
workflowRefquerynostring
stepRefquerynostring
idpathyesstring

#POST /v1/worker/decisions/{id}/consume

Consume an approval: authorize exactly one action (API-key scope)

Atomically marks an APPROVED decision as spent by one action. Succeeds once per decision; a retry with the same consumer key returns consumed=true with alreadyConsumed=true, while a different consumer is refused with reason consumed. Refused with the same reasons as verify when the approval does not authorize the action.

Parameters:

ParamInRequiredType
idpathyesstring

Request body:

FieldTypeRequiredDescription
factsHashstringno
workflowRefstringno
stepRefstringno
consumerstringyes

#POST /v1/worker/decisions/{id}/cancel

Cancel a pending decision (API-key scope)

Withdraw a decision the agent no longer needs. Only PENDING decisions cancel; an already-resolved one returns cancelled=false with its current status.

Parameters:

ParamInRequiredType
idpathyesstring

#POST /v1/worker/policies/check

Check that policy keys exist and can reach quorum (API-key scope)

Preflight for CI. For each key: ok, missing, or unsatisfiable (with the reason and any approvers who still need verifying). ok is true only if every key is ok.

Request body:

FieldTypeRequiredDescription
keysstring[]yes

#POST /v1/worker/policies

Upsert a named approval policy

Declare an org-scoped approval policy as code: who approves (assignee, approver group, quorum) and the surface. Idempotent upsert keyed by (org, key); key is the immutable slug decisions reference, name and description are editable labels. A body with only name is read as key = name.

Request body:

FieldTypeRequiredDescription
namestringno
descriptionstringno
defaultsobjectno
keystringno