Request Example and Signature Verification

Request method: APIs mainly use `GET` / `POST`; JSON requests use `application/json`.

Authentication: OpenAPI requests are verified with request headers and HMAC-SHA256 signatures.

Request Headers

FieldTypeRequiredDescription
x-api-keystringYesMerchant API Key. Use the value beginning with mch_ from the merchant API settings page.
x-merchant-uidstringYesMerchant UID.
x-timestampstringYes13-digit millisecond timestamp. The default allowed clock drift is 5 minutes.
x-noncestringYesUnique random string for each request, up to 128 characters. Reuse is rejected.
x-signaturestringYesHex signature generated with HMAC-SHA256. The payload contains Merchant UID, timestamp, nonce, method, path, canonical query, and canonical body.

Signature Rules

  • Requests use application/json. For GET APIs with no body, the body part in the signature is an empty string.
  • The signature path must be the raw API path, for example /openapi/payin/orders, without the domain.
  • Query parameters are sorted by key; JSON body keys are sorted before serialization.
  • Common signature failures include expired timestamps, repeated nonce values, inconsistent field order, or extra spaces.

The fixed timestamp, nonce and credentials below are offline signature test values. Use the current millisecond timestamp and a new random nonce for real requests. API paths have no version prefix; v1 refers only to callback signing.

Signature Payload Example

880001
1776193200000
2f5c7b147c3748f0a8b3d9bb38aa91a4
POST
/openapi/payin/orders

{"amount":"100.00","chainCode":"TRON","merchantOrderNo":"M202604150001","notifyUrl":"https://merchant.example.com/api/uugate/payin-notify","tokenSymbol":"USDT"}

Full Request Example

POST /openapi/payin/orders HTTP/1.1
Host: api.uugate.com
Content-Type: application/json
x-api-key: mch_xxxxxxxxxxxxxxxxxxxx
x-merchant-uid: 880001
x-timestamp: 1776193200000
x-nonce: 2f5c7b147c3748f0a8b3d9bb38aa91a4
x-signature: 6d7e96fdbf3ec37c1ec515540f46c6c19b08754973c43293e54644c2da910838

{
  "chainCode": "TRON",
  "tokenSymbol": "USDT",
  "merchantOrderNo": "M202604150001",
  "amount": "100.00",
  "notifyUrl": "https://merchant.example.com/api/uugate/payin-notify"
}

Signature Code Example

  • All four languages use the same endpoint paths, parameters and response contract. Credentials come from UUGATE_MERCHANT_UID and UUGATE_API_KEY; UUGATE_BASE_URL defaults to https://api.uugate.com.
  • canonicalBody is compact JSON with sorted field names. After changing parameters, sort object keys recursively, preserve array order and use UTF-8 without extra slash or Unicode escaping. Amounts are strings; booleans are true / false.
  • Successful responses return the business object directly, without a code / data wrapper. Check HTTP status before processing the body. Business errors return code, message, data and requestId; security denials may only return HTTP 401 / 403 with an empty body.
  • After a timeout or HTTP 5xx, query the order before retrying creation or submission. Generate a new timestamp, nonce and signature for every new request.

Run: save Java as UUGateExample.java (UUGateCallback.java for callbacks) and use java filename; PHP: php example.php; Go: go run example.go; Node.js: node example.mjs. Callback verifiers read the raw body from standard input.

import { createHmac, randomBytes } from 'node:crypto';

function required(name) {
  const value = process.env[name]?.trim();
  if (!value) throw new Error(name + ' is required');
  return value;
}
const uid = "880001", key = "mch_xxxxxxxxxxxxxxxxxxxx";
const timestamp = "1776193200000", nonce = "2f5c7b147c3748f0a8b3d9bb38aa91a4";
const method = 'POST', path = '/openapi/payin/orders';
const canonicalQuery = '', canonicalBody = "{\"amount\":\"100.00\",\"chainCode\":\"TRON\",\"merchantOrderNo\":\"M202604150001\",\"notifyUrl\":\"https://merchant.example.com/api/uugate/payin-notify\",\"tokenSymbol\":\"USDT\"}";
const payload = [uid, timestamp, nonce, method, path, canonicalQuery, canonicalBody].join('\n');
const signature = createHmac('sha256', key).update(payload, 'utf8').digest('hex');
console.log(signature);

Ordinary business errors return JSON with code, message, data and requestId. Invalid keys, signatures, timestamps, nonces or security restrictions may return HTTP 401 / 403 with an empty body and no business code. In every language, check the HTTP status and body before parsing JSON. The localized message is not a decision key.

Error Response Fields

FieldTypeRequiredDescription
codenumberYesBusiness error code.
messagestringYesError message.
dataobject | nullYesAdditional error data.
requestIdstring | nullYesServer request trace ID.

Error Response Example

HTTP/1.1 401 Unauthorized
Cache-Control: no-store
Content-Length: 0