Optional analytics on public pages. No session recording. Support works either way. Privacy details
Accept payments
Underpaid, overpaid and late payments never become paid silently. You decide, and you refund from your own wallet.
| Situation | status | paymentException | What to do |
|---|---|---|---|
| Transfer seen, confirming | payment_detected | — | Show "received"; do not fulfill yet. |
| Paid in full | paid | — | Fulfill once, keyed on the event id. |
| Paid more than due | paid | overpaid | Fulfill. overpaidAmount was settled to your wallet; refund it if your policy says so, then record the refund. |
| Paid less, invoice still open | partial | underpaid | Show amountRemaining to the customer; they can send the rest before expiresAt. |
| Closed while underpaid | expired | underpaid | Money received so far stays at the payment address until someone settles it. |
| Short amount settled | manual_review | underpaid | Your wallet received less than due. Ask for the rest, fulfill partially, or refund. |
| Paid after the invoice expired or was cancelled | manual_review | late_payment | The money reached your wallet. Fulfill or refund; do not assume the order is still wanted. |
| Settlement failed or quarantined | manual_review | — | Contact support with the invoice id. |
| Chain reorganisation | reverted | — | Reverse fulfilment if you already shipped. |
| Unpaid and cancelled | cancelled | — | Only before a payment is seen; afterwards cancel returns 409 state_conflict. |
| Field | Meaning |
|---|---|
| cryptoAmount | Amount due, in the token. Quoted once when the invoice is created and never changes. |
| amountPaid | Amount received (settled amount once settled). |
| amountRemaining | Still owed while underpaid, else null. |
| overpaidAmount | Received above the amount due, else null. |
| paymentException | null, underpaid, overpaid or late_payment. |
| amountRefunded | Total of refunds you recorded. Defaults to "0". |
Token amounts are decimal strings. Compare them as decimals (or in base units), never as floating-point numbers.
BOSPay never holds funds, so it never sends refunds. Send the refund from your payout wallet, then record the transaction on the invoice. Recording is idempotent on the transaction hash and cannot exceed the amount received; it updates amountRefunded and is written to your audit log. Cancelling an invoice is not a refund.
const response = await fetch(`${process.env.BOSPAY_API_BASE}/invoices/inv_1048/refunds`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"BOSPay-Version": "2026-09-23",
"X-API-Key": process.env.BOSPAY_API_KEY,
"Idempotency-Key": "order-1048-attempt-1",
},
body: JSON.stringify({
"amount": "2.10",
"txHash": "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060",
"reason": "Overpayment returned"
})
});
if (!response.ok) {
throw new Error(`BOSPay request failed: ${response.status}`);
}
const data = await response.json();