Skip to content

Transaction callback (Deposits and Withdrawals)#

Once a merchant has been enabled for customer payments within the XGateway system, incoming customer deposits are processed automatically. To keep you informed, a callback (webhook) is sent once a transaction reaches its final state - confirmed or failed.

Merchants can also request to receive processing-type callbacks. This may be useful in certain cases, for example, to notify users that processing started, but handling these callbacks is not required for proper transaction processing, and they are not enabled by default.

Prefer callbacks over polling; they are signed and retried. For high-risk operations, confirm state via API (see the risks and details on the Callbacks Handling page). API responses are the source of truth.

Set up the transaction callback endpoint#

To accept the KYC status updates you should configure the endpoint on your side and provide it during the integration setup.

It is always best to ensure that your callback endpoint is up and running so that the notifications can reach you. XGateway will retry failed requests up to 10 times.

All notifications (delivered or not) will be available on your dashboard. You can also see the error messages for failed notifications and investigate the issue on your side.

Crypto transactions are permanently recorded on the public blockchain as well as stored in our database. This data may be used for cross check and debugging.

Callback endpoint#

POST https://your-callback-url-here.com/handle-transaction

This endpoint must properly handle deposit callbacks. If withdrawals requested - the same endpoint will be used to send the withdrawal transaction status, see the payload examples below.

Callback payload (deposits and withdrawals)#

The amount is sent as a string to avoid unintended transformations during hash encoding and decoding.

Callback body breakdown

NameTypeDescription
callbackType"transaction"The type of a callback
amountStringThe transaction amount how it was sent by the customer
applicationIdStringThe unique application ID in the merchant system
currencyStringThe currency sent by the customer. A full list of supported currencies can be found on the supported currencies page
customerIdStringThe unique customer ID in the merchant system
hashString

The base64-encoded hash is generated using the sha512 algorithm and includes the transaction ID, customer ID, amount, currency, and secret key

The string that will be hashed:
{transaction ID}.{customer ID}.{amount}.{currency}.{secretKey}

idStringThe unique transaction ID in the XGateway system
invoiceIdStringThe unique invoice ID in the XGateway system
networkStringThe blockchain network the transaction was made in
orderIdStringThe unique order ID in the merchant system
statusStringThe transaction status
transactionHashStringThe transaction hash in a blockchain
typeStringThe transaction type
info.exchangeRateStringThe exchange rate used for the conversion from fiat currency to crypto currency, if applicable
info.referenceAmountStringThe transaction amount in the reference currency set during the sign-up process
info.referenceCurrencyStringThe reference currency set during the sign-up process
info.referenceExchangeRateStringThe exchange rate used for the conversion from transaction currency to the reference currency
info.transactionAmountStringThe transaction amount received by the merchant after swaps applied
info.transactionCurrencyStringThe transaction currency received by the merchant
info.invoiceBaseAmountStringThe amount how it sent in invoice
info.invoiceBaseCurrencyStringThe currency how it sent in invoice
info.transactionAmountBaseCurrencyStringThe actual transaction amount converted into currency of the invoice
fees.processingStringProcessing fee in transaction currency
fees.technicalStringTechnical fee in transaction currency
senderDetails.senderIbanStringThe sender IBAN, used to initiate the deposit. The entire block is sent only for Fiat to Crypto deposits
additionalParams.utrStringUTR for UPI payments

Here is an example of how the different currencies work. Let's say a merchant operates in USD (reference currency). A customer sends 10 EUR through SEPA Secure with a conversion to USDT on Polygon. In this case the callback will contain:

  1. Amount and currency field will contain 10 and EUR.
  2. Reference currency USD and amount of the transaction as 10 EUR converted to USD.
  3. info.transactionAmount and info.transactionCurrency will contain the amount in pUSDT after swap to pUSDT.

Callback example: deposit#

The callback you get after a confirmed or failed Deposit transaction might look like this:

Deposit callback

