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

# Pay with card

> Collect a card through hosted fields and run 3-D Secure when the issuer requires it.

Card payments go through the processor’s hosted fields (CyberSource Flex or Mastercard MPGS). Vestrapay does not receive the card number or CVV.

## Flow

<Steps>
  <Step title="Initialize">
    Create the payment on your server. Keep `data.accessCode` and `data.reference`.
  </Step>

  <Step title="Prepare a card session">
    From the browser (or your checkout backend that holds the access code):

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    curl -X POST https://server.staging.vestrapay.app/v1/payment/checkout/card/session \
      -H "x-access-code: ACCESS_CODE"
    ```

    `hostedCard.provider` is `cybersource` or `mpgs`:

    ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
    {
      "status": "success",
      "data": {
        "sessionId": "FLEX_OR_MPGS_SESSION",
        "reference": "VPY_TXN_…",
        "hostedCard": {
          "provider": "cybersource",
          "scriptUrl": "https://…",
          "captureContext": "eyJ…"
        }
      }
    }
    ```
  </Step>

  <Step title="Mount hosted fields">
    **CyberSource:** load `hostedCard.scriptUrl`, create `new Flex(hostedCard.captureContext).microform()`, mount number and CVV only, keep expiry as your own inputs, then `createToken({ expirationMonth, expirationYear })`. Send that JWT on charge.

    **MPGS:** load `hostedCard.scriptUrl` and mount Mastercard hosted fields against the session id.
  </Step>

  <Step title="Charge">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    curl -X POST https://server.staging.vestrapay.app/v1/payment/checkout/charge/card \
      -H "x-access-code: ACCESS_CODE" \
      -H "Content-Type: application/json" \
      -d '{
        "sessionId": "FLEX_OR_MPGS_SESSION",
        "browser": "Mozilla/5.0 …",
        "browserDetails": {
          "screenHeight": 982,
          "screenWidth": 1512,
          "colorDepth": 24,
          "javaEnabled": false,
          "language": "en-GB",
          "timeZone": -60
        }
      }'
    ```

    `transientToken` is accepted as an alias of `sessionId` for CyberSource. If you omit both, we use the token stored at session create.
  </Step>

  <Step title="Handle data.status">
    Branch on **`data.status`**:

    | `data.status`          | What you do                                                                                                       |
    | ---------------------- | ----------------------------------------------------------------------------------------------------------------- |
    | `fingerprint_required` | Inject `data.fingerprintHtml` in a hidden iframe. Wait for device data (or \~12 seconds), then call authenticate. |
    | `3ds_required`         | Inject `data.threeDsHtml` into an on-page \~390×400 frame.                                                        |
    | `success`              | Paid. Show a receipt and verify on the server.                                                                    |
    | `failed`               | Show `data.message`. Let them try another card.                                                                   |
    | `processing`           | Wait on checkout events or verify.                                                                                |
  </Step>
</Steps>

## 3-D Secure after fingerprinting

Only call this when charge returned `data.status` `fingerprint_required`. No session id is needed; it is already stored.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://server.staging.vestrapay.app/v1/payment/checkout/charge/card/authenticate \
  -H "x-access-code: ACCESS_CODE" \
  -H "Content-Type: application/json" \
  -d '{ "browser": "Mozilla/5.0 …" }'
```

You get `success`, `failed`, or `3ds_required` plus `threeDsHtml` on `data`.

When the issuer challenges, the iframe posts back to our 3-D Secure callback (not your `callbackUrl`). The callback page notifies the parent with:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "type": "vestrapay.3ds.complete",
  "reference": "VPY_TXN_…",
  "status": "success",
  "message": null
}
```

Also listen for checkout event `checkout.completed` as a fallback.

## Constraints

* Card number and CVV go to hosted fields, not to Vestrapay.
* Run the 3-D Secure challenge in an on-page iframe, not `window.open`.
* Keep the top window on your checkout origin during 3-D Secure.
* Call authenticate only when charge returned `fingerprint_required`.

## Test cards

On the mock card processor (test): `4111111111111111` and `4242424242424242` succeed. Any other number is rejected. Live CyberSource / MPGS use the processor’s own test PANs.
