Skip to content

Payment methods · Cards

Encrypt card fields with your RSA public key before you send them

Encrypt the card number, CVV, expiration month and expiration year one by one with RSA-OAEP (SHA-256), then Base64-encode each result. Your RSA public key is under Merchant details in your merchant dashboard.

Server-side only. Card encryption must happen on your server. Never expose the RSA public key or raw card data in the browser.

1 Merchant details Your RSA public key in the merchant dashboard
2 Your server Encrypts each field · RSA-OAEP (SHA-256)
3 Altitude Pay API Receives the four Base64 values in the authorize request
Altitude Pay Your systems

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.