Callback Webhooks
Callback webhooks notify your server about incoming payments, confirmation updates and forwarding results for addresses created via the /{ticker}/create/ endpoint. Your endpoint must respond with HTTP 2xx and JSON {"status":"ok"} to confirm successful processing. The legacy text response *ok* is also accepted.
The callback request can be sent as GET (query string), POST form (application/x-www-form-urlencoded) or POST JSON (application/json) depending on your address creation settings (post and json). Default is GET; post=1 selects form POST; json=1 selects JSON POST regardless of post. Both flags may be enabled together.
Callback destinations must resolve to public Internet addresses. Private, loopback and reserved addresses are blocked at delivery time, including DNS results and queued retries. URL credentials and fragments are not accepted; redirects are not followed. Private development exceptions can only be configured by the service operator for exact endpoints.
Verify Core callbacks
Direct Core callbacks carry x-ca-signature: Base64 RSA-SHA256 with PKCS#1 v1.5 padding. Get the public key from GET /pubkey/ on your trusted Core API origin and pin it. Verify the full URL with its unchanged query for GET, or the raw request body for POST, before processing the payment. Never parse and reserialize data before verification.
This signature has no timestamp; keep payment processing idempotent for retries and delayed events. KingPay Merchant API webhooks use the separate project-level x-cryptapi-signature HMAC scheme described in the merchant signature guide.
Callback lifecycle
payment_status: pending— UTXO, EVM or TRON payment detected, awaiting the required confirmations or execution checks. Reports observed progress; counts may jump.payment_status: confirmed— incoming payment accepted at the required network stage. Confirmation updates stop. Distribution may start later, especially on TRON.payment_status: completed— distribution sent to the network. This does not promise confirmation of the outgoing transaction.- Delivery acknowledgement — acknowledge each event when your server responds with HTTP
2xxand{"status":"ok"}(or legacy*ok*). Until then the notification may be retried for up to 48 hours. Retries never repeat a transfer of funds. - A single incoming transaction (
txid_in) can generate several callbacks over time as its status evolves.
Retry policy
- Recommended: answer with HTTP
2xxand a JSON object whosestatusis exactly"ok", for example{"status":"ok"}. Additional JSON fields are allowed. - For compatibility, HTTP
2xxwith the plain text body*ok*is also accepted (case-insensitive, surrounding whitespace ignored). Empty bodies, malformed JSON, and any otherstatusvalue do not acknowledge delivery. - Any other HTTP status or response body is treated as a failure and the callback will be retried.
- Network errors, timeouts or connection failures also trigger retries.
- The first attempt is immediate. After failures, delays are 1 min → 5 min → 15 min → 1 h, then 3 hours between further attempts. Each delay starts when the preceding attempt finishes.
- Automatic delivery lasts 48 hours from notification creation. No new attempt starts after this deadline. An attempt already in progress may finish. Unacknowledged notifications become
failed; their history remains available. Anonymous API does not provide a manual retry endpoint. - Requests time out after 30 seconds. Notifications are stored before sending and queued attempts resume after service restarts. Delivery may be delayed while the service or the recipient is unavailable.
- Retries keep the same
uuidand request payload, including converted values. Record processed UUIDs and acknowledge duplicates without crediting the payment again. Different status events have different UUIDs and may arrive out of order. - All attempts (successful or not) are recorded and can be inspected via the
/{ticker}/logs/endpoint undercallbacks[].logs[].callbacks[].deliveries[]shows each new notification's delivery status, next attempt and expiration time. Historical logs are not automatically replayed.
Callback payload fields
uuid— unique identifier of the callback event.address_in— payment address generated for the customer (input address).address_out— forwarding destinations and their share.- In POST JSON mode: an object, for example:
{"0x...1":0.6,"0x...2":0.4}. - In GET and POST form modes: a JSON string containing the same object (because query/form values are strings).
- In POST JSON mode: an object, for example:
txid_in— incoming transaction hash detected onaddress_in.txid_out— forwarding transaction hash (if funds were forwarded and the network provides it).confirmations— current number of blockchain confirmations fortxid_in. On Solana, 1 denotes the accepted network stage rather than measured slot depth.payment_status—pending,confirmed, orcompleted. Replaces the old numericpendingfield.required_confirmations— configured merchant threshold for UTXO, EVM and TRON. It is independent of TRON's distribution safety threshold.- Solana sends confirmed and completed without pending updates. Both confirmation fields are 1; custom numeric depth is not enforced. Native SOL discovery uses finalized commitment; SPL uses confirmed commitment.
- TRON emits confirmed at the configured depth once execution checks pass. Distribution waits for the higher of that setting and 23 confirmations for TRX or 20 for TRC20, plus a successful solidified receipt. With a setting of 5, credit occurs at 5 and distribution later. Early credit does not guarantee finality or automatic reversal on a reorganization.
- At a threshold of one, the first UTXO event is
confirmed. Mempool detection is not included. Progress events omit outgoing hashes, fees and fiat conversions until available. - Delivery can be repeated or out of order. Deduplicate by
uuid, never regress a payment status or counter, and credit each incoming payment only once. coin— asset symbol (for exampleBTC,LTC,USDT).price— last known asset price in USD at the time of the callback (may be omitted for some networks).value_coin— received amount in cryptocurrency units (string in GET/FORM mode, number or string in JSON mode).value_forwarded_coin— total amount forwarded to your destination wallet(s) after fees.fee_coin— service fee in the payment currency (coin or token units). Network-cost deductions are reported separately asnetwork_fee, in the payment currency. This is the amount charged to cover network costs, which can differ from the final on-chain cost. Historical unknown values arenull.value_coin_convert— optional fiat conversion ofvalue_coin.- With
convert=1, Core expands the available USD value to a fiat map. If the source is missing, invalid or nonpositive, the result is the string"{}". This also applies to forwarded conversion before distribution. - In every transport, including POST JSON, this map is a JSON-encoded string. Parse the field separately with
JSON.parse(payload.value_coin_convert)when conversion is enabled. - Without
convert=1, Core preserves the original field if supplied by the chain handler. It may be a numeric USD value (a number or string), or absent. Do not assume it is always a fiat map. - The set of fiat currencies is taken from the server fiat database (all available codes).
- With
value_forwarded_coin_convert— optional fiat conversion ofvalue_forwarded_coin, same format rules asvalue_coin_convert.- Any custom parameters passed via
cb_paramswhen creating the address are appended to the callback URL and preserved in every webhook request.
Security recommendations
- Always validate your own secret or signature embedded in
cb_paramsbefore processing a callback. - Verify
txid_in,value_coinandconfirmationsagainst your own data or a trusted explorer for high-value payments. - Use HTTPS for all callback URLs.
- Treat callback data as untrusted input: sanitize and validate before storing or displaying.
{
"address_in": "14PqCsA7KMgseZMPwg6mJy754MtQkrgszu",
"address_out": "{\"ltc1qc8ks9meqmxtd7kkth5s8vv2edju3dy4qykvvek\":0.6,\"ltc1q2j3n39vasef6guakk40gug0u044cdz67qrwf6u\":0.4}",
"txid_in": "33f11...",
"txid_out": "5ea53...",
"value_coin": "0.1",
"value_coin_convert": "{\"USD\":\"3.20\",\"EUR\":\"3.05\",\"GBP\":\"2.62\",\"CAD\":\"4.16\"}",
"value_forwarded_coin": "0.0987",
"value_forwarded_coin_convert": "{\"USD\":\"3.17\",\"EUR\":\"3.01\",\"GBP\":\"2.59\",\"CAD\":\"4.12\"}",
"confirmations": "2",
"payment_status": "completed",
"required_confirmations": "1",
"fee_coin": "0.0013",
"price": "80.51",
"coin": "LTC",
"uuid": "883d30bc-d53b-46e4-9f4d-425001a6a45d"
}{
"address_in": "14PqCsA7KMgseZMPwg6mJy754MtQkrgszu",
"address_out": {
"ltc1qc8ks9meqmxtd7kkth5s8vv2edju3dy4qykvvek": 0.6,
"ltc1q2j3n39vasef6guakk40gug0u044cdz67qrwf6u": 0.4
},
"txid_in": "33f11...",
"txid_out": "5ea53...",
"value_coin": 0.1,
"value_coin_convert": "{\"USD\":\"3.20\",\"EUR\":\"3.05\",\"GBP\":\"2.62\",\"CAD\":\"4.16\"}",
"value_forwarded_coin": 0.0987,
"value_forwarded_coin_convert": "{\"USD\":\"3.17\",\"EUR\":\"3.01\",\"GBP\":\"2.59\",\"CAD\":\"4.12\"}",
"confirmations": 2,
"payment_status": "completed",
"required_confirmations": 1,
"fee_coin": 0.0013,
"price": "80.51",
"coin": "LTC",
"uuid": "883d30bc-d53b-46e4-9f4d-425001a6a45d"
}