Docs · Objects
Reconciliation
LiveUpdated
Agents and Sellers. Written for people who build agents, the hosts they run in, and the people and companies the agents pay for and merchants that receive agent orders.
The three parties have no shared key: the mandate id lives with the agent, the order id with the merchant, the authorization id with the rail. Enruta writes the mandate id into every slot the others carry at issuance, then joins the five legs back into one line per mandate.
The line
| Field | Contents |
|---|---|
id, mandate_id, record_id, period | rcl_…; the mandate is the root; period is the ISO week of issuance (2026-W37) |
agent_leg | credential_id, amount_mandated, payee_mandated, issued_at, agent_id, principal_login_id, policy_version |
rail_auth_leg | rail, authorization_id, amount_authorized, merchant_descriptor, mcc, at, answered_in_ms |
rail_settle_leg | transaction_id, amount_settled, fees, settled_at, batch_id, finality_class |
merchant_leg | protocol, order_id, client_reference_id, amount_total, line_items_hash, catalog_snapshot_hash, order_confirmation_url, shipped, fulfilled_at, adjustments (the shipment and returns as the merchant reports them after the order) |
adjustments_leg[] | { source: merchant_webhook | rail | enruta_reversal, kind, amount, at, reversal_id, reversal_record_id } |
match_method, confidence | key_exact (the order’s checkout id equals the mandate’s, or the order carries the mandate id) 1.0 · rail_ref (only the authorization id links) 0.9 · heuristic (merchant name and amount ± 2 % inside 72 h) 0.6 |
match_state | matched · partial · unmatched_agent (issued, never authorized) · unmatched_rail (a rail posting with no mandate) · unmatched_merchant (an order whose checkout matches no request) |
exception_codes[], suggested_actions[] | See below |
human_outcome | What the person who approves decided, and the signing event |
sealed, line_record_id | Set when the report is signed and the line becomes a linked record |
Exceptions
| Code | Meaning | Suggested action |
|---|---|---|
AMOUNT_AUTH_NE_MANDATE | The rail authorized a different amount than the mandate | Check the rail’s limit semantics; the mandate account is the truth |
AMOUNT_CLEARED_NE_AUTH | The rail cleared more or less than it authorized | A candidate reversal (initiator: enruta_policy, kind: chargeback_credit, status: requested) is created, not executed, and a dispute packet can be generated |
PAYEE_MISMATCH | The merchant descriptor is not the mandated payee | Review the authorization and the merchant lock |
DUPLICATE_RAIL_TXN | Two rail postings for one mandate | Query the rail |
REFUND_UNMATCHED | A refund on the rail with no reversal or merchant adjustment | Ask the merchant; a rail-initiated reversal was created |
ORDER_CONFIRMATION_MISSING | No merchant order for a consumed mandate | Poll the merchant’s order endpoint |
RAIL_LIMIT_SEMANTICS_DIFF | The rail’s limit and the mandate account disagree | Adjust the rail-side limit tier |
SETTLEMENT_OVERDUE | 24 hours past expected_settlement_at without a settled event | Check the rail |
FINALITY_MISMATCH | The settlement’s finality_class differs from the one stamped at issuance | Review the rail adapter |
The three parties, one line
The $24.98 order of 2026-09-10 with the $9.99 refund of 2026-09-13:
| Source | Object | Amount | Key |
|---|---|---|---|
| Enruta | mnd_01M2512M8FQ7ZK4T1V9W3N6BXC, credential ic_1S7Kq1… | Ceiling $24.98 | Card metadata mandate = mnd_01M2512M… |
| Stripe Issuing | iauth_1S7Kq2…, ipi_1S7Kq9… | Authorized $24.98, cleared $24.98 | Same card |
| reamandrule.com | ord_01M2512SM3V3A9R4EBJM8RRRV5 | $24.98; adjustments: [{ refund 9.99 }] | checkout_id = the mandate’s checkout reference |
| Stripe Issuing | ipi_1S7Rn4… (refund) | −$9.99 | Linked to ipi_1S7Kq9… |
{
"id": "rcl_01M2GD4T7Q1W9K3N5B8H2D6XRS", "period": "2026-W37",
"mandate_id": "mnd_01M2512M8FQ7ZK4T1V9W3N6BXC", "record_id": "rec_01M25129GZMJXTNQ47TMZRDGHN",
"match_method": "key_exact", "confidence": 1.0, "match_state": "matched",
"agent_leg": { "amount_mandated": "24.98", "payee_mandated": "reamandrule.com", "agent_id": "agt_procurement_02", "principal_login_id": "halvern/dana.reyes@halvernrobotics.com", "policy_version": 4 },
"rail_auth_leg": { "rail": "stripe_issuing", "authorization_id": "iauth_1S7Kq2…", "amount_authorized": "24.98", "answered_in_ms": 44 },
"rail_settle_leg": { "transaction_id": "ipi_1S7Kq9…", "amount_settled": "24.98", "finality_class": "reversible" },
"merchant_leg": { "protocol": "ucp", "order_id": "ord_01M2512SM3V3A9R4EBJM8RRRV5", "amount_total": "24.98", "line_items_hash": "sha256:…" },
"adjustments_leg": [
{ "source": "merchant_webhook", "kind": "refund", "amount": "9.99", "reversal_id": "rev_01M2G8YV5R3T7W2Q9K4N8B6DXP" },
{ "source": "rail", "kind": "refund", "amount": "9.99", "reversal_id": "rev_01M2G8YV5R3T7W2Q9K4N8B6DXP" }
],
"exception_codes": [], "suggested_actions": [], "sealed": false
}Had the rail cleared $27.48 (the merchant added shipping after authorization), the line would carry AMOUNT_CLEARED_NE_AUTH, a candidate chargeback_credit reversal, and the suggestion to generate a dispute packet.
The weekly report
| Field | Contents |
|---|---|
id, period | rcr_…; one report per organization and ISO week |
counts_by_match_state | How many lines are matched, partial, unmatched |
exceptions[] | Every exception with its line, code and suggested action |
coverage_pct | matched ÷ (all lines − unmatched_agent); the target is 99 % or better |
line_ids[], root_hash | The lines, and a Merkle root over their JCS digests in id order |
state, signed_by, signed_at, signature | draft → signed; passkey (challenge = the 32 bytes of the root hash) or link key |
report_record_id | The sealed linked record |
Every Monday at 01:00 UTC the weekly job builds the draft for the previous week for every organization and emits reconciliation.report_ready; the finalize job rebuilds the lines of every mandate touched since its last run. Signing seals every line as a linked record (kind: reconciliation_line, chain: reconciliation_of the payment record) and then the report (kind: reconciliation_report, chain: report_for, agent: null, the signature as approval: a passkey makes it third_party_signed, a link customer_attested). What was signed is what the auditor re-runs.
Interfaces
| Surface | Call | Who |
|---|---|---|
| REST | GET /v0/reconciliation/lines?period=&state=, GET /v0/reconciliation/lines/{mandate_id}, GET /v0/reconciliation/reports/{period}, POST …/reports/{period}/build, POST …/reports/{period}/sign (link key) | Developer; auditor reads |
| REST, sellers | GET /v0/sellers/reconciliation?period=, the seller’s slice by order | Seller key |
| MCP | get_reconciliation({ mandate_id }), get_reconciliation({ period }) | The agent, read-only |
| SDK | reconciliation.lines(q), .line(mandateId), .report(period), .buildReport(period), .signReport(period) | |
| CLI | enruta reconciliation lines [--period 2026-W37], enruta reconciliation report 2026-W37 [--build] [--sign] | |
| Console | /reconciliation: period picker, lines with match-state chips and exception codes, the report card, “Build report”, “Sign with passkey” | Owner, approver |
How the person who approves reads and signs it: Weekly report.