> ## 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.

# Cards

> Virtual Visa cards, instantly. Multiple per agent, never visible to the model.

A card is a virtual Visa issued by Ovra's regulated EU banking partner. Card data (PAN, CVV) is encrypted with AES-256-GCM at rest and never returned to the agent's context — the model only ever interacts with a tokenized DPAN derived through the network token service.

**Multi-card per agent is a first-class concept.** You can issue named cards within a single agent (`subscriptions`, `travel`, `one-off`) and the agent picks which one to charge for each transaction.

## The card model

| Field                             | Description                                         |
| --------------------------------- | --------------------------------------------------- |
| `id`                              | `ca_*`                                              |
| `agentId`                         | Bound to one agent, immutable                       |
| `name`                            | Unique per agent — e.g. `default`, `subs`, `travel` |
| `usage`                           | `single` (closes after first tx) or `multi`         |
| `status`                          | `active` · `frozen` · `terminated`                  |
| `last4`                           | Last four digits — safe to display                  |
| `brand`                           | Always `visa` today                                 |
| `pan_encrypted` / `cvv_encrypted` | AES-256-GCM ciphertext, server-only                 |

## Lifecycle

| State        | Meaning                                                 |
| ------------ | ------------------------------------------------------- |
| `active`     | Authorizes transactions                                 |
| `frozen`     | Reversible block — `POST /cards/:id/unfreeze` to resume |
| `terminated` | Irreversible. Issue a new card.                         |

## Operations

| Endpoint                                              | Purpose                                                                |
| ----------------------------------------------------- | ---------------------------------------------------------------------- |
| `POST /cards/agent/:agentId`                          | Issue (idempotent) — every card belongs to exactly one agent           |
| `GET /cards/:cardId`                                  | Read — PAN/CVV never in response                                       |
| `GET /cards/agent/:agentId/sensitive`                 | Sensitive reveal (PAN/CVV) — rate-limited 3/min, audit-logged          |
| `POST /cards/:cardId/freeze` / `/unfreeze` / `/close` | Lifecycle (per-card)                                                   |
| `POST /fund`                                          | Top-up the org wallet (cards draw from wallet — no card-level funding) |
| `PUT /cards/:cardId/limits`                           | Update spending limits                                                 |

## Issue a card

<CodeGroup>
  ```bash curl theme={}
  curl -X POST https://api.getovra.com/cards/agent/ag_... \
    -H "Authorization: Bearer $OVRA_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: $(uuidgen)" \
    -d '{
      "agentId": "ag_...",
      "name": "subscriptions",
      "usage": "multi",
      "purpose": "Recurring SaaS only",
      "maxTransactionEuros": 250,
      "monthlyLimitEuros": 1000
    }'
  ```

  ```ts SDK theme={}
  const card = await ovra.cards.create({
    agentId: "ag_...",
    name: "subscriptions",
    usage: "multi",
    purpose: "Recurring SaaS only",
    maxTransactionEuros: 250,
    monthlyLimitEuros: 1000,
  });
  ```

  ```text MCP theme={}
  ovra_card { action: "issue", agentId: "ag_...", usage: "multi", purpose: "Recurring SaaS only" }
  ```
</CodeGroup>

## Card selection at transaction time

Reference a card on every intent. Pass either `cardId` or `cardName` (within the agent). Omitting both returns `E_CARD_REQUIRED` — there is no implicit default card by design.

```bash theme={}
curl -X POST https://api.getovra.com/intents \
  -H "Authorization: Bearer $OVRA_API_KEY" \
  -d '{
    "agentId": "ag_...",
    "cardName": "subscriptions",
    "purpose": "Renew Hetzner",
    "expectedAmountEuros": 4.51,
    "expectedMerchant": "hetzner.com"
  }'
```

## DPAN — the only card identifier the merchant sees

The DPAN (Device Primary Account Number) is a network token issued by Visa's tokenization service through the banking partner. It's:

* Deterministically derived from the FPAN
* Non-reversible — useless if leaked
* Auto-updates across merchants when the underlying card is rotated

Every MPP credential and CUA autofill token resolves to a DPAN, never the FPAN.

## Fill tokens (`ftok_*`)

Internal-only encrypted wrappers for PAN/CVV/expiry. Used inside the credential flow, never returned to agents. If you see `ftok_` in your logs, our sanitizer missed something — file a bug.

## Card-controls sync

Spend caps, MCC allow/block, country allow/block on the [policy](/concepts/policies) attached to the card's agent are pushed to the card-issuer-native control surface. Policy is the source of truth; the card mirror is a best-effort projection.

## Webhooks

| Event                           | Trigger                                     |
| ------------------------------- | ------------------------------------------- |
| `card.issued`                   | New card provisioned                        |
| `card.activated`                | Card status flipped to `active`             |
| `card.frozen` / `card.unfrozen` | Status change                               |
| `card.closed`                   | Terminal lifecycle                          |
| `card.rotated`                  | New card credentials issued, old one closed |
| `card.funded`                   | Funds moved onto the card                   |
| `card.shipped`                  | Reserved (no physical card today)           |
| `card.limits_changed`           | Limits updated                              |
| `card.details_changed`          | Cardholder/expiry/etc updated               |

## Plan-tier limits

| Plan       | Cards     |
| ---------- | --------- |
| Free       | 1         |
| Starter    | 10        |
| Business   | 25        |
| Enterprise | Unlimited |

## Next

<CardGroup cols={2}>
  <Card title="Agents" icon="user-robot" href="/concepts/agents">
    The owner of every card.
  </Card>

  <Card title="Policies" icon="shield-check" href="/concepts/policies">
    What governs each card's spending.
  </Card>

  <Card title="Pay" icon="credit-card" href="/concepts/pay">
    How a card actually charges.
  </Card>

  <Card title="Transactions" icon="receipt" href="/concepts/transactions">
    The record every successful charge writes.
  </Card>
</CardGroup>
