PIN management
Let cardholders set or reset the PIN of their physical card, without your servers ever handling the digits in the clear.
A PIN is used where a card is presented at a terminal or a machine, so it belongs to a physical card. Virtual cards don't have one.
Before you begin
You'll need:
- An
activephysical card. See issuing a physical card. Activate the card first: a card that isn'tactiveis refused. - An app that can encrypt on the cardholder's device with RSA-OAEP using SHA-256.
- The
cards:secretsscope on your credential. This scope isn't enabled by default.
How it works
The cardholder types their PIN into your app. The app encrypts it on the device to a short-lived key we issue, and your backend passes the ciphertext to us. Your servers only ever hold something they can't read.
The same two calls set a PIN for the first time and reset an existing one.
Steps
1. Get an encryption key
Call Get a PIN encryption key when the cardholder is about to enter their PIN, not when the screen loads. The key is for one card, expires after a few minutes, and opens one PIN: once it has been sent with a PIN, whatever the outcome, it can't be used again.
2. Encrypt the PIN on the device
Encrypt the PIN, as its digits, to the key's public key with RSA-OAEP using SHA-256, and encode the result as base64. Do it on the cardholder's device and send only the ciphertext to your backend. A PIN that your servers handle as readable text puts those servers in PCI DSS scope.
Validate the PIN on the device before you encrypt it. We only require digits, in
the length the key response gives as pin_length. Every other rule is yours,
such as refusing repeated digits or sequences, so the cardholder is told at once
and nothing weak is sent. See PCI DSS scope.
3. Set the PIN
Call Set a PIN with the key_id and the
encrypted PIN. A successful call returns nothing.
Never write the PIN, encrypted or not, to a log, an analytics event, web storage or a support ticket.
Verifying
- Setting a PIN returns no content, and no response carries a PIN.
- A key that is unknown, has expired or was used already is refused. Get a new one.
- A PIN that isn't digits of the right length, or that can't be decrypted with the
key you were given, is refused with
pin_invalid. We apply no other rule. - A virtual card, or a card that isn't
active, is refused withcard_invalid_state. - A credential without
cards:secretsreturnsinsufficient_scope.
Common errors
| Status | code | Fix |
|---|---|---|
400 | missing_parameter | key_id or encrypted_pin wasn't sent |
400 | invalid_parameter | The key is unknown, has expired or was already used. Get a new key |
403 | insufficient_scope | The credential doesn't have cards:secrets |
404 | card_not_found | The card doesn't exist, or belongs to another organization |
404 | not_found | This program can't take a PIN by a call, so the route isn't available |
422 | pin_invalid | The PIN isn't the right length, isn't digits, or wasn't encrypted to the key you were given |
422 | card_invalid_state | The card is virtual, or isn't active. A PIN is set on an active physical card |
422 | card_closed | The card is closed. Issue a new card |
422 | program_not_configured | The program isn't set up to take a PIN. Raise it with your account contact |
502 | processor_permission_denied | The program isn't approved to set PINs at the processor. Send us the request_id |
502 | processor_unavailable | The outcome is unknown: the PIN may or may not be set. Don't resend on your own; ask the cardholder to try again, with a new key |