Skip to content

Epusdt API Documentation ​

Developers can integrate Epusdt payment collection into business systems through its HTTP API. This document follows the routes available in the current source code.

The legacy POST /api/v1/order/create-transaction route is no longer registered. Use POST /payments/gmpay/v1/order/create-transaction to create orders.

API Overview ​

ScenarioMethodPathSignature Required
Create GMPay transactionPOST/payments/gmpay/v1/order/create-transactionYes
Get public payment configGET/payments/gmpay/v1/configNo
Cashier pageGET/pay/checkout-counter/{trade_id}No
Cashier initialization dataGET/pay/checkout-counter-resp/{trade_id}No
Check payment statusGET/pay/check-status/{trade_id}No
Switch payment network/channelPOST/pay/switch-networkNo
Create EPay-compatible transactionGET/POST/payments/epay/v1/order/create-transaction/submit.phpYes
OkPay platform callbackPOST/payments/okpay/v1/notifyOkPay signature

Unified Response Format ​

Except for redirects and plain-text callback endpoints, APIs return JSON:

json
{
  "status_code": 200,
  "message": "success",
  "data": {},
  "request_id": "b1344d70-ff19-4543-b601-37abfb3b3686"
}

Fields:

FieldTypeDescription
status_codeintegerBusiness status code. Success is 200; error codes are listed at the end of this document.
messagestringResponse message.
dataobject/nullResponse data.
request_idstringRequest ID generated by the server.

Signature errors return HTTP 401. Business errors usually return HTTP 400 with a specific business code in status_code.

Signature Rules ​

The current version uses unified merchant credentials. Each request must include pid; the server uses pid to find the matching secret_key as the signing key. A default installation creates a default API key with PID 1000.

GMPay Signature ​

Since v2.0.0, GMPay uses HMAC-SHA256. This is a breaking change from the pre-v2 MD5 rule. Existing GMPay clients must update request and callback signing before deploying v2.0.0 or later. The EPay-compatible API still uses MD5.

  1. Sort all non-empty parameters by ASCII key order in ascending order.
  2. Join them as key=value pairs with &.
  3. Exclude the signature field.
  4. Calculate HMAC-SHA256 using the merchant secret_key as the HMAC key and the joined parameter string as the message.
  5. Encode the result as 64-character lowercase hexadecimal text and send it as signature.

Notes:

  • pid must participate in the signature.
  • GMPay payment_type is optional. If a non-empty payment_type is submitted, it must participate in the GMPay signature calculation like other non-empty parameters.
  • Empty strings and null do not participate in signing.
  • Parameter names are case-sensitive.
  • JSON numbers participate in signing using the server-side numeric format. For example, 100.00 is parsed as 100; use application/x-www-form-urlencoded if you need to preserve string formatting.

Example parameters:

text
pid=1000
order_id=ORD202605230001
currency=cny
token=usdt
network=tron
amount=100
notify_url=https://merchant.example/notify
redirect_url=https://merchant.example/return
name=VIP

The following example assumes secret_key is epusdt_secret_key, only to demonstrate signature calculation.

Canonical parameter string:

text
amount=100&currency=cny&name=VIP&network=tron&notify_url=https://merchant.example/notify&order_id=ORD202605230001&pid=1000&redirect_url=https://merchant.example/return&token=usdt

Result:

text
signature=6f874b1919d95081835e2809b620e354a5866f5a6dbb2e432d1627f1eb10059d

PHP Signature Examples ​

GMPay uses the signature field and excludes only signature during signing:

php
function gmpaySign(array $params, string $secretKey): string
{
    unset($params['signature']);
    ksort($params, SORT_STRING);

    $pairs = [];
    foreach ($params as $key => $value) {
        if ($value === '' || $value === null) {
            continue;
        }
        $pairs[] = $key . '=' . $value;
    }

    return hash_hmac('sha256', implode('&', $pairs), $secretKey);
}

The EPay-compatible API uses the sign field and excludes sign plus sign_type during signing:

