Before deploying CityPay Elements to production, ensure the following security controls are in place.
These controls are designed to:
- maintain a reduced PCI DSS scope
- protect cardholder data and authentication flows
- support PCI DSS v4 expectations and common security reviews
They apply whether you are using Direct or Proxy (middleware) integration modes.
Credential handling
API Keys
- API Keys must be stored and used on the backend only.
- API Keys must never be exposed in client-side code, build artefacts, or logs.
- Keys should be rotated periodically and revoked when no longer required.
- Test and production API Keys must be strictly separated.
Public Keys
- Public Keys are safe to embed in browser applications.
- Public Keys are used only to initialise the Elements SDK.
- Public Keys do not grant access to merchant APIs or sensitive operations.
- Separate Public Keys should be used for test and production environments.
Session Tokens
- Session Tokens are short-lived, intent-scoped credentials generated by your backend.
- A Session Token is always associated with a specific Payment Intent.
- Session Tokens authorise the browser to perform limited client-side actions for that intent.
- Session Tokens must be generated server-side and delivered to the browser securely.
- Session Tokens must not be reused across intents or sessions.
Opaque Intent Keys
- Payment Intents expose an opaque key used internally to bind browser and backend operations.
- Opaque keys must be treated as confidential operational identifiers.
- Opaque keys must not be logged or exposed beyond their intended scope.
Transport security
- All payment-related traffic must use HTTPS.
- HTTP Strict Transport Security (HSTS) should be enabled on production domains.
- Mixed-content requests must not be permitted.
Content Security Policy (CSP)
A restrictive Content Security Policy must be configured to explicitly allow CityPay resources while denying all others by default.
At a minimum:
- CityPay domains must be allow-listed for:
script-srcframe-srcconnect-src
- All other sources should be denied unless explicitly required.
Illustrative example (adjust to your environment):
Content-Security-Policy:
default-src 'none';
script-src 'self' https://*.citypay.com;
frame-src https://*.citypay.com;
connect-src 'self' https://*.citypay.com;
Additionally:
- Configure
frame-ancestorsto prevent unauthorised embedding. - Avoid wildcarding unrelated third-party domains.
Iframe and embedding controls
- CityPay-hosted iframes must be allowed to render without sandbox restrictions that interfere with payment flows.
- Merchant pages should be protected from hostile embedding using
frame-ancestorsor equivalent controls. - Applications must not attempt to inspect iframe contents or intercept
postMessagetraffic.
Backend endpoint hardening
For any middleware or proxy endpoints:
- API Keys must never be exposed to the browser.
- Endpoints should accept path-only URLs by default.
- Absolute URLs should be explicitly whitelisted if external forwarding is required.
- Input payloads must be validated strictly.
- Authentication and authorisation must be enforced.
- Rate limiting should be applied to payment-related routes.
Session binding and intent isolation
- Every browser session must be bound to a single Payment Intent via a Session Token.
- Client-side operations must be rejected if the Session Token does not match the intended Payment Intent.
- Expired or invalid Session Tokens must fail safely and require re-issuance from the backend.
- Do not allow browser-driven operations without a valid Session Token.
Idempotency and retries
- Always propagate the SDK-generated
idempotencyKeyto backend → CityPay API calls. - The same idempotency key must be reused for retries of the same logical attempt.
- Idempotency keys should be stored or cached for the duration of the payment flow.
- New idempotency keys should be generated only when starting a new attempt.
Logging and data handling
- Card numbers (PAN), CVV/CVC values, and magnetic-stripe data must never be logged.
- 3DS challenge payloads and authentication artefacts must never be logged.
- Session Tokens and opaque intent keys must not be logged.
- Tokens and intent identifiers should be treated as sensitive operational data.
- Logs should be correlated using:
intentIdidempotencyKey- Elements event names (
cpe:*) - Access to logs must be restricted and retention policies defined.
Frontend integration hygiene
- Elements must be initialised client-side only and never during server-side rendering.
- Mount containers must exist and be visible before initialisation.
- Payment submission controls should be disabled during
cpe:processing:start. - Errors emitted via
cpe:errorshould be handled gracefully with user-safe messaging. - No custom handling of raw card data should exist outside Elements components.
Environment separation
- Test and production environments must be fully isolated.
- Separate API Keys, Public Keys, and endpoints must be used for each environment.
- Production frontends must never reference test credentials or services.
Apple Pay Production Readiness
If you are using Apple Pay:
- Ensure your production domain is registered and whitelisted with CityPay.
- Verify that your domain association file is hosted correctly at
/.well-known/apple-developer-merchantid-domain-association. - Test the flow in an Apple-supported browser (Safari) on a compatible device.
Final validation before launch
Before enabling production traffic:
- Complete an end-to-end payment using a real 3DS challenge.
- Verify frictionless and challenge authentication flows.
- Confirm correct behaviour for declines and retries.
- Ensure refunds and captures are correctly linked to the originating Payment Intent.
- Review CSP reports and browser console output for warnings or violations.
Shared responsibility model
CityPay is responsible for:
- hosted payment components
- tokenisation
- authentication orchestration (3DS)
- Payment Intent state management
- payment processing infrastructure
You remain responsible for:
- securing your application and backend systems
- protecting credentials and Session Tokens
- enforcing transport and browser security controls
- implementing Elements in accordance with this documentation