Docs Concepts

Policy

LiveUpdated

View as Markdown

A policy is a signed, versioned object written in the terms of the user’s own approval rules. Every decision references the exact version it was made under.

What a policy expresses

RuleFieldExampleEnforced by
Payee allowlist and verification statepayees[]{domain, name, verified, category, mcc[]}reamandrule.com, verifiedEnruta; merchant lock on a single-use card
Per-payment caplimits.per_payment≤ $200Enruta; card amount = mandate amount
Cumulative budgetlimits.budget{amount, window}≤ $1,000 per calendar monthEnruta, reserved atomically at decision time
Time windowwindow{hours, expiry_seconds}Business hours, expiry 15 minutesEnruta; card expiry
Categorycategories[] and MCCOffice supplies (MCC 5943, 5111)Enruta; rail MCC controls where offered
Approval thresholdapproval{above, approvers[]}> $150 needs the person who approvesEnruta step-up; nothing is minted before the approval
Duplicate and idempotency checksduplicate_windowSame payee, amount and reference inside 24 hEnruta
Sanctions screeningscreeningPayee against current listsEnruta
Which agentsagents[]agt_procurement_02Enruta (selectPolicy)

Fields added in 0.2 and 0.3

All optional. A policy signed before they existed keeps its hash and its meaning.

FieldValuesWhat it does
modespecified · bounded · bounded_stepup (default)Sets the autonomy level: a locked target, autonomy inside the boundary, or autonomy inside the boundary with a step-up beyond it
refill_policynever (default) · on_void_only · on_settled_refund · on_any_reversalWhether a reversal gives the amount back to the mandate account and the budget
deviation{tolerance, action}"0.05"; pause_and_notify · auto_cancelPrice deviation the agent may accept without asking; the card limit is opened at amount × (1 + tolerance)
finality_rules{irreversible_per_payment}decimal string or nullA lower per-payment cap for rails whose payments cannot be reversed
retry_policy{max_attempts, window_seconds, same_amount_only}max_attempts ≥ 1, the first attempt included; window_seconds; booleanAt most max_attempts attempts at one payment (the same agent, payee and purpose, after a deny, a rail decline or a hand-off) within window_seconds; the attempt beyond them, and with same_amount_only a retry for another amount, is denied with retry_limit_reached. Signed into the mandate (retrying)
visibility_scope{merchant[], issuer_only[]}policy · mode · refill_policy · finality_class · principal_login_id · retry_policy · deviation · per_payment_cap · budget · recurrenceWhich of the mandate’s constraints the merchant sees. The others leave the mandate the merchant receives and are committed to by hidden_constraints_digest, their values kept in the record bundle (mandate)
shadowbooleanShadow mode: decisions that would step up or deny come back as observe, sealed and reported, never enforced
require_consentboolean (default false)A request without an active consent record for the agent is denied with consent_revoked
reversal{window_days, step_up_above}120 days; decimal string or nullHow long after settlement a refund may be requested, and above which amount a person signs the refund
intent{ required_slots, clarify, rules, model }What a request must say, the rules on its slots, and whether a model judges what rules cannot (intent and clarification)
identity_requirements[]{ above, rails, require, on_fail }Which identity anchors a payment needs, by amount and rail
payee_identity{ require_verified_above, on_fail }Whether the merchant must be verified before paying (trust model)

Retries and what the merchant sees

A retry is a new request by the same agent, to the same payee, for the same purpose (compared without case or extra spaces) after one that failed inside the window: it was denied, the rail declined it, or it was handed off. A request still waiting for a person, and a payment that went through, are not failed attempts. visibility_scope changes no decision: it decides what the merchant’s copy of the mandate says. The amount, currency, payee, checkout and expiry are not constraints; the merchant always sees them.

"retry_policy": { "max_attempts": 3, "window_seconds": 86400, "same_amount_only": true },
"visibility_scope": { "merchant": ["retry_policy"], "issuer_only": ["per_payment_cap", "budget", "policy"] }

// three attempts at one payment a day, the first included, never for another amount;
// the merchant sees the amount, the payee, the checkout and the retry rule, not the ceilings or which policy decided

When a policy declares no visibility_scope, the merchant sees policy, mode, refill_policy, finality_class, principal_login_id and retry_policy, and deviation, per_payment_cap, budget and a recurrence’s caps are not signed into the mandate at all. A name in neither list keeps that default; no name may be in both.

Atomic budgets

Budgets are reserved when a decision is made and released or consumed when the rail posts. Ten concurrent agents cannot each pass the same $100 check, because the first reservation lowers the budget the others see. A completed reversal with a refill effect gives the amount back to the budget, never below zero.

Enforced twice

Enruta decides first, then compiles the decision into the control the rail itself offers: a single-use card for the exact amount at the named merchant, a spend limit scoped to one purpose, an approval bound to one bill. If Enruta is wrong, the rail still refuses anything outside the mandate. If the rail is loose, Enruta already refused. The five checks page lists each moment.

Versions

Policies are immutable once signed. An edit creates version n+1; mandates issued under n remain valid until they expire or are consumed, and every record names the version it was decided under. Your auditor can read version 7 in 2033 exactly as it was in 2026.

Fail closed

A request that matches no policy is denied with reason no_matching_policy. There is no default allow. A paused agent is denied with agent_paused before any policy is read.