php
function epaySign(array $params, string $secretKey): string
{
    unset($params['sign'], $params['sign_type']);
    ksort($params, SORT_STRING);

    $pairs = [];
    foreach ($params as $key => $value) {
        if ($value === '' || $value === null) {
            continue;
        }
        $pairs[] = $key . '=' . $value;
    }

    return strtolower(md5(implode('&', $pairs) . $secretKey));
}

Create a GMPay Transaction ​

POST /payments/gmpay/v1/order/create-transaction

Supported content types:

  • Content-Type: application/json
  • Content-Type: application/x-www-form-urlencoded

GMPay Request Example ​

json
{
  "pid": "1000",
  "order_id": "ORD202605230001",
  "currency": "cny",
  "token": "usdt",
  "network": "tron",
  "amount": 100,
  "notify_url": "https://merchant.example/notify",
  "redirect_url": "https://merchant.example/return",
  "name": "VIP",
  "signature": "6f874b1919d95081835e2809b620e354a5866f5a6dbb2e432d1627f1eb10059d"
}

GMPay Request Parameters ​

FieldTypeRequiredDescription
pidstringYesMerchant PID, used to find the API key and included in signing.
order_idstringYesMerchant order number, maximum 32 characters, must be unique.
currencystringYesFiat currency, such as cny or usd.
tokenstringConditionally requiredPayment token, such as usdt, trx, usdc, or sol. GMPay can omit both token and network to create a placeholder order with status 4.
networkstringConditionally requiredPayment network, such as tron, solana, ethereum, bsc, polygon, or plasma. GMPay can omit both network and token to create a placeholder order with status 4.
amountnumberYesFiat amount; must be greater than 0.01.
notify_urlstringYesAsynchronous callback URL for successful payment.
redirect_urlstringNoSynchronous redirect URL after payment completion.
namestringNoProduct or order name.
payment_typestringNoGMPay-compatible field. It is not required. If a non-empty value is sent, it must participate in the GMPay signature calculation. If omitted in normal GMPay, the backend stores it as Gmpay; sending Epay case-insensitively stores it as Epay and uses the EPay callback format, and PID must be numeric.
signaturestringYesGMPay signature.

token and network must either both be provided or both omitted. If both are omitted, only a placeholder order containing amount/currency is created with status 4; no wallet is assigned, no on-chain payable amount is calculated, and no transaction amount is locked. The cashier can later call /pay/switch-network to choose a specific chain/token or OkPay. Providing only one of the two fields returns a parameter error.

Call /payments/gmpay/v1/config first to obtain the available network and token combinations.

GMPay Success Response ​

json
{
  "status_code": 200,
  "message": "success",
  "data": {
    "trade_id": "20260523171652123456001",
    "order_id": "ORD202605230001",
    "amount": 100,
    "currency": "CNY",
    "actual_amount": 14.29,
    "receive_address": "TTestTronAddress001",
    "token": "USDT",
    "status": 1,
    "expiration_time": 1779530812,
    "payment_url": "https://pay.example.com/pay/checkout-counter/20260523171652123456001"
  },
  "request_id": "b1344d70-ff19-4543-b601-37abfb3b3686"
}
FieldTypeDescription
trade_idstringEpusdt transaction number.
order_idstringMerchant order number.
amountnumberFiat amount submitted by the merchant.
currencystringFiat currency.
actual_amountnumberCrypto amount that must actually be paid.
receive_addressstringReceiving address.
tokenstringPayment token.
statusintegerOrder status. Status 4 means waiting for the user to choose token/network.
expiration_timeintegerOrder expiration time as a Unix timestamp in seconds.
payment_urlstringCashier URL. This URL redirects to the frontend cashier.

For a status 4 placeholder order, actual_amount is 0, while receive_address and token are empty. Expiration tasks or backend closure only change it to status 3; they do not unlock a transaction amount. On the first successful /pay/switch-network call, if a normal on-chain token/network is selected, the same parent order is completed in place with on-chain fields and becomes status 1, and only then is a real transaction lock created. If network=okpay is selected, the same parent order is converted in place into an OkPay order and returns the hosted OkPay payment link; no child order is created, and no local wallet address or on-chain lock is allocated. After the placeholder parent is first completed, is_selected remains false; a later selection of the same target marks the parent as selected, while switching to another payment target creates exactly one child order.

