Payments
Payment Orders
Check payment-order status and trigger the built-in payment webhook simulation.
Flow Summary
The current payment-order flow is:
Step 1. Read a payment orderGET /api/v1/payment-orders/{merchant_order_sn}
Step 2. Simulate a paid webhookPOST /api/v1/payment-orders/paid
Both routes should be treated as protected and require Authorization.
Important Scope Note
- these routes are mounted after the global
AuthMiddleware() - the current repository lookup uses only
merchant_order_sn - there is no extra ownership check in the handler or repository
That means any authenticated token that knows a valid merchant_order_sn can currently query that order.
1. Get Payment Order By Merchant Order SN
GET /api/v1/payment-orders/{merchant_order_sn}
Returns the payment-order snapshot for one merchant order serial number.
Path parameter
merchant_order_snis required
Response shape
The response includes fields such as:
idorder_snmerchant_order_snamount_usdtactual_usdtmerchant_usdtchain_typepayment_addresspayment_urlstatustransaction_hashconfirmationswebhook_urlcallback_urlqr_codeevent_typeexchange_ratenet_amountexpires_atexpires_incard_type
Important backend behavior
- if
expires_athas already passed, the service updates the order status toEXPIREDbefore returning it - when that happens, the repository also updates the related card request
payment_statustoEXPIRED expires_inis calculated at response time in seconds; once expired, it becomes0exchange_rateis truncated throughutils.TruncateExchangeRate(...)before responsecard_typeis populated by a left join fromcard_requestsusing the samemerchant_order_sn
Error behavior
- missing path values return a logical
400 - unknown order numbers return a logical
404
2. Simulate Paid Webhook
POST /api/v1/payment-orders/paid
Triggers the built-in test webhook flow for a payment order.
Request body
{
"merchant_order_sn": "PO-20260228-0001"
}
Success response shape
The response returns a generated payload with fields such as:
order_snmerchant_order_snamount_usdtactual_usdtmerchant_usdtstatuschain_typetransaction_hashpaid_attimestamppayment_address
Important backend behavior
- this is a simulation/testing endpoint, not a real payment callback receiver
- the service loads the order, builds a synthetic
PAIDpayload, and sends it asynchronously in a goroutine - the webhook target URL is currently hardcoded to
https://htp-webhook.vai247.pro/api/v1/webhooks/tokenb/payment - the webhook secret is also hardcoded in the service
merchant_usdtis currently simulated asamount_usdt * 0.9- the handler returns success immediately; it does not wait for the external webhook request to finish
- a successful API response here does not guarantee that the remote webhook accepted the request
Current implementation caveat
- the response payload adds
payment_addressbefore returning to the client - but the external webhook body is marshaled before that field is added
- in the current code, the client sees
payment_address, while the remote webhook body does not include it
Encryption note
- this route passes through
DecryptField() - you can send plain JSON or the encrypted wrapper format described in the overview
Integration Notes
- Use
GET /api/v1/payment-orders/{merchant_order_sn}for status polling after card-request payment creation. - Do not treat
POST /api/v1/payment-orders/paidas a production settlement API; it is a simulation helper. - Because lookup is not user-scoped yet, avoid exposing arbitrary order lookup in an untrusted client UI without extra server-side controls.