OTP approvals workflow
This guide assembles the two-officer approval loop for Verify end to end: turn the gate on, queue a change, take a decision, watch it execute, and wire the notifications. The per-field reference lives in OTP approvals; the setup walkthrough is Second-officer approvals for Verify. Use this page when you want the whole loop — policy, queue, decision, execution, webhooks — in one run-through with worked curl on every route.The five-route group
The approvals API is one group of five routes under/api/v1/verify/approvals:
The same surface is in the dashboard at Outbound → OTP approvals — the queue and the Policy card sit on one page, and only owners and admins see it.
The two-officer workflow
The loop branches through create → review → commit:- Create. A requester edits an OTP template or drives resends past the configured burst threshold. Their change queues as a
pendingrow instead of applying. A requester who readsGET /settingsfirst can predict this. - Review. An approver (an owner or admin who is not the requester) opens Outbound → OTP approvals or lists
GET /pending. Template rows show the exact rendered body to judge; burst rows show the count and window. - Commit. The approver posts
approve(release) orreject(hold, optionalreason). Approving as the requester returns409 FOUR_EYES_VIOLATIONand nothing moves. Approved items execute — the template goes live, or the burst re-enters the normal dispatch chain. Rejected items stop; the requester may re-submit, which queues a fresh row.
Worked curl across the loop
1. Read the policy (requester)
200
2. Set the policy (approver)
Sendrequire_approval_default on every update — it is required. resend_burst_threshold accepts a positive integer or null (gate every burst); the window defaults to 60 seconds (max 86,400).
200
3. Review the queue (approver)
200
4a. Commit: approve
200
409 FOUR_EYES_VIOLATION and nothing is recorded.
4b. Commit: reject
The body is optional;reason goes back to the requester.
200
Webhooks and idempotency
There is no approvals-specific webhook event. Downstream notification rides the standard Verify events: an approved resend burst emits the ordinaryverification.sent event as it dispatches, and an approved template shows up in the ordinary verification events of its next transmission. Subscribe to the standard events with the signatures pattern in Verify webhook signatures — raw body before any JSON parser, X-Orbit-Signature (legacy X-Devotel-Signature fallback), answer 401 on failure.
Delivery is at-least-once, so dedupe on the stable envelope id (the Idempotency-Key header mirrors it) — the same event may arrive twice after an ambiguous outcome. Inside the loop, decisions are naturally idempotent too: approving or rejecting an already-decided item returns 404, and a self-approve attempt returns 409 before any state moves.
Every queue decision and policy change lands in the audit log: verify.approval.approved, verify.approval.rejected (with the reason), and verify.approval.settings.updated.
Failure modes
See also
- OTP approvals reference — policy fields, queue item shape, and role rules.
- Second-officer approvals for Verify — the setup walkthrough.
- Verify webhook signatures — per-language signature handlers.
- Audit log — the decision trail.