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

# Secure Card Data

> Show a cardholder their card number, expiry, and CVV without that data touching your servers or Dakota's

<Warning>
  **Cards is available in sandbox only while we finish development.** Dakota enables Cards per
  account. The Cards endpoints are in the [API reference](/api-reference/introduction), marked
  **Sandbox only**. Endpoints, fields, and flows can still change before release.
</Warning>

No Dakota endpoint or webhook returns the full card number (PAN), expiry, or CVV. The most any card object carries is `last4`. To show the details, your backend mints a short-lived **reveal session**, and [Cards.js](/documentation/cards/cards-js) uses it to render the values in the cardholder's browser, inside a frame served by the card-data processor. The values never pass through your backend or Dakota's.

```mermaid theme={null}
sequenceDiagram
    participant U as Cardholder's browser
    participant JS as Cards.js
    participant BE as Your backend
    participant D as Dakota API
    participant P as Card-data processor

    U->>JS: Taps "Show details"
    JS->>BE: fetchSession({sessionType, origin})
    BE->>BE: Authenticate the user, confirm they own the card
    BE->>D: POST /cards/{card_id}/reveal_session
    D-->>BE: {session, expires_at}
    BE-->>JS: {session, expiresAt}
    JS->>P: Redeem the session
    P-->>U: Card number, expiry, CVV
```

## Mint a reveal session

Call [`POST /cards/{card_id}/reveal_session`](/api-reference/cards/create-a-card-reveal-session) from your backend. Your frontend never holds a Dakota API key.

```json theme={null}
POST /cards/{card_id}/reveal_session
x-api-key: <YOUR_DAKOTA_API_KEY>

{
  "session_type": "card_details",
  "origin": "https://app.example.com"
}

200 OK
{
  "session": "<opaque single-use credential>",
  "expires_at": "2026-07-22T15:04:05Z"
}
```

* `origin` is the HTTPS origin of the page that shows the card: scheme and host only, with no path. The session only works on that origin. Plain `http://localhost` is rejected, including in development.
* Cards.js sends `sessionType` and expects `expiresAt`. Your backend renames `sessionType` to `session_type` on the request to Dakota, and `expires_at` to `expiresAt` on the response it returns to Cards.js.
* Do not send an `X-Idempotency-Key`. Every call mints a new session, including a retry.
* Use the host that matches the `environment` you give Cards.js.

Rules to design around:

1. **One session per reveal.** A session works once. To show the details again, mint a new one.
2. **Short-lived.** A session expires within minutes.
3. **The card must be `active`.** A `pending`, `frozen`, or `closed` card cannot mint a session.
4. **Rate limited.** Any of your API keys can mint sessions, up to 60 per minute and 600 per hour for your account. Over that, the call returns `429`.

<Warning>
  **Your backend is the access check.** Dakota verifies that the card belongs to your account, but it cannot know which of your users is asking. Authenticate the user and confirm they own the card before every mint. Without that check, any signed-in user could reveal any of your cards.
</Warning>

## Show it with Cards.js

[Cards.js](/documentation/cards/cards-js) (`@dakota-xyz/cards-js`) renders a masked card, mints a session through your backend when the user asks, reveals the values, and masks them again when the session window ends. It has React bindings.

* [Quickstart](/documentation/cards/cards-js) for vanilla JavaScript and React
* [Integration guide](/documentation/cards/cards-js/integration-guide), including the backend endpoint
* [Network & CSP](/documentation/cards/cards-js/network-and-csp): the frame origins your content security policy must allow

Showing card details needs a browser application. A Dakota-hosted reveal page for integrations without a frontend is planned.
