HubPix API
API REST para receber e pagar via PIX e sacar em USDT (BSC), com webhooks assinados e gerenciáveis pela própria API. Tudo o que o painel faz com dinheiro e integração também pode ser feito por aqui, inclusive por agentes de IA.
Começando: crie a conta em hubpixtech.com/cadastro, ative o autenticador (2FA), gere sua chave em API e segurança e cadastre o IP do seu servidor na whitelist de saque.
| Base URL | https://hubpixtech.com/v1 |
| Formato | JSON. Sucesso: { "success": true, "data": ... }. Erro: { "success": false, "error": { "code", "message" } } |
| Valores | Sempre string decimal com ponto, em reais: "100.00" |
| Datas | ISO 8601 em UTC: 2026-10-02T12:00:00.000Z |
| OpenAPI | /openapi.json (OpenAPI 3.1), e esta documentação em Markdown em /llms.txt |
Autenticação
As chaves são geradas no painel, em API e segurança → Nova chave (pede o código do autenticador). Cada chave é um par: a pública e o segredo de saque. Elas são exibidas uma única vez: guarde em local seguro e nunca as coloque no frontend. Você pode ter até 5 chaves ativas (por exemplo, uma por sistema) e revogar qualquer uma a qualquer momento.
| Header | Credencial | Onde é exigida |
|---|---|---|
X-API-Key |
hpx_pk_... |
Todas as requisições |
X-Secret-Key |
hpx_sk_... |
Saques e ações sensíveis (POST /v1/pix/withdrawals, POST /v1/usdt/withdrawals, PUT /v1/ip-allowlist, DELETE /v1/api-keys/{id}) |
O X-Secret-Key precisa ser o do mesmo par da X-API-Key usada na requisição.
Whitelist de IP
São duas listas, ambas editáveis no painel (com 2FA). Cada lista aceita até 20 entradas, com IP único (203.0.113.10) ou faixa CIDR (203.0.113.0/24, até /16 no IPv4 e /48 no IPv6).
| Lista | Efeito |
|---|---|
| Saque | Obrigatória para sacar pela API. Só esses IPs podem chamar os endpoints que exigem X-Secret-Key. Sem nenhum IP cadastrado, o saque pela API é recusado com 403 IP_NOT_ALLOWED, e a mensagem traz o IP que chegou até nós |
| API | Opcional. Se tiver algum IP, todas as chamadas da API (inclusive consultas) passam a ser aceitas só desses IPs. Vazia: qualquer IP |
A primeira lista de saque é cadastrada pelo painel. Depois disso você também pode trocá-la pela API (PUT /v1/ip-allowlist), mas só a partir de um IP que já esteja nela. Assim, uma chave vazada não consegue liberar o IP de quem a roubou. Para descobrir o IP que o seu servidor usa para chegar até nós, chame GET /v1/account dele e veja requestIp.
Idempotência
Envie o header Idempotency-Key (um UUID gerado por você, de 8 a 100 caracteres) em todo POST que cria cobrança ou saque. Se a rede cair e você repetir a chamada com a mesma chave, a operação não é duplicada: devolvemos a mesma transação, com HTTP 200 em vez de 201.
Idempotency-Key: 9f3c2a1e-7b4d-4f1a-9c3e-2d5b8a7f6e01
O externalRef também é único por tipo de operação: repetir um externalRef já usado devolve 409 DUPLICATE.
Erros
| HTTP | code |
Quando |
|---|---|---|
| 400 | INVALID_JSON / BAD_REQUEST |
Corpo mal formado |
| 401 | INVALID_KEY |
X-API-Key ausente, inválida ou revogada |
| 401 | INVALID_SECRET |
X-Secret-Key ausente ou inválida em um saque |
| 403 | ACCOUNT_BLOCKED |
Conta bloqueada |
| 403 | ACCOUNT_PENDING |
Conta aguardando aprovação |
| 403 | SCOPE_DENIED |
Operação não habilitada para sua conta |
| 403 | IP_NOT_ALLOWED |
IP fora da whitelist (de saque ou da API) |
| 404 | NOT_FOUND |
Recurso inexistente ou de outra conta |
| 409 | DUPLICATE |
externalRef ou Idempotency-Key já usados |
| 422 | VALIDATION_ERROR |
Campo inválido (detalhe em message) |
| 422 | AMOUNT_OUT_OF_RANGE |
Valor fora dos limites da sua conta |
| 422 | INSUFFICIENT_BALANCE |
Saldo insuficiente para o saque |
| 429 | RATE_LIMITED |
Limite de requisições excedido |
| 502 | CHARGE_UNAVAILABLE |
Não foi possível gerar a cobrança agora; tente de novo |
| 503 | QUOTE_UNAVAILABLE |
Cotação de USDT indisponível no momento |
Limites de requisição
Até 600 requisições por minuto por conta. Acima disso a resposta é 429 RATE_LIMITED. Para acompanhar o status de uma transação, use webhooks. Se precisar consultar, faça no máximo 1 consulta por minuto por transação.
Conta e saldo
GET /v1/account
Dados da conta: status, saldo, suas taxas (fees), limites por operação, recursos habilitados e requestIp (o IP de onde a chamada chegou).
{
"success": true,
"data": {
"id": "c802502e-...", "name": "Minha Loja", "email": "[email protected]", "status": "ACTIVE",
"balance": "1520.40", "heldBalance": "250.00",
"fees": { "pixIn": { "percent": "7", "fixed": "0.00", "minimum": "0.00" }, "pixOut": { "percent": "0", "fixed": "0.00" }, "usdt": { "spreadPercent": "0" } },
"limits": { "pixInMin": "10.00", "pixInMax": null, "pixOutMin": "1.00", "pixOutMax": null },
"features": { "pixIn": true, "pixOut": true, "usdtOut": true, "usdtNetworks": ["BEP20"] },
"requestIp": "203.0.113.10"
}
}
A taxa do PIX In é max(mínimo, valor × percent% + fixo). A taxa do saque PIX é valor × percent% + fixo, somada por fora.
GET /v1/balance
curl https://hubpixtech.com/v1/balance -H "X-API-Key: hpx_pk_SUA_CHAVE"
{ "success": true, "data": { "balance": "1520.40", "heldBalance": "250.00" } }
balance é o que está disponível para saque. heldBalance é o que está reservado em saques ainda em andamento.
PIX In (cobranças)
POST /v1/pix/charges
Cria uma cobrança PIX e devolve o copia e cola (qrCode), que você mostra ao pagador como texto ou QR Code.
| Campo | Descrição | |
|---|---|---|
amount |
obrigatório | Valor bruto, string: "100.00" |
externalRef |
opcional | Seu identificador (id do pedido), até 100 caracteres. Volta nos webhooks e permite consulta |
description |
opcional | Até 140 caracteres |
expiresIn |
opcional | Segundos até expirar, de 60 a 1800. Padrão: 1800 (30 min) |
curl -X POST https://hubpixtech.com/v1/pix/charges \
-H "X-API-Key: hpx_pk_SUA_CHAVE" \
-H "Idempotency-Key: 9f3c2a1e-7b4d-4f1a-9c3e-2d5b8a7f6e01" \
-H "Content-Type: application/json" \
-d '{ "amount": "100.00", "externalRef": "pedido-1042", "description": "Pedido #1042" }'
Resposta 201:
{
"success": true,
"data": {
"id": "6f1d2c3b-9a8e-4f7d-b6c5-1a2b3c4d5e6f",
"type": "PIX_IN",
"status": "PENDING",
"amount": "100.00",
"fee": "7.00",
"netAmount": "93.00",
"externalRef": "pedido-1042",
"description": "Pedido #1042",
"qrCode": "00020126580014br.gov.bcb.pix...",
"expiresAt": "2026-10-02T12:30:00.000Z",
"paidAt": null,
"endToEndId": null,
"payer": null,
"createdAt": "2026-10-02T12:00:00.000Z",
"updatedAt": "2026-10-02T12:00:00.000Z"
}
}
netAmount é o que entra no seu saldo depois da taxa.
GET /v1/pix/charges/{id}
Consulta uma cobrança pelo id. Para consultar pelo seu identificador, use GET /v1/pix/charges?externalRef=pedido-1042.
Status: PENDING → PAID | EXPIRED | CANCELLED. Uma cobrança que não pôde ser gerada fica FAILED.
Quando PAID, a resposta traz paidAt, endToEndId e payer (name, document, institution, quando disponíveis).
O pagamento só é marcado como
PAID, e o saldo só é creditado, depois de confirmado na liquidação. Por isso o status muda alguns segundos depois do pagamento, nunca antes.
GET /v1/pix/charges
Lista paginada. Query: status, from, to (ISO 8601), page (padrão 1) e limit (padrão 50, máximo 100).
{ "success": true, "data": { "items": [ ... ], "page": 1, "limit": 50, "total": 132 } }
PIX Out (saques)
POST /v1/pix/withdrawals
Envia um PIX a partir do seu saldo. Exige X-API-Key, X-Secret-Key e o IP na whitelist de saque.
amount é o valor que chega ao recebedor. A taxa é somada por fora, e o total (totalAmount) sai do seu saldo no momento do pedido.
| Campo | Descrição | |
|---|---|---|
amount |
obrigatório | Valor que o recebedor recebe, string |
pixKey + pixKeyType |
opção A | pixKeyType: CPF, CNPJ, EMAIL, PHONE ou EVP (chave aleatória) |
brCode |
opção B | Código PIX copia e cola do recebedor |
externalRef |
opcional | Seu identificador. Volta nos webhooks |
description |
opcional | Até 140 caracteres |
curl -X POST https://hubpixtech.com/v1/pix/withdrawals \
-H "X-API-Key: hpx_pk_SUA_CHAVE" \
-H "X-Secret-Key: hpx_sk_SEU_SECRET" \
-H "Idempotency-Key: 41d1f2ab-90c7-4e2b-b7d3-0f6a8c9d1e22" \
-H "Content-Type: application/json" \
-d '{ "amount": "250.00", "pixKey": "12345678900", "pixKeyType": "CPF", "externalRef": "repasse-778" }'
Resposta 201:
{
"success": true,
"data": {
"id": "0b7e6f2a-3c4d-4e5f-8a9b-0c1d2e3f4a5b",
"type": "PIX_OUT",
"status": "PROCESSING",
"amount": "250.00",
"fee": "3.00",
"totalAmount": "253.00",
"pixKey": "12345678900",
"pixKeyType": "CPF",
"externalRef": "repasse-778",
"endToEndId": null,
"failureReason": null,
"createdAt": "2026-10-02T12:05:00.000Z"
}
}
Formato da chave: CPF e CNPJ só com dígitos (pontuação é removida). Telefone com DDD; aceitamos 11999998888, 5511999998888 ou +5511999998888.
Status do saque
| Status | Significado | Saldo |
|---|---|---|
PROCESSING |
Pagamento enviado, aguardando liquidação | totalAmount reservado |
COMPLETED |
Pago. endToEndId é o comprovante |
debitado |
FAILED |
Não foi pago. Motivo em failureReason |
devolvido ao saldo |
UNDER_REVIEW |
Resultado não confirmado; em análise manual pela nossa equipe | continua reservado |
Cada saque é enviado uma única vez. Nunca reenviamos um pagamento automaticamente. Quando o resultado não pode ser confirmado com segurança, o saque vai para UNDER_REVIEW e o valor fica reservado até a nossa equipe concluir a análise. Ao final, ele vira COMPLETED ou FAILED, e você recebe o webhook correspondente. Não crie outro saque para o mesmo pagamento enquanto ele estiver em análise.
GET /v1/pix/withdrawals/{id}
Consulta pelo id, ou por GET /v1/pix/withdrawals?externalRef=.... GET /v1/pix/withdrawals lista os saques, com os mesmos filtros da listagem de cobranças.
Saque em USDT
Saque do seu saldo em reais convertido para USDT, enviado para uma carteira sua na BNB Smart Chain (BEP20). É a única rede aceita: o campo network pode ser omitido ou enviado como "BEP20".
GET /v1/usdt/quote
Simula o saque. Informe network e um destes: amountUsdt (quanto você quer receber) ou amountBrl (quanto quer gastar, já com a taxa de rede).
curl "https://hubpixtech.com/v1/usdt/quote?amountUsdt=100" -H "X-API-Key: hpx_pk_SUA_CHAVE"
{
"success": true,
"data": {
"network": "BEP20",
"rate": "5.4210",
"amountUsdt": "100.00",
"networkFeeUsdt": "1.00",
"amountBrl": "542.10",
"feeBrl": "5.43",
"totalBrl": "547.53",
"validForSeconds": 30,
"networks": ["BEP20"]
}
}
A cotação é indicativa. O valor final é calculado no momento do POST.
POST /v1/usdt/withdrawals
Exige X-API-Key, X-Secret-Key e o IP na whitelist de saque.
| Campo | Descrição | |
|---|---|---|
network |
opcional | BEP20 (única rede; é o padrão) |
address |
obrigatório | Endereço 0x... (40 hex) da sua carteira na BNB Smart Chain |
amountUsdt ou amountBrl |
obrigatório | Um dos dois, como na cotação |
externalRef, description |
opcional | Como nos outros saques |
curl -X POST https://hubpixtech.com/v1/usdt/withdrawals \
-H "X-API-Key: hpx_pk_SUA_CHAVE" -H "X-Secret-Key: hpx_sk_SEU_SECRET" \
-H "Idempotency-Key: 7a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d" \
-H "Content-Type: application/json" \
-d '{ "address": "0x9f8e7d6c5b4a39281706f5e4d3c2b1a098765432", "amountUsdt": "100.00", "externalRef": "cripto-55" }'
O total em reais (totalAmount) é debitado na hora e o pedido nasce com status REQUESTED. Depois do envio na blockchain, ele vira COMPLETED com usdt.txHash (consulte em https://bscscan.com/tx/<txHash>). Se não puder ser enviado, vira FAILED e o valor volta ao seu saldo. Confira o endereço e a rede: USDT enviado para endereço ou rede errados não tem como ser recuperado.
GET /v1/usdt/withdrawals/{id} consulta o pedido. GET /v1/usdt/withdrawals lista os pedidos.
Extrato
GET /v1/transactions
Todas as suas transações. Filtros: type (PIX_IN, PIX_OUT, USDT_OUT), status, externalRef, from, to, page e limit. GET /v1/transactions/{id} consulta uma transação de qualquer tipo.
Webhooks
Você cadastra, edita e remove as URLs que recebem os eventos pela própria API (ou pelo painel). Pode ter até 10 URLs, cada uma com sua lista de eventos e seu próprio segredo de assinatura. GET /v1/webhooks/events lista os eventos disponíveis.
Eventos
| Evento | Quando dispara |
|---|---|
pix_in.paid |
Cobrança paga e confirmada. O valor líquido já está no seu saldo |
pix_in.expired |
Cobrança expirou ou foi cancelada sem pagamento |
pix_out.completed |
Saque PIX pago (com endToEndId) |
pix_out.failed |
Saque PIX não foi pago. O valor voltou ao seu saldo |
pix_out.under_review |
Saque PIX entrou em análise manual. O valor segue reservado |
usdt_out.completed |
Saque USDT enviado (com usdt.txHash) |
usdt_out.failed |
Saque USDT cancelado. O valor voltou ao seu saldo |
webhook.test |
Disparo de teste feito por você |
Use "*" para assinar todos os eventos.
POST /v1/webhooks: cadastrar
| Campo | Descrição | |
|---|---|---|
url |
obrigatório | URL HTTPS pública |
events |
opcional | Lista de eventos. Padrão: ["*"] |
description |
opcional | Rótulo livre |
active |
opcional | Padrão true |
curl -X POST https://hubpixtech.com/v1/webhooks \
-H "X-API-Key: hpx_pk_SUA_CHAVE" -H "Content-Type: application/json" \
-d '{ "url": "https://seusite.com.br/webhooks/hubpix", "events": ["pix_in.paid", "pix_out.completed", "pix_out.failed"] }'
{
"success": true,
"data": {
"id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
"url": "https://seusite.com.br/webhooks/hubpix",
"events": ["pix_in.paid", "pix_out.completed", "pix_out.failed"],
"description": null,
"active": true,
"secret": "whsec_3f9a...",
"createdAt": "2026-10-02T12:00:00.000Z"
}
}
O secret aparece só nesta resposta e na rotação. Guarde-o para validar a assinatura.
Demais operações
| Método e rota | O que faz |
|---|---|
GET /v1/webhooks |
Lista suas URLs |
GET /v1/webhooks/{id} |
Detalhe de uma URL |
PATCH /v1/webhooks/{id} |
Altera url, events, description ou active (envie só o que muda) |
DELETE /v1/webhooks/{id} |
Remove a URL. Entregas pendentes para ela são canceladas |
POST /v1/webhooks/{id}/rotate-secret |
Gera um segredo novo. O anterior para de valer na hora |
POST /v1/webhooks/{id}/test |
Envia um webhook.test agora e devolve o resultado da entrega |
GET /v1/webhooks/{id}/deliveries |
Últimas entregas: status, tentativas, último HTTP e erro |
POST /v1/webhooks/{id}/deliveries/{deliveryId}/redeliver |
Reenvia uma entrega |
Formato da entrega
POST https://seusite.com.br/webhooks/hubpix
Content-Type: application/json
X-HubPix-Event: pix_in.paid
X-HubPix-Delivery: evt_5c1a9e0b7f3d2a4e6b8c0d1f
X-HubPix-Signature: t=1791000000,v1=6a1c9d...
{
"id": "evt_5c1a9e0b7f3d2a4e6b8c0d1f",
"event": "pix_in.paid",
"createdAt": "2026-10-02T12:03:12.000Z",
"data": {
"transaction": {
"id": "6f1d2c3b-9a8e-4f7d-b6c5-1a2b3c4d5e6f",
"type": "PIX_IN",
"status": "PAID",
"amount": "100.00",
"fee": "7.00",
"netAmount": "93.00",
"externalRef": "pedido-1042",
"paidAt": "2026-10-02T12:03:10.000Z",
"endToEndId": "E1234567820261002...",
"payer": { "name": "Maria Souza", "document": "12345678900", "institution": "BANCO X" }
}
}
}
data.transaction tem o mesmo formato da consulta da transação. Responda com qualquer 2xx em até 10 segundos. Processe de forma assíncrona se precisar de mais tempo.
O mesmo evento pode chegar mais de uma vez (reentrega). Use X-HubPix-Delivery (igual ao id do corpo) para processar cada evento uma vez só.
Verificar a assinatura
O header X-HubPix-Signature tem o formato t=<unix>,v1=<hex>, onde:
v1 = HMAC_SHA256(secret, t + "." + corpoBruto)
Rejeite entregas com assinatura inválida ou com t a mais de 5 minutos do seu relógio.
const crypto = require('node:crypto');
function verificaHubPix(rawBody, header, secret) {
const t = (header.match(/t=(\d+)/) || [])[1];
const v1 = (header.match(/v1=([a-f0-9]+)/) || [])[1];
if (!t || !v1) return false;
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const esperado = crypto.createHmac('sha256', secret).update(t + '.' + rawBody).digest('hex');
return v1.length === esperado.length && crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(esperado));
}
function verificaHubPix(string $rawBody, string $header, string $secret): bool {
preg_match('/t=(\d+)/', $header, $t); preg_match('/v1=([a-f0-9]+)/', $header, $v);
if (!$t || !$v || abs(time() - (int)$t[1]) > 300) return false;
return hash_equals(hash_hmac('sha256', $t[1] . '.' . $rawBody, $secret), $v[1]);
}
Use o corpo bruto da requisição, exatamente como chegou, e não o JSON já convertido.
Reentregas
Se a sua URL não responder 2xx em 10 segundos, reenviamos com intervalos crescentes: 1 min, 5 min, 15 min, 1 h, 6 h e 24 h (7 tentativas no total). Depois disso a entrega fica como FAILED e você pode reenviá-la por POST /v1/webhooks/{id}/deliveries/{deliveryId}/redeliver.
Mesmo sem webhook, você sempre pode conferir pela consulta da transação ou pelo extrato.
Chaves e whitelist pela API
| Método e rota | Credencial | O que faz |
|---|---|---|
GET /v1/api-keys |
X-API-Key |
Lista suas chaves (nome, final, último uso e IP). current: true marca a chave usada na chamada |
DELETE /v1/api-keys/{id} |
+ X-Secret-Key, IP da whitelist de saque |
Revoga uma chave na hora |
GET /v1/ip-allowlist |
X-API-Key |
Mostra as duas listas e o requestIp |
PUT /v1/ip-allowlist |
+ X-Secret-Key, IP da whitelist de saque |
Substitui api e/ou withdraw. A nova lista de saque precisa continuar contendo o IP da requisição |
Criar chave nova só é possível pelo painel, porque exige o código do autenticador.
curl -X PUT https://hubpixtech.com/v1/ip-allowlist \
-H "X-API-Key: hpx_pk_SUA_CHAVE" -H "X-Secret-Key: hpx_sk_SEU_SECRET" -H "Content-Type: application/json" \
-d '{ "withdraw": ["203.0.113.10", "198.51.100.0/24"], "api": [] }'
Integração com IA e automação
A API foi feita para ser operada por código e por agentes de IA, do mesmo jeito que pelo painel:
/openapi.json: especificação OpenAPI 3.1 com todos os endpoints, campos e erros. Importe no seu agente, no Postman ou num gerador de SDK./llms.txt: esta documentação em Markdown puro, para colocar no contexto do modelo.- Respostas sempre no mesmo envelope (
success,dataouerror.code) e códigos de erro estáveis, fáceis de tratar automaticamente. Idempotency-Keytorna seguro repetir chamadas: um agente que repete umPOSTnão duplica cobrança nem saque.
Recomendação de segurança para agentes: dê ao agente uma chave própria (crie uma só para ele) e rode-o num servidor cujo IP esteja na whitelist. Se o agente não deve sacar, não entregue o X-Secret-Key a ele: só com a X-API-Key ele cria cobranças, consulta e gerencia webhooks, mas não move dinheiro para fora.
Boas práticas
- Confirme pedidos pelo webhook
pix_in.paid. Na dúvida, consulteGET /v1/pix/charges/{id}, sem polling agressivo. - Gere uma
Idempotency-Keypor operação e reutilize a mesma ao repetir uma chamada que falhou por rede. - Trate
UNDER_REVIEWcomo "aguardando". O dinheiro não sumiu: está reservado até a análise terminar. - Guarde
X-Secret-Keysó no servidor que faz saques e mantenha na whitelist de saque apenas os IPs dele. - Use uma chave por sistema. Se uma vazar, revogue só ela.