Checksum Authentication Guide

Generate and verify HMAC-SHA256 checksums for API requests and callbacks.

To guarantee data integrity and authenticity for all communications, Facilero uses a checksum verification mechanism based on HMAC-SHA256 and your merchantSecret.

The checksum ensures that:

  • Signed request and callback fields have not been altered in transit.
  • The sender is authenticated using the shared secret.

When to Use the Checksum

DirectionChecksum locationFields used, in order
APM request to FacileroBody field: checksumaccountIdamountcurrencyrequestId
Callback from FacileroHTTP header: X-ChecksumSee the callback matrix below

Callback Checksum Matrix

Callback typeFields used, in order
APM paymentaccountIdorderAmountorderCurrencytransactionId
Card paymenttransactionIdrequestIdtransactionStatus
Card payouttransactionIdrequestIdtransactionStatus
APM payouttransactionIdrequestIdtransactionStatus
Card refundtransactionId (original card-payment ID) → requestIdtransactionStatus

Important: Select the checksum formula based on the API flow that originated the callback. Do not infer APM payment versus APM payout from the presence of accountId.

For card refunds:

  • transactionId is the original card-payment transaction ID, not refundId.
  • requestId identifies the individual refund.
  • refundId remains available in the callback payload for reconciliation, but it is not included in the checksum.

How to Generate the Checksum

1. Merchant → Facilero: APM Request

Concatenate these fields in this exact order:

accountId|amount|currency|requestId

2. Facilero → Merchant: APM Payment Callback

Concatenate these fields in this exact order:

accountId|orderAmount|orderCurrency|transactionId

3. Facilero → Merchant: Transaction-Result Callback

For card payments, card payouts, card refunds, and APM payouts, concatenate:

transactionId|requestId|transactionStatus

4. Apply HMAC-SHA256

  1. Join the required values with the pipe character |.
  2. Sign the resulting string with HMAC-SHA256 using your merchantSecret.
  3. Encode the resulting bytes using standard Base64.

Do not use hexadecimal encoding or URL-safe Base64. Standard Base64 may contain +, /, and =; these characters must be preserved.


Example: Request

For an APM request, build the checksum input from:

accountId|amount|currency|requestId

Then:

HMAC-SHA256(checksum_string, merchantSecret)

Finally, Base64-encode the HMAC bytes:

checksum = Base64(HMAC-SHA256(checksum_string, merchantSecret))

Send the result in the request body's checksum field.


Example: APM Payment Callback

For an APM-payment callback, build the checksum input from:

accountId|orderAmount|orderCurrency|transactionId

Then:

HMAC-SHA256(checksum_string, merchantSecret)

Base64-encode the HMAC bytes:

expected_checksum = Base64(HMAC-SHA256(checksum_string, merchantSecret))

Compare the result with the value received in the X-Checksum header.

The APM-payment checksum formula is unchanged.


Example: Card Payment, Card Payout, Card Refund, or APM Payout Callback

For these transaction-result callbacks, build the checksum input from:

transactionId|requestId|transactionStatus

Then:

HMAC-SHA256(checksum_string, merchantSecret)

Base64-encode the HMAC bytes:

expected_checksum = Base64(HMAC-SHA256(checksum_string, merchantSecret))

Compare the result with the X-Checksum header using a constant-time comparison.

+, /, and = are valid standard-Base64 characters. Do not replace or remove them.

Card Refund Identity Example

For a card-refund callback, transactionId contains the original card-payment ID. refundId is available for refund reconciliation but is not signed.

Secret:

test-secret

Callback data:

transactionId:     payment_1001
refundId:          refund_3001          (not signed)
requestId:         refund_request_2001
transactionStatus: SUCCEED

Checksum string:

payment_1001|refund_request_2001|SUCCEED

Sent as header:

X-Checksum: /BFiJrrWikPLUdHEWjCRssGHROiKy5U68NxFqjmc/d0=

APM Amount Formatting

This section applies only to:

  • APM requests
  • APM-payment callbacks

Card payments, card payouts, card refunds, and APM payouts use the three-field transaction-result checksum and therefore do not sign amount or currency.

