How card data stays off your servers
Why ShiftxPay never sees a card.
ShiftxPay is card-data-free by construction: a raw card never touches the gateway. The card always travels from the buyer's browser directly to the payment service provider (PSP), and ShiftxPay only ever holds PSP tokens, intent ids, and the card brand and last four digits. This is not a policy you can opt out of — it is built into the architecture.
The invariant
The raw card (PAN/CVC) goes browser → PSP only. The gateway and its database never receive, store, or transmit a primary account number or security code.
The buyer enters their card into a surface the PSP owns — the Peach embedded widget, rendered in an iframe served by the PSP. The card data is captured inside that iframe and submitted straight to the PSP's backend. Your page and the ShiftxPay gateway are never in the path of the card itself.
What the gateway holds
After the PSP captures the card, it hands ShiftxPay only non-sensitive references:
- PSP payment-method tokens (
pm_...) — an opaque handle to the saved instrument, not the card. - Intent ids — the PSP's identifier for the in-progress payment.
- Card brand and last four digits — e.g.
visa/4242— enough to display "Visa ending 4242", and nothing more.
None of these can be turned back into a usable card number. That is the whole point: the data ShiftxPay holds is safe to store, log (minus secrets), and reason about without holding sensitive card data.
Four enforcement layers
The invariant is defended in depth, so a single mistake cannot quietly reintroduce card handling:
- No CDE component. There is no card-tokenizer or cardholder data environment anywhere in the system. Nothing is built that could accept or serve a raw card, so there is no path to misuse.
- PSP-direct surface only. The only checkout surface is PSP-hosted: the Peach embedded widget. There is no ShiftxPay-owned field that takes a card number.
RawCardGuardmiddleware. Every inbound request body is inspected at the HTTP edge. If it carries card-shaped fields (a PAN or CVC), it is rejected with422 raw_card_rejectedbefore any handler runs. Inbound PSP webhooks are exempt, since they are signature-verified and never carry raw cards.- CI tripwire. A build-time test fails the pipeline if any change reintroduces a raw-card path or a non-PSP card surface. The invariant cannot regress unnoticed.
What this means for you
As an integrator, you never send a card number to ShiftxPay, and you never need to. Collect the card only inside the PSP surface the SDK mounts, hand ShiftxPay the session and the tokens, and let the PSP own the sensitive data. If you ever find yourself with a PAN in your own code reaching for a ShiftxPay endpoint, stop — the guard will reject it, and the design is telling you to move that capture into the PSP surface instead.