Skip to main content

Encrypting Sensitive Data

When making direct API calls to Nimbbl (not using a Nimbbl SDK), certain sensitive data must be RSA-encrypted before submission. This applies to card details (Initiate Payment, Card Details APIs) and OTP values (Complete Payment API).

This guide covers RSA encryption (asymmetric, for sensitive fields). For AES-GCM payload encryption (symmetric, for full API request/response payloads), see the Using Encrypted Payloads guide.

PCI DSS Compliance

Merchants who are not PCI DSS certified must encrypt card data on the client side (browser or mobile app) so that raw card numbers, CVV, and expiry dates never pass through or are stored on their servers.

Nimbbl will regularly audit integrations for compliance, including before go-live approval. Non-compliant integrations will not be approved for production.

If you use a Nimbbl checkout SDK, card encryption is handled automatically — this guide is only for merchants making direct API calls.

Fetching the Public Key

Call the Get Public Key endpoint to retrieve the RSA public key. This endpoint requires no authentication.

GET https://api.nimbbl.tech/api/v2/get-nimbbl-public-key

Response:

{
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki...\n-----END PUBLIC KEY-----"
}

The key is rotated periodically. Cache it for performance, but refresh it if encryption or payment processing fails with an encryption-related error.

Preparing the Payload

Format the sensitive data as a JSON object depending on what you're encrypting:

Used with Initiate Payment and Card Details APIs.

{
"card_no": "4111111111111111",
"cvv": "123",
"expiry": "12/25",
"card_holder_name": "Diana Prince"
}
FieldTypeDescription
card_nostringFull card number (no spaces or dashes)
cvvstring3 or 4 digit security code
expirystringExpiry date in MM/YY format
card_holder_namestringName as printed on the card

Pass the encrypted result as card_details with card_input_type set to card_pan.

Encrypting

Once you have the JSON payload:

  1. Convert the JSON object to a UTF-8 string
  2. Encrypt using RSA with PKCS1 v1.5 padding and the public key
  3. Base64-encode the encrypted result

Example requests:

{
"order_id": "o_BrbcdefghAD7zg",
"payment_mode_code": "credit_card",
"card_input_type": "card_pan",
"card_details": "base64-encoded-encrypted-string..."
}

Sample Code

// Using JSEncrypt library (https://github.com/nicke920/jsencrypt)
// Include via: <script src="https://cdn.jsdelivr.net/npm/jsencrypt/bin/jsencrypt.min.js"></script>

async function encryptCardData(cardData) {
// Step 1: Fetch the public key
const response = await fetch('https://api.nimbbl.tech/api/v2/get-nimbbl-public-key');
const { public_key } = await response.json();

// Step 2: Prepare the payload
const payload = JSON.stringify({
card_no: cardData.cardNumber,
cvv: cardData.cvv,
expiry: cardData.expiry, // MM/YY format
card_holder_name: cardData.name
});

// Step 3: Encrypt with RSA PKCS1 v1.5
const encrypt = new JSEncrypt();
encrypt.setPublicKey(public_key);
const encrypted = encrypt.encrypt(payload);

return encrypted; // Base64-encoded encrypted string
}

// Usage
const cardDetails = await encryptCardData({
cardNumber: '4111111111111111',
cvv: '123',
expiry: '12/25',
name: 'Diana Prince'
});

// Step 4: Pass in Initiate Payment request
const paymentRequest = {
order_id: 'o_BrbcdefghAD7zg',
payment_mode_code: 'credit_card',
card_input_type: 'card_pan',
card_details: cardDetails
};