Human approval
When a policy decides an action needs human review, ProofRail pauses execution, notifies an approver, and resumes only when a human makes a decision. This guide walks through the full flow so you know what your code sees, what your approvers see, and how to configure timeouts and fallbacks.When approval gets triggered
Approval is one of four policy outcomes (see Policies). It fires when:- A single transaction exceeds the configured medium-financial threshold ($5,000 by default)
- Cumulative chain financial exposure exceeds your threshold ($10,000 by default)
- An agent makes its first external communication
- A bulk operation touches 100+ records, or a bulk deletion touches 10+ items
- An action is tagged irreversible (contract signing, public posts, legal filings)
- A high-risk agent executes any action
- An agent accesses resources outside its declared scope
- Content containing PII is being sent to an external domain
- A custom policy you’ve defined matches the action
What your code sees
When approval is triggered, the SDK blocks until a decision arrives. Yourrecord_agent_action call (or the wrapped framework call) waits:
record_agent_action call, but the event loop is free to handle other coroutines while waiting.
What the approver sees
When approval is triggered, an email goes to your configured approvers via Resend. The email contains:- Chain name and ID
- Triggering action (which agent, what it tried to do)
- The cumulative metrics for the chain so far (financial exposure, external comms, records modified, etc.)
- Signed one-click approve and deny links
/dashboard/approvals where they see:
- The full chain history — every action taken so far
- The triggering action highlighted with policy reasoning
- A clear summary of what executing the action will do
- Approve and Deny buttons, with an optional notes field
- A “Grant time-boxed exception” checkbox with a duration selector (1 hour, 1 day, 1 week, 1 month) — see Time-boxed exceptions below
Configuring approvers
Approvers are configured in your dashboard under/dashboard/settings/team. Any user with the approver role receives approval emails by default.
Currently the SDK applies the same approver list and timeout to every chain in your organization — there is no per-chain approver override via Chain(metadata={...}). If you need different approvers for different workflows, two options:
- Define custom policies in the dashboard that match on chain
nameand route to different approver groups - Initialize the SDK separately per workflow boundary with the appropriate config (this means separate processes or separate
init()calls, which has trade-offs)
Timeouts
By default, approvals expire after 24 hours. If no decision arrives in that window, the approval is marked timed-out and the SDK raisesActionDeniedError with a timeout condition.
You can configure the default timeout globally:
168 for 7 days). For workflows where you need quick decisions, set a short one (0.25 for 15 minutes).
Fallback approvers
If your primary approvers don’t respond within half the configured timeout, the approval escalates to a fallback list:Time-boxed exceptions
When approving an action, the approver can grant an exception that covers future similar actions for a chosen duration: 1 hour, 1 day, 1 week, or 1 month. For example: an approver approvesemail-agent sending to vendor.com for the first time. Without an exception, the next email to vendor.com triggers approval again. With a “1 week” exception, future emails to vendor.com from email-agent proceed without approval for the next 7 days.
Exceptions are scoped — they cover the specific combination of conditions that triggered the original approval (agent, action type, destination domain), not “anything goes” for that agent. When an exception applies, the action is treated as allow_with_flag rather than require_approval. The audit trail records which exception authorized which action.
Exceptions expire automatically at the configured duration. Once expired, the next matching action will trigger approval again normally.
Early revocation of an active exception is not yet exposed in the dashboard. If you need to revoke an exception before it expires, contact us — we can revoke directly via the backend. A self-service revocation UI is on the roadmap.
Polling behavior
The SDK pollsGET /v1/chains/{chain_id}/approval-status (or the chain’s status endpoint) every 5 seconds while waiting for an approval to resolve. The interval is constant for the entire wait window — there is no tiered cadence and no exponential backoff in the current version.
If the backend is unreachable during polling, the SDK retries on the next 5-second tick. Backend transient errors don’t fail the approval — they just delay polling.
This polling is asynchronous: your application code awaits the record_agent_action call, but the event loop continues running other coroutines, handling other requests, etc. while waiting.
Handling denial
If the approver clicks Deny or the approval times out,record_agent_action raises:
decision_source (where the decision came from) and condition (what the decision said). See Exceptions reference for the full handling pattern.
Your application decides how to handle this. Some options:
- Show the user a “request reviewed and denied” message
- Trigger an escalation workflow (page a human, retry tomorrow)
- Log the denial and move on with the next workflow
Approval and receipts
Every approval decision is recorded in the chain receipt. The receipt’s approval history captures:- Who approved or denied
- The decision and any notes the reviewer left
- Timestamp of the decision
- Whether the approval created a time-boxed exception
Where to go next
Policies
What triggers approval in the first place.
Audit receipts
How approvals get cryptographically recorded.
Kill switch
Halting all agent activity in an emergency.
Configuration
Tune approval thresholds and timeouts.