{
  "callbackType": "transaction",
  "amount": "200",
  "applicationId": null,
  "currency": "EUR",
  "customerId": "000394",
  "hash": "rpn1za+9YmGDKSZBMVBd...i8DjYOhiq51g==",
  "id": "123486c2-4dbd-4a72-8be2-3338bef9a696",
  "invoiceId": "edef7683-a900-4e6a-8973-24949910017c",
  "network": null,
  "orderId": null,
  "status": "confirmed",
  "transactionHash": "0x58f6",
  "type": "deposit",
  "info": {
    "exchangeRate": "1.03759",
    "referenceAmount": "207.52",
    "referenceCurrency": "USD",
    "referenceExchangeRate": "1.000065",
    "transactionAmount": "207.51518",
    "transactionCurrency": "tUSDT",
    "invoiceBaseAmount": "200",
    "invoiceBaseCurrency": "EUR",
    "transactionAmountBaseCurrency": "199.98"
  },
  "fees": {
    "processing": "7.263031",
    "technical": null
  },
  "eur": "200.12",
  "usd": "207.52",
  "senderDetails": {
    "senderIban": "GB29NWBK60161331926819",
    "senderAccountNumber": "31926819",
    "senderSortCode": "601613"
  },
  "additionalParams": {
    "utr": "111111111111"
  },
  "customer": {
    "email": "string",
    "fullname": "string"
  },
  "billingAddress": {
    "city": "string",
    "state": "string",
    "postalCode": "string",
    "addressLine": "string",
    "countryCode": "string"
  },
  "paymentMethodDetails": {
    "cardType": "string",
    "cardExpiryYear": "string",
    "cardholderName": "string",
    "cardExpiryMonth": "string",
    "customerAccountNumber": "string",
    "cardIssuingCountryCode": "string"
  },
  "rejectionReason": null
}

Callback example: withdrawal#

The callback you get after a confirmed or failed Withdraw transaction might look like this:

Withdrawal callback

{
  "callbackType": "transaction",
  "senderDetails": null,
  "amount": "1.71",
  "applicationId": null,
  "currency": "EUR",
  "customerId": "sepa-secure-wilson",
  "hash": "FA5h8Ff4Onr...Ms7T2fjN/JybzwwMAjgg6g==",
  "id": "1234c71f-70fa-407b-b532-c5a219d3eb74",
  "invoiceId": "edefc865-2513-4409-a944-133b06011b4d",
  "network": null,
  "orderId": "order_test_prod",
  "status": "confirmed",
  "transactionHash": null,
  "type": "withdrawal",
  "createdAt": "2025-07-18T07:45:18.732Z",
  "updatedAt": "2025-07-18T07:46:38.611Z",
  "info": {
    "exchangeRate": "1.162371703223256733",
    "referenceAmount": "2",
    "referenceCurrency": "USD",
    "referenceExchangeRate": "1.000065",
    "transactionAmount": "2",
    "transactionCurrency": "tUSDT",
    "invoiceBaseAmount":"1.71",
    "invoiceBaseCurrency":"EUR",
    "transactionAmountBaseCurrency":"1.92"
  },
  "additionalParams": {
    "utr": "111111111111"
  },
  "fees": {
    "processing": "0.08",
    "technical": null
  },
  "eur": "1.72",
  "usd": "2"
}

Response and data handling#

You may handle the payload information as needed. You do not need to send anything back other than a success status to confirm that the callback has been received and processed on your side.

FYI: Transaction Statuses#

Below are the statuses - not an exhaustive list - of transactions supported in the system. Note that callbacks are sent only for processing (if explicitly enabled during the merchant setup), confirmed and failed transaction statuses. Other statuses are listed for informational purpose. They exist in the system and displayed in Merchant Back Office.

Transaction Statuses
Status Description
confirmed The transaction has been successfully processed
created The transaction has been initiated but is awaiting further processing
failed The transaction has failed
processing The transaction is currently being processed
misdirected The transaction has been processed but cannot be linked to an existing invoice
on_hold_review The transaction is under review for additional checks to prevent potential risks
manually_approved The transaction has been manually reviewed and is awaiting further processing
manually_rejected The transaction has been manually rejected due to identified vulnerabilities