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

# Vault

> Store a user's own card once, then authorize checkouts that pay with it.

The **Vault** holds a user's own cards, encrypted on their device with a passkey. Three resources make it up:

* A **vault session** is a single-use link you send the user. They open it, type their card, and save it with a passkey. A master password is offered afterwards as a backup. The page asks for a master password before the card is stored when the card will open only in this browser. When it links you get their `user_id`.
* A **checkout authorization** is a paused payment. Your browser (or the SDK) captured the request the merchant's page sent to its payment processor with a placeholder card; you post it here, the user approves on their own device, and that device pays with the real card.
* A checkout preparation lets the user approve before your browser starts a short-lived card request. The SDK applies that approval to one fresh request on Square, Braintree, Worldpay, Bambora or Mercado Pago.

Every call takes a platform access token. An API key is refused with `400 client_credentials_required`.

## The vault session object

| Field | Type | Description |
| - | - | - |
| `object` | string | `vault_session` |
| `id` | string | `vs_…`. Read the session by this id, never by the token inside `url`. |
| `status` | string | `pending`, `linked`, or `expired`. |
| `url` | string | The single-use link to send the user. |
| `user_id` | string or null | The user the session belongs to. Null on an open session until it links. |
| `linked_at` | string or null | When the session linked. |
| `poll_interval` | integer | Seconds to wait between reads. |
| `code_sends`, `verify_attempts` | integer or null | Connected sessions only: how many times the code was sent and tried. |
| `expires_at` | string | Lifetime end. Default 24 hours after creation. |
| `test_mode` | boolean | Whether a sandbox credential created it. |
| `payment_permission` | object | Only on a session that asked for app auto-approval: whether your app can pay with the card the user gave it. See [Enable auto-approval](/vault/app-auto-approval). |

```json theme={null}
{
  "object": "vault_session",
  "id": "vs_2q9d1x8f3k2m4t7w",
  "status": "linked",
  "url": "https://vault.agentcard.sh/v?vs=vs_2q9d1x8f3k2m4t7w.3k1v…",
  "user_id": "usr_8f3k2m",
  "linked_at": "2026-09-02T18:41:07Z",
  "poll_interval": 3,
  "expires_at": "2026-09-03T18:00:00Z",
  "test_mode": false
}
```

## The vault card object

Display fields only. Never a card number or anything that could decrypt one.

| Field | Type | Description |
| - | - | - |
| `id` | string | An opaque id that starts with `vc_`, such as `vc_7f3a9c2e1b4d6f8a0c2e4b6d`, though a card stored earlier may carry no prefix. Pass it as `card_id` to pay with a specific card. |
| `brand` | string | `visa`, `mastercard`, `amex`, `discover`, … |
| `last4` | string | |
| `expiry_month`, `expiry_year` | integer | |
| `created_at` | string | |
| `payment_permission` | object | Whether your app can pay with this card without an approval link. `ready` is `true` once the user gave your app this card. |

## The checkout authorization object