Get Public Payment Config ​

GET /payments/gmpay/v1/config

Returns cashier display settings, available chains/tokens, EPay defaults, and OkPay public configuration.

Public Config Success Response Example ​

json
{
  "status_code": 200,
  "message": "success",
  "data": {
    "supported_assets": [
      {
        "network": "tron",
        "display_name": "TRON",
        "tokens": ["TRX", "USDT"]
      },
      {
        "network": "solana",
        "display_name": "Solana",
        "tokens": ["SOL", "USDC", "USDT"]
      }
    ],
    "site": {
      "cashier_name": "Acme Cashier",
      "logo_url": "https://cdn.example.com/logo.png",
      "website_title": "Acme Payments",
      "support_link": "https://example.com/support",
      "background_color": "#0f172a",
      "background_image_url": "https://cdn.example.com/background.png"
    },
    "epay": {
      "default_token": "",
      "default_currency": "cny",
      "default_network": ""
    },
    "okpay": {
      "enabled": false,
      "allow_tokens": ["USDT", "TRX"]
    },
    "version": "v1.0.1"
  },
  "request_id": "b1344d70-ff19-4543-b601-37abfb3b3686"
}

supported_assets only includes combinations that satisfy all of the following:

  • The chain is enabled.
  • The chain has available wallet addresses.
  • The chain has at least one enabled token.

Cashier Page ​

GET /pay/checkout-counter/{trade_id}

Used by the browser to open the cashier. The current implementation returns 301 and redirects to:

text
/cashier/{trade_id}

The payment_url returned by the create transaction API is this address.

Cashier Initialization Data ​

GET /pay/checkout-counter-resp/{trade_id}

Used by the frontend cashier to read order display data. This endpoint only confirms that the order exists and returns basic data; call /pay/check-status/{trade_id} for the current payment status.

Cashier Init Success Response Example ​

json
{
  "status_code": 200,
  "message": "success",
  "data": {
    "trade_id": "20260523171652123456001",
    "amount": 100,
    "actual_amount": 14.29,
    "token": "USDT",
    "currency": "CNY",
    "receive_address": "TTestTronAddress001",
    "network": "tron",
    "status": 1,
    "payment_type": "gmpay",
    "expiration_time": 1779530812000,
    "redirect_url": "https://merchant.example/return",
    "payment_url": "",
    "created_at": 1779530212000,
    "server_time": 1779530312000,
    "is_selected": false
  },
  "request_id": "b1344d70-ff19-4543-b601-37abfb3b3686"
}

Note: expiration_time, created_at, and server_time returned by this endpoint are millisecond timestamps. server_time is the server timestamp used by the hosted cashier to calculate countdowns without relying on client clock accuracy.

If the order is a status 4 placeholder order, the response still uses the same parent trade_id, but on-chain payment fields have not been generated yet. This status can come from GMPay creation with empty token/network, or from EPay submit.php when neither the request nor database defaults provide a complete token/network:

json
{
  "status_code": 200,
  "message": "success",
  "data": {
    "trade_id": "20260523171652123456001",
    "amount": 100,
    "actual_amount": 0,
    "token": "",
    "currency": "CNY",
    "receive_address": "",
    "network": "",
    "status": 4,
    "payment_type": "gmpay",
    "expiration_time": 1779530812000,
    "redirect_url": "https://merchant.example/return",
    "payment_url": "",
    "created_at": 1779530212000,
    "server_time": 1779530312000,
    "is_selected": false
  },
  "request_id": "b1344d70-ff19-4543-b601-37abfb3b3686"
}

payment_type is the normalized integration type. The underlying order storage uses Epay/Gmpay; this endpoint returns lowercase epay/gmpay. epay uses the EPay callback format, while gmpay uses the default GMPay JSON callback format.

