Callbacks

The gateway calls your callback URL to tell you about a deposit. Each forwarded deposit produces its own confirmed callback, and, when the order was created with pending=1, its own pending callback. Custom query parameters of your callback URL (such as order and nonce) are sent back unchanged in every callback.

Events

EventpendingWhen
Pending (detection)"1"A deposit of at least the minimum was first seen by the indexer. Only with pending=1 at create. Do not fulfill an order on this event.
Confirmed"0"The deposit was forwarded to your payout address and the forwarding transaction is confirmed.

Pending and confirmed callbacks have different uuid values. Detection uses indexed chain data rather than a separate mempool subscription. Deposits below the minimum, and transfers of other tokens, produce no callback.

Transports

Create parameterMethodContent
none (default)GETFields appended to the query string after your own parameters, sorted by field name.
post=1POSTapplication/x-www-form-urlencoded body. Your own query parameters stay in the URL.
json=1POSTapplication/json body with string values. Your own query parameters stay in the URL. json=1 wins over post=1.

Avoid field names from the table below in your own query parameters. A default GET callback looks like this:

Text
GET /hook?order=1001&nonce=7f3a9c&address_in=TDepositAddressExample0000000000&address_out=TXyzPayoutAddressExample0000000000000&coin=trc20_usdt&confirmations=21&fee_coin=1.800000&pending=0&price=1.0002&txid_in=9f2c1a0e5b7d4c3a8e6f1b2d3c4a5e6f7a8b9c0d1e2f30415263748596a7b8c9&txid_out=1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f809&uuid=8c4e2a61-5b3d-47f9-a0e2-1d6c9b7f3e45&value_coin=100.000000&value_forwarded_coin=98.200000
x-ca-signature: <base64 RSA-SHA256 signature>

Fields

All values are strings. The examples below are shown as JSON; with GET and post=1 the same fields arrive as query or form parameters.

Detection (pending) callback

Sent to the order callback URL when a deposit of at least the ticker minimum is first seen and the order was created with pending=1. GET sends the fields in the query string after any custom parameters; post=1 sends a form body; json=1 sends a JSON body. All values are strings. Header x-ca-signature carries the base64 RSA-SHA256 signature. Acknowledge with HTTP 200 and the body *ok* within 30 seconds. Do not fulfill an order on a pending callback.

FieldTypeRequiredDescription
uuidstringyesEvent identifier, stable across retries. Deduplicate on it. Pending and confirmed events have different uuids.
address_instringyesDeposit address of the order.
address_outstringyesPayout address of the order.
txid_instringyesHash of the inbound deposit transaction.
coinstringyesTicker with the slash replaced by an underscore, for example trc20_usdt.
pendingstring, always 1yes"1" for a detection callback.
pricestringnoUSD price of one whole token, up to 8 decimals. Present only when a fresh price existed at event creation.
JSON
{
  "uuid": "3f1b7c9e-8a52-4d0e-9c41-6b2e5f0a7d13",
  "address_in": "TDepositAddressExample0000000000",
  "address_out": "TXyzPayoutAddressExample0000000000000",
  "txid_in": "9f2c1a0e5b7d4c3a8e6f1b2d3c4a5e6f7a8b9c0d1e2f30415263748596a7b8c9",
  "coin": "trc20_usdt",
  "pending": "1",
  "price": "1.0002"
}

Confirmed callback

Sent after the deposit was forwarded to the payout address and the forwarding transaction is confirmed. Same transports, signature and acknowledgement as the pending callback. Each forwarded deposit produces its own confirmed callback with its own uuid.

FieldTypeRequiredDescription
uuidstringyesEvent identifier, stable across retries. Deduplicate on it.
address_instringyesDeposit address of the order.
address_outstringyesPayout address of the order.
txid_instringyesHash of the inbound deposit transaction this callback is about.
coinstringyesTicker with the slash replaced by an underscore, for example trc20_usdt.
pendingstring, always 0yes"0" for a confirmed callback.
pricestringnoUSD price of one whole token, up to 8 decimals. Present only when a fresh price existed at event creation.
txid_outstringyesHash of the forwarding transaction to the payout address.
confirmationsstringyesConfirmations of the inbound deposit at event creation; at least 1.
value_coinstringyesInbound amount before fees, in whole asset units.
value_forwarded_coinstringyesAmount forwarded to the payout address after fees.
fee_coinstringyesService and charged network fees, in whole asset units.
value_coin_convertstringnoJSON object serialized as a string, keyed by upper-case fiat code with 2-decimal values. Only for orders created with convert=1 and only when a fresh price existed.
value_forwarded_coin_convertstringnoSame shape as value_coin_convert, for the forwarded amount.
JSON
{
  "uuid": "8c4e2a61-5b3d-47f9-a0e2-1d6c9b7f3e45",
  "address_in": "TDepositAddressExample0000000000",
  "address_out": "TXyzPayoutAddressExample0000000000000",
  "txid_in": "9f2c1a0e5b7d4c3a8e6f1b2d3c4a5e6f7a8b9c0d1e2f30415263748596a7b8c9",
  "coin": "trc20_usdt",
  "pending": "0",
  "price": "1.0002",
  "txid_out": "1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f809",
  "confirmations": "21",
  "value_coin": "100.000000",
  "value_forwarded_coin": "98.200000",
  "fee_coin": "1.800000",
  "value_coin_convert": "{\"EUR\":\"92.00\",\"USD\":\"100.02\"}",
  "value_forwarded_coin_convert": "{\"EUR\":\"90.34\",\"USD\":\"98.22\"}"
}

Signature

Every callback carries the header x-ca-signature. For GET it signs the full request URL, for POST the exact raw body. Verify it before trusting anything else in the request. See Verify callback signatures.

Acknowledge

Answer with HTTP status 200 and the body *ok* (plain ok is accepted too, in any letter case) within 30 seconds. Any other status, body or a timeout counts as a failure and the callback is retried. Redirects are not followed, and destinations resolving to private addresses are refused at send time.

Retries

There are eight attempts: the initial send, then after 30 seconds, 2 minutes, 10 minutes, 30 minutes, 2 hours, 6 hours and 24 hours, each with up to 10% added jitter. The uuid stays the same across retries. Duplicates are possible, so store the uuid and ignore events you have processed. A confirmed callback whose retries are exhausted shows as sent in the logs, which you can poll to reconcile.

Order

The pending and the confirmed callback of a deposit can arrive in either order after retries. A pending callback never replaces a confirmed one: once you have processed pending equal to "0" for a deposit, ignore a late "1".

Key rotation

Callbacks carry no key id and no timestamp, so a rotation is announced rather than negotiated. The operator creates a new key pair, installs the private key on the workers and the public key on the API, and restarts them together; from that moment every callback, including retries of older ones, is signed with the new key. After a failed verification, fetch GET /pubkey/ once, replace your stored key, and verify again before rejecting the callback. A callback that still fails with the fresh key is not from the gateway.

Checklist

  • Verify x-ca-signature against the key from GET /pubkey/.
  • Compare the nonce and order reference in the query string with your stored order.
  • Check address_in, coin and the amount against the order.
  • Deduplicate on uuid before doing work.
  • Fulfill only on pending equal to "0".
  • Answer *ok*.