Approval Workflows
Status: Roadmap. The conceptual model and storage layer are implemented. Public REST endpoints (
/v1/approval-workflow-templates,/v1/approval-requests/...) are not yet wired into the API router; the page below describes the planned shape. Track progress in the engineering backlog before integrating.
An approval workflow gates a state transition (e.g., invoice finalization, large discount application) behind one or more human approval steps. Workflows are defined as templates and instantiated as ApprovalRequest rows when a triggering event occurs.
Why this matters. As billing operations scale, individual write actions need governance - SOX compliance, internal financial controls, and dispute prevention all demand a review layer over high-impact mutations. Kontorion's approval workflows let you define multi-step templates with role-based approvers, threshold rules, timeouts, escalation, and auto-approval conditions, so the right humans are in the loop without slowing routine work. The same engine supports a finance team requiring CFO sign-off on invoices above a threshold, a sales-ops process routing custom-priced quotes through deal-desk review, an enterprise platform requiring two-person approval on wallet adjustments, and a regulated business gating credit-note issuance behind compliance review.
Concepts
| Object | Purpose |
|---|---|
ApprovalWorkflowTemplate | Reusable definition: trigger conditions, ordered steps, escalation rules. |
ApprovalStep | One step inside a template: who approves, threshold, timeout. |
ApprovalRequest | A live instance: which entity, current step, decisions so far. |
ApprovalDecision | One person's vote (approve / reject) on one step. |
Trigger conditions
Templates carry an entity_type (invoice, subscription, credit_note, wallet_adjustment) and a set of trigger conditions. When a matching event occurs, an ApprovalRequest is created automatically and the entity stays in a pending state until the request resolves.
Common triggers:
- Invoice subtotal above N
- Plan transition that crosses a tier
- Wallet adjustment over a threshold
- Credit note above a percentage of the original invoice
Steps and decision rules
Each step has:
- Approvers - a list of users, roles, or both
- Threshold - how many approvers must sign off (
any,all,majority, integer count) - Timeout - how long before escalation kicks in
- Auto-approve condition - optional condition that bypasses the step
Steps run sequentially; a rejected step rejects the whole request immediately (approval.request_rejected).
Lifecycle
Code
| Webhook | Fires when |
|---|---|
approval.request_created | A new request was instantiated |
approval.step_started | Workflow advanced to a new step |
approval.step_approved | Step met its threshold |
approval.step_auto_approved | Step's auto-approve condition matched |
approval.step_escalated | Step timed out and escalated to a fallback approver |
approval.request_approved | Final step approved; entity transition can now apply |
approval.request_rejected | An approver explicitly rejected |
approval.request_auto_rejected | Request timed out with no resolution |
approval.request_cancelled | Operator cancelled the request |
Creating a template
Code
Approving and rejecting
Code
Escalation
When a step times out without meeting its threshold, the runner escalates per the template's escalation rules - typically to the approver's manager or a fallback role. Escalation emits approval.step_escalated and resets the timeout for the fallback approver.
Cancelling
Code
Cancellation is appropriate when the underlying entity no longer needs the gated transition (e.g., the invoice was voided before approval).
Next steps
- Invoices - the most common gated entity
- Webhooks - event types emitted by the runner
- API Reference - Approval Workflows