When the frontend sees status=4, it should show the network and token/payment-channel selector and call /pay/switch-network after the user chooses. After a successful on-chain selection, the parent order becomes status=1, and actual_amount, token, network, and receive_address are completed, but is_selected remains false until a later same-target selection marks it as selected. After a successful OkPay selection, the endpoint returns the same parent trade_id and a third-party payment_url; the parent order becomes status=1, is_selected=false, pay_provider=okpay, network=okpay, and receive_address=OKPAY.

Check Payment Status ​

GET /pay/check-status/{trade_id}

Payment Status Success Response Example ​

json
{
  "status_code": 200,
  "message": "success",
  "data": {
    "trade_id": "20260523171652123456001",
    "status": 1
  },
  "request_id": "b1344d70-ff19-4543-b601-37abfb3b3686"
}

Order statuses:

ValueDescription
1Waiting for payment
2Payment successful
3Expired
4Waiting for payment network/token selection

Submit Cashier Transaction Hash ​

POST /pay/submit-tx-hash/{trade_id}

This endpoint lets the hosted cashier submit an on-chain transaction hash for manual verification. It is intentionally narrower than the admin mark-paid action:

  • the order must be an on-chain order
  • the order must still be status=1 waiting for payment
  • expired orders are rejected before chain verification
  • OkPay/provider orders are not supported

Admin mark-paid can repair waiting or expired on-chain orders after the submitted chain transaction is verified. The cashier endpoint stays waiting-order only.

Submit Transaction Hash Request ​

json
{
  "block_transaction_id": "0xabc123..."
}

Submit Transaction Hash Success Response ​

json
{
  "status_code": 200,
  "message": "success",
  "data": {
    "trade_id": "20260523171652123456001",
    "block_transaction_id": "0xabc123...",
    "status": 2
  },
  "request_id": "b1344d70-ff19-4543-b601-37abfb3b3686"
}

TON accepts canonical ton:<receive_raw>:<lt>:<hash>, lt:hash, or a unique recent hash-only reference for the order receive address. Aptos accepts a transaction hash.

Switch Payment Network/Channel ​

POST /pay/switch-network

This endpoint is usually called by the cashier frontend to switch to another on-chain receiving address, or to switch to the OkPay hosted cashier.

Switch Network Request Example ​

json
{
  "trade_id": "20260523171652123456001",
  "token": "USDT",
  "network": "solana"
}

Switch to OkPay:

json
{
  "trade_id": "20260523171652123456001",
  "token": "USDT",
  "network": "okpay"
}

Switch Network Request Parameters ​

FieldTypeRequiredDescription
trade_idstringYesParent order transaction number.
tokenstringYesTarget token.
networkstringYesTarget network, or the special value okpay.

Switch Network Success Response ​

Returns the same structure as cashier initialization data. For on-chain orders, payment_url is empty; for OkPay orders, payment_url is the hosted payment link returned by OkPay. If the parent order is still status=4, the first switch to on-chain or OkPay completes the parent order in place and returns the same trade_id.

Notes:

  • Only parent orders can switch networks; child orders cannot be switched again.
  • The parent order must be waiting for payment with status 1, or be a placeholder with status 4.
  • The first concrete chain/token selection for status 4 completes the parent order in place and returns the same trade_id; it does not create a child order.
  • The first network=okpay selection for status 4 does not require the parent order to already have on-chain fields; the system completes the parent as an OkPay order in place and returns the same trade_id plus the OkPay payment_url; it does not create a child order.
  • After status 4 is completed, the order becomes status 1 but is_selected remains false; a later same-target selection returns the parent and marks it selected, while switching to another payment target creates a child order.
  • Each parent order can create at most one child order. After a child order has been created, the parent cannot be used to create a second new child order. Child orders themselves cannot switch networks.
  • If switching to the same token + network combination, the existing order is returned.

Create an EPay-Compatible Transaction ​

GET /payments/epay/v1/order/create-transaction/submit.php

POST /payments/epay/v1/order/create-transaction/submit.php

