Why this is worth an afternoon of your attention
I maintain two Cybersource payment gateway modules on drupal.org, one on each side of this line, so the question of which self-assessment questionnaire (SAQ) a store falls under comes up on every payment job I do. What surprises me is how rarely anyone else on the project has asked it. The developer picked a gateway module because it worked. The merchant signed whatever the acquirer sent. Nobody joined the two up.
The gap matters because the two questionnaires are not close. SAQ A, the short one for merchants who have fully outsourced the payment page, runs to roughly thirty requirements. SAQ A-EP, for merchants whose own website affects the payment page, runs to roughly a hundred and forty, and it pulls the merchant's web server into the cardholder data environment. That is not a longer form. It is a different operating regime, and it costs real money every year.
This article is about what actually puts a Drupal Commerce site on one side or the other, what a hosted-fields or iframe integration changes, the eligibility rule the PCI Council added to SAQ A in 2025 that most people have not read, and the mistakes that quietly move a site back into A-EP without anyone noticing.
The usual caveat, stated once. Your SAQ eligibility is confirmed by your acquirer, your card brands, or a Qualified Security Assessor, not by a developer and not by this article. What a developer controls is the technical facts they assess. This article is about those facts.
The one fact that decides it
The PCI Council's own eligibility wording is the clearest guide. A merchant is eligible for SAQ A when, among other things, all elements of the payment page delivered to the customer's browser originate only and directly from a PCI DSS compliant third-party service provider. A merchant falls under SAQ A-EP when their website does not receive account data but controls how customers, or their account data, are redirected to the provider, and when elements of the payment page originate from the merchant's own website.
In practice that reduces to a single question about the card number field:
- If the card field is rendered by your page, even when the form posts straight to the processor and your server never sees the number, you are in SAQ A-EP. Your page built the field, so your page can be tampered with to steal from it.
- If the card field is rendered by the processor, either on a page you redirected the customer to, or inside an iframe whose content came from the processor's domain, you are eligible for SAQ A. Your page merely hosts a box it cannot read.
Notice what is not on the list. Whether your server ever touches the card number is necessary for both questionnaires, but it does not distinguish them. Drupal Commerce's own vocabulary of "on-site" and "off-site" gateways is not the line either. Whether you use tokens is not the line. The line is who renders the input the customer types the sixteen digits into.
What that looks like across Drupal Commerce gateways
Most Commerce stores use one of a handful of integration patterns. Here is where each one lands, using my own two modules as the worked example because I know exactly how they are built.
| Integration pattern | Who renders the card field | Questionnaire |
|---|---|---|
| Full redirect to a hosted payment page | The processor, on its own domain | SAQ A |
| Processor iframes embedded in your checkout (hosted fields, Flex Microform, Stripe Elements, Braintree hosted fields) | The processor, inside a frame on your page | SAQ A, subject to the 2025 script condition below |
| Direct post or Silent Order POST: your page renders the fields, the browser posts them to the processor | Your page | SAQ A-EP |
| JavaScript tokenisation over inputs that live in your DOM | Your page | SAQ A-EP |
| Card fields that post to your server, even briefly, even "just to forward" | Your page, and your server receives the number | SAQ D. You are now a card-handling merchant. |
My Cybersource Secure Acceptance Silent Order POST module is the third row. The card fields are part of the Drupal checkout, styled like the rest of the site, and the browser posts them directly to Cybersource. The server never sees a card number, every reply is signature-checked before anything is recorded, and it is still SAQ A-EP, because the merchant's page rendered the inputs. The module's README says so plainly, and it should: telling a merchant they have SAQ A when they do not is worse than the extra questions.
My Cybersource REST module is the second row. The card number and security code are typed into Cybersource-hosted iframes (Flex Microform v2), which hand back a single-use transient token that Drupal charges server-side. The merchant page hosts the frames but cannot read their contents. That is the integration shape SAQ A was written for, and moving a merchant from the first module to the second is the "cut" in this article's title.
What SAQ A-EP actually makes you do
The number of questions is the least of it. What matters is that A-EP treats your web server as part of the cardholder data environment, because your server decides what the payment page contains. From the v4 questionnaire, the obligations that bite a typical Drupal host are:
- Requirement 6.4.3: an inventory of every script that loads on the payment page, with a written justification for each, a method of authorising each one and a method of assuring its integrity. That means the tag manager, the chat widget, the analytics snippet and the A/B testing library all need a line in a document and a technical control.
- Requirement 11.6.1: a change and tamper detection mechanism on the payment page as received by the browser, checking the HTTP headers and the page contents, running at least weekly by default. This exists because of Magecart-style skimming, and it is not something Drupal does for you.
- Requirement 11.4: penetration testing of the environment, internal and external, at least annually and after significant changes.
- Requirement 11.3.2: quarterly external vulnerability scans by an Approved Scanning Vendor. This one applies to SAQ A as well.
- Requirement 10: audit logging on the server, with logs retained for twelve months and reviewed. Drupal's watchdog is not this.
- Requirement 6.3.3: critical security patches installed within one month of release, across the operating system, PHP, the web server and Drupal itself, with evidence.
- Requirement 8: multi-factor authentication and password controls for everyone with administrative access to the server, and arguably to Drupal's admin as well, since a Drupal administrator can change what the payment page contains.
Some of that is good practice a well-run site does anyway. Patching within a month and MFA on admin accounts should not need a questionnaire to justify. But the script inventory, the tamper detection and the annual penetration test are real recurring costs, and they exist only because the merchant's page renders the card field. Change that one fact and most of this list falls away.
What SAQ A still requires, and the 2025 change most people missed
SAQ A is not nothing. Under v4.0.1 it still asks for quarterly ASV scans, for the merchant to have checked their provider's attestation of compliance, for basic access control and password hygiene on anything that touches the payment flow, and for the annual attestation itself.
It also changed in January 2025 in a way that matters specifically to iframe integrations, which is to say to almost everyone who moved to SAQ A on purpose. The PCI Council removed requirements 6.4.3 and 11.6.1 from SAQ A, which sounds like a relaxation, and at the same time added a new eligibility criterion: the merchant has confirmed that their site is not susceptible to attacks from scripts that could affect the merchant's e-commerce systems.
The Council's own FAQ 1588 explains how a merchant confirms that. Either deploy the techniques described in 6.4.3 and 11.6.1 anyway, or obtain written confirmation from the payment provider that its embedded payment form solution includes script attack protections when properly deployed. The FAQ is explicit that the criterion is aimed at merchants with embedded payment forms, and does not apply to full redirects.
Read that as a developer and the message is simple. An iframe integration gets you the short questionnaire only if you can honestly say the page around the iframe is not open to script injection. A checkout page with an unrestricted Content-Security-Policy, a stale tag manager container and three marketing scripts you have never audited is not that page. The iframe protects the card number from your server. It does not protect it from a malicious script running on your page that overlays a fake form, and that is exactly the attack the criterion is about.
So the honest position for a hosted-fields Drupal store is: SAQ A, plus a proper CSP on the checkout route, plus a written script inventory, plus either the provider's letter or a weekly integrity check. It is still far less than A-EP. It is not zero.
The seven mistakes that put a site back into A-EP
These are the things I find when I review a Commerce store that believes it is on SAQ A. Most of them were not decisions. They were drift.
1. A "hosted fields" library that is not actually hosted
Some tokenisation libraries render ordinary <input> elements in your DOM and tokenise their contents with JavaScript before submission. That is a direct-post integration with extra steps. Your page rendered the field. Open the browser inspector on the checkout page: if the card number input is inside an <iframe> served from the processor's domain, you are fine. If it is a plain input with a fancy class name, you are A-EP and nobody told you.
2. A card form somewhere else on the site
The checkout is fine, and then there is a Webform for "phone orders" where staff type a customer's card number into Drupal, or a contact form that customers use to send their details, or a legacy "pay an invoice" page from the previous build. Any one of those means Drupal receives account data electronically, and the store is not even A-EP any more. It is SAQ D. I have found this on stores that had been attesting to SAQ A for years.
3. Logging the payment reply
Nobody logs card numbers on purpose. What happens is that a developer, debugging a failed payment, adds a line that dumps the full return POST or the full gateway response to watchdog, and never removes it. With a hosted-fields integration the reply should not contain a card number, but it may contain the last four digits, the expiry, the cardholder name and the transient token, and depending on the provider and the failure it can contain more. Log retention then means it is in the database backups too. Every gateway module I write logs the fact of an outcome and an identifier, never the payload, and the security review of my SOP module specifically moved a log write until after the signature check for a related reason.
4. Scripts on the checkout page that nobody owns
This does not push you into A-EP on its own, but under the 2025 criterion it makes your SAQ A attestation untrue. A tag manager is the worst offender, because it means the set of scripts on the payment page can be changed by a marketing login without a deployment. Either keep the tag manager off the checkout route entirely, or lock the container down and put it on the inventory with a justification.
5. A CSP that allows everything, or none at all
The confirmation SAQ A now asks for is, in technical terms, largely a Content-Security-Policy question. A checkout route with no CSP header, or one with 'unsafe-inline' and a wildcard script-src, cannot support the claim that the page is not susceptible to script attacks. On Drupal this is a route-specific response header, and it needs to allow exactly the processor's iframe origin and script origin, your own assets, and nothing else. Both of my modules document the required checkout CSP because it is part of the integration, not an optional extra.
6. Re-creating the redirect in the wrong place
A merchant on a hosted payment page redirect is SAQ A. Then someone decides the redirect looks unprofessional and asks for the card form to be "brought into the site". If that is done with the processor's iframes, scope is unchanged. If it is done by adopting a direct-post profile so the fields can be styled freely, the merchant has just walked into A-EP to gain some CSS. That is a legitimate trade, and it is the trade my SOP module offers, but it should be a decision, made with the merchant, not a side effect of a design review.
7. A staging or dev copy that takes real card numbers
Test cards on a test profile are fine. What is not fine is a staging site pointed at the live processor profile, reachable on the internet, with the same card form as production. It is in scope, it is usually unpatched, and it is usually outside the ASV scan. Test profiles and test cards everywhere except production is the rule, and it should be enforced in settings, not by remembering.
How to actually make the move
Assume a Drupal Commerce store currently on a direct-post or Silent Order POST gateway, correctly attesting to SAQ A-EP, and a merchant who would like to stop. The work is roughly a week, and it is mostly not coding.
- Confirm the processor offers a hosted-fields or iframe method and that the merchant's contract covers it. For Cybersource that is Flex Microform through the REST API. Some acquirers will need a new profile or a new merchant ID.
- Swap the gateway plugin, not the checkout. On Commerce 3 the gateway is a plugin configured on the payment gateway entity. Add the new gateway, test it on the sandbox profile, then switch the checkout flow's payment step to it. Keep the old one disabled rather than uninstalled until the first month of live orders is through, because refunds and voids on old orders still reference it.
- Put the checkout CSP in place before go-live, not after. Allow the processor's frame and script origins and your own, deny the rest, and test that 3-D Secure challenges, which open in another frame, still work. This is where most hosted-fields integrations break on launch day.
- Walk the site for other card entry points. Webforms, contact forms, legacy routes, a staff "take a phone order" page. Each one is either removed or moved to a processor-hosted virtual terminal.
- Write the script inventory for the checkout route and either get the provider's written confirmation or set up a weekly integrity check. This is the part that makes the SAQ A attestation true rather than merely filed.
- Re-do the questionnaire with the acquirer. Do not simply start submitting SAQ A next year. Tell them the integration changed, what to, and when, and let them confirm eligibility. That conversation is what protects the merchant if a dispute ever turns on which questionnaire applied.
What you give up
Honesty about the trade, because I built the module on the other side of it. A direct-post integration gives you card fields that are genuinely part of your page: your fonts, your layout, your validation messages, your accessibility work, all applied directly. Hosted iframes give you a box you can style from the outside and only through whatever styling API the processor exposes, and every processor's is different. Live card brand detection, accepted-brand enforcement and inline validation are still possible, but they are done by listening to events from the frame rather than reading the field, and the result is never quite as seamless. If the store's checkout conversion depends on a pixel-perfect card form, that is a real cost to weigh against the questionnaire.
For most merchants it is not close. The annual cost of A-EP, in penetration testing, in scanning, in the script inventory and tamper detection, in the developer hours spent producing evidence, is larger than the value of styling the card field. The exceptions are stores with very high volume where checkout conversion is measured in fractions of a percent, and even there I would want to see the measurement before accepting the wider scope.
If you want this done properly
Reducing a merchant's PCI scope is a specific piece of work with a clear before and after, which is why agencies subcontract it. I do it as a fixed-price job under Drupal for agencies: gateway swap, checkout CSP, card entry point sweep, script inventory, and a written summary the merchant can hand to their acquirer. The two Cybersource modules are cybersource_sop and cybersource_rest on drupal.org, both covered by the Drupal security advisory policy, if you would rather read the code first.
If the store is already on a hosted-fields integration and the question is whether the attestation is actually true, the card entry point sweep and the checkout script review are part of a fixed-price site audit, and merchants on a Commerce support plan get the PCI scope check-in every year as standard.
