Skip to content

Accepting a payment

  1. Customer clicks pay; you open the checkout.
  2. The SDK creates the payment and shows the available chains and tokens.
  3. Customer connects a wallet and switches to the right chain.
  4. The SDK checks the balance before letting them submit.
  5. Customer signs; onSuccess fires.
  6. Your server confirms the payment and fulfils the order.

Steps 2 to 5 are the SDK’s job. Step 6 is yours, and it is the one that gets skipped.

onSuccess means the wallet accepted the transaction and broadcast it. It does not mean the money arrived. The transaction can fail, be replaced by a higher-fee one, or be dropped from the mempool.

It is also client-side, so it can be triggered by anyone who can open the browser console on your checkout page. Fulfilment decided in the browser is fulfilment anyone can ask for.

onSuccess={(paymentId, txHash) => {
// Right: hand it to your server and let the server decide.
fetch('/api/orders/awaiting-confirmation', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ paymentId, txHash }),
});
// Wrong: fulfilling here trusts the browser.
// grantAccess();
}}

Then confirm server-side, either by webhook or by reading the status with your key.

The SDK checks the customer has enough of the token, and enough native currency for gas, before allowing submission. This catches the most common failure, having USDC but no ETH for gas, before a transaction is attempted rather than after it reverts.

A customer can send more or less than invoiced. Neither breaks the payment, and both have defined handling: see Overpayments and refunds.