This endpoint is compatible with traditional EPay/YiPay integration flows. On success, it does not return JSON. It responds with HTTP 302 and redirects to:

text
/pay/checkout-counter/{trade_id}

EPay Request Parameters ​

FieldLocationTypeRequiredDescription
pidquery/formstringYesMerchant PID. Numeric PID is recommended; EPay callbacks output PID as a number.
moneyquery/formnumberYesFiat amount.
out_trade_noquery/formstringYesMerchant order number.
notify_urlquery/formstringYesAsynchronous callback URL.
return_urlquery/formstringNoSynchronous redirect URL after payment completion.
namequery/formstringNoProduct or order name.
typequery/formstringNoalipay or a valid token.network selector, such as usdt.tron. A valid selector determines the actual on-chain token and network and overrides EPay default token/network.
tokenquery/formstringNoOptional payment token. It has higher priority than backend epay.default_token; if sent, it must participate in EPay signing.
networkquery/formstringNoOptional payment network. It has higher priority than backend epay.default_network; if sent, it must participate in EPay signing.
currencyquery/formstringNoOptional fiat currency. It has higher priority than backend epay.default_currency; if sent, it must participate in EPay signing.
signquery/formstringYesEPay signature.
sign_typequery/formstringNoUsually MD5.

Signature rules:

  • Use the secret_key that corresponds to pid.
  • Exclude sign and sign_type.
  • Join all other non-empty parameters in ASCII key order, append secret_key, and MD5 the result. If the integration plugin sends extra fields such as sitename, those fields must also participate in signing.

Example string to sign:

text
money=100&name=VIP&notify_url=https://merchant.example/notify&out_trade_no=ORD202605230001&pid=1000&return_url=https://merchant.example/return&type=alipayepusdt_secret_key

Result:

text
sign=b865b0acbb2b01554c35a1bd33351452

EPay type/token/network/currency resolution priority:

  • type=token.network: if it is a currently available on-chain combination, such as usdt.tron, it determines token/network first. If type is neither a valid selector nor alipay, the API returns a parameter error.
  • token / network: if no valid type selector is used, request parameters are read. Explicitly submitted fields must participate in EPay signing.
  • epay.default_token / epay.default_network: used when the request does not provide the corresponding fields. A valid type selector bypasses these two defaults.
  • currency: request currency > database epay.default_currency > cny; this fallback rule is unchanged even when a valid type selector is used.
  • If final token/network both have values, a concrete on-chain order is created. If both are empty, a status 4 placeholder order is created. If only one is missing, the API returns a parameter error.
  • After the EPay signature passes, the server internally injects payment_type=Epay. That field does not participate in the inbound EPay signature. However, explicitly submitted type/token/network/currency are original EPay parameters and must participate in signing.

Backend defaults can be inspected through the epay field in /payments/gmpay/v1/config. A new installation only seeds epay.default_currency=cny; epay.default_token and epay.default_network are empty, so EPay requests without explicit token/network create status 4 placeholder orders. Existing database configuration is not overwritten by seeds. After deleting or emptying epay.default_token and epay.default_network, these two fields return empty strings.

Direct Token/Network Selection ​

Pass type=token.network to directly create an order for a specific on-chain asset. This is useful when an upstream “New API” or custom payment-method list exposes each chain/token combination as an independent payment option.

Example payment-method configuration:

json
[
  {
    "color": "rgba(var(--semi-blue-5), 1)",
    "name": "GM Pay",
    "type": "custom1"
  },
  {
    "color": "rgba(var(--semi-blue-5), 1)",
    "name": "GM Pay usdt.binance",
    "type": "usdt.binance"
  },
  {
    "color": "rgba(var(--semi-blue-5), 1)",
    "name": "GM Pay usdt.tron",
    "type": "usdt.tron"
  }
]

