Início rápido

Se você deseja apenas concluir a primeira integração, esta página é suficiente: gere cabeçalhos assinados, crie uma ordem de pagamento, verifique o retorno de chamada e retorne uma resposta 2xx.

Os exemplos usam a criação de ordem de pagamento por padrão. Os pedidos de pagamento usam a mesma assinatura, cabeçalhos de solicitação e cabeçalhos de retorno de chamada; apenas o endpoint e a carga útil do negócio mudam.

API de produçãohttps://api.uugate.com
Ativos compatíveisTRC20-USDT · BEP20-USDT · BEP20-USDC · SPL-USDC
Configuração de callbackAPI Key + notifyUrl
✓Merchant UID é a identidade exclusiva do comerciante atribuída pela plataforma. Ele é usado em cargas úteis x-merchant-uid e de retorno de chamada.
✓Prepare o API Key começando com mch_ nas configurações do comerciante API.
✓Prepare um notifyUrl publicamente acessível de propriedade do comerciante; é necessário ao criar pedidos.
Step 1

Gerar cabeçalhos assinados

As solicitações OpenAPI usam cinco cabeçalhos: x-api-key, x-merchant-uid, x-timestamp, x-nonce e x-signature.

  • Use o mesmo mch_ API Key como x-api-key e o segredo de assinatura.
  • O caminho da assinatura deve ser apenas o caminho API, por exemplo /openapi/payin/orders, sem o domínio.
  • A carga útil da assinatura é Merchant UID, timestamp, nonce, método, caminho, query canônico e body canônico.
Node.js
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);
Step 2

Criar pedido de cobrança

Depois de preparar os cabeçalhos assinados, chame a criação da ordem de pagamento API. Em caso de sucesso, use orderNo, cashierUrl e paymentUri.

  • Ponto final: POST /openapi/payin/orders.
  • Use o cashierUrl retornado quando o front-end do comerciante precisar redirecionar para a finalização da compra.
  • notifyUrl é obrigatório e passado com a solicitação de pedido. Nenhuma configuração separada de retorno de chamada de back-end é necessária.
Node.js
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/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');
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);
Step 3

Receber e processar retorno de chamada

Quando a plataforma chamar seu notifyUrl, verifique-o primeiro com apiKey, atualize a ordem comercial após a verificação e, em seguida, retorne 200 ou outra resposta 2xx.

  • A verificação de retorno de chamada usa apiKey, não a assinatura x OpenAPI.
  • Para pagamento, trate status=completed como o estado final de sucesso.
  • Este código apenas verifica callbacks. Envie o corpo original à entrada padrão e mapeie os cabeçalhos para UUGATE_CALLBACK_TIMESTAMP, UUGATE_CALLBACK_NONCE e UUGATE_CALLBACK_SIGNATURE. UUGATE_API_KEY deve ser a chave usada na criação. Valide o pedido e persista com idempotência em uma transação antes de retornar HTTP 2xx.
Node.js
import { createHmac, timingSafeEqual } from 'node:crypto';

function required(name) {
  const value = process.env[name]?.trim();
  if (!value) throw new Error(name + ' is required');
  return value;
}
const key = required('UUGATE_API_KEY');
const timestamp = required('UUGATE_CALLBACK_TIMESTAMP'), nonce = required('UUGATE_CALLBACK_NONCE');
const signature = required('UUGATE_CALLBACK_SIGNATURE');
const chunks = [];
for await (const chunk of process.stdin) chunks.push(chunk);
const rawBody = Buffer.concat(chunks);
const expected = createHmac('sha256', key).update(timestamp + '.' + nonce + '.', 'utf8').update(rawBody).digest();
const actual = Buffer.from(signature, 'hex');
if (!/^[a-fA-F0-9]{64}$/.test(signature) || actual.length !== expected.length || !timingSafeEqual(expected, actual))
  throw new Error('Invalid callback signature');
console.log('VERIFIED');

O timestamp, nonce e as credenciais fixos são valores de teste de assinatura offline. Em solicitações reais, use o timestamp atual em milissegundos e um novo nonce aleatório. As rotas API não têm prefixo de versão; v1 identifica apenas a assinatura de callbacks.

Execução: salve Java como UUGateExample.java (UUGateCallback.java para callbacks) e use java nome do arquivo; PHP: php example.php; Go: go run example.go; Node.js: node example.mjs. A verificação de callbacks lê o corpo original da entrada padrão.

O pagamento e o pagamento compartilham o mesmo algoritmo de assinatura e cabeçalhos de retorno de chamada, portanto, você não precisa de dois fluxos de autenticação.

Quando esta página fizer sentido, continue para parâmetros detalhados, estruturas de resposta e downloads de SDK.