Exemplo de solicitação e verificação de assinatura

Método da requisição: as APIs usam principalmente `GET` / `POST`; requisições JSON usam `application/json`.

Autenticação: as solicitações OpenAPI são verificadas com cabeçalhos e assinaturas HMAC-SHA256.

Cabeçalhos

CampoTipoObrigatórioDescrição
x-api-keystringSimComerciante API Key. Use o valor que começa com mch_ na página de configurações do comerciante API.
x-merchant-uidstringSimMerchant UID.
x-timestampstringSimMilissegundos de 13 dígitos timestamp. O desvio padrão permitido do relógio é de 5 minutos.
x-noncestringSimString aleatória exclusiva para cada solicitação, com até 128 caracteres. A reutilização é rejeitada.
x-signaturestringSimAssinatura hexadecimal gerada com HMAC-SHA256. A carga útil contém Merchant UID, timestamp, nonce, método, caminho, query canônico e body canônico.

Regras de assinatura

  • As solicitações usam application/json. Para GET APIs sem body, a parte body na assinatura é uma string vazia.
  • O caminho da assinatura deve ser o caminho API bruto, por exemplo /openapi/payin/orders, sem o domínio.
  • Os parâmetros de consulta são classificados por chave; As chaves JSON body são classificadas antes da serialização.
  • Falhas comuns de assinatura incluem timestamps expirados, valores nonce repetidos, ordem de campo inconsistente ou espaços extras.

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.

Exemplo do payload de assinatura

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

Exemplo completo

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

Exemplos de assinatura

  • As quatro linguagens usam as mesmas rotas, parâmetros e respostas. As credenciais vêm de UUGATE_MERCHANT_UID e UUGATE_API_KEY; UUGATE_BASE_URL usa https://api.uugate.com por padrão.
  • canonicalBody é JSON compacto com campos ordenados. Ao alterar parâmetros, ordene objetos recursivamente, preserve arrays e use UTF-8 sem escapes adicionais de barras ou Unicode. Valores monetários são strings; booleanos são true / false.
  • O sucesso retorna o objeto de negócio diretamente, sem envelope code / data. Verifique primeiro o status HTTP. Erros retornam code, message, data e requestId; recusas de segurança podem retornar apenas HTTP 401 / 403 com corpo vazio.
  • Após timeout ou HTTP 5xx, consulte o pedido antes de repetir a criação ou envio. Gere timestamp, nonce e assinatura novos em cada solicitação.

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.

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);

Erros de negócio retornam JSON com code, message, data e requestId. Chaves, assinaturas, timestamps, nonces inválidos ou restrições de segurança podem retornar HTTP 401 / 403 com corpo vazio e sem código de negócio. Verifique o status HTTP e o corpo antes de interpretar JSON. Não tome decisões pelo texto traduzido de message.

Campos de erro

CampoTipoObrigatórioDescrição
codenumberSimCódigo de erro comercial.
messagestringSimMensagem de erro.
dataobject | nullSimDados de erro adicionais.
requestIdstring | nullSimID de rastreamento de solicitação do servidor.

Exemplo de erro

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