> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getovra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# CUA

> Tokenized browser autofill — the model never sees the card.

CUA stands for **Computer-Use Autofill**. It exists for the (vast) majority of merchants that don't speak [MPP](/concepts/mpp): they only have a checkout form. Instead of pasting a real PAN into the LLM context, you mint a single-use **autofill token** (`aft_*`); a separate harness process redeems it and writes the tokenized DPAN into the form via Chrome DevTools `Input.insertText`.

The model only ever sees `{ status: "filled", masked_last4: "1234" }`. The DPAN never enters the prompt, the chat history, or any LLM-visible memory.

<Note>
  Phase 8 (just shipped). Sandbox-only end-to-end. Mirrors the architecture of Mastercard Agentic Tokens and Visa Intelligent Commerce.
</Note>

## Threat model

The whole point: **the LLM never holds the card data, period.** If your agent runtime is compromised, jailbroken, or instructed to exfiltrate "everything you know", there is nothing card-shaped in scope to leak.

The boundary is enforced by:

1. The **autofill token** carries no card data — it's a 30-second-TTL handle bound to (intent, card, merchant origin, max amount).
2. The **redeem endpoint** requires `X-CUA-Harness-Secret`, which the harness process holds and the LLM does not.
3. The **R7-05 Luhn-scan blocking CI gate** rejects any commit where a PAN-shaped string could land in `messages[]`.

## Wire flow

<Steps>
  <Step title="Mint an autofill token">
    Agent posts an approved intent + card + the merchant origin + amount cap. Ovra returns `aft_id` + `expires_at`. The token is single-use, 30s TTL.
  </Step>

  <Step title="Hand off to the harness">
    Pass `aft_id` to your CUA harness over your own internal channel. The LLM context closes here.
  </Step>

  <Step title="Harness redeems">
    Harness calls `GET /v1/cua/autofill-tokens/:id/redeem` with `X-CUA-Harness-Secret`. Returns DPAN, cryptogram, expiry month/year. **One-shot.** Replays return 410.
  </Step>

  <Step title="Harness fills the form">
    Computer Use locates `#pan`, `#expiry`, `#cvc` (locked merchant contract IDs). Harness uses CDP `Input.insertText` to inject — never `evaluateOnNewDocument` and never via LLM-driven sampling.
  </Step>

  <Step title="LLM resumes">
    LLM sees `{ status: "filled", masked_last4: "1234" }` and clicks submit. Merchant settles via its own acquirer.
  </Step>
</Steps>

## Mint the token

```bash theme={}
curl -X POST https://api.getovra.com/v1/cua/autofill-tokens \
  -H "Authorization: Bearer $OVRA_AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "intentId": "int_...",
    "cardId": "ca_...",
    "merchantOrigin": "https://shop.example.com",
    "amountCentsMax": 2999
  }'
```

Response (201):

```json theme={}
{
  "aft_id": "aft_a1b2c3d4e5f6",
  "expires_at": "2026-04-20T10:00:30Z"
}
```

## Redeem (harness only)

```bash theme={}
curl https://api.getovra.com/v1/cua/autofill-tokens/aft_.../redeem \
  -H "X-CUA-Harness-Secret: $HARNESS_SECRET"
```

Response (200, one-shot):

```json theme={}
{
  "dpan": "4111111111111234",
  "cryptogram": "AJk...",
  "expires_at": "2026-04-20T10:00:30Z",
  "merchant_origin": "https://shop.example.com",
  "amount_cents_max": 2999,
  "card_expiry_month": 12,
  "card_expiry_year": 2028
}
```

## Error matrix

| Status | Code                           | Meaning                                          |
| ------ | ------------------------------ | ------------------------------------------------ |
| 400    | `E_VALIDATION`                 | Bad body — see `issues` array                    |
| 401    | `E_AUTH_MISSING`               | No auth at all                                   |
| 403    | `E_AFT_INTENT_NOT_APPROVED`    | Intent not approved                              |
| 403    | `E_AFT_INTENT_AMOUNT_MISMATCH` | `amountCentsMax` ≠ intent max                    |
| 403    | `E_AFT_CARD_INACTIVE`          | Card is frozen, terminated, or wrong agent       |
| 404    | `E_AFT_NOT_FOUND`              | Token not found, intent missing, or card missing |
| 410    | `E_AFT_EXPIRED`                | TTL passed                                       |
| 410    | `E_AFT_REPLAY`                 | Already redeemed once                            |

## Trusted Agent Protocol prep

For each agent, an Ed25519 keypair is provisioned async. The public JWK is exposed at:

```http theme={}
GET /.well-known/agent-jwks/{agent_id}
Cache-Control: public, max-age=300
Content-Type: application/jwk-set+json
```

This sets the table for **Visa Trusted Agent Protocol** (RFC 9421 HTTP Message Signatures): once a TAP-aware merchant requests it, the harness will start signing outbound requests with the agent's key. No outbound signing is enabled in v1.2 — this is wiring, not behavior.

## Sacred guarantees

* **Card data never enters LLM scope.** Enforced architecturally (separate process, separate credential) and by CI (R7-05).
* **Single-use.** CAS-style consume; replay returns 410.
* **Bound to one merchant origin and one intent.** The harness cannot pivot to a different merchant with the same token.
* **30-second TTL.** Even an exfiltrated `aft_id` is useless after half a minute.

## What CUA is *not*

* **Not a browser-automation framework.** Bring your own (Anthropic Computer Use, Browserbase, Stagehand, etc.). CUA is the credential boundary, not the runtime.
* **Not a payment processor.** The merchant settles via their own acquirer. Ovra issues the card; the merchant clears the auth.
* **Not live-mode yet.** Sandbox card data with sandbox-shaped DPANs in v1.2.

## Next

<CardGroup cols={2}>
  <Card title="MPP" icon="lock-keyhole" href="/concepts/mpp">
    The other Pay mode — for machine-readable merchants.
  </Card>

  <Card title="Pay overview" icon="credit-card" href="/concepts/pay">
    Both modes side-by-side.
  </Card>

  <Card title="Cards" icon="rectangle" href="/concepts/cards">
    DPAN, network tokenization, multi-card per agent.
  </Card>

  <Card title="Intents" icon="file-signature" href="/concepts/intents">
    The approval primitive every autofill token binds to.
  </Card>
</CardGroup>
