Payload Encryption
Encrypt API request bodies before sending them to PayoFlux, and decrypt encrypted responses on your server. Applies to all payment API endpoints.
Overview
PayoFlux supports end-to-end payload encryption for server-to-server integrations. Instead of sending plain JSON payment data over the wire, you encrypt the full request body on your server, send the ciphertext to PayoFlux, and receive an encrypted response that you decrypt locally.
- Build your request payload as documented on each API page (e.g. Charge, Refunds, Status).
- Serialize the payload to a JSON string and encrypt it with your Encryption Key.
- Send the encrypted string wrapped in a
payloadfield to the API endpoint. - PayoFlux decrypts the request, processes the payment, and returns an encrypted response.
- Decrypt the response on your server before using the result.
Important
Encryption Key
Each merchant receives a unique Encryption Key when onboarding is complete. You can view and copy it from the merchant dashboard at any time.
Where to find your key
- Sign in to the PayoFlux merchant dashboard
- Complete merchant onboarding if you have not already
- Go to Config (Settings → API Configuration) in the sidebar
- Copy the Encryption Key shown alongside your Test and Live secret keys
Example Encryption Key format
a1b2c3d4e5f6789012345678abcdef01a1b2c3d4e5f6789012345678abcdef01Important
Algorithm & Format
PayoFlux uses AES-256-CBC for payload encryption and decryption.
| Property | Value |
|---|---|
| Algorithm | AES-256-CBC |
| Key derivation | 64-character hex string decoded to 32 raw bytes (legacy 32-char UTF-8 keys still supported) |
| IV | 16 random bytes, unique per encryption operation |
| Ciphertext encoding | Hexadecimal |
| Output format | {iv_hex}:{ciphertext_hex} |
Note
Encrypting Requests
Before calling any payment API endpoint, encrypt your JSON request body and wrap it in a payload field.
Step-by-step
- Build the JSON object exactly as shown on the relevant API page (Charge, Refunds, etc.).
- Call
JSON.stringify()(or equivalent) to produce a compact JSON string. - Encrypt the string using AES-256-CBC with your Encryption Key.
- Format the result as
{iv_hex}:{ciphertext_hex}. - POST to the API endpoint with body
{"payload": "<encrypted_string>"}.
Encrypted request body
Request body
{
"payload": "3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a:8e4f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0"
}Required headers
Headers
Content-Type: application/json
Authorization: Bearer your_api_key_or_sandbox_api_keyImportant
Example cURL
Encrypted charge request
curl -X POST https://api.payoflux.com/api/test/charge \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_api_key_or_sandbox_api_key" \
-d '{
"payload": "3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8:8e4f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a"
}'Decrypting Responses
Every authenticated payment API response is encrypted — including success, declined/failed, blocked, and validation errors. Decrypt the payload field to obtain the standard response object documented on each API page.
Encrypted response body (success)
Response body
{
"success": true,
"payload": "7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7:4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8"
}Encrypted response body (declined / error)
When the payment is declined or the request fails validation, the outer envelope still uses a payload field, but success is false:
Encrypted declined/error wire format
{
"success": false,
"payload": "<iv_hex>:<ciphertext_hex>"
}After decryption — success
Decrypted success response (Charge)
{
"success": true,
"status": "SUCCESS",
"data": {
"amount": 100,
"currency": "USD",
"merchantOrderId": "ORD-12345",
"transactionId": "FP260231SJWKL80027"
}
}After decryption — declined
Decrypted declined response (Charge)
{
"success": false,
"status": "FAILED",
"message": "Transaction declined by issuer",
"error": {
"code": "DECLINED",
"message": "Transaction declined by issuer"
},
"data": {
"amount": 100.5,
"currency": "USD",
"merchantOrderId": "ORD-12345",
"transactionId": "FP260231SJWKL80027",
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"webhookUrl": "https://your-domain.com/webhook"
}
}Note
payload field and decrypt it before parsing. Do not assume declined or validation errors arrive as plain JSON — they use the same encryption contract as success responses when your API key is valid.Important
Code Examples
Complete examples showing how to encrypt a request, call the API, and decrypt the response. Select a language tab below.
Encrypt & decrypt
const crypto = require('crypto');
/**
* Derive a 32-byte AES key from the merchant Encryption Key.
* 64-char hex keys are decoded directly; legacy 32-char keys are UTF-8 padded.
*/
function deriveKey(encryptionKey) {
if (/^[0-9a-fA-F]{64}$/.test(encryptionKey)) {
return Buffer.from(encryptionKey, 'hex');
}
return Buffer.from(
encryptionKey.padEnd(32, '0').substring(0, 32),
'utf-8',
);
}
/**
* Encrypt a plain-text JSON string using AES-256-CBC.
* Returns "{iv_hex}:{ciphertext_hex}".
*/
function encryptPayload(plainText, encryptionKey) {
const keyBuffer = deriveKey(encryptionKey);
const iv = crypto.randomBytes(16); // fresh IV per request
const cipher = crypto.createCipheriv('aes-256-cbc', keyBuffer, iv);
let encrypted = cipher.update(plainText, 'utf-8', 'hex');
encrypted += cipher.final('hex');
return `${iv.toString('hex')}:${encrypted}`;
}
/**
* Decrypt an encrypted payload string back to plain text.
*/
function decryptPayload(encryptedPayload, encryptionKey) {
const keyBuffer = deriveKey(encryptionKey);
const [ivHex, encrypted] = encryptedPayload.split(':');
if (!ivHex || !encrypted) {
throw new Error('Invalid encrypted payload format');
}
const iv = Buffer.from(ivHex, 'hex');
const decipher = crypto.createDecipheriv('aes-256-cbc', keyBuffer, iv);
let decrypted = decipher.update(encrypted, 'hex', 'utf-8');
decrypted += decipher.final('utf-8');
return decrypted;
}
// 1. Load your Encryption Key from environment (Dashboard → Config)
const encryptionKey = process.env.PAYOFLUX_ENCRYPTION_KEY;
// 2. Build the request body exactly as documented on the API page
const requestBody = {
merchantOrderId: 'ORD-12345',
payment: { amount: 100, currency: 'USD' },
card: {
number: '4111111111111111',
expiryMonth: 12,
expiryYear: 2030,
cvv: '123',
holderName: 'John Doe',
},
customer: {
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
ip: '185.23.44.91',
},
billing: {
addressLine1: '12, Hill',
city: 'Nevada',
state: 'Nevada',
country: 'US',
postalCode: '12345',
},
callback: {
webhookUrl: 'https://your-domain.com/webhook',
returnUrl: 'https://your-domain.com/payment/callback',
},
};
// 3. Encrypt the JSON string and wrap it in a payload field
const encrypted = encryptPayload(JSON.stringify(requestBody), encryptionKey);
// 4. Send the encrypted request to PayoFlux
const response = await fetch('https://api.payoflux.com/api/test/charge', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer your_api_key_or_sandbox_api_key',
},
body: JSON.stringify({ payload: encrypted }),
});
// 5. Decrypt the encrypted response payload field
const { payload: encryptedResponse } = await response.json();
const decrypted = JSON.parse(decryptPayload(encryptedResponse, encryptionKey));
console.log(decrypted);Applies To
Security Best Practices
- Do not share your API key or Encryption Key with anyone — including in email, chat, or with untrusted third parties.
- Perform all encryption and decryption on your backend server — never in the browser or mobile app.
- Store the Encryption Key in environment variables or a dedicated secrets manager.
- Use HTTPS for all API calls; encryption protects the payload content, not the transport layer alone.
- Rotate keys immediately if you suspect the Encryption Key has been compromised — contact support to regenerate.
- Log decrypted payloads only in secure, PCI-compliant environments; never log full card numbers or CVV.
Critical
400 Bad Request error. Always encrypt before sending when payload encryption is enabled for your merchant account.