GET /api/v1/transactions/{transaction_id}
Verifies a specific transaction — mainly used to confirm the paygate_transaction_id you receive on your success_url/cancel_url redirect (see 03.01 — What comes back on success_url/cancel_url). Requires auth (HMAC or Firebase ID Token).
Unlike GET /api/v1/subscriptions/{external_ref}, which only reflects the current subscription state, this endpoint also covers one-time (mode="payment") transactions, which never create a subscription record at all.
With Firebase ID Token, the transaction’s external_ref must match the token’s own sub claim, same as 03.02 — requesting another user’s transaction returns 404 not_found (not 403, so a caller can’t distinguish “not yours” from “doesn’t exist”). With HMAC, you can query any transaction_id that belongs to your own app.
Response — success
{
"success": true,
"data": {
"transaction_id": 42,
"external_ref": "user-123",
"plan_ref": "premium_1m",
"amount": 199000,
"currency": "VND",
"mode": "subscription",
"status": "completed",
"created_at": "2026-09-15 06:45:42"
}
}
status is one of pending / completed / failed / canceled. completed here is the authoritative, server-verified value — unlike the paygate_status query param on your redirect, which only reflects which URL you landed on.
Response — not found
{ "success": false, "error": { "code": "not_found", "message": "No transaction found for this transaction_id." } }
HTTP 404. Returned both when the id doesn’t exist and when it belongs to a different app/user — never distinguishes the two.
Recommended flow
- User lands on your
success_url?paygate_transaction_id=42&paygate_external_ref=user-123&paygate_status=completed&.... - Call
GET /api/v1/transactions/42. - Check
data.status === "completed"anddata.external_ref === "user-123"(matches the redirect) before unlocking anything. - For subscriptions, you may additionally call GET /api/v1/subscriptions/user-123 to get
current_period_end.