ROOKDocs
Cards Guide

Secure card display

Show PAN, expiry, and CVV in a PCI iframe. Do not put those values in your page DOM, logs, or JSON APIs unless the caller is in PCI scope.

When to use which operation

GoalCall
Display PAN / expiry / CVV in a web or mobile WebViewPOST /v1/cards/{card_id}/embed-sessions, then load embed_url in an iframe
Receive PAN / expiry / CVV as JSONPOST /v1/cards/{card_id}/reveal: PCI DSS compliant callers only
Look up a card you already hold the PAN forPOST /v1/cards/search-by-pan: request body includes pan; the card in the response does not
GET /v1/cards, GET /v1/cards/{card_id}, and every other card object return last_four, exp_month, and exp_year only.

Embed flow

1. From your backend, POST /v1/cards/{card_id}/embed-sessions with Authorization and Idempotency-Key. The response is:

json
   {
     "object": "card_embed_session",
     "card_id": "0c4e8f16-2a7b-4d93-b5e1-8f3a6c9d0142",
     "session_token": "8f2b1c400c1a4b7e9a3d6d5f2e1a7b90",
     "expires_at": "2026-08-27T15:09:05Z",
     "embed_url": "https://api.rookpayments.com/v1/cards/embed?session_token=8f2b1c400c1a4b7e9a3d6d5f2e1a7b90"
   }
   

This JSON never includes PAN or CVV. Treat session_token as a secret until expires_at.

2. Pass embed_url to the client. Do not proxy the HTML through your origin.

3. Render an iframe whose src is embed_url:

html
   <iframe
     title="Card number"
     src="https://api.rookpayments.com/v1/cards/embed?session_token=8f2b1c400c1a4b7e9a3d6d5f2e1a7b90"
     sandbox="allow-scripts"
     referrerpolicy="no-referrer"
     width="320"
     height="160">
   </iframe>
   

4. GET /v1/cards/embed authenticates with session_token only. Do not send Authorization or X-Program-ID. An expired or unknown token returns 401.

Create a new session when the token expires or when the cardholder opens the display again. Do not reuse a token after expires_at.

Content-Security-Policy

On your page that hosts the iframe, allow Rook as a frame source. A minimal directive:

Code
Content-Security-Policy: frame-src https://api.rookpayments.com https://api.sandbox.rookpayments.com

If you already set frame-src or default-src, add those hosts rather than replacing the rest of the policy. frame-ancestors on your page does not control this iframe; frame-src does.

The embed document itself is served with a restrictive CSP (default-src 'none' plus the styles needed to render the PAN). Do not expect to inject scripts into the iframe. sandbox="allow-scripts" is enough for the page to render; omit allow-same-origin so the parent cannot read the iframe DOM.

Iframe usage

  • Use HTTPS parents only. Mixed content blocks the iframe.
  • Size the iframe so PAN, expiry, and CVV are visible without the parent overlaying them.
  • Do not copy iframe contents with contentDocument or window.frames. Cross-origin access is blocked; do not work around it.
  • For copy-to-clipboard, keep a control in the iframe (served by Rook) rather than reading PAN in the parent.
  • Mobile WebViews: enable third-party cookies only if your WebView otherwise strips the query string; session_token is in the URL, so cookies are not required.
Sandbox embed_url hosts use https://api.sandbox.rookpayments.com. Production uses https://api.rookpayments.com. Match frame-src to the environment.

Reveal JSON (PCI callers)

POST /v1/cards/{card_id}/reveal returns:

json
{
  "object": "card_reveal",
  "card_id": "0c4e8f16-2a7b-4d93-b5e1-8f3a6c9d0142",
  "pan": "4111111111111111",
  "exp_month": 8,
  "exp_year": 2029,
  "cvv": "123"
}

Requirements:

  • The API key must be enabled for PAN reveal. Other keys receive 403 with code permission_denied.
  • The caller must be PCI DSS compliant (SAQ D or a listed Level 1 processor) and must handle PAN only inside a PCI environment.
  • Do not log the response body, write it to analytics, or send it to a browser that is not in PCI scope.
  • Prefer the embed iframe for cardholder display.
Search-by-PAN (POST /v1/cards/search-by-pan) accepts pan in the request and returns a card without PAN or CVV. Handle the request body under PCI DSS the same way you handle any PAN you already store.