Core API

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 2xx and {"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 2xx and a JSON object whose status is exactly "ok", for example {"status":"ok"}. Additional JSON fields are allowed.
  • For compatibility, HTTP 2xx with the plain text body *ok* is also accepted (case-insensitive, surrounding whitespace ignored). Empty bodies, malformed JSON, and any other status value 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 uuid and 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 under callbacks[].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).
  • txid_in — incoming transaction hash detected on address_in.
  • txid_out — forwarding transaction hash (if funds were forwarded and the network provides it).
  • confirmations — current number of blockchain confirmations for txid_in. On Solana, 1 denotes the accepted network stage rather than measured slot depth.
  • payment_status — pending, confirmed, or completed. Replaces the old numeric pending field.
  • 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 example BTC, 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 as network_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 are null.
  • value_coin_convert — optional fiat conversion of value_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).
  • value_forwarded_coin_convert — optional fiat conversion of value_forwarded_coin, same format rules as value_coin_convert.
  • Any custom parameters passed via cb_params when 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_params before processing a callback.
  • Verify txid_in, value_coin and confirmations against 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.
Example callback payload (GET / form mode)
{
  "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"
}
Example callback payload (POST JSON mode)
{
  "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"
}