Create Payout Order

Creates a payout order. After success, the platform freezes the payout amount and network fee, then returns order details.

If fromAddress is not provided, the system automatically selects an address with enough balance. If none is available, it returns insufficient address balance.

POST/openapi/payout/orders

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.

Request Parameters

FieldTypeRequiredDescription
chainCodestringYesChain code. Supported values: TRON / BSC / SOL.
tokenSymbolstringYesToken symbol.
fromAddressstringNoSpecified sender address. If omitted, the system assigns one automatically. Maximum 128 characters.
toAddressstringYesReceiving address. Maximum 128 characters.
amountstringYesPayout amount, up to 6 decimal places.
deleteSourceAfterSuccessbooleanNoOptional JSON boolean, false by default. When true, soft-delete the source only after this payout is confirmed on-chain; failure or cancellation does not delete it. Payouts require no balance reserve.
merchantOrderNostringYesMerchant-side order number. Maximum 128 characters.
notifyUrlstringYesOrder-specific callback URL. A public HTTPS URL owned by the merchant is recommended. Maximum 500 characters; private, loopback and unsafe destinations are forbidden.

Request Example

{
  "chainCode": "TRON",
  "tokenSymbol": "USDT",
  "fromAddress": "TNjBrNq2a9FK2vwu4W9C1QdLKSZ42Yx5YY",
  "toAddress": "TS7b7iD8G2PaPqK1TqSmLJ9nrrYH4oKX1S",
  "amount": "35.50",
  "deleteSourceAfterSuccess": false,
  "merchantOrderNo": "PO202604150001",
  "notifyUrl": "https://merchant.example.com/api/uugate/payout-notify"
}

Response Fields

FieldTypeRequiredDescription
orderNostringYesPlatform payout order number.
merchantOrderNostring | nullYesMerchant order number.
fromAddressstring | nullYesActual sender address.
toAddressstringYesReceiving address.
amountstringYesPayout amount.
txHashstring | nullYesOn-chain hash returned after broadcast.
statusstringYessubmitted / broadcasted / confirmed / failed.
submittedAtstring | nullYesSubmitted time.
broadcastedAtstring | nullYesBroadcast time.
confirmedAtstring | nullYesConfirmation time.
failedAtstring | nullYesFailed time.
createdAtstring | nullYesCreated time.

Response Example

{
  "orderNo": "PO1776193200A1B2C3D4",
  "merchantOrderNo": "PO202604150001",
  "fromAddress": "TNjBrNq2a9FK2vwu4W9C1QdLKSZ42Yx5YY",
  "toAddress": "TS7b7iD8G2PaPqK1TqSmLJ9nrrYH4oKX1S",
  "amount": "35.500000",
  "txHash": "b3d4fb0cb11eb86bb906d1e0ee3b84e17f40d5441d1e4c651ea46920a48a9a01",
  "status": "broadcasted",
  "submittedAt": "2026-04-15T03:00:00Z",
  "broadcastedAt": "2026-04-15T03:00:08Z",
  "confirmedAt": null,
  "failedAt": null,
  "createdAt": "2026-04-15T03:00:00Z"
}

Code Examples

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 = required("UUGATE_MERCHANT_UID"), key = required("UUGATE_API_KEY");
const timestamp = String(Date.now()), nonce = randomBytes(16).toString("hex");
const method = 'POST', path = '/openapi/payout/orders';
const canonicalQuery = '', canonicalBody = "{\"amount\":\"35.50\",\"chainCode\":\"TRON\",\"deleteSourceAfterSuccess\":false,\"fromAddress\":\"TNjBrNq2a9FK2vwu4W9C1QdLKSZ42Yx5YY\",\"merchantOrderNo\":\"PO202604150001\",\"notifyUrl\":\"https://merchant.example.com/api/uugate/payout-notify\",\"toAddress\":\"TS7b7iD8G2PaPqK1TqSmLJ9nrrYH4oKX1S\",\"tokenSymbol\":\"USDT\"}";
const payload = [uid, timestamp, nonce, method, path, canonicalQuery, canonicalBody].join('\n');
const signature = createHmac('sha256', key).update(payload, 'utf8').digest('hex');
const base = (process.env.UUGATE_BASE_URL || 'https://api.uugate.com').replace(/\/+$/, '');
const response = await fetch(base + path, {
  method, redirect: 'error', signal: AbortSignal.timeout(30000),
  headers: { 'Content-Type': 'application/json', 'x-api-key': key, 'x-merchant-uid': uid,
    'x-timestamp': timestamp, 'x-nonce': nonce, 'x-signature': signature },
  ...(canonicalBody ? { body: canonicalBody } : {}),
});
const raw = await response.text();
if (!response.ok) throw new Error('HTTP ' + response.status + ': ' + (raw || 'empty response body'));
JSON.parse(raw);
console.log(raw);

Notes

  • The public API supports single payouts only. Batch payouts are available only in the merchant dashboard.
  • A payout of 10 requires at least 10 in available source balance, with no additional reserve, regardless of deleteSourceAfterSuccess. The payout amount is not reduced; the fee account must still cover the network fee.
  • Pass true / false, not strings. Retries with the same merchantOrderNo must keep this parameter unchanged. Source deletion cannot be selected while other transfers are unfinished.
  • Successful creation or broadcast is not on-chain confirmation. Soft deletion preserves order history, ledgers and key references. Failure or cancellation does not delete the source.
  • The create API automatically attempts submission. Use status from the response or a later query; an HTTP 2xx alone is not on-chain success.
  • 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.