Payment lifecycle & statuses
Every payment reports two independent axes — status, where the money is, and subStatus, what exactly is happening. Read both; never infer one from the other.
status tells you where the money is (pending → accepted → success, or failed); subStatus tells you what exactly is happening (awaitingPayment, confirming, overpaid, expired, …). They move independently.
The lifecycle
- Created.
pending / createdwhen an activation flow is configured (no address yet), otherwisepending / awaitingPaymentwith the deposit address issued and the payment window counting. - Activated. With
activationFlowSecondsset, the window starts counting only when you callPOST /v1/payments/{paymentId}/activateor the customer opens the hosted page — so the timer never runs while the customer is still in your cart. Range: 1–3600 seconds. - Paying. The first on-chain transfer moves the payment to
pending / confirming. All transfers detected for the payment are listed atGET /v1/payments/{paymentId}/transactions. - Accepted. Enough confirmations have accumulated to act on — ship, credit, deliver. The balance is credited, a
payment.acceptedwebhook fires. Not final yet. - Success. Irreversible; funds are withdrawable.
payment.successfires. Terminal. - Failed. Expired, cancelled, or invalidated without a valid payment.
payment.failedfires. Terminal.
Statuses and sub-statuses
Values are the enumerations of the public specification; descriptions come from the same source. → PaymentStatusEnum, PaymentSubStatusEnum
| status | Funds | subStatus you can see under it | What it means |
|---|---|---|---|
| pending | Not credited | created activated awaitingPayment confirming complianceHold | Awaiting funds, or funds seen and confirming. Nothing is credited yet. complianceHold means the transaction is held for compliance review. |
| accepted | Credited | completed overpaid underpaid | Safe confirmations reached and the balance is credited. Act on it — ship, credit, deliver. |
| success | Credited · withdrawable | completed overpaid underpaid | Irreversible and withdrawable. The sub-status records how the amount landed. |
| failed | Not credited | expired cancelled partiallyPaid complianceRejected | No valid payment; terminal. partiallyPaid means a partial transfer arrived but never reached acceptance; complianceRejected means screening rejected it and nothing was credited. |
Treat the status set as open
New sub-statuses may appear as the product grows. Read statuses from API responses instead of hardcoding exhaustive lists, and route anything unknown to a safe default in your code.
Timing you control
paymentWindowSeconds— how long the payment accepts funds: 300–86400 (5 minutes to 24 hours); project default applies when omitted.activationFlowSeconds— grace period before the window starts counting: 1–3600.expiresAtalways tells you the real deadline.- Both are fixed at creation.
{
"amount": "10000000",
"asset": "USDT_ARBITRUM",
"paymentWindowSeconds": 1800,
"activationFlowSeconds": 600,
"underpaymentTolerance": "500000"
}Underpayment, overpayment, expiry
- Underpaid: less arrived than requested. Set
underpaymentTolerance(integer string, same unit asamount, ≥ 0 and < amount) to accept small shortfalls — dust, gas rounding — as fully paid. Default 0: exact amount required. Example: for"10000000"(10 USDT), a tolerance of"500000"forgives a 0.50 USDT shortfall. - Overpaid: more arrived than requested. The excess is credited alongside the expected amount; the payment completes as
overpaid. - Expired: the window closed without sufficient funds —
failed / expired. A partial transfer that never reached acceptance ends asfailed / partiallyPaid; the amounts received are reported on the payment. - The dashboard and the API always show the real received amounts:
amountReceivedandamountConfirmed.
Idempotency and cancellation
externalIdis your reference, echoed on the payment and its webhooks. A request with anexternalIdthat already exists never creates a second payment — retries, timeouts, and double clicks are safe. The duplicate call is rejected with a409and the stable error code; fetch the existing payment instead.POST /v1/payments/{paymentId}/cancelstops a payment that hasn't completed; valid only from early statuses, moves it tofailed / cancelled.
Next: how Accepted and Success are decided → Settlement & finality.
Something unclear? payments@suward.com — we treat every integration question as a documentation defect.