Architecture
The browser encrypts and decrypts. Your backend only forwards encrypted values and never sees plaintext.- Read card details or PIN
- Set a PIN
The browser creates a single-use session key and sends only its encrypted form through your backend.
Backend routes
The examples on this page use/api/payment-cards/... for routes on your own backend. Your backend maps each one to a Partner API route, without decrypting or changing the sensitive payload.
Encryption contract
Use these values exactly.Fetch the current keys immediately before each sensitive operation. Select from
encryption_keys. Don’t build against the top-level public_key field, which exists only for compatibility.Browser helpers
These helpers use the Web Crypto API, which works only in a secure browser context over HTTPS. The examples in the sections that follow build on them.TypeScript
Retrieve card details
1
Get the current keys
Ask your backend for the current response from
GET /pci/public-key.2
Create a fresh session
Call
createSession. Keep aesKey only in browser memory.3
Request the encrypted details
Send
encrypted_key and key_id to your backend. Your backend URL-encodes them and calls GET /pci/cards/{card_id}/details with its Partner API token.4
Forward the response unchanged
Your backend returns the encrypted response to the UI as-is.
5
Decrypt in the browser
Decrypt
card_number and cvv with the returned iv. expiration_date is returned in plaintext.TypeScript
Retrieve the PIN
PIN retrieval uses the same key setup, but callsGET /pci/cards/{card_id}/pin. Decrypt encrypted_pin, then parse the result as an ISO 9564 format 2 PIN block.
TypeScript
Create a new session for the PIN request, even if the user has just retrieved card details.
Set a PIN
Accept a PIN of 4 to 6 digits in the UI and ask the user to confirm it. Convert it to an ISO 9564 format 2 PIN block, encrypt it with a fresh AES key and IV, and send only the encrypted request to your backend.TypeScript
POST /pci/cards/{card_id}/pin and returns only the result of the operation.
Safeguards
Apply all of these before going live.Backend
Backend
- Authenticate the end user and check that they may access the requested
card_idbefore every proxy call. - Keep the Partner API access token on your backend. Never return it to the browser, and never accept a tenant or partner scope from the UI.
- Don’t decrypt card data or PINs on your backend. Forward encrypted responses without changing them.
Logging and caching
Logging and caching
- Redact query strings and request and response bodies for these routes from application, proxy, tracing, analytics, and error logs.
- Return
Cache-Control: no-store, and exclude these routes from browser, CDN, reverse-proxy, and service-worker caches.
UI
UI
- Keep session keys, decrypted values, and PIN input only in memory. Never write them to local storage, session storage, IndexedDB, persisted app state, crash reports, or analytics.
- Show sensitive values only after an explicit user action, and only briefly. Mask them again when the page loses focus, the user navigates away, or the display timer runs out.
- Clear PIN inputs and references to decrypted values and keys after success, failure, or cancellation.
- Turn off session replay and DOM capture on every view that can show sensitive card data.
Next step
Handle 3DS challenges
Respond to 3D Secure verification during online payments.