Skip to content

Verify a payment

POST /api/v1/checkout/verify claims a session from your own backend. Use it when you already hold the TrxID: a customer sent it over chat, your support team read it from a screenshot, or you collect it in your own checkout instead of the hosted page.

Request

POST /api/v1/checkout/verify
curl -X POST "$KRONX_BASE_URL/api/v1/checkout/verify" \
  -H "x-api-key: $KRONX_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "sessionId": "3f8c2a10-5b7e-4d21-9c6f-8e1a2b3c4d5e",
    "trxId": "9ABCD123",
    "provider": "bkash"
  }'
FieldRules
sessionIdThe session UUID from checkout_url. Anything that is not a UUID returns 404.
trxIdTrimmed and upper-cased, then required to match [A-Z0-9]{6,20}.
providerLower-cased. One of bkash, nagad, rocket, upay, cellfin.

Success

200 OK
{
  "success": true,
  "message": "Payment verified successfully",
  "data": { "trx_id": "9ABCD123", "amount": 1200 }
}

The claim runs inside a single Postgres function that checks the amount, the expiry, your account status and the attempt count together. Two requests racing the same TrxID cannot both succeed, and a TrxID already applied to another session will not match.

Ownership is checked inside the claim, not before it.Passing a session that belongs to a different account returns the same 404 NOT_FOUND as a session that does not exist, so the endpoint cannot be used to probe for other merchants’ sessions.

Outcomes

StatuserrorWhat happened
200NoneClaimed, or already claimed with this same TrxID.
409ALREADY_COMPLETEDThe session was already completed with a different transaction.
400VERIFICATION_FAILEDNo matching unclaimed transaction. The TrxID or the amount does not line up.
429TOO_MANY_ATTEMPTSToo many failed attempts against this session. It is locked.
410SESSION_EXPIREDPast expires_at.
410SESSION_UNAVAILABLEThe session is cancelled or otherwise not accepting money.
404NOT_FOUNDNo such session for this account.
403VENDOR_INACTIVEThe account is not active.

The buyer-facing counterpart

POST /api/v1/checkout/submit takes the same three fields and returns the same outcomes, without an API key. The hosted page uses it; the session id is the authorisation. There is no ownership check because there is no authenticated account on that request.

A successful claim through either endpoint queues the callback, so you do not need to poll. See webhooks.