Créer un ordre de paiement sortant

Crée un ordre de paiement. En cas de succès, la plateforme gèle le montant du paiement et les frais de réseau, puis renvoie les détails de la commande.

Si fromAddress n’est pas fourni, le système sélectionne automatiquement une adresse avec un solde suffisant. Si aucun n’est disponible, le solde d’adresses est insuffisant.

POST/openapi/payout/orders

En-têtes

ChampTypeObligatoireDescription
x-api-keystringOuiMarchand API Key. Utilisez la valeur commençant par mch_ de la page des paramètres API du marchand.
x-merchant-uidstringOuiMerchant UID.
x-timestampstringOuiMilliseconde à 13 chiffres timestamp. La dérive d'horloge autorisée par défaut est de 5 minutes.
x-noncestringOuiChaîne aléatoire unique pour chaque requête, jusqu'à 128 caractères. La réutilisation est rejetée.
x-signaturestringOuiSignature hexadécimale générée avec HMAC-SHA256. La charge utile contient Merchant UID, timestamp, nonce, la méthode, le chemin, le query canonique et le body canonique.

Paramètres

ChampTypeObligatoireDescription
chainCodestringOuiCode de chaîne. Valeurs prises en charge : TRON / BSC / SOL.
tokenSymbolstringOuiSymbole de jeton.
fromAddressstringNonAdresse de l'expéditeur spécifiée. En cas d'omission, le système en attribue un automatiquement. Maximum 128 caractères.
toAddressstringOuiAdresse de réception. Maximum 128 caractères.
amountstringOuiMontant du paiement, jusqu'à 6 décimales.
deleteSourceAfterSuccessbooleanNonBooléen JSON facultatif, false par défaut. Si true, supprime logiquement la source uniquement après confirmation de ce paiement sur la blockchain ; aucun effacement en cas d’échec ou d’annulation. Les paiements n’exigent aucune réserve de solde.
merchantOrderNostringOuiNuméro de commande côté marchand. Maximum 128 caractères.
notifyUrlstringOuiRappel spécifique à la commande URL. Un HTTPS URL public appartenant au commerçant est recommandé. Maximum 500 caractères ; les destinations privées, loopback ou non sécurisées sont interdites.

Exemple de requête

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

Champs de réponse

ChampTypeObligatoireDescription
orderNostringOuiNuméro d’ordre de paiement de la plateforme.
merchantOrderNostring | nullOuiNuméro de commande du commerçant.
fromAddressstring | nullOuiAdresse réelle de l'expéditeur.
toAddressstringOuiAdresse de réception.
amountstringOuiMontant du paiement.
txHashstring | nullOuiLe hachage en chaîne est revenu après la diffusion.
statusstringOuisoumis / diffusé / confirmed / failed.
submittedAtstring | nullOuiHeure soumise.
broadcastedAtstring | nullOuiHeure de diffusion.
confirmedAtstring | nullOuiHeure de confirmation.
failedAtstring | nullOuiTemps raté.
createdAtstring | nullOuiTemps créé.

Exemple de réponse

{
  "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"
}

Exemples de code

Exécution : enregistrez Java sous UUGateExample.java (UUGateCallback.java pour les callbacks), puis utilisez java nom du fichier ; PHP : php example.php ; Go : go run example.go ; Node.js : node example.mjs. Les vérificateurs de callback lisent le corps brut sur l’entrée standard.

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

  • L API publique prend uniquement en charge les paiements unitaires. Les paiements par lot sont disponibles uniquement dans le tableau de bord marchand.
  • Un paiement de 10 nécessite au moins 10 de solde disponible à la source, sans réserve supplémentaire, quelle que soit la valeur de deleteSourceAfterSuccess. Le montant n’est pas réduit ; le compte de frais doit couvrir les frais réseau.
  • Transmettez true / false, pas des chaines. Les nouvelles tentatives avec le meme merchantOrderNo doivent conserver ce parametre. La suppression est impossible si d autres transferts sont inacheves.
  • La creation ou la diffusion reussie ne vaut pas confirmation sur la blockchain. La suppression logique conserve historique, comptabilite et references de cles. L echec ou l annulation conserve la 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.
  • Les quatre langages utilisent les mêmes chemins, paramètres et réponses. Les identifiants proviennent de UUGATE_MERCHANT_UID et UUGATE_API_KEY ; UUGATE_BASE_URL vaut https://api.uugate.com par défaut.
  • canonicalBody est un JSON compact aux clés triées. Après modification, triez les objets récursivement, conservez l’ordre des tableaux et utilisez UTF-8 sans échappement supplémentaire des barres obliques ou Unicode. Les montants sont des chaînes, les booléens true / false.
  • Une réponse réussie renvoie directement l’objet métier, sans enveloppe code / data. Vérifiez d’abord le statut HTTP. Les erreurs métier renvoient code, message, data et requestId ; les refus de sécurité peuvent se limiter à HTTP 401 / 403 avec un corps vide.
  • Après un timeout ou HTTP 5xx, consultez la commande avant de répéter sa création ou son envoi. Générez un nouveau timestamp, nonce et une nouvelle signature pour chaque requête.