# Five checks M0 to M4

The five moments a payment is checked, from before the mandate exists to after the money settled, and what fails at each.

Status: Live · Updated: 2026-09-13
Source: https://enruta.ai/docs/checks

A policy is enforced twice by design: Enruta decides, then the rail’s own control decides again. Spelled out, that is five checks, each with a moment, a question and a failure action. The fifth, after settlement, is the one no agent-payment protocol writes down.

| Check | When | What is checked | On failure | Status |
|---|---|---|---|---|
| M0 | Before the mandate is created | Policy applicability: is there a signed policy that covers this agent, payee and category; is the agent paused; is a consent required and present | No mandate; `deny` with `no_matching_policy`, `agent_paused` or `consent_revoked` | Live |
| M1 | Before the credential is issued | Payee, category, time window, per-payment cap, cumulative budget (atomic reservation), duplicate and idempotency, screening; the approval threshold | `deny` or `step_up`; under a shadow policy, `observe` | Live |
| M2 | Before the rail is called | The credential is bound to the mandate; the amount within tolerance; the rail’s `finality_class` matches what the mandate was stamped with | `deny` | Binding and finality stamping live; the lower cap for irreversible rails (`finality_irreversible_cap`) is enforced when the first irreversible rail adapter lands |
| M3 | When the rail asks | Amount, currency and merchant against the mandate, answered inside the issuer’s two-second window | The authorization is refused: `amount_exceeds_mandate`, `merchant_mismatch`, `mandate_consumed`, `mandate_expired` | Live; 44 ms in production |
| M4 | After fulfillment and settlement | Fulfillment confirmed, cleared amount, refunds, the merchant’s order, all joined per mandate | An exception with a suggested action on the [reconciliation line](https://enruta.ai/docs/reconciliation), into the weekly report | Live |

Beyond the five there is the `observe` state ([shadow mode](https://enruta.ai/docs/shadow-mode)): the checks run, the result is recorded, nothing is enforced.

## Two failures, two checks

Ten agents each request $100 with $500 left in the month. The only authority on the budget is M1’s atomic reservation (`UPDATE budgets … WHERE reserved + spent + amount ≤ cap`): the sixth mandate cannot be issued, and the remaining five are denied with `over_budget`. M3 catches a different class of error: a single-use card presented at another merchant, or a merchant trying to clear $120 on a $100 card, is refused by the rail with `merchant_mismatch` or `amount_exceeds_mandate`. Together they are the answer to “you budgeted $100 and spent $1,000”.

## Where each check is recorded

| Check | In the record |
|---|---|
| M0, M1 | `decision.checks[]`, `decision.reasons[]`, `decision.risk` |
| M2 | `mandate`, `card_control_state`, `execution` |
| M3 | `rail_authorization_record` with `answered_in_ms` |
| M4 | The `settlement_record` and `reconciliation_line` records chained to the payment |
