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.
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:
- Card Details
- OTP
Used with Initiate Payment and Card Details APIs.
{
"card_no": "4111111111111111",
"cvv": "123",
"expiry": "12/25",
"card_holder_name": "Diana Prince"
}
| Field | Type | Description |
|---|---|---|
card_no | string | Full card number (no spaces or dashes) |
cvv | string | 3 or 4 digit security code |
expiry | string | Expiry date in MM/YY format |
card_holder_name | string | Name as printed on the card |
Pass the encrypted result as card_details with card_input_type set to card_pan.
Used with Complete Payment API.
{
"otp": "123456"
}
Pass the encrypted result as encrypted_otp (instead of the plain otp field).
Encrypting
Once you have the JSON payload:
- Convert the JSON object to a UTF-8 string
- Encrypt using RSA with PKCS1 v1.5 padding and the public key
- Base64-encode the encrypted result
Example requests:
- Card Payment
- OTP Submission
{
"order_id": "o_BrbcdefghAD7zg",
"payment_mode_code": "credit_card",
"card_input_type": "card_pan",
"card_details": "base64-encoded-encrypted-string..."
}
{
"transaction_id": "o_BrbcdefghAD7zg-260330120000",
"payment_flow": "otp",
"encrypted_otp": "base64-encoded-encrypted-string..."
}
Sample Code
- JavaScript (Browser)
- Python
- Java
// 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
};
import json
import base64
import requests
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
# Step 1: Fetch the public key
response = requests.get('https://api.nimbbl.tech/api/v2/get-nimbbl-public-key')
public_key_pem = response.json()['public_key']
# Step 2: Prepare the payload
card_payload = json.dumps({
"card_no": "4111111111111111",
"cvv": "123",
"expiry": "12/25",
"card_holder_name": "Diana Prince"
})
# Step 3: Encrypt with RSA PKCS1 v1.5
public_key = RSA.import_key(public_key_pem)
cipher = PKCS1_v1_5.new(public_key)
encrypted = cipher.encrypt(card_payload.encode('utf-8'))
card_details = base64.b64encode(encrypted).decode('utf-8')
# Step 4: Use in Initiate Payment request
payment_request = {
"order_id": "o_BrbcdefghAD7zg",
"payment_mode_code": "credit_card",
"card_input_type": "card_pan",
"card_details": card_details
}
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import java.util.Base64;
public class CardEncryption {
public static String encryptCardData(String publicKeyPem, String cardPayload)
throws Exception {
// Parse PEM public key
String keyContent = publicKeyPem
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s", "");
byte[] keyBytes = Base64.getDecoder().decode(keyContent);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(keySpec);
// Encrypt with RSA PKCS1 v1.5
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encrypted = cipher.doFinal(cardPayload.getBytes("UTF-8"));
return Base64.getEncoder().encodeToString(encrypted);
}
public static void main(String[] args) throws Exception {
// Step 2: Prepare the payload
String cardPayload = "{\"card_no\":\"4111111111111111\","
+ "\"cvv\":\"123\","
+ "\"expiry\":\"12/25\","
+ "\"card_holder_name\":\"Diana Prince\"}";
// Step 1: Fetch public key from API (use your HTTP client)
String publicKeyPem = "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----";
// Step 3: Encrypt
String cardDetails = encryptCardData(publicKeyPem, cardPayload);
// Step 4: Use cardDetails in Initiate Payment request
System.out.println("Encrypted card_details: " + cardDetails);
}
}