Payment Statuses
A payment starts PENDING and ends in exactly one terminal status:
| Status | Terminal | Meaning | Merchant action |
|---|---|---|---|
PENDING | No | Awaiting payment — the customer has not completed an on-chain transfer yet. | Do not fulfil yet. |
SUCCESS | Yes | Paid — the received amount matches the expected amount. | Fulfil after verify. |
ACCEPTABLE | Yes | Paid with a small deviation that is within the tolerance you configured. | Fulfil after verify. |
MISMATCH | Yes | Paid, but under- or over-paid outside your tolerance. | Hold for manual review. |
EXPIRED | Almost | The payment window elapsed with no payment. | Do not fulfil — but see below. |
SUCCESS, ACCEPTABLE and MISMATCH are final: a payment never leaves them, and never changes into another one.
EXPIRED has one exception, described next.
An EXPIRED payment can still be paid
A customer who sends the transfer after the payment window has closed is still paid into the address Finomesh gave them — the blockchain does not know the window elapsed. Rather than lose those funds, Finomesh keeps watching that address for a grace period after expiry — currently 7 days, the same for every gateway, network, and asset. If the money arrives inside it, the payment reopens and resolves to SUCCESS, ACCEPTABLE or MISMATCH exactly as a timely payment would.
This means:
- An
EXPIREDpayment can change status days later, with no action by you or the customer. - You receive a second webhook for that payment, carrying the new status. If you cancelled the order on the
EXPIREDnotification, treat this one as a genuine late payment, not a duplicate — webhooks are delivered once per status change. - The amount is judged against the price quoted when the payment was created, not the price on the day it arrived. For a stablecoin that makes no difference. For a volatile asset, a deposit that lands days late may resolve
ACCEPTABLEorMISMATCHwhere a fresh quote would have saidSUCCESS. - Verify still decides. Call verify as usual;
depositPathon the response tells you why a payment resolved after expiring (see below).
A payment that expired and was never paid stays EXPIRED forever — which is the overwhelming majority of them.
depositPath — how the deposit reached us
Verify returns depositPath once a payment has a recorded deposit:
| Value | Meaning |
|---|---|
scanner | The ordinary case: paid inside the payment window. |
late_confirmation | Paid inside the window, but the blockchain confirmation reached us after it closed. The customer was on time. |
late_capture | Paid after the window closed, and credited anyway through the grace period described above. |
manual_inquiry | Matched to the payment from a transaction hash submitted after the fact. |
You do not need to branch on it to fulfil correctly — status remains the decision. It exists so a payment that resolved days after it expired can be explained rather than guessed at.
A second deposit to an already-resolved payment
A payment is settled by one deposit. Its deposit address stops being watched as soon as that deposit is detected — before the payment has even resolved. A later deposit to the same address is not detected, not credited, and produces no webhook, and Submit transaction inquiry cannot recover it either: inquiry only accepts a payment that is still PENDING or EXPIRED, and refuses one that has already resolved to SUCCESS, ACCEPTABLE or MISMATCH. Contact Finomesh support about such funds.
The same is true of a deposit that lands after the grace period has ended — it is not detected. There, because the payment is still EXPIRED, submitting the transaction hash via inquiry is the recovery path.
Wrong-asset deposits
A customer can send a different asset than the one they selected on the checkout (for example native TRX to a USDT deposit address). Finomesh still credits it: the deposit is valued in USD at the received asset's own market price and compared against what was expected, so it can resolve to SUCCESS, ACCEPTABLE, or MISMATCH exactly like a same-asset deposit — and, inside the grace period, it can reopen an EXPIRED payment the same way. Verify's receivedAssetSymbol / receivedAmountUsd fields tell you what actually arrived and its USD value.
If the price of either the quoted or the received asset is unavailable at the time, the deposit is not auto-credited and is handled manually instead. There is no per-gateway setting that forces every wrong-asset deposit to MISMATCH — don't design an integration around one.
How SUCCESS / ACCEPTABLE / MISMATCH is decided
Finomesh compares the USD value of what arrived on-chain (minus any fees the customer covers) against the USD value of what was expected:
- Exact match →
SUCCESS - Deviation within your configured tolerance (
overAcceptableDiff/underAcceptableDiff, as flat USD or a percentage) →ACCEPTABLE - Anything else →
MISMATCH
You configure the tolerance per payment at creation (or inherit your gateway's defaults). Setting checkAmountDeviation: false disables the check entirely — any paid amount resolves to SUCCESS.
The arithmetic behind that comparison:
- The base for a
PERCENTAGEtolerance is the USD value of the invoice principal at the price snapshot taken when the payment was created (≈amountUsd, up to sub-cent rounding) — nottotalValue(which includes fees). - The received side is gross received minus any fee the customer covers — a merchant-paid fee is never subtracted from it.
- Both sides are rounded to cents before comparison, a
PERCENTAGEtolerance is computed aspct / 100 × baserounded to cents, and the bounds are inclusive (<=). - On a wrong-asset deposit the received side is valued at the received asset's current market price, not a price captured at creation.
- If the offered asset has no USD price at all, the comparison falls back to asset units against
totalValue(without subtracting fees), and anABSOLUTEtolerance is then read in asset units rather than USD;deviationUsdis omitted in that case. deviationUsdon the verify response is computed againsttotalValue, not thisamountUsdbase — the two figures can differ by a cent right at the acceptance boundary. Usestatusto decide whether to fulfil; usedeviationUsdto explain aMISMATCH, not to re-derive the accept/reject decision yourself. On an open-amount payment it is computed againstamountUsdinstead and appears only onMISMATCH.
SUCCESS and ACCEPTABLE are the only statuses you should fulfil on, and only after a server-side verify call — never from the callback or webhook alone.