Guides

Payments

A payment (called a payment intent in the API) represents one request to be paid a fixed amount of USDC. You create it, the customer pays it, and we tell you when it is done.

Amounts

amount is a string containing a whole number of USDC base units. USDC has 6 decimals, so 1 USDC is "1000000". The smallest payment is 0.01 USDC and the largest is 1,000,000 USDC.

// USDC amounts are integer strings in base units (6 decimals). Never use floats for money.
export function toUnits(usdc) {
  const m = /^(\d{1,12})(?:\.(\d{1,6}))?$/.exec(usdc.trim());
  if (!m) throw new Error("amount must have at most 6 decimals");
  return (BigInt(m[1]) * 1_000_000n + BigInt((m[2] ?? "").padEnd(6, "0"))).toString();
}
export function fromUnits(units) {
  const v = BigInt(units);
  return `${v / 1_000_000n}.${(v % 1_000_000n).toString().padStart(6, "0")}`;
}
toUnits("25.50"); // "25500000"

Fees

Your fee is set by ClearGateway per merchant, in basis points (100 bps = 1%). It is applied like this:

  • fee_amount = amount × fee_bps ÷ 10,000, rounded down to a whole base unit.
  • merchant_amount = amount − fee_amount: what you receive.

Example: 100 USDC at 200 bps gives a fee of 2 USDC and a merchant amount of 98 USDC. The fee is recorded on the payment when it is created, so a later fee change never affects existing payments.

Statuses

createdThe payment exists. The customer has not started paying.
awaiting_paymentThe customer opened checkout and we are ready to see their payment.
confirmingA payment was seen on-chain and is collecting confirmations. Do not fulfil yet.
succeededConfirmed and final. Your share is in your wallet. Fulfil the order.
expiredNobody paid before the payment expired.
underpaidLess than the full amount arrived. Contact the customer; the payment is not complete.
failedThe transaction was reorganised out of the chain or failed. Nothing was booked.
canceledYou canceled it before it was paid.
partially_refundedPart of a paid amount has been refunded.
refundedThe full amount has been refunded.

The normal path is: created → awaiting_payment → confirming → succeeded.

Fulfil on succeeded only

Only succeeded means the money is final. A redirect back to your site, or a payment that is still confirming, is not proof of payment. Rely on the webhook, or fetch the payment from your server.

Confirmations and reorganisations

We wait for a number of network confirmations (currently 5 blocks on the test network) and then re-check that the payment is still in the chain before marking it succeeded. If the network reorganises and the transaction disappears, the payment is failed and nothing is booked.

Late, over- and under-payments

  • Late payment (after a payment expired or was canceled): the money is never dropped. The payment status does not change; it is flagged for review and you get a payment_intent.requires_review webhook. ClearGateway staff will work it out with you, usually by refunding the customer.
  • Underpaid: the payment moves to underpaid and you get payment_intent.underpaid.
  • Overpaid (deposit-address payments): flagged for review with the extra amount recorded.

Options when creating a payment

  • merchant_order_id: your own reference. Searchable in the dashboard.
  • metadata: up to 50 key-value string pairs (keys up to 40 characters, values up to 500) that come back on the payment and in webhooks.
  • customer_email: stored on the payment for your records.
  • success_url, cancel_url: where checkout offers to send the customer back (http or https).
  • expires_in_seconds: 300 to 86,400. Defaults to 3,600 (one hour).

Reading and canceling

  • GET /v1/payment_intents/{id} fetches one payment. GET /v1/payment_intents lists them (filter by status, created_gte, created_lte; page with limit and starting_after).
  • POST /v1/payment_intents/{id}/cancel works only while the payment is created or awaiting_payment. A customer who already started paying can still complete a payment on-chain; if that lands after cancellation it is flagged for review.