PixUSDT v1
API REST para gerar cobranças PIX e receber USDT na sua carteira automaticamente. Construída sobre HTTPS com auth Bearer e webhooks assinados via HMAC-SHA256.
Introdução
O PixUSDT é uma plataforma de pagamentos que recebe PIX em BRL e envia USDT (TRON / Polygon / BSC) automaticamente para a carteira configurada do lojista. Esta API permite integrar o PixUSDT ao seu checkout, sistema de gestão ou painel administrativo.
Fluxo típico: seu sistema chama POST /v1/charges com o valor → PixUSDT retorna QR code PIX e copia-e-cola → o pagador paga → PixUSDT recebe webhook do PSP, confirma o pagamento, e envia POST assinado para a sua URL configurada → seu sistema marca o pedido como pago.
Autenticação
Todas as requisições à API /v1/* exigem autenticação via API Key. Gere a sua em Dashboard → API Keys & Webhooks. As chaves começam com pk_live_ e devem ser tratadas como senha.
Header padrão (recomendado)
httpAuthorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Alternativa
httpX-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Health check
Endpoint público pra monitoramento (UptimeRobot, statuspage etc):
json{
"status": "ok",
"checks": {
"database": "ok",
"psp_mode": "pushinpay"
},
"uptime_seconds": 3600,
"response_time_ms": 2,
"version": "1.1.0",
"timestamp": "2026-05-06T12:00:00Z"
}
Retorna HTTP 200 quando tudo OK, 503 se algum serviço crítico está degradado.
Carteira & Rede USDT
O PixUSDT é não-custodial: nós convertemos PIX em USDT e enviamos diretamente para a carteira que você cadastra no painel. Não custodiamos cripto — assim que o PIX é confirmado, o operador da plataforma envia USDT direto pro seu wallet, on-chain, com TX hash registrado e auditável.
Redes suportadas
| Rede | Token | Taxa de rede aprox. | Tempo de confirmação |
|---|---|---|---|
| TRON | USDT (TRC-20) | ~$1 USD | ~30 segundos |
| POLYGON | USDT (Polygon PoS) | ~$0.05 USD | ~5 segundos |
| BSC | USDT (BEP-20) | ~$0.30 USD | ~3 segundos |
Cadastre seu endereço e a rede em Dashboard → Meu Perfil → Carteira USDT.
O endereço é validado automaticamente conforme o formato da rede escolhida.
A consulta da rede atual está disponível em GET /v1/account:
json{
"id": 42,
"name": "Loja Exemplo",
"email": "loja@exemplo.com",
"role": "admin",
"usdt_wallet": {
"address": "TXyz...AbCd",
"network": "TRON",
"configured": true
}
}
GET /v1/account no setup da sua integração e confirme que usdt_wallet.configured é true. Se for false, novas cobranças funcionam mas o envio de USDT fica pendente até você cadastrar uma carteira.
Erros
Todas as respostas de erro retornam JSON com a estrutura abaixo. O HTTP status indica a categoria do erro.
json{
"error": "validation_error",
"message": "Dados inválidos",
"details": { ... }
}
| Status | Code | Significado |
|---|---|---|
| 400 | validation_error | Body inválido ou campo faltando |
| 400 | amount_above_limit | Valor da cobrança ultrapassa o max_charge_brl da sua conta. Response inclui max_charge_brl com seu limite atual. |
| 401 | unauthorized | API key ausente, inválida ou revogada |
| 403 | profile_incomplete | Perfil do lojista não tem nome legal + WhatsApp cadastrados. Complete em Dashboard → Meu Perfil → Dados de Contato. |
| 403 | account_blocked_med | Conta bloqueada por débito de MED (devolução PIX) acima do limite. Anexe documentação em Dashboard → Compliance. |
| 403 | account_suspended | Conta suspensa pelo operador. Contate o suporte. |
| 404 | not_found | Cobrança ou recurso não existe |
| 429 | rate_limit | Limite de requisições excedido (50.000/24h) |
| 502 | psp_error | Erro no PSP que processa o PIX |
| 500 | internal_error | Erro interno do servidor |
Criar cobrança PIX
Gera um QR code PIX que o pagador escaneia / copia-e-cola pra pagar. O valor já vem com taxa da plataforma calculada: 3% sobre o valor do PIX + R$ 0,55 fixo (a taxa fixa é aplicada em todas as cobranças, independente do valor).
Request body
| Campo | Tipo | Descrição |
|---|---|---|
| amount obrigatório | number | Valor em reais. Mín R$ 1, máx limitado pelo seu max_charge_brl per-conta (default R$ 200, operator eleva caso a caso até R$ 100.000). Se ultrapassar, retorna 400 amount_above_limit com o seu limite atual. |
| external_id | string | ID do seu sistema (ex: ID do pedido). Usado pra consultar e idempotência |
| description | string | Descrição livre (até 255 chars) |
| expires_in_minutes | number | Tempo de expiração. Default 30, máx 1440. Piso silencioso de 30min — valores menores são automaticamente elevados, porque o PSP pode confirmar pagamento depois do QR "expirar" e disparar pix.expired antes do pix.received quebra integrações que travam a cobrança no expired. |
| webhook_url | string (URL) | URL de callback específica desta cobrança. Recebe pix.received e pix.expired assinados. Alternativa ao cadastro no painel. |
| customer.name | string | Nome do pagador |
| customer.email | string | Email do pagador |
| customer.document | string | CPF/CNPJ do pagador |
Exemplo cURL
bashcurl -X POST https://pixusdt.org/v1/charges \
-H "Authorization: Bearer pk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"amount": 49.90,
"external_id": "pedido-12345",
"description": "Plano Premium mensal",
"webhook_url": "https://seu-sistema.com/webhook/pixusdt",
"customer": {
"name": "João Silva",
"email": "joao@example.com",
"document": "12345678901"
}
}'
webhook_url no corpo da cobrança, o PixUSDT envia pix.received e pix.expired diretamente para essa URL — sem precisar cadastrar nada no painel. Útil quando seu sistema já sabe pra onde quer receber o callback antes de criar a cobrança (ex: integração com Gestor Inove). O payload e a assinatura HMAC-SHA256 são idênticos aos webhooks do painel.
pix.qr_code_base64epix.qr_code_image_url: strings prontas pra<img src=>(data URIdata:image/png;base64,…ou URL externa). Use direto:<img src={pix.qr_code_image_url} />.pix.qr_code_base64_raw: base64 puro (sem prefixo). Só use se você quiser montar o data URI manualmente:<img src={`data:image/png;base64,${pix.qr_code_base64_raw}`} />.
<img src={`data:image/png;base64,${pix.qr_code_base64}`} /> — isso duplica o prefixo e quebra a imagem (use qr_code_base64_raw nesse caso).
Response 201
json{
"id": "1842",
"external_id": "pedido-12345",
"status": "pending",
"amount": 49.90,
"amount_cents": 4990,
"fees": {
"platform_fee_pct": 3.0,
"percentage_fee_brl": 1.50,
"fixed_fee_brl": 0.55,
"total_fee_brl": 2.05,
"net_brl": 47.85
},
"pix": {
"qr_code": "00020126580014BR.GOV.BCB.PIX...",
"qr_code_base64": "data:image/png;base64,iVBORw0...",
"qr_code_image_url": "data:image/png;base64,iVBORw0...",
"qr_code_base64_raw": "iVBORw0KGgoAAAANSUhEUgAAA...",
"copy_paste": "00020126580014BR.GOV.BCB.PIX..."
},
"expires_at": "2026-05-05T18:30:00.000Z",
"created_at": "2026-05-05T18:00:00",
"psp_id": "a1b5323c-9e68-4afb-8927-94cdcef7a156"
}
Consultar cobrança
Retorna o status atual de uma cobrança. O {id} pode ser tanto o id retornado pelo PixUSDT quanto o external_id que você passou no momento da criação.
bashcurl https://pixusdt.org/v1/charges/pedido-12345 \
-H "Authorization: Bearer pk_live_xxx"
Status possíveis
| Status | Significado |
|---|---|
| pending | Aguardando pagamento |
| paid | Pago e confirmado pelo PSP |
| expired | QR code expirou sem pagamento |
| failed | Erro no processamento |
| refunded | Estornado |
Listar cobranças
bashcurl "https://pixusdt.org/v1/charges?status=paid&limit=50" \
-H "Authorization: Bearer pk_live_xxx"
Info da conta
Retorna informações do dono da API key. Útil pra validar a chave durante setup da integração.
Saldo
json{
"gross_received_brl": 12483.50,
"pending_brl": 347.00,
"sent_usdt_brl": 11250.00,
"total_fees_brl": 374.50,
"net_brl": 12109.00,
"med": {
"debt_brl": 0,
"block_threshold_brl": 200,
"account_blocked": false
},
"account_status": "active"
}
Campos
| Campo | Descrição |
|---|---|
| gross_received_brl | Total bruto recebido em PIX (todo histórico) |
| pending_brl | Cobranças pending aguardando pagamento |
| sent_usdt_brl | Equivalente BRL do USDT já enviado pra sua carteira |
| total_fees_brl | Soma das taxas da plataforma cobradas até hoje |
| net_brl | Saldo líquido (gross − fees) |
| med.debt_brl | Débito acumulado por MEDs (devoluções PIX) abertos |
| med.block_threshold_brl | Limite a partir do qual a conta é bloqueada por MED |
| med.account_blocked | true se conta bloqueada por MED — POST /v1/charges vai retornar 403 account_blocked_med |
| account_status | active | suspended | blocked_med |
Conversões USDT
Histórico de envios USDT confirmados pelo operador. Cada PIX pago gera uma transaction quando o USDT é enviado on-chain.
bashcurl "https://pixusdt.org/v1/transactions?status=confirmed" \
-H "Authorization: Bearer pk_live_xxx"
Filtros disponíveis
| Query param | Tipo | Descrição |
|---|---|---|
| status | string | pending | sent | confirmed |
| charge_id | string | ID interno PixUSDT da cobrança |
| external_id | string | ID que você passou na criação da cobrança |
| network | string | TRON | POLYGON | BSC |
| limit | number | Default 50, máx 200 |
| offset | number | Paginação |
Response
json{
"data": [
{
"id": "42",
"charge_id": "1842",
"external_id": "pedido-12345",
"amount_brl": 49.90,
"usdt_amount": 9.18,
"rate_brl": 5.22,
"network": "BSC",
"to_address": "0x95c4d336087276c291bade26b556562be4d52c7b",
"tx_hash": "0x482cc3...0137",
"explorer_url": "https://bscscan.com/tx/0x482cc3...0137",
"network_fee_usd": 0.30,
"status": "confirmed",
"sent_at": "2026-05-06T18:23:10Z",
"confirmed_at": "2026-05-06T18:23:42Z"
}
],
"total": 1,
"limit": 50,
"offset": 0
}
Pra consultar uma conversão específica:
Eventos de Webhook
O PixUSDT envia POST para a URL configurada no dashboard sempre que um evento da sua conta acontece. Cadastre suas URLs em Dashboard → API Keys & Webhooks → Webhooks Configurados.
| Evento | Quando dispara |
|---|---|
| pix.received | Quando uma cobrança PIX é confirmada como paga pelo PSP |
| pix.expired | Quando uma cobrança expira sem pagamento |
| usdt.sent | Quando o USDT é enviado pra carteira do lojista (TX hash registrado) |
| usdt.confirmed | Quando a transação USDT é confirmada na blockchain (em roadmap) |
Exemplo de payload usdt.sent
json{
"event": "usdt.sent",
"timestamp": "2026-05-06T18:23:42.521Z",
"data": {
"charge": {
"id": 1842,
"external_id": "pedido-12345",
"amount_brl": 49.90,
"psp_id": "a1b5323c-9e68-4afb-8927-94cdcef7a156"
},
"transaction": {
"id": 42,
"usdt_amount": 9.18,
"rate_brl": 5.22,
"network": "BSC",
"to_address": "0x95c4d336087276c291bade26b556562be4d52c7b",
"tx_hash": "0x482cc3...0137",
"network_fee": 0.30,
"explorer_url": "https://bscscan.com/tx/0x482cc3...0137",
"batch": false,
"status": "sent"
}
}
}
usdt.sent separado, com transaction.batch: true e transaction.batch_size indicando quantas cobranças compartilham o mesmo tx_hash.
Payload do webhook
Todos os webhooks chegam como POST application/json com a estrutura:
json{
"event": "pix.received",
"timestamp": "2026-05-05T18:23:14.521Z",
"data": {
"charge": {
"id": 1842,
"amount_brl": 49.90,
"status": "paid",
"paid_at": "2026-05-05 18:23:10",
"created_at": "2026-05-05 18:00:00",
"psp_id": "a1b5323c-9e68-4afb-8927-94cdcef7a156",
"payer_name": "João Silva",
"payer_document": "123.456.789-01"
},
"client": null
}
}
Headers enviados
httpContent-Type: application/json
X-Webhook-Signature: 4e8c5f3a2b1c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e
X-Webhook-Timestamp: 1714000000
X-Webhook-Id: 9f2d4e8a-1b3c-4d5e-8f9a-1b2c3d4e5f6a
X-Webhook-Source: pixusdt
Validação HMAC-SHA256 + Timestamp (anti-replay)
O PixUSDT assina o webhook em 2 etapas pra prevenir ataques de replay:
X-Webhook-Timestamp— Unix timestamp (segundos) de quando o webhook foi assinadoX-Webhook-Signature— HMAC-SHA256 de"{timestamp}.{body_bruto}"usando seuwebhook_secretcomo chave
Sua validação deve fazer 2 checks:
- O
timestampestá dentro de uma janela de tolerância (recomendado: ±5 minutos) — se for fora, rejeita (suspeita de replay) - Recalcula HMAC-SHA256 sobre
"{timestamp}.{body}"e compara em tempo constante (usehmac.compare_digest,crypto.timingSafeEqual, etc — nunca===)
Node.js (Express)
javascriptimport crypto from 'node:crypto';
import express from 'express';
const SECRET = process.env.PIXUSDT_WEBHOOK_SECRET; // whsec_...
const TOLERANCE_SEC = 300; // 5 minutos
const app = express();
app.post('/webhook/pixusdt',
express.raw({ type: 'application/json' }),
(req, res) => {
const ts = req.header('X-Webhook-Timestamp');
const sig = req.header('X-Webhook-Signature');
if (!ts || !sig) return res.status(401).send('missing headers');
// 1) Janela temporal
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(ts, 10)) > TOLERANCE_SEC) {
return res.status(401).send('timestamp out of tolerance');
}
// 2) Recalcula HMAC sobre "timestamp.body"
const expected = crypto.createHmac('sha256', SECRET)
.update(`${ts}.${req.body.toString()}`)
.digest('hex');
// 3) Compara em tempo constante
const ok = sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
if (!ok) return res.status(401).send('invalid signature');
const event = JSON.parse(req.body.toString());
if (event.event === 'pix.received') {
console.log('PIX confirmado:', event.data.charge.external_id);
}
res.status(200).json({ ok: true });
}
);
PHP (Laravel)
php$secret = env('PIXUSDT_WEBHOOK_SECRET');
$tolerance = 300; // 5 minutos
$body = $request->getContent();
$ts = $request->header('X-Webhook-Timestamp');
$sig = $request->header('X-Webhook-Signature');
if (!$ts || !$sig) abort(401, 'missing headers');
// 1) Janela temporal
if (abs(time() - intval($ts)) > $tolerance) {
abort(401, 'timestamp out of tolerance');
}
// 2) Recalcula HMAC sobre "timestamp.body"
$expected = hash_hmac('sha256', $ts . '.' . $body, $secret);
// 3) Compara em tempo constante
if (!hash_equals($expected, $sig)) {
abort(401, 'invalid signature');
}
$event = json_decode($body, true);
if ($event['event'] === 'pix.received') {
Order::where('external_id', $event['data']['charge']['external_id'])
->update(['status' => 'paid']);
}
Python (FastAPI)
pythonimport hmac, hashlib, os, json, time
from fastapi import FastAPI, Request, HTTPException
SECRET = os.environ['PIXUSDT_WEBHOOK_SECRET'].encode()
TOLERANCE = 300 # 5 minutos
app = FastAPI()
@app.post('/webhook/pixusdt')
async def webhook(request: Request):
body = await request.body()
ts = request.headers.get('x-webhook-timestamp', '')
sig = request.headers.get('x-webhook-signature', '')
if not ts or not sig:
raise HTTPException(401, 'missing headers')
# 1) Janela temporal
if abs(int(time.time()) - int(ts)) > TOLERANCE:
raise HTTPException(401, 'timestamp out of tolerance')
# 2) Recalcula HMAC sobre "timestamp.body"
payload = f"{ts}.{body.decode()}".encode()
expected = hmac.new(SECRET, payload, hashlib.sha256).hexdigest()
# 3) Compara em tempo constante
if not hmac.compare_digest(sig, expected):
raise HTTPException(401, 'invalid signature')
event = json.loads(body)
if event['event'] == 'pix.received':
... # processa pagamento
return {'ok': True}
X-Webhook-Timestamp agora é obrigatório.
Rotação do Webhook Secret
Quando você regenera sua API key (botão 🔄 REGENERAR no dashboard), o webhook_secret também é trocado.
A revogação é imediata — não há grace period no nosso lado:
- O secret antigo é marcado como
revokedatomicamente no momento da regeneração - Webhooks já em voo (disparados antes do clique) podem chegar com a assinatura do secret antigo, dependendo da latência
- Webhooks disparados depois usam o novo secret
Estratégia recomendada do lado cliente pra rotação sem perder webhooks:
- Configure 2 variáveis de ambiente:
PIXUSDT_WEBHOOK_SECRET(atual) ePIXUSDT_WEBHOOK_SECRET_PREV(anterior) - No handler do webhook, valide a assinatura contra ambos os secrets — aceita se qualquer um bater
- Quando rotacionar: pegue o secret novo no dashboard, copie o atual pra
_PREV, coloque o novo em_SECRET, faça reload da app - Após ~5 minutos (janela de webhooks em voo + retries), pode descartar o
_PREV
javascript// Validação aceitando 2 secrets durante janela de rotação
const SECRETS = [
process.env.PIXUSDT_WEBHOOK_SECRET,
process.env.PIXUSDT_WEBHOOK_SECRET_PREV
].filter(Boolean);
function isValid(ts, body, sig) {
return SECRETS.some(secret => {
const expected = crypto.createHmac('sha256', secret)
.update(`${ts}.${body}`)
.digest('hex');
return sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
});
}
SDKs / Bibliotecas
Atualmente não fornecemos SDKs oficiais — a API é pequena o suficiente pra ser consumida com qualquer client HTTP (axios, requests, Guzzle, etc.). SDKs em Node.js, PHP e Python estão no roadmap.
Changelog
- v1.2 · 2026-05-15
- Taxa da plataforma simplificada: 3% + R$ 0,55 fixo aplicados em TODAS as cobranças (antes a taxa fixa só caía em PIX abaixo de R$ 50). Campos
fees.percentage_fee_brl,fees.fixed_fee_brlefees.total_fee_brlrefletem a nova fórmula. POST /v1/charges: response agora tem 3 campos pra QR Code —pix.qr_code_base64epix.qr_code_image_url(string pronta pra<img src=>) +pix.qr_code_base64_raw(base64 puro pra montar manual).- Limite por cobrança agora é per-conta (
max_charge_brl, default R$ 200). Erro 400amount_above_limitretorna o limite atual. - Gate de perfil:
POST /v1/chargesexige nome legal + WhatsApp cadastrados — retorna 403profile_incompletese incompleto. - Erro 403
account_blocked_med: se conta bloqueada por débito de MED, novas cobranças são rejeitadas. Estado consultável viaGET /v1/balance.med. - Endpoint novo:
GET /v1/transactionseGET /v1/transactions/{id}— histórico de envios USDT comtx_hash,network,explorer_url. GET /v1/balance: response expandido comsent_usdt_brl,med.*eaccount_status.
- Taxa da plataforma simplificada: 3% + R$ 0,55 fixo aplicados em TODAS as cobranças (antes a taxa fixa só caía em PIX abaixo de R$ 50). Campos
- v1.1 · 2026-05-06
- Webhook signature agora inclui
X-Webhook-Timestamp(HMAC sobre"{timestamp}.{body}", anti-replay com janela ±5min). - Novo evento
usdt.sentcom TX hash on-chain.
- Webhook signature agora inclui
- v1.0 · lançamento
- Endpoints
/v1/charges,/v1/account,/v1/balance. - Webhooks
pix.receivedepix.expiredcom assinatura HMAC-SHA256.
- Endpoints
PixUSDT é uma solução de pagamento que converte PIX em USDT (stablecoin Tether). Não somos afiliados, parceiros ou licenciados pela Tether Limited. "USDT" refere-se ao ativo de liquidação utilizado pela plataforma.