Intent → Grant → Issue: How Ovra Controls Agent Spend
Every agent payment on Ovra follows a strict state machine: declare intent, get authorization, receive credentials. No step can be skipped. Here's how the attestation-before-access pattern works.
Most payment APIs work like this: create a charge, pass credentials, done. That works when a human is clicking "Buy Now." It falls apart when an autonomous agent is making the decision.
The problem isn't authorization — it's the lack of pre-authorization. By the time a charge hits your card, the money is already gone. Any policy check that runs after the fact is damage control, not prevention.
Ovra flips this. Every payment follows a strict state machine where the agent must declare its intent before it gets access to any payment credentials. We call this attestation-before-access.
The state machine
Every Ovra payment moves through six states, in order. No state can be skipped.
Intent → Grant → Issue → Redeem → Charge → Verify
Each transition is a checkpoint. Each checkpoint enforces rules. If any check fails, the flow stops.
1. Intent
The agent declares what it wants to buy.
POST /intents
{
"purpose": "Monthly Notion Team subscription",
"expectedAmountEuros": 79,
"expectedMerchant": "Notion"
}
This is a declaration, not a payment. No money moves. No credentials are issued. The agent is saying: "I want to spend €79 at Notion." The system records this as an auditable event.
If the intent violates policy — amount too high, merchant blocked, daily limit exceeded — it's rejected immediately. The agent never gets further.
2. Grant
If the intent passes policy evaluation, Ovra issues an authorization grant. The grant confirms: "Yes, this agent is allowed to spend up to €79 at Notion within the next 30 minutes."
The grant has an expiration. If the agent doesn't act within the window, the authorization expires and the agent must start over. This prevents stale authorizations from accumulating.
3. Issue
With a valid grant, the agent can request payment credentials. Ovra returns a fill token — an opaque, encrypted reference to a one-time DPAN and cryptogram.
The agent never sees the card number. The fill token is scoped to this specific transaction and expires with the grant.
4. Redeem
The agent uses the fill token at checkout. The checkout system (whether a browser form or an API) decrypts the token server-side and submits the actual card data to the payment processor.
The agent's involvement ends here. It provided the token. It never touched the PAN, CVV, or expiry date.
5. Charge
The payment processor charges the card. Ovra receives the authorization webhook from the card issuer, matches it against the original intent, and records the transaction.
6. Verify
Post-payment verification checks three things:
- Amount match — Does the charged amount match the intent (within tolerance)?
- Merchant match — Is the merchant descriptor consistent with the expected merchant?
- Timing — Did the charge happen within the grant's validity window?
If all three pass, the transaction is marked as verified. If any fail, it's flagged for review.
Why the order matters
The strict ordering prevents entire classes of attacks:
- No credentials without intent — An agent can't get card data without first declaring what it's buying. This creates an audit trail before any money moves.
- No intent without policy — Every intent is evaluated against the active policy. Limits, merchant rules, time windows — all checked before authorization.
- No grant without approval — High-value transactions can require human approval before the grant is issued. The agent waits, or the request expires.
- No reuse — Grants expire. Fill tokens expire. DPANs are one-time. Nothing from a previous transaction can be reused in a new one.
Compare this to "here's a card number, go buy stuff." The difference is architectural.
Policy evaluation in detail
When an intent arrives, the policy engine evaluates it against the agent's assigned policy. A policy can include:
| Rule | Example | |---|---| | Max per transaction | €200 | | Daily limit | €500 | | Weekly limit | €1,500 | | Monthly limit | €5,000 | | Auto-approve threshold | Under €100 = auto-approved | | Merchant allowlist | Only "Notion", "GitHub", "AWS" | | Merchant blocklist | Never "gambling", "crypto exchange" | | MCC restrictions | Block category 7995 (gambling) | | Country restrictions | Block RU, KP, IR | | Time window | Mon–Fri, 06:00–22:00 CET | | Cooldown | Minimum 2 minutes between transactions | | Max usage count | 50 transactions total |
Every rule is evaluated. A single violation stops the flow. The enforcement level determines the response:
- Enforce — Hard block. The intent is rejected.
- Approve — Soft block. The intent is held for human approval.
- Warn — The intent proceeds, but an advisory is logged.
Defense in depth
Policy enforcement happens at two layers:
- Ovra's policy engine — Application-level checks before credentials are issued.
- Card network — The issuer's hard limits (synced from the policy) enforce at the Visa/Mastercard network level.
If the policy engine has a bug, the card network still enforces the limit. If the card network fails to catch something, the post-payment verification flags it. Two independent enforcement layers, neither trusting the other.
The result
Every transaction on Ovra has a complete, auditable chain:
Agent "demo-agent" declared intent int_abc123 for €79 at Notion
→ Policy "standard" evaluated: ALLOWED (under daily limit, merchant not blocked)
→ Grant gra_def456 issued, expires in 30 minutes
→ Credential cre_ghi789 issued with DPAN ****4521
→ Transaction txn_jkl012 charged €79 at "Notion Labs Inc"
→ Verification: amount ✓, merchant ✓, timing ✓ → VERIFIED
No step was skipped. No credential was exposed. The blast radius was €79. And if anything went wrong at any point, the flow would have stopped before money moved.
That's what attestation-before-access means in practice.