In this example:

  • type=usdt.binance is parsed directly as token=usdt and network=binance.
  • type=usdt.tron is parsed directly as token=usdt and network=tron.
  • These type values must be currently available token.network combinations on the server. Use supported_assets from /payments/gmpay/v1/config as the source of truth.
  • custom1 is not an Epusdt on-chain selector. If the upstream uses it as a generic “GM Pay” entry, the upstream plugin should map it to no type, to type=alipay, or to a normal GMPay placeholder-order flow. Do not submit custom1 unchanged to EPay submit.php, or the current server rejects it as a parameter error.

When submitting to EPay submit.php, type is an original inbound parameter and must participate in the EPay signature.

Merchant Asynchronous Callback ​

After an order is paid successfully, Epusdt sends an asynchronous notification to the order's notify_url. The target server must return HTTP 200 with response body ok or success case-insensitively. Otherwise, Epusdt retries according to queue configuration: after the first failure, it retries up to order_notice_max_retry times, using exponential backoff based on callback_retry_base_seconds, capped at 5 minutes.

GMPay Callback ​

Normal GMPay orders use a POST JSON callback.

json
{
  "pid": "1000",
  "trade_id": "20260523171652123456001",
  "order_id": "ORD202605230001",
  "amount": 100,
  "actual_amount": 14.29,
  "receive_address": "TTestTronAddress001",
  "token": "USDT",
  "block_transaction_id": "0xabc123...",
  "signature": "a1b2c3d4e5f6...",
  "status": 2
}
FieldTypeDescription
pidstringPID of the API key that owns the order. Merchants should use this PID to find the local key and verify the signature.
trade_idstringEpusdt transaction number.
order_idstringMerchant order number.
amountnumberFiat amount submitted by the merchant.
actual_amountnumberActual crypto amount received.
receive_addressstringReceiving address.
tokenstringPayment token.
block_transaction_idstringOn-chain transaction hash or third-party payment order number.
signaturestringCallback signature.
statusintegerCurrently callbacks are sent only for successful payments; the value is 2.

GMPay callback signature verification is the same HMAC-SHA256 rule as order creation, excluding the signature field.

EPay-Compatible Callback ​

Orders created through the EPay-compatible API use a GET request to callback notify_url with these parameters:

EPay callbacks output pid as a number. When using the EPay-compatible API or payment_type=Epay, make sure the API key PID is numeric.

text
pid=1000
trade_no=20260523171652123456001
out_trade_no=ORD202605230001
type=alipay
name=VIP
money=100.0000
trade_status=TRADE_SUCCESS
sign=a1b2c3d4...
sign_type=MD5

For verification, exclude sign and sign_type, join all other non-empty parameters in ASCII key order, append secret_key, and MD5 the result.

OkPay Platform Callback ​

POST /payments/okpay/v1/notify

This is the endpoint where the OkPay/OkayPay platform notifies Epusdt. It is not an endpoint that merchant systems call proactively. When configuring OkPay, set the callback URL to this path.

It supports JSON, application/x-www-form-urlencoded, multipart form, and raw query-string style bodies. Success returns plain text:

text
success

Failure returns HTTP 400:

text
fail

Epusdt verifies the OkPay signature with the configured OkPay shop token. After verification succeeds, it marks the matching OkPay order as paid and triggers the merchant callback. This OkPay order may come from completing a status 4 placeholder parent order in place, or from a child order created by a later switch.

status_code Values ​

Status CodeHTTP StatusDescription
200200Success
400400System error, or general parameter/validation error
401401Signature authentication error
10001400Wallet address already exists
10002400Payment transaction already exists; do not create it repeatedly
10003400No available wallet address; unable to start payment
10004400Invalid payment amount; unable to satisfy minimum payment unit
10005400No available amount channel
10006400Exchange-rate calculation error
10007400Order block already processed
10008400Order does not exist
10009400Unable to parse parameters
10010400Order status has changed
10011400Child order count limit exceeded
10012400Cannot switch network for a child order
10013400Order is not waiting for payment
10014400Chain is not enabled
10016400Supported asset does not exist
10017400Payment provider is not enabled
10018400Payment provider configuration is incomplete
10019400Payment provider does not support this token or network
最近更新