Skip to main content

Verify Payments

Verification is the step that makes your integration safe. The callback is a forgeable browser redirect and the webhook is a thin trigger — neither carries amounts, and neither should be trusted for fulfilment. The verify endpoint is the single source of truth.

The call

curl -X POST https://api-staging.finomesh.com/api/v1/payments/{paymentId}/verify \
-H "X-Api-Key: $FINOMESH_API_KEY"

No request body. The payment must belong to your gateway — a foreign or unknown ID returns 404 not_found.

The response

{
"success": true,
"data": {
"paymentId": "0d9f3a64-4f0c-4b6e-9f6e-2f4f4c1b8a21",
"status": "ACCEPTABLE",
"checkoutMode": "HOSTED",
"isVerified": true,
"verifiedAt": "2026-06-12T10:21:43Z",
"amount": "49.99",
"currencyCode": "USD",
"amountUsd": "49.99",
"txHash": "0xabc…",
"expectedAmount": "51.69",
"receivedAmount": "51.42",
"assetSymbol": "USDT",
"deviationUsd": "-0.27"
}
}
FieldMeaning
statusThe gateway's verdict. Fulfil on SUCCESS / ACCEPTABLE; withhold on MISMATCH / EXPIRED; wait on PENDING.
isVerified, verifiedAtWhether (and when) this payment has been verified. Flips on the first verify of a determined payment.
amount, currencyCode, amountUsdYour own invoice figures — use them to sanity-check the order you're about to fulfil.
expectedAmount, receivedAmount, assetSymbolThe comparable crypto pair: what the customer was quoted vs. what landed on-chain, both in assetSymbol units. Present only once a resolving transaction exists (SUCCESS / ACCEPTABLE / MISMATCH); absent for EXPIRED and PENDING.
deviationUsdSigned USD value of received − expected — negative for underpayment, positive for overpayment, "0" for an exact match. The single number to branch on for MISMATCH review.
txHashThe resolving on-chain transaction.

All monetary values are strings — parse them with a decimal type, never a float.

Semantics worth knowing

  • Idempotent — call it as many times as you like; repeat calls return the current authoritative state. verifiedAt keeps the timestamp of the first verification.
  • Verifying a PENDING payment is a no-op — you get status: "PENDING" with isVerified: false. Poll-verify is therefore a valid (if blunt) integration style; the webhook is the push alternative.
  • Verification quiets the webhook — once a payment is verified, any still-undelivered webhook for it is skipped. If your callback handler verifies promptly, you will often never receive the (now redundant) webhook.
  • Ownership-scoped — the payment must belong to the API key's gateway, otherwise 404. Cross-tenant payment IDs cannot be probed.
on callback OR webhook (both give you paymentId):
resp = POST /payments/{paymentId}/verify

switch resp.data.status:
SUCCESS, ACCEPTABLE → mark order paid, fulfil
MISMATCH → hold order, alert staff (deviationUsd tells the story)
EXPIRED → cancel order
PENDING → do nothing yet (trigger was early or forged)