HASH PAY Docs
Docs/Reference/Payments
API reference

Payments

A payment is one buyer's attempt to pay one amount. It's created by checkout, read by its id, and the source of truth for fulfilment is its webhook — not the browser.

The payment object

FieldTypeNotes
paymentIdstringpay_…. The capability for status/cancel.
statusenumSee the lifecycle below.
modestring"test" or "live".
network · tokenstringThe chain and stablecoin chosen.
payTostringYour receiving address for this payment.
contractstringThe token's contract / mint address.
amountstringDisplay amount, e.g. "29.00".
amountBaseUnitsstringExact on-chain integer amount.
decimalsnumberToken decimals (6, or 18 on BNB Chain).
txHashstring · nullThe settling transaction; null until detected.
expiresAtstringWhen an unpaid payment lapses to EXPIRED.
brandingobjectSeller display name / logo / color, when set.

Status lifecycle

The happy path is PENDING → DETECTED → CONFIRMED. The terminal states tell you what actually happened.

StatusMeaningWebhook
PENDINGCreated; waiting for the transfer.
DETECTEDA matching transfer is seen on-chain, not yet final.payment.detected
CONFIRMEDBuried under enough confirmations. The money is yours. Fulfil here.payment.confirmed
UNDERPAIDLess than the amount due arrived.payment.underpaid
OVERPAIDMore than the amount due arrived (still credited).payment.overpaid
EXPIREDThe window closed with nothing received.payment.expired
CANCELEDThe buyer canceled while pending.payment.canceled

How many confirmations "enough" means is per-chain — from 1 on Avalanche to 32 on Solana. See confirmation depths.

Get a payment

GET/v1/payments/{id}capability

Returns the payment object. No key required — the unguessable id is the capability, so the buyer's browser can poll it directly. Each call may trigger a fresh on-chain check at most once every ~12 seconds per payment; in between you get the last known state, so polling every few seconds is fine.

poll.shcurl
curl https://api.hashpay.dev/v1/payments/pay_66f2a19b03c84d2ea1b7c4de

Cancel a payment

POST/v1/payments/{id}/cancelcapability

Lets a buyer abandon a PENDING payment — useful for a "cancel" button in checkout. Moves it to CANCELED and fires payment.canceled. A payment that's already detected or settled is returned unchanged.

Simulate a test payment

POST/v1/test/payments/{id}/simulatetest only

Drives a test payment straight to CONFIRMED and fires a real payment.confirmed webhook — no chain, no money, no quota used. This is exactly what the dashboard's Simulate payment button calls. Returns 400 not_test_mode for a live payment, or 409 not_open if it's already settled.

Polling is great for the buyer's live UI, but make fulfilment hang off the webhook, not the poll. The webhook is signed and authoritative; a browser poll is neither.

Listing payments

Your full payment history (live and test) lives on the dashboard's Payments tab, backed by GET /v1/stores/{storeId}/payments — a cursor-paginated list your server can also call with its sk_ key as the bearer. Day-to-day, though, react to webhooks rather than scanning history.