Skip to main content

Overview

Partners with PCI DSS compliance can retrieve sensitive card data (PAN, CVV, expiry) via a direct API call. The response is RSA-encrypted with your public key — Contro never exposes card data in plaintext.

Prerequisites

  1. Your organization must be PCI DSS compliant
  2. An RSA-4096 (or larger) key pair
  3. Your public key uploaded via the partner dashboard https://partner.contro.me/settings

Step 1: Generate an RSA key pair

# Generate 4096-bit RSA private key
openssl genrsa -out private_key.pem 4096

# Extract the public key
openssl rsa -in private_key.pem -pubout -out public_key.pem
Keep your private key secure. Contro only stores your public key and never has access to your private key.

Step 2: Upload your public key

Upload your PEM-encoded public key via the dashboard Settings page, or programmatically:
curl -X PUT https://api.contro.me/v1/dashboard/partner/settings/rsa-key \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "rsaPublicKey": "-----BEGIN PUBLIC KEY-----\nMIICIjAN...\n-----END PUBLIC KEY-----"
  }'

Step 3: Call the reveal endpoint

curl https://api.contro.me/v1/partner/cards/{card_id}/reveal \
  -H "Authorization: Bearer sk_live_YOUR_KEY"
Response:
{
  "data": "base64-encoded-RSA-encrypted-payload..."
}

Step 4: Decrypt the response

The data field is a Base64-encoded RSA-OAEP-SHA256 ciphertext. Decrypt with your private key:
import { privateDecrypt, constants } from "node:crypto";
import { readFileSync } from "node:fs";

const privateKey = readFileSync("private_key.pem", "utf-8");
const encrypted = Buffer.from(response.data, "base64");

const decrypted = privateDecrypt(
  {
    key: privateKey,
    padding: constants.RSA_PKCS1_OAEP_PADDING,
    oaepHash: "sha256",
  },
  encrypted,
);

const cardData = JSON.parse(decrypted.toString("utf-8"));
// { data: { cardNumber: "4111...", cvv: "123", expiryDate: "12/2030" } }
# Using OpenSSL CLI
echo "BASE64_DATA" | base64 -d | openssl pkeyutl -decrypt \
  -inkey private_key.pem -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256

Sandbox testing

In sandbox mode (sk_test_ keys), the endpoint returns encrypted test data:
FieldValue
cardNumber4000000000000000
cvv123
expiryDate12/2030
If you haven’t uploaded an RSA key, sandbox mode uses a built-in sandbox key pair automatically. You can use the corresponding sandbox private key to verify your decryption logic.
In live mode, you must have an RSA public key configured. The endpoint returns a 400 error if no key is set.

Security considerations

  • Card data is encrypted end-to-end — Contro’s API response is encrypted with your key before leaving the server
  • Key rotation: Replacing your public key takes effect immediately. Coordinate rotation to avoid decryption failures during the swap window