Integrate
API conventions
Base URL, response format, amounts, idempotency, retries and rate limits.
Base URL
/open/v1Sandbox and production share the host. The environment is that of the API key that signed the request; a key only sees orders of its own environment (others return ORDER_NOT_FOUND), and out_order_no is unique per environment.
Response format
Responses use real HTTP status codes and one envelope:
{
"trace_id": "6c1f0b9a3e2d4f5a",
"status_code": 200,
"message": "success",
"data": { "id": "…", "status": "CREATED" }
}{
"trace_id": "6c1f0b9a3e2d4f5a",
"status_code": 422,
"message": "The amount exceeds the app's payment limit.",
"error_code": "LIMIT_EXCEEDED"
}- Branch on
error_code, never onmessage(English, may change). - Log
trace_idand include it when contacting support. INVALID_REQUESTmessages name the field that failed — useful while developing.
Data formats
| Type | Format |
|---|---|
| Amount | String, USDT, positive, at most 2 decimals on input ("5", "5.5", "5.50"); always 2 decimals on output. Never use floats. |
| Currency | "USDT" only (CURRENCY_NOT_SUPPORTED) |
| Time | RFC 3339 UTC, e.g. 2026-11-07T09:30:00Z |
| IDs | HTP order id is a UUID. Your out_order_no / out_refund_no: 1–64 characters [A-Za-z0-9_-] |
| User | OIDC sub string (max 128) |
Idempotency
Create endpoints (POST /payments, POST /payments/{id}/refunds, POST /payouts) require an Idempotency-Key.
- Same key + same body → the first successful response is replayed. Nothing is created twice.
- Same key + different body →
409 IDEMPOTENCY_KEY_REUSED. - Same key while the first request is still running →
409 IDEMPOTENCY_IN_PROGRESS; retry shortly. - A request that failed does not consume the key: retrying it runs again.
Generate the key once per business operation (for example, store it with your order) and reuse it on every retry. Each retry still needs a fresh X-Nonce, X-Timestamp and signature.
out_order_no gives a second safety net: a different Idempotency-Key with an already used out_order_no returns ORDER_ALREADY_EXISTS.
Retries and timeouts
| Situation | What to do |
|---|---|
| Network error or timeout on a create | Retry with the same Idempotency-Key, or look up GET /open/v1/orders?out_order_no=… |
5xx, REPLAY_PROTECTION_UNAVAILABLE, IDEMPOTENCY_IN_PROGRESS |
Retry with exponential backoff |
429 TOO_MANY_REQUESTS |
Wait for Retry-After seconds |
Other 4xx |
Do not retry unchanged — fix the request |
Rate limits
Signed requests are limited per app (default 600 per minute). Over the limit you get 429 with Retry-After: 60.
Body size
Request bodies are limited to 64 KB.