Security & PCI

The security model in one sentence: card data never touches your servers, every secret has exactly one place to live, and everything that crosses a boundary is encrypted and signed.

Built to PCI DSS Level 1 standards

Finscale's platform is built to PCI DSS Level 1 standards — the controls the standard prescribes for the highest transaction volumes: segmented cardholder-data environments, quarterly scanning, continuous logging and monitoring, strict key-management ceremony, and documented change control.

For you, the practical effect is scope reduction. Because your servers never see cardholder data (see tokenization below), your integration is designed to qualify for the lightest self-assessment track — SAQ A rather than SAQ D. Your annual PCI conversation gets short.

Your PCI scope: SAQ A vs SAQ D

Every merchant that accepts cards attests to PCI DSS, usually through a Self-Assessment Questionnaire (SAQ). Which questionnaire applies is decided by one thing: how card data flows through your systems. The two ends of the spectrum:

SAQ ASAQ D
Who it's for Merchants that fully outsource cardholder-data handling — card data never touches your servers, your code, or your pages' scripts. Merchants whose systems store, process, or transmit PANs themselves.
What you attest to A short questionnaire: the integrity of the pages that hand off to the payment provider, and how you manage that provider. The full control set of the standard — network segmentation, vulnerability scanning, logging and monitoring, key management, physical controls. Effectively running your own cardholder-data environment.
Finscale path Hosted checkout or hosted fields — both keep entry on Finscale-served surfaces. Accepting PANs server-side — a path that doesn't exist on Finscale: the live API refuses raw card numbers by design.

Between the two sits SAQ A-EP, for merchants whose own page scripts touch card data even though their servers don't. This is why hosted fields are iframes served from Finscale's domain rather than JavaScript running in your page: your scripts never see the card inputs, keeping the integration on the SAQ A side of that line.

Who decides Your SAQ level is determined with your acquirer or assessor — Finscale gives you the architecture that keeps cardholder data out of your environment, and documentation of it for your assessment. "Designed to qualify" is the honest phrasing: the attestation is yours to make.

Tokenization — card data skips your stack

In live mode, any request carrying a raw card number is rejected with an invalid_request_error, by design (test mode accepts only the published test PANs, which are not cardholder data). There are exactly two ways a real card reaches Finscale, and both bypass your servers:

  1. Hosted checkout

    The customer types their card on pay.finscale.dev pages served by Finscale. Your systems only ever see the resulting payment id.

  2. Finscale fields (hosted fields)

    For custom checkouts, card inputs are isolated iframes served from Finscale's domain — hosted fields. Card data travels directly from the customer's browser to Finscale's vault, which returns a one-time token (tok_…) — the only thing your frontend passes to your backend. Your page composes the look; it never touches the values.

  3. Vault → provider

    At authorization time, Finscale's vault injects the card details into the provider request — whichever provider routing selects, on every failover attempt. Providers can change; the token is yours and stays stable.

The invariant Card data never touches your servers — not in transit, not in logs, not in crash dumps. There is no configuration in which the live-mode API accepts a PAN from your backend; the only exception anywhere is the fixed set of test cards in test mode.

PAN handling rules

What you may keep, per card data element — and what the API gives you so you never need the dangerous ones:

Data elementMay your systems hold it?What Finscale gives you instead
PAN (the card number) No. Storing PANs puts you in SAQ D territory and makes you a breach target. The live API refuses raw PANs, so the question never arises. A stable token (tok_… / pm_…) plus last4 and brand in payment_method_details.card.
Expiry date Yes — not sensitive on its own, and useful for "card expiring" flows. exp_month / exp_year on the payment object.
Cardholder name Yes — ordinary personal data; handle under GDPR like any other customer field. Whatever you collected at checkout.
CVV / CVC Never — by anyone, in any form, not even encrypted. The standard forbids storing it after authorization; Finscale's vault discards it once the authorization completes. Nothing — the API never returns it. Only the cvv_result check outcome surfaces, on risk.checks.

Two practical corollaries:

  • The payment object is safe to log and store. It carries last4, brand, and expiry — nothing on it is a PAN, so your logs, database, and analytics stay out of PCI scope by construction.
  • Display at most brand + last4 in receipts, dashboards, and support tools ("Visa ····4242"). Since last4 is all the API returns, over-displaying isn't possible by accident.

Network tokens

For saved cards (pm_… instruments), Finscale's vault goes one step beyond its own tokenization: where the card's network supports it, the vault provisions a network token — a scheme-issued stand-in for the PAN, scoped to this merchant relationship and accompanied by a one-time cryptogram on each transaction. Authorizations then travel without the real card number end to end.

  • Cards update themselves. When a card is reissued, replaced after loss, or gets a new expiry, the network re-points the token at the new credentials. Your stored pm_… id keeps working — no "your card on file expired" emails campaign, fewer failed renewals.
  • Issuers approve more. A network token with a valid cryptogram is a stronger signal than a vaulted PAN — issuers treat it accordingly, which shows up as authorization-rate lift on recurring and stored-credential traffic.
  • Exposure shrinks further. A network token intercepted anywhere is useless outside this merchant context and without a fresh cryptogram.

Provisioning is automatic and invisible in the API: your ids don't change, and routing decides per attempt whether the network token or the vaulted credential is used with the selected provider. There is nothing to integrate — it's part of what the vault does with a stored card.

Encryption in transit and at rest

  • In transit: TLS 1.2+ is required on every connection — API, dashboard, webhooks, and the provider-facing side. Plain HTTP is refused, not redirected, on API endpoints. Webhook endpoints must be HTTPS.
  • At rest: databases, backups, and object storage are encrypted with AES-256. Cardholder data is additionally encrypted at field level inside the vault, separately from the storage-layer encryption.
  • In logs: PANs, CVCs, and bank credentials are structurally excluded from logging — redaction happens at the serialization layer, not by pattern-matching after the fact.

Key hierarchy

Every key has one job, one scope, and a rotation story:

KeyScopeHandling
Root keys Platform Generated and held in HSM-backed key management; never exportable. Everything below is envelope-encrypted under them.
Data-encryption keys Per service / data class Rotated automatically every 90 days; old ciphertext re-wrapped on rotation.
Vault field keys Cardholder data Separate hierarchy from general data keys; access limited to the authorization path.
API secret keys (sk_live_••••••••••••) Your account Stored hashed — shown once at creation, irretrievable after. Rotate from the dashboard with a grace window so old and new overlap.
Webhook secrets (whsec_…) Per endpoint Independent per endpoint, so rotating one integration never breaks another. See rotation pattern.

On your side: secret keys are server-side only — never in browsers, mobile apps, or repositories. Use publishable keys (pk_test_… / pk_live_…) in client code; they can tokenize but never move money. See Authentication.

Webhook signing

Every webhook delivery is signed with a per-endpoint secret: Finscale-Signature: t=…,v1=…, where v1 is an HMAC-SHA256 over the timestamp and the raw body. Verify the signature in constant time and enforce the 5-minute timestamp tolerance before parsing anything. Verification code in Node and Python is in Webhooks — verifying signatures.

Data residency

Finscale stores and processes payment data in the European Union, across redundant EU regions. Backups and disaster-recovery replicas remain inside the EU. Finscale operates under GDPR: data-processing agreements are available for merchants, sub-processors are contractually bound to the same residency commitments, and personal data is retained only as long as payment regulation requires.

Non-EU rails (for example ACH, or SEA wallets) require passing transaction data to the provider operating that rail — that's the payment itself, not a residency exception for stored data.

Responsible disclosure

Found a vulnerability? We want it — reported privately, before anyone else has it.

  • Report it privately with a reproducible description. Include request ids (req_…) where relevant.
  • You'll get an acknowledgement within 2 business days and a triage verdict within 7.
  • We ask for coordinated disclosure: give us 90 days before publishing, and don't access data that isn't yours — test against test mode with your own sk_test_ keys wherever possible.
  • Good-faith research within these rules will never trigger legal action from Finscale.
Scope note This page describes the controls Finscale builds to. It intentionally makes no third-party certification claims — current compliance documentation is available under NDA through your Finscale representative.