payfjordUSDT payment gateway
HomePricingFAQGuides
Sign inStart free
payfjordUSDT payment gateway

Payfjord reads public blockchain data and reports back to your website. Your customers' money goes straight to your wallet — we never hold it.

Product

  • Pricing
  • Create account
  • API docs

Support

  • FAQ
  • Contact
  • Sign in

Legal

  • Terms & Privacy
  • Privacy policy

© 2026 Payfjord

A technical service that reads blockchain data. Not an exchange — we never hold or convert your assets.

All guides
1 September 2026·8 min read·Updated Sept 2026

Crypto Payment Callbacks: How to Handle Them Without Double-Crediting

The callback is where most integrations break, and the breakage is always the same shape: the same notification arrives twice and the customer gets credited twice.

On this page

  1. 1.Why the same callback arrives more than once
  2. 2.The rule
  3. 3.Verify before you trust
  4. 4.Read the right field
  5. 5.Return the right response
  6. 6.A worked example of the failure

Why the same callback arrives more than once

A gateway cannot tell the difference between 'your server did not receive this' and 'your server received it but the reply got lost'. When in doubt it retries, because the alternative — silently dropping a payment notification — is far worse.

So retries are a feature, not a bug. Your handler has to be built for them.

The rule

Processing the same payment notification twice must have exactly the same effect as processing it once. That is all idempotency means here.

The way to get it is to make your own order the source of truth, not the callback. Look the order up, check whether it is already paid, and stop there if it is.

  • Find your order using the request_id you generated
  • If it is already marked paid — return success immediately, change nothing
  • Otherwise credit the customer and mark it paid in one database transaction
  • Return success so the gateway stops retrying

Verify before you trust

Your callback URL is reachable by anyone who guesses it. Treat every request as untrusted until it proves otherwise.

Check the merchant credentials in the request. Check that the transaction id belongs to an order you actually created. Never credit based on the amount alone — an attacker can send you any amount they like.

Read the right field

Credit the amount the gateway reports as received, not the amount you originally asked for. Those differ by the identifying decimals, and the difference is real money the customer paid.

Amounts are reported in USD even when the customer paid in Bitcoin or Litecoin. That is deliberate: most shop code reads the amount field and credits it straight to the customer, and handing that code a coin amount is an accounting error nobody notices until the books stop balancing.

Return the right response

Return HTTP 200 with a success body once you have finished. Anything else is read as failure and schedules another attempt.

Do not return success before you have committed the credit. If your database write fails after you replied, the gateway will never retry and the payment is lost from your side.

A worked example of the failure

A customer pays a $100 invoice. Your server is briefly overloaded and the reply times out. The gateway retries thirty seconds later. Your handler, which credits on every call, adds another $100 to the customer's balance.

Nobody notices until reconciliation, and by then the pattern is discoverable: pay once, deliberately time out, get credited twice. The fix is four lines — check whether the order is already paid.

Frequently asked questions

How many times will a failed callback retry?
Typically up to eight attempts with an exponential backoff: 30 seconds, then 1, 2, 4 minutes and so on, up to an hour between attempts.
Should I verify a signature?
Verify whatever the gateway offers — signature, credentials, or both — and additionally confirm the transaction id matches an order you created. Layered checks cost nothing.
What if my site was down for the whole retry window?
The payment is still in your wallet and the invoice is still marked paid. You can look the invoice up by its transaction id and reconcile manually.
Can I test the callback without spending real money?
Yes. Create an invoice, then use the gateway's manual reconciliation to attach a payment to it, which triggers the same callback path your production code will see.

Related guides

  • How to Accept USDT Payments on Your Website in 2026

    9 min read

  • Non-Custodial Crypto Payment Gateway: Why Holding Your Keys Matters

    6 min read

  • USDT vs USDC for Merchants: Which Stablecoin Should You Accept?

    6 min read

Payfjord reads the blockchain and calls your callback. Money goes straight to your own wallet — we never hold it.

Get started