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
| Field | Type | Notes |
|---|---|---|
paymentId | string | pay_…. The capability for status/cancel. |
status | enum | See the lifecycle below. |
mode | string | "test" or "live". |
network · token | string | The chain and stablecoin chosen. |
payTo | string | Your receiving address for this payment. |
contract | string | The token's contract / mint address. |
amount | string | Display amount, e.g. "29.00". |
amountBaseUnits | string | Exact on-chain integer amount. |
decimals | number | Token decimals (6, or 18 on BNB Chain). |
txHash | string · null | The settling transaction; null until detected. |
expiresAt | string | When an unpaid payment lapses to EXPIRED. |
branding | object | Seller display name / logo / color, when set. |
Status lifecycle
The happy path is PENDING → DETECTED → CONFIRMED. The terminal states tell you what actually happened.
| Status | Meaning | Webhook |
|---|---|---|
PENDING | Created; waiting for the transfer. | — |
DETECTED | A matching transfer is seen on-chain, not yet final. | payment.detected |
CONFIRMED | Buried under enough confirmations. The money is yours. Fulfil here. | payment.confirmed |
UNDERPAID | Less than the amount due arrived. | payment.underpaid |
OVERPAID | More than the amount due arrived (still credited). | payment.overpaid |
EXPIRED | The window closed with nothing received. | payment.expired |
CANCELED | The 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
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.
curl https://api.hashpay.dev/v1/payments/pay_66f2a19b03c84d2ea1b7c4de
Cancel a payment
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
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.