Encryption Example¶
All sensitive card data must be encrypted using your merchant RSA public key with RSA-OAEP (SHA-256) padding before sending to the API. Each field is encrypted individually and the result is Base64-encoded.
Fields requiring encryption: card number, CVV, expiration month, expiration year.
Your RSA public key is available in your merchant dashboard under Merchant details.
encrypt_field() {
echo -n "$1" | openssl pkeyutl -encrypt \
-pubin -inkey <(echo "$PUBLIC_KEY") \
-pkeyopt rsa_padding_mode:oaep \
-pkeyopt rsa_oaep_md:sha256 \
-pkeyopt rsa_mgf1_md:sha256 | base64
}
PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----"
ENCRYPTED_CARD_NUMBER=$(encrypt_field "4111111111111111")
ENCRYPTED_CVV=$(encrypt_field "123")
ENCRYPTED_EXP_MONTH=$(encrypt_field "12")
ENCRYPTED_EXP_YEAR=$(encrypt_field "2027")
Save as encrypt-card.mjs and run with node encrypt-card.mjs:
// encrypt-card.mjs
import { publicEncrypt, constants } from 'node:crypto';
const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----`;
function encryptField(plaintext) {
const encrypted = publicEncrypt(
{
key: PUBLIC_KEY,
padding: constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256',
},
Buffer.from(plaintext, 'utf-8')
);
return encrypted.toString('base64');
}
console.log('encrypted_card_number:', encryptField('4111111111111111'));
console.log('encrypted_cvv:', encryptField('123'));
console.log('encrypted_expiration_month:', encryptField('12'));
console.log('encrypted_expiration_year:', encryptField('2027'));
Save as EncryptCard.java and run with java EncryptCard.java (Java 11+):
// EncryptCard.java
import javax.crypto.Cipher;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class EncryptCard {
// Paste the Base64 body of your PEM key here (without BEGIN/END markers)
private static final String PUBLIC_KEY_BASE64 =
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...";
public static String encryptField(String plaintext) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(
PUBLIC_KEY_BASE64.replaceAll("\\s", "")
);
PublicKey publicKey = KeyFactory.getInstance("RSA")
.generatePublic(new X509EncodedKeySpec(keyBytes));
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey, new OAEPParameterSpec(
"SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT
));
byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encrypted);
}
public static void main(String[] args) throws Exception {
System.out.println("encrypted_card_number: " + encryptField("4111111111111111"));
System.out.println("encrypted_cvv: " + encryptField("123"));
System.out.println("encrypted_expiration_month: " + encryptField("12"));
System.out.println("encrypted_expiration_year: " + encryptField("2027"));
}
}
Using the Encrypted Values¶
Include the encrypted fields in your authorize request:
{
"payment_method": {
"type": "card",
"data": {
"encrypted_card_number": "<base64 encrypted value>",
"encrypted_cvv": "<base64 encrypted value>",
"encrypted_expiration_month": "<base64 encrypted value>",
"encrypted_expiration_year": "<base64 encrypted value>"
}
}
}
Field Format Requirements¶
Encrypt the plain-text value before Base64-encoding. The table below shows the expected plain-text format for each field.
| Field | Plain-text format | Example values | Notes |
|---|---|---|---|
encrypted_card_number |
Digits only, no spaces | 4111111111111111 |
|
encrypted_cvv |
Digits only | 123, 0987 |
|
encrypted_expiration_month |
Integer, no leading zero | 1, 12 |
Range: 1–12 |
encrypted_expiration_year |
2-digit or 4-digit year | 26, 2026 |
Must be current or future year |
Expiration Year Formats¶
Both 2-digit and 4-digit year formats are accepted:
Valid expiry year values
26 ✅ 2-digit short year
2026 ✅ 4-digit full year
Invalid expiry year values
2026-01 ❌ Date string — not accepted
01/26 ❌ MM/YY format — not accepted
Server-side only
Card encryption must happen on your server. Never expose the RSA public key or raw card data in the browser.