Checksum Authentication Guide
To guarantee data integrity and authenticity for all communications, Exirom implements a checksum verification mechanism using the HMAC-SHA256 algorithm with your merchantSecret.
This checksum ensures:
- The request/callback data has not been altered in transit.
- The sender is genuinely authenticated using the shared secret.
#When to Use the Checksum
| Direction | Location of Checksum | Fields Used (in order) |
|---|---|---|
| Request → Exirom API | Body field (checksum) | accountId → amount → currency → requestId |
| Callback → Merchant | HTTP Header (X-Checksum) | accountId → orderAmount → orderCurrency → transactionId |
#How to Generate the Checksum
#From Merchant to Exirom (Request)
Use the following fields in this exact order as strings:
accountId | amount | currency | requestId
#From Exirom to Merchant (Callback)
Use the following fields in this exact order as strings:
accountId | orderAmount | orderCurrency | transactionId
#Apply HMAC-SHA256
- Use the pipe character (
|) as a delimiter. - Sign the concatenated string using HMAC-SHA256 with your
merchantSecret. - Base64-encode the resulting hash before sending.
#Example: Request
Data:
accountId: merchant_001
amount: 10.00
currency: USD
requestId: req-789123
Checksum string:
merchant_001|10.00|USD|req-789123
Send in body:
{
"accountId": "merchant_001",
"amount": "10.00",
"currency": "USD",
"requestId": "req-789123",
"checksum": "<Base64EncodedChecksum>"
}#Example: Callback
Data:
accountId: merchant_001
orderAmount: 200.0
orderCurrency: USD
transactionId: tx-456789
Checksum string:
merchant_001|200.0|USD|tx-456789
Sent as header:
X-Checksum: <Base64EncodedChecksum>
#How to Format the amount Field
Use the exact decimal string as it appears in the request body — no conversion needed.
#✅ Correct Format
| Currency | Request amount | amount for checksum |
|---|---|---|
| USD | "10.00" | "10.00" |
| EUR | "25.50" | "25.50" |
| GBP | "99.99" | "99.99" |
| JPY | "500" | "500" |
| ILS | "3.75" | "3.75" |
💡 Use the same string value in the checksum as you send in the request body — no multiplication or unit conversion required.
🚧 Important – Amount Type and Checksum Validation
The
amountfield uses different numeric representations depending on the message direction:
- Requests:
amountis sent as a string (e.g."200.00")- Callbacks:
amountis returned as a numeric value (e.g.200.0)Exirom processes amounts using native numeric types. As a result, decimal formatting (such as trailing zeros) is not preserved in callbacks.
Example:
- Request:
"200.00"- Callback:
200.0When validating or generating a callback checksum, always use the exact
amountvalue received in the callback payload.Do not reuse or reformat the original request amount, as this may cause checksum mismatches.
#Validation Rules
Checksum validation ensures every request and callback is trusted, tamper-free, and authentically signed. Requests without a valid checksum field are rejected with 400 BadRequest. Callbacks with an invalid X-Checksum header should be ignored by your system.
const crypto = require('crypto');
function generateChecksum(fields, merchantSecret) {
const data = fields.join('|');
return crypto
.createHmac('sha256', merchantSecret)
.update(data)
.digest('base64');
}
// Request checksum
const requestChecksum = generateChecksum(
['merchant_001', '10.00', 'USD', 'req-789123'],
'your_merchant_secret'
);
// Callback verification
function verifyCallbackChecksum(payload, receivedChecksum, merchantSecret) {
const fields = [payload.accountId, payload.orderAmount, payload.orderCurrency, payload.transactionId];
const computed = generateChecksum(fields, merchantSecret);
return crypto.timingSafeEqual(
Buffer.from(computed),
Buffer.from(receivedChecksum)
);
}#Common Mistakes
| Mistake | Symptom | Fix |
|---|---|---|
Converting amount to minor units ("1000") | Checksum mismatch | Use the decimal string as-is: "10.00" |
| Wrong field order | Checksum mismatch | Request: accountId|amount|currency|requestId |
| Not Base64-encoding | Checksum mismatch | Always Base64-encode the HMAC output |
Using amount instead of orderAmount/orderCurrency in callback | Checksum mismatch | Callback fields are orderAmount and orderCurrency, not amount/currency |
| String comparison (not constant-time) | Timing attack vulnerability | Use timingSafeEqual / hmac.compare_digest |
#Security Best Practices
- Never expose your
merchantSecretin client-side code or logs. - Always verify both request and callback checksums.
- Use constant-time comparison to prevent timing attacks.
- Rotate
merchantSecretperiodically for better security.