Back to Docs
Recipe: Payment card tokenization (PCI scope reduction)
Replace raw PANs with provider tokens so your servers never touch cardholder data. This recipe shrinks your PCI DSS footprint from SAQ-D to SAQ-A.
Architecture
The browser collects card details inside an iframe hosted by your tokenization provider (Stripe Elements, Braintree Hosted Fields, or Spreedly). The provider returns a single-use token. Your backend forwards that token to the provider's API, receives a permanent multi-use token, and stores only that opaque reference.
Step 1 — Client-side iframe
<div id="card-element">
<!-- Provider mounts iframe here -->
</div>
<script>
const stripe = Stripe('pk_live_xxx');
const elements = stripe.elements();
const card = elements.create('card');
card.mount('#card-element');
</script>Step 2 — Token creation
const {token, error} = await stripe.createToken(card);
if (error) { /* handle */ }
// POST token.id to your backendStep 3 — Server-side exchange
POST /v1/payment_methods Authorization: Bearer sk_live_xxx Content-Type: application/x-www-form-urlencoded card=tok_visa&customer=cus_xxx
Store the returned pm_xxx ID. Never log or persist the raw token beyond the exchange window.
PCI scope impact
- SAQ-A eligibility (22 controls vs SAQ-D's 329)
- No cardholder data traverses your network
- Provider handles key management and rotation
- Chargebacks and refunds use the stored token
Meridian note: Combine with the “Secrets rotation” recipe to rotate your provider API keys automatically. Tokenization alone does not remove the need for transport-layer encryption — always enforce TLS 1.3.