Skip to content
Taylorz CRM Developers
Esc
↑↓navigate↵open⌘Jpreview
On this page

Approvals

A definition says who approves a record in how many stages; a request walks them one at a time; one rejection ends it. What each refusal means.

Every endpoint here needs the approvals module. A definition is written once; requests are submitted against records and move through its stages.

A definition is up to three stages

POST /approval-definitions takes a label, the objectId it applies to, a version, and stages — one to three of them, each naming exactly one approver:

{ "approverUserId": "…", "label": "Manager" }

Every approver must be a member of the organization. A user id that is not answers approver_outside_organization, and the whole definition is refused rather than created with a gap.

Submitting pins the record

POST /approvals takes a definitionId, a recordId and the record’s revision.

It snapshots what the approvers will read. The request stores the recordRevision, a snapshot of the record and its relations, and a contentHash. Approvers decide on that snapshot, not on whatever the record has become since.

Sending a stale revision is refused — see revisions for why that is not resolved to the newest.

A submitter cannot be an approver. If the submitter’s own user id appears in any stage of the definition, the submission is refused with approver_is_submitter. The check is at submission, not at decision time, so a definition that names you is simply unusable by you.

Deciding walks one stage at a time

POST /approvals/{id}/decisions takes decision — approve or reject — the stage number, and an optional comment of up to 4,000 characters.

The stage number is required and checked. A request carries an activeStage, and a decision whose stage is not the active one is refused with approval_stage_moved, as is any decision on a request that is no longer pending. Read the request before deciding rather than assuming which stage is open.

Only the assigned approver may decide. The approver of stage n is stages[n-1].approverUserId, and anyone else — including the submitter — gets approver_not_assigned.

A request’s state is one of four, and the transitions are not a graph worth drawing:

Decision Result
reject at any stage rejected. One rejection ends the request, whatever stages remain
approve at the last stage approved
approve at an earlier stage still pending, with activeStage advanced by one

Withdrawing

POST /approvals/{id}/withdraw sets the state to withdrawn.

Only the submitter may withdraw, and only while the request is pending: anyone else gets withdraw_not_submitter, and a request already decided gets approval_not_pending.

Approvals block other work

A pending approval is not only a record of intent. Editing the record it was submitted against is refused with record_approval_pending — withdraw the approval first. A quote with one open likewise refuses to be revised, as quote_approval_pending. Submitting for approval is therefore closer to taking a lock on the thing being approved than to sending a notification.

Four scopes, not one

Scope What it covers
approvals.read Listing definitions, requests and decisions
approvals.manage Creating a definition. Admin only
approvals.submit Submitting and withdrawing — the two travel together
approvals.decide Deciding a stage

The split mirrors the rule above: submitting and deciding are different scopes, so a client built to file requests cannot approve them even before the per-request check runs.

Reading

GET /approvals lists requests and GET /approvals/{id}/decisions answers the decisions made on one, each with its stage, decision, comment and decidedBy. A rejected request keeps its decisions, so the reason survives the refusal.

Was this page helpful?