> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.alphax.asia/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.alphax.asia/_mcp/server.

# Card widget

Card numbers, expiry, and CVV are rendered by the card widget **directly in the
end-user's browser** using a short-lived access token from our API. Your servers
and AlphaX never see the raw card data, keeping you out of PCI scope.

## Step 1 — Load the card widget SDK

Add the SDK script to the page that shows the card. It exposes a global
`window.widget`. Use the **staging** SDK against the sandbox API and the
**production** SDK against production.

```html
<!-- Production -->
<script src="https://static.univisioncard.com/api/sdk/card/1.0.0/index.min.js"></script>

<!-- Staging -->
<script src="https://staging-static.univisioncard.com/api/sdk/card/1.0.0/index.min.js"></script>
```

## Step 2 — Get a card access token

When the user asks to reveal the card, call the details endpoint from **your
backend** so your API key stays server-side:

```
POST /v1/cards/{cardId}/details
X-API-Key: <your partner API key>
X-Company-Id: <the company id>
```

```json
{
  "type": "CardAccessToken",
  "data": { "accessToken": "eyJhbGciOi..." }
}
```

The `accessToken` is short-lived and single-use per reveal. Fetch a fresh one
each time the user reveals the card — don't cache or store it.

## Step 3 — Add containers for the secure fields

Place empty elements where each field should render. The widget injects secure
iframes into these by `id`:

```html
<div id="card-pan"></div>
<div id="card-exp"></div>
<div id="card-cvv"></div>
```

## Step 4 — Bootstrap the widget with the token

Call `bootstrap(...)` **after** the container elements exist in the DOM. If you
re-reveal, fetch a new token and call `bootstrap` again.

```js
window.widget.bootstrap({
  clientAccessToken: accessToken, // from Step 2
  component: {
    showPan: {
      cardPan: {
        domId: 'card-pan',
        format: true, // group digits (e.g. 4242 4242 ...)
        styles: {
          span: {
            color: '#111',
            'font-family': 'monospace',
            'font-size': '14px',
            'letter-spacing': '2px',
            'font-weight': 'bold',
          },
        },
      },
      cardExp: {
        domId: 'card-exp',
        format: true,
        styles: { span: { color: '#111', 'font-family': 'monospace', 'font-size': '14px' } },
      },
      cardCvv: {
        domId: 'card-cvv',
        styles: { span: { color: '#111', 'font-family': 'monospace', 'font-size': '14px' } },
      },
    },
  },
});
```

## Register your domain (required)

The widget only runs on domains **pre-registered** with the card processor. The
registered domain must match the domain where the widget is loaded — if you
register a root domain, all of its subdomains are covered.

If the page's domain isn't registered, the widget's request for card secrets is
rejected with an HTTP `403`. Register the domain where you embed the widget
before going live. Contact AlphaX support to register your domain.

## Notes

* **No OTP from AlphaX.** We don't send an OTP to view card details — you own
  the end-user authentication and gating before you call the endpoint.
* **Styling** is controlled via the `styles.span` object per field.
* **Security:** the SDK renders values inside iframes it controls; the raw
  PAN/CVV are never exposed to your JavaScript, your backend, or AlphaX.