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)#

All fields, including amount, are sent as a string to avoid unintended transformations during hash encoding and decoding. Optional fields can be null

XGateway supports multiple payment methods but uses a single, unified transaction callback format. As a result, some fields are optional and payment-method-specific. For example, rejectionReason applies only to credit card payments and will be null for other methods. Important fields for a specific payment method are typically documented on a dedicated page. All non-core fields are informational only and may change over time.

The core fields include:

  • the callbackType (transaction);
  • the transaction type (deposit or withdraw);
  • fields used for callback validation
    • transactionId
    • customerId
    • amount
    • currency
  • signed with the hash;
  • and the transaction status (confirmed, failed, or, if explicitly set up, processing).
Callback body breakdown
Name Description
callbackType The type of callback: transaction
amount The transaction amount as sent by the customer
applicationId The unique application ID in the merchant system
currency The currency sent by the customer. See supported currencies for the full list
customerId The unique customer ID in the merchant system
hash Base64-encoded SHA-512 hash of: {transactionId}.{customerId}.{amount}.{currency}.{secretKey}
id The unique transaction ID in the XGateway system
invoiceId The unique invoice ID in the XGateway system
network The blockchain network the transaction was made on
orderId The unique order ID in the merchant system
status The transaction status
transactionHash The transaction hash on the blockchain
type The transaction type
info
info.exchangeRate The exchange rate used for fiat-to-crypto conversion, if applicable
info.referenceAmount The transaction amount in the reference currency set during sign-up
info.referenceCurrency The reference currency set during sign-up
info.referenceExchangeRate The exchange rate used for conversion from transaction currency to the reference currency
info.transactionAmount The transaction amount received by the merchant after swaps
info.transactionCurrency The transaction currency received by the merchant
info.invoiceBaseAmount The amount as specified in the invoice
info.invoiceBaseCurrency The currency as specified in the invoice
info.transactionAmountBaseCurrency The actual transaction amount converted to the invoice currency
fees
fees.processing Processing fee in transaction currency
fees.technical Technical fee in transaction currency
senderDetails
senderDetails.senderIban The sender IBAN used to initiate the deposit. This block is sent only for fiat-to-crypto deposits
additionalParams
additionalParams.utr UTR 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-customer",
  "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 is a non-exhaustive list of transaction statuses supported in the system. Callbacks are sent only for confirmed and failed statuses — and optionally for processing, if this was explicitly enabled during merchant setup. Other statuses (such as created or hold) are visible in the Merchant Back Office but are not sent as callbacks.

  • confirmed - the transaction has been successfully processed
  • created - the transaction has been initiated and is awaiting further processing
  • failed - the transaction processing failed
  • processing - the transaction is currently being processed
  • hold - the transaction is temporarily paused and awaiting manual resolution