PCI DSS for Developers
PCI DSS is the payment card industry's security standard, and the most useful thing to understand about it is that the goal is to be out of scope. The requirements are extensive — twelve requirement groups, hundreds of sub-requirements, annual assessment — and they apply to any system that stores, processes, or transmits cardholder data. Every system you keep out of that path is a system you don't have to bring into compliance.
Modern payment integration is designed around this. Hosted fields (Stripe Elements, Adyen Components, Braintree Hosted Fields) render an iframe served by the payment provider, so the card number is typed into their page, transmitted to their servers, and never touches your infrastructure. You receive a token — a meaningless reference — and store that. Your scope collapses from "everything that handles a card" to "the page that includes their script."
The failure mode is a team that builds a card form on their own domain because it's easier to style, posts the number to their own server, and discovers they've pulled their entire application, database, backups, and logs into PCI scope.
TL;DR
- The goal is scope reduction. Every system out of the card data path is one you don't have to certify.
- Never store the PAN unless you have an unavoidable reason. Store a token instead.
- Never store CVV/CVC after authorization. This is prohibited outright, with no exception.
- Hosted fields / iframes keep card data off your servers and cut you to the smallest SAQ.
- SAQ A is the easiest path — fully outsourced card entry. SAQ D is the hardest.
- Merchant levels are set by annual transaction volume and determine assessment rigor.
- PCI DSS v4.0 is current; v3.2.1 retired in March 2024, and future-dated v4 requirements phased in during 2025.
- Compliance is contractual, enforced by acquirers and card brands, not by law.
Core Concepts
What counts as cardholder data
The CVV rule is absolute and is the one violated most often — usually accidentally, by logging a full request body or storing a payment payload for debugging. It's also the one that causes the most damage when a breach occurs, because PAN plus CVV is directly usable for fraud.
Scope reduction
Storing the last four digits and the brand is explicitly permitted and is what you display to users. The full PAN never exists in your system.
SAQ levels
Self-Assessment Questionnaires, by integration type:
The gap between A and D is enormous, and it's determined entirely by an integration decision. Choosing hosted fields at design time is worth more than any amount of subsequent security work.
A-EP is the trap: a JavaScript-based integration where the card posts directly to the provider but your page controls the form. Because your site's compromise could alter that form and skim cards — which is exactly what Magecart attacks do — you carry more requirements than SAQ A, including script integrity monitoring.
Merchant levels
Thresholds and requirements vary slightly by card brand, and a breach can move you to Level 1 regardless of volume. Your acquirer tells you your level and what they require.
The requirements that touch code
PCI DSS v4.0
Version 4.0 became the only active standard in March 2024, with a set of future-dated requirements that became mandatory on 31 March 2025. The changes engineers most need to know:
- Payment page script management (6.4.3 and 11.6.1) — inventory every script on a payment page, justify it, and monitor for unauthorized changes. This is a direct response to Magecart-style skimming, and it applies to SAQ A-EP integrations.
- MFA everywhere in the CDE (8.4.2) — not just for remote access.
- Targeted risk analysis — some frequencies (of scans, reviews) can be justified by your own documented risk analysis rather than a fixed schedule.
- The customized approach — meet a requirement's objective differently, with documented evidence. Powerful and requires a QSA to validate.
Best Practices
Use hosted fields, always
Stripe Elements, Adyen Components, Braintree Hosted Fields, or a fully hosted checkout page. This one decision determines whether you file a 20-question SAQ A or a several-hundred-question SAQ D. The styling limitations are real and are worth an order of magnitude less than the compliance cost.
Never let a PAN reach your servers
If a card number is in a request to your infrastructure, it's in your load balancer logs, your application logs, your APM traces, your error tracker, and your request replay tooling. Keeping it out of the request entirely is the only reliable control.
Store tokens and the last four
Tokens for charging, last4 and brand for display. That's everything a normal application needs. If you believe you need the full PAN, the answer is almost always a provider feature you haven't found — network tokens, saved payment methods, and account updaters all exist to avoid it.
Filter card patterns at the logging layer
Even with hosted fields, someone will eventually paste a card number into a support ticket, a form field, or a debug log. A regex filter in the logging pipeline that redacts anything matching a PAN with a valid Luhn checksum is a cheap safety net.
Never put production card data in lower environments
Test card numbers are published by every provider precisely so you don't need real ones. A staging environment containing real PANs has production PCI obligations and pre-production controls.
Segment the network if anything is in scope
If you genuinely must handle card data, isolate that environment — separate VPC or subnet, strict firewall rules, no shared credentials with the rest of the estate. Segmentation is what keeps the rest of your infrastructure out of scope, and its effectiveness must be tested.
Monitor payment page scripts
Subresource Integrity where possible, a strict Content Security Policy, an inventory of every script on the checkout page, and alerting on change. This is now an explicit v4.0 requirement and is the control that actually prevents card skimming.
Ask your provider what SAQ your integration implies
They know, and they'll tell you — often with documentation mapping each integration method to its SAQ. Confirming this before building is a five-minute conversation that occasionally saves a rewrite.
Common Mistakes
Building your own card form
Storing CVV
Logging the payment request body
Real card data in test environments
Unmonitored third-party scripts on the checkout page
Assuming a provider makes you compliant
FAQ
Do we need to be PCI compliant if we use Stripe?
Yes, at a much smaller scope. Using a provider doesn't remove your obligation — it reduces which SAQ applies. With fully hosted fields you file SAQ A, roughly twenty questions, annually. With a custom form posting to your server you're in SAQ D territory regardless of who processes the charge. The provider handles their side; you attest to yours.
Can we ever store the full card number?
Technically yes, with a documented business need, strong encryption, separated key management, and full SAQ D obligations. Practically, almost never — recurring billing, saved cards, and one-click checkout are all solved by provider tokens and network tokens. If someone proposes storing PANs, the first question is which provider feature they haven't found.
What about the CVV for recurring charges?
You never need it, and you may never store it. CVV is required only for the initial transaction; subsequent charges against a stored payment method don't use it. Any design that appears to need a stored CVV is a design that should be using the provider's recurring-payment or saved-method flow.
Is PCI DSS a law?
No — it's a contractual requirement imposed by the card brands through your acquiring bank. Non-compliance means fines levied through your acquirer, higher transaction fees, or losing the ability to accept cards. Several jurisdictions have written PCI-like requirements into law, and a breach involving card data will also trigger the applicable data protection regimes. See GDPR for Engineers.
How does PCI relate to SOC 2?
They overlap substantially in access control, logging, vulnerability management, and change management, and they differ in focus: PCI DSS is prescriptive and specific to cardholder data, SOC 2 is criteria-based and covers your controls broadly. Organizations doing both typically find PCI evidence largely satisfies the equivalent SOC 2 controls, though the prescriptiveness runs one way — SOC 2 lets you define controls, PCI tells you what they must be.
What is a Magecart attack and why does v4.0 care?
Malicious JavaScript injected into a checkout page — usually through a compromised third-party script or a supply-chain attack on a dependency — that reads card fields and exfiltrates them. It bypasses server-side controls entirely because the theft happens in the browser before the data ever reaches your provider. PCI DSS v4.0 added explicit script inventory and change-monitoring requirements (6.4.3, 11.6.1) specifically because this became the dominant card-theft vector for e-commerce.
Related Topics
- Payment Processing — Integration patterns and provider selection
- PII & Sensitive Data Handling — Tokenization and classification generally
- SOC 2 & Security Compliance — Overlapping control requirements
- Audit Logging — Requirement 10
- Security — The underlying practices
- Encryption — Requirements 3 and 4
- Security Headers — CSP and SRI on payment pages
- OWASP Top 10 — Requirement 6's vulnerability classes