| Field | Type | Description |
| - | - | - |
| `object` | string | `checkout_authorization` |
| `id` | string | `cauth_…` |
| `status` | string | `awaiting_approval`, `approved`, `submitted_on_device` (hosted-form processors), `declined`, `expired`. |
| `execution_mode` | string | `user_approval` when the user approves in the Vault, `autopilot` when Agentcard pays without asking. |
| `grant_id` | string | With `autopilot`: the permission that paid. |
| `autopilot_status` | string | Present once Agentcard tried to pay without asking: `dispatching`, `succeeded`, `declined`, `not_submitted`, `outcome_unknown`, or `action_required`. |
| `execution_reason`, `execution_detail` | string | `unverified_origin` and a sentence when the purchase waits for the user because the create carried no `checkout_origin`. |
| `outcome` | object or null | What your app reported the merchant charged, on an auto-approved purchase with `charged_kind: "none"`. Null on any other purchase. See [Report a checkout outcome](/api-reference/vault/authorizations-outcome). |
| `mode` | string | `token`, `cse` (Adyen), or `hosted_form` (Tranzila). How the card reaches the processor. |
| `psp` | string | The processor: `stripe`, `shopify`, `square`, `recurly`, `razorpay`, `adyen`, `tranzila`. |
| `merchant` | string | What the user saw on the approval screen. |
| `amount`, `currency`, `amount_display` | integer, string, string | The amount in the currency's smallest unit (2306 for \$23.06), its ISO code, and the human form (`$23.06`). Null until an authority names one. |
| `amount_authority` | string | Who named the amount: `processor` (the payment request, or the Stripe intent read back), `agent` (your `amount`), `page` (the checkout page's total), or `none`. |
| `amount_verified` | boolean or null | After the charge: whether the processor charged the approved amount. Null when there was nothing to compare. |
| `charged_amount`, `charged_currency`, `charged_kind` | | What was collected. `charged_kind` is `captured`, `authorized`, `none`, or null. |
| `approvalUrl` | string | The link to send the user while `awaiting_approval`. Absent when `execution_mode` is `autopilot`. |
| `response` | object | On `approved` in `token` mode: the processor's response to replay into the paused request. |
| `substitutions` | object | On `approved` in `cse` mode: encrypted fields to write into the paused body, plus `remove`. |
| `reason` | string | On `declined`: `user_declined`, `amount_mismatch`, `intent_not_confirmable`, `processor_refused`, `processor_declined` (an auto-approved purchase the processor refused), `merchant_request_aborted`. |
| `psp_error_code` | string or null | The processor's refusal code when `reason` is `processor_refused`. |
| `processor_error` | object | Optional bounded Razorpay `reason`, `source`, `step`, `payment_id`, and `order_id` identifiers on `processor_refused`. No raw processor body or description. A generic request error does not prove issuer decline or no charge; reconcile before retrying. |
| `replay_attempted` | boolean | True when a device may already have sent the card. |
| `settlement` | object or null | Whether the charge settled, read back from the processor by Agentcard once the authorization finished: `status` (`settled`, `not_settled`, `unknown`), `reason`, `final`, `processor_reference`, `processor_status`, `processor_error_code`, `settled_amount`, `settled_currency`, `checked_at`, `resolved_at`, `message`. Stripe PaymentIntent confirms are read back; every other request is `unknown` / `no_processor_reference`. See [Get a checkout authorization](/api-reference/vault/authorizations-get). |
| `expiresAt` | string | 15 minutes after creation. |

```json theme={null}
{
  "id": "cauth_2q9d1x8f3k2m4t7w",
  "object": "checkout_authorization",
  "status": "approved",
  "mode": "token",
  "psp": "stripe",
  "merchant": "shop.example.com",
  "amount": 2306,
  "currency": "usd",
  "amount_display": "$23.06",
  "amount_authority": "processor",
  "amount_verified": true,
  "charged_amount": 2306,
  "charged_currency": "usd",
  "charged_kind": "captured",
  "replay_attempted": true,
  "settlement": {
    "status": "settled",
    "reason": "processor_succeeded",
    "final": true,
    "processor_reference": "ch_3Qxample",
    "processor_status": "succeeded",
    "processor_error_code": null,
    "settled_amount": 2306,
    "settled_currency": "usd",
    "checked_at": "2026-09-17T20:59:12.000Z",
    "resolved_at": "2026-09-17T20:59:12.000Z",
    "message": "The processor reports this payment succeeded: the charge settled."
  }
}
```

## Approve before Pay

Ask for approval before starting the merchant’s card request. A preparation carries the same displayed amount and merchant fields as an authorization, plus:

| Field | Type | Description |
| - | - | - |
| `object` | string | `checkout_preparation` |
| `id` | string | `cprep_…` |
| `status` | string | `awaiting_approval` → `ready` → `bound`, or `cancelled` / `expired`. |
| `checkout_key` | string | Your key for repeating the create request without creating another preparation. |
| `merchant_origin` | string | The exact origin of the merchant page. |
| `psp` | string | `square`, `braintree`, `worldpay`, `bambora`, `mercado_pago`, `recurly` or `adyen`. |
| `mode` | string | `token`, or `cse` for Adyen. |
| `environment` | string | `production` or `sandbox` for Square, Braintree, Worldpay and Adyen; `shared` for Bambora, Mercado Pago and Recurly. Shared endpoints do not establish processor test mode. |
| `card_id` | string or null | The card the user selected (or you preselected). |
| `approvalUrl` | string | Present while `awaiting_approval` or `ready`. |
| `ready_expires_at` | string or null | How long a `ready` approval can still be bound. |
| `authorization_id` | string or null | Set once `bound`. The authorization then speaks for the payment. |
| `payment_status` | string | `not_started`, or `authorization_pending` once bound. |

Adyen (`cse`) preparations name the host family: `sandbox` is `checkoutshopper-test.adyen.com` with a `test_` client key, `production` is the live hosts with a `live_` key, and the bound request is the Sessions `/payments` call carrying a fresh card's four encrypted fields. Prepare before Pay: Adyen Web abandons its Sessions payment request 60 seconds after Pay (observed on Adyen Web 6.41 and 6.44, not enforced by Agentcard), and a prepared approval leaves only the device-side encryption inside that window.

## Endpoints

| Endpoint | |
| - | - |
| `POST /api/v2/vault_sessions` | [Create a vault session](/api-reference/vault/sessions-create) |
| `GET /api/v2/vault_sessions/{id}` | [Get a vault session](/api-reference/vault/sessions-get) |
| `GET /api/v2/vault_cards` | [List a user's vaulted cards](/api-reference/vault/cards-list) |
| `POST /api/v2/checkout/vault_link` | [Send a user their vault link](/api-reference/vault/vault-link): Agentcard delivers it for you |
| `POST /api/v2/checkout/authorizations` | [Create a checkout authorization](/api-reference/vault/authorizations-create) |
| `GET /api/v2/checkout/authorizations/{id}` | [Get a checkout authorization](/api-reference/vault/authorizations-get) |
| `POST /api/v2/checkout/authorizations/{id}/cancel` | [Cancel a checkout authorization](/api-reference/vault/authorizations-cancel) |
| `POST /api/v2/checkout/authorizations/{id}/outcome` | [Report a checkout outcome](/api-reference/vault/authorizations-outcome) |
| `GET /api/v2/checkout/recognizers` | [List recognized processors](/api-reference/vault/recognizers) |
| `GET /api/v2/checkout/coverage` | [Get checkout coverage](/api-reference/vault/coverage-get) |
| `POST /api/v2/checkout/coverage/assess` | [Assess checkout cases](/api-reference/vault/coverage-assess) |
| `POST /api/v2/checkout/preparations` | [Create a checkout preparation](/api-reference/vault/preparations-create) |
| `GET /api/v2/checkout/preparations/{id}` | [Get a checkout preparation](/api-reference/vault/preparations-get) |
| `POST /api/v2/checkout/preparations/{id}/cancel` | [Cancel a checkout preparation](/api-reference/vault/preparations-cancel) |

Webhooks: `vault.session_linked`, `vault.card_stored`, `vault.payment_permission.updated`, `checkout_authorization.approved`, `checkout_authorization.submitted`, `checkout_authorization.declined`, `checkout_authorization.expired`, `checkout_authorization.amount_mismatch`, `checkout_authorization.settled`, `checkout_authorization.settlement_unconfirmed`, `checkout_authorization.outcome_reported`.

The `@agent-cards/checkout` SDK wraps the authorization and preparation calls for Playwright and CDP browsers. See [Creating a cart](/vault/creating-a-cart).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.