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

# Approve before checkout

> Ask the user to approve before a short-lived card tokenization request starts.

Ask the user to approve the merchant and amount before your browser clicks Pay. The user picks a card and keeps the approval page open. Your browser then starts one fresh card request while the approval is ready. Approval does not mean the merchant received payment.

Use `controller.prepare()` with the checkout SDK on Playwright or CDP. Call this API directly only when your integration handles request interception. Create the preparation before the first card request; a preparation cannot resume an earlier request that timed out.

<ParamField body="user" type="string" required>The connected user whose added card pays.</ParamField>
<ParamField body="merchant" type="string" required>The merchant name shown to the user. Up to 120 printable characters.</ParamField>
<ParamField body="amount_cents" type="integer" required>The displayed amount in the smallest currency unit. For example, `100` with `usd` displays `$1.00`; the card token does not enforce the merchant's eventual charge.</ParamField>
<ParamField body="currency" type="string" required>The ISO 4217 currency code, such as `usd`.</ParamField>
<ParamField body="psp" type="string" required>`square`, `braintree`, `worldpay`, `bambora` or `mercado_pago`.</ParamField>
<ParamField body="mode" type="string" required>Use `token`.</ParamField>
<ParamField body="checkout_key" type="string" required>A stable key for this checkout attempt, from 16 to 128 characters. An identical request returns the existing preparation; a changed merchant, amount, card or other approved value is refused.</ParamField>
<ParamField body="merchant_origin" type="string" required>The exact HTTPS merchant origin, such as `https://merchant.example`. Use `http://localhost` only for local checkout.</ParamField>
<ParamField body="environment" type="string" required>Use the processor's environment from the table below.</ParamField>
<ParamField body="card_id" type="string">Preselect one of the user's added cards.</ParamField>

| Processor    | `environment`             | Request that can use the approval                                                                          |
| ------------ | ------------------------- | ---------------------------------------------------------------------------------------------------------- |
| Square       | `production` or `sandbox` | Card tokenization on the matching Square host.                                                             |
| Braintree    | `production` or `sandbox` | A single guest `TokenizeCreditCard` mutation with explicit `options.validate: false`.                      |
| Worldpay     | `production` or `sandbox` | A fresh card request to `/sessions/card` on the matching Access Worldpay host.                             |
| Bambora      | `shared`                  | A fresh card request to `/scripts/tokenization/tokens` on `api.bam.shift4api.net` or `api.na.bambora.com`. |
| Mercado Pago | `shared`                  | A fresh card request to `api.mercadopago.com/v1/card_tokens`.                                              |

Bambora and Mercado Pago use the same endpoint for test and live requests. `shared` does not select test mode. Configure the merchant's processor account for testing; Agentcard cannot determine that account's mode from the request URL or a key prefix. The response's `sandbox` field describes the connected app's Agentcard mode separately.

Braintree configuration queries do not consume an approval. Braintree saved-card operations, compound mutations and its REST fallback cannot use a preparation. Worldpay, Bambora and Mercado Pago preparations require fresh card details; saved-card and recurring requests cannot use the approval.

The request and responses below come from a local API test with sample user and card records. The test made no processor request. Replace the user and card identifiers with your connected user's values.

## Send the request

<RequestExample>
  ```bash theme={null}
  curl -X POST https://api.agentcard.sh/api/v2/checkout/preparations \
    -H "Authorization: Bearer $ORG_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
    "user": "cmturxope0000cbpss123jxee",
    "merchant": "Merchant example",
    "amount_cents": 100,
    "currency": "usd",
    "card_id": "cmturxopj0004cbpswhqdeyju",
    "psp": "worldpay",
    "mode": "token",
    "checkout_key": "ed8f8370-2e7a-4255-b1eb-116f1220d687",
    "merchant_origin": "https://merchant.example",
    "environment": "sandbox"
  }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "id": "cprep_2e357e4b01c88063fd805764",
    "object": "checkout_preparation",
    "status": "awaiting_approval",
    "user": "cmturxope0000cbpss123jxee",
    "merchant": "Merchant example",
    "merchant_origin": "https://merchant.example",
    "amount": "$1.00",
    "amount_cents": 100,
    "currency": "usd",
    "amount_authority": "display_only",
    "psp": "worldpay",
    "mode": "token",
    "environment": "sandbox",
    "sandbox": true,
    "testMode": true,
    "vaultOrigin": "https://vault.agentcard.sh",
    "url": "https://try.access.worldpay.com/sessions/card",
    "card_id": "cmturxopj0004cbpswhqdeyju",
    "cardId": "cmturxopj0004cbpswhqdeyju",
    "checkout_key": "ed8f8370-2e7a-4255-b1eb-116f1220d687",
    "binding_hash": null,
    "expiresAt": "2026-09-10T00:28:24.470Z",
    "ready_expires_at": null,
    "createdAt": "2026-09-10T00:13:24.471Z",
    "authorization_id": null,
    "payment_status": "not_started",
    "approvalUrl": "https://vault.agentcard.sh/authorize?id=cprep_2e357e4b01c88063fd805764"
  }
  ```
</ResponseExample>

<ResponseField name="status" type="string">`awaiting_approval` waits for the user. `ready` allows one fresh request until `ready_expires_at`. `bound` links to `authorization_id`; `cancelled` and `expired` cannot be used.</ResponseField>
<ResponseField name="approvalUrl" type="string">Deliver the link when the preparation is created. The user must keep the same page open after approving.</ResponseField>

Start Pay immediately after the preparation becomes `ready`. Readiness lasts at most 30 seconds. A changed checkout, navigation, cancellation or early request prevents the SDK from using the approval. Check the merchant's outcome before creating a new checkout attachment; the SDK never retries the payment automatically.

## Correct the environment

An unsupported processor and environment combination returns HTTP `400`. For example, Worldpay with `environment: "shared"` returned this response from the local API test:

```json theme={null}
{
  "error": {
    "code": "invalid_request",
    "message": "Choose an environment supported by this processor.",
    "docs": "https://docs.agentcard.sh"
  }
}
```

Retry with `environment: "sandbox"` for the Worldpay sandbox:

```bash theme={null}
curl -X POST https://api.agentcard.sh/api/v2/checkout/preparations \
  -H "Authorization: Bearer $ORG_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "user": "cmturxope0000cbpss123jxee",
  "merchant": "Merchant example",
  "amount_cents": 100,
  "currency": "usd",
  "card_id": "cmturxopj0004cbpswhqdeyju",
  "psp": "worldpay",
  "mode": "token",
  "checkout_key": "ed8f8370-2e7a-4255-b1eb-116f1220d687",
  "merchant_origin": "https://merchant.example",
  "environment": "sandbox"
}'
```

| Code              | Meaning                                                                       | What to do                                             |
| ----------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------ |
| `invalid_request` | A required value is missing or invalid, including an unsupported environment. | Correct the named value and resend the create request. |
| `not_found`       | The user is not connected to your app.                                        | Connect the user before creating a preparation.        |
| `card_not_found`  | The requested card is unavailable to that user.                               | Choose a card from the user's added cards.             |