APM Requests

Use the exact decimal string that appears in the request body. Do not multiply it, convert it to minor units, or otherwise reformat it.

CurrencyRequest amountValue used in checksum
USD"10.00""10.00"
EUR"25.50""25.50"
GBP"99.99""99.99"
JPY"500""500"
ILS"3.75""3.75"

Rule: Use exactly the same string value in the checksum that you send in the request body.

APM-Payment Callbacks

The numeric representation differs by message direction:

  • Request: amount is a string, for example "200.00".
  • APM-payment callback: orderAmount is a numeric value, for example 200.0.

Facilero processes amounts using native numeric types. Therefore, formatting such as trailing zeros is not guaranteed to be preserved in callbacks.

Example:

Request amount:        "200.00"
Callback orderAmount:  200.0

When validating an APM-payment callback:

Always use the exact orderAmount representation received in the callback payload.

Do not reuse or reformat the amount from the original request. Doing so can cause checksum mismatches.


Validation Rules

Incoming Requests

APM requests without a valid checksum body field are rejected with:

400 BadRequest

Incoming Callbacks

Ignore callbacks when the X-Checksum header is missing or invalid.

For card payment, card payout, card refund, and APM payout callbacks, the checksum protects only:

transactionId
requestId
transactionStatus

Amount, currency, and all other payload fields are intentionally unsigned. If your business logic depends on those fields, validate them separately.

Card Refund Deduplication

For card refunds, deduplicate verified callbacks using the combination of:

transactionId
requestId
transactionStatus

Do not deduplicate only by transactionId and status. Multiple refunds can reference the same original card-payment transaction, while each refund has its own requestId.

Preserving APM Callback Amounts

For APM-payment callbacks, parse JSON numbers without losing their source representation.

For Node.js 20, the JavaScript implementation can use lossless-json:

npm install lossless-json

Implementation Pattern

The general verification flow is:

1. Determine the callback type from the originating API flow.
2. Select the correct ordered fields.
3. Preserve each signed value exactly as required.
4. Join the values with "|".
5. Calculate HMAC-SHA256 using merchantSecret.
6. Encode the HMAC bytes with standard Base64.
7. Compare the calculated checksum with X-Checksum using constant-time comparison.
8. Reject or ignore the message if verification fails.

Common Mistakes

MistakeSymptomFix
Converting amount to minor units, e.g. "1000"Checksum mismatchUse the decimal string as-is, e.g. "10.00"
Using the wrong field orderChecksum mismatchUse the exact order defined in the callback matrix
Using hexadecimal or URL-safe Base64Checksum mismatchUse standard Base64 and preserve +, /, and =
Using the APM-payment formula for an APM payoutChecksum mismatchAPM payouts use **`transactionIdrequestIdtransactionStatus`**
Using refundId as the refund transactionIdChecksum mismatchUse the original card-payment ID; requestId identifies the refund
Reformatting APM-payment orderAmountChecksum mismatchUse the exact representation received in the callback
Comparing checksums as normal stringsTiming-attack vulnerabilityUse a constant-time comparison such as timingSafeEqual or hmac.compare_digest

Security Best Practices

  • Never expose merchantSecret in client-side code or application logs.
  • Verify checksums before processing requests or callbacks.
  • Use constant-time comparison when comparing checksum values.
  • Process card-refund callbacks idempotently using transactionId, requestId, and transactionStatus.
  • For other applicable callbacks, use transactionId and status for idempotency according to your integration logic.
  • Validate unsigned payload fields separately whenever your business logic relies on them.
  • Rotate merchantSecret periodically according to your security policy.

Quick Reference

APM Request

accountId|amount|currency|requestId

Checksum location:

Request body: checksum

APM Payment Callback

accountId|orderAmount|orderCurrency|transactionId

Checksum location:

HTTP header: X-Checksum

Card Payment / Card Payout / Card Refund / APM Payout Callback

transactionId|requestId|transactionStatus

Checksum location:

HTTP header: X-Checksum

Encoding

HMAC algorithm: HMAC-SHA256
Secret:         merchantSecret
Output:         Standard Base64
Delimiter:      |