Skip to content

Callback validation and rounding#

This page describes how to validate transaction callback authenticity using the hash field and explains the rounding behaviour for monetary amounts.

Hash validation#

Each transaction callback includes a hash field that allows you to verify the callback originated from XGateway and has not been tampered with. The hash is generated using SHA-512 and encoded in Base64.

Hash composition#

The hash is computed from a concatenated string of specific transaction fields, separated by dots:

{transactionId}.{customerId}.{amount}.{currency}.{secretKey}
Component Description
transactionId The unique transaction ID (id field in the callback)
customerId The customer ID (customerId field in the callback). If no customer ID is present, the literal string N/A is used
amount The original transaction amount as sent by the customer
currency The original transaction currency
secretKey Your merchant secret key (provided during integration setup)

The amount and currency used in the hash are the original values as sent by the customer, not the converted or reference amounts.

Validation example#

For a callback with the following relevant fields:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "customerId": "customer_123",
  "amount": "100.50",
  "currency": "EUR",
  "hash": "YOUR_EXPECTED_HASH_HERE"
}

Using a secret key of your_secret_key_here, you would construct the string:

a1b2c3d4-e5f6-7890-abcd-ef1234567890.customer_123.100.50.EUR.your_secret_key_here

Then compute the SHA-512 hash of this string and encode the result in Base64. Compare your computed hash with the hash field in the callback to verify authenticity.

Example validation in pseudocode
concatenated = transactionId + "." + customerId + "." + amount + "." + currency + "." + secretKey
computedHash = base64Encode(sha512(concatenated))
isValid = (computedHash == callback.hash)

If the callback is for a transaction without a customer ID (such as settlement transactions), use the literal string N/A as the customer ID component.


Amount rounding#

Transaction amounts may undergo currency conversion during processing. Understanding how these amounts are rounded is important for reconciliation.

Original amount as source of truth#

The original amount (amount and currency fields) represents the exact value as submitted by the customer. This is the authoritative source for the transaction value.

When converting to reference or transaction currencies, the system applies the exchange rate and then rounds the result to the target currency's precision (typically 2 decimal places for fiat currencies).

Rounding behaviour change#

Historically, XGateway used truncation (round down) after the precision digit. This behaviour is being updated to use round half to even (banker's rounding), which is the IEEE 754 standard for financial calculations.

Method Description Example (2 decimal places)
Truncation (legacy) Discards digits beyond precision 13.53999... → 13.53
Round half to even (new) Rounds to nearest; ties go to even 13.53999... → 13.54

Practical example#

Consider a transaction with:

  • Original amount: 0.005691801955558544 ETH
  • Exchange rate: 2378.86 USD/ETH

The conversion calculation:

2378.86 × 0.005691801955558544 = 13.53999999999999797984
Rounding method Result
Truncation (legacy) 13.53 USD
Round half to even (new) 13.54 USD

The difference arises because truncation simply discards the digits beyond the precision point, whilst round half to even considers the value of those digits to determine whether to round up or down.

Reconciliation guidance#

When reconciling transactions:

  1. Use the original amount and original currency as your primary reference
  2. Be aware that converted amounts (reference amount, transaction amount) may differ slightly due to rounding
  3. For precise verification, replicate the conversion using the provided exchange rate and apply the appropriate rounding method

If you observe small discrepancies (typically ≤ 0.01 in the target currency) between your calculated values and the callback amounts, this is likely due to the rounding method. Always verify using the original amount as the source of truth.