Referência da API

API PagPix Hub

REST sobre HTTPS, JSON em UTF-8. Crie cobranças PIX, consulte saldo, dispare saques e receba webhooks assinados. Cada endpoint traz request e response completos, prontos pra colar.

https://pagpixhub.com/api/v1v1OpenAPI JSON

Pra agentes de IA

Regras que valem pra TODA a API, pra não precisar inferir do resto: o único método de pagamento é PIX (method: "pix"); todo valor é inteiro em centavos, nunca decimal; datas são ISO-8601 em UTC; listagem pagina por cursor, nunca por offset; erro sempre vem como {"error": {"code", "message"}} com o código estável na tabela de erros abaixo. Toda transação tem id e public_id (o id que o lojista vê no painel), e os dois servem no GET /transactions/{id}. O ÚNICO campo obrigatório para cobrar é amount_cents. Não invente campos: o que não está documentado aqui é ignorado pelo servidor.

Resumo rápido#

Base URLhttps://pagpixhub.com/api/v1
AuthAuthorization: Bearer bp_live_...
Content-Typeapplication/json
EncodingUTF-8
MétodosPIX. Cartão não é aceito nesta plataforma.
Rate limitSem limite na criação de cobrança. Saque: 10 req/min por chave.
ChaveGerada por você em Dashboard → Integrações (pede a senha da conta)
IdempotênciaHeader Idempotency-Key em POST /transactions e /withdrawals (TTL 24h)
WebhookHMAC-SHA256 t=<ts>,v1=<sig> nos headers PagPixHub-Signature e X-PagPixHub-Signature
OpenAPI/api/v1/openapi.json

Integração em 5 passos#

  1. Gere a chave em Dashboard → Integrações e guarde no servidor. Ela nunca vai para o navegador do comprador.
  2. Cobre com POST /transactions mandando amount_cents. A resposta traz pix.copy_paste, o codigo copia-e-cola (EMV) — é o que você mostra pro comprador, e é dele que você desenha o QR na sua tela. Não mandamos imagem de QR: não existe campo qr_code_base64 na resposta, e o pix.qr_code do GET é um campo legado que vem null nas cobranças criadas pela API.
  3. Nem toda criação volta com o copia-e-cola na hora. Quando a resposta for 202 com pix_status: "generating", a cobrança existe e o código está sendo gerado: consulte GET /transactions/{id} até pix_status sair de generating. Detalhe completo em Ciclo do PIX.
  4. Cadastre uma URL de webhook e espere transaction.paid. Não fique consultando a transação em laço: o evento chega em segundos e o polling só gasta os dois lados. Valide a assinatura antes de confiar no evento.
  5. Confira o dinheiro em GET /balance e retire com POST /withdrawals.
Ambiente: não existe sandbox separado. A mesma URL atende produção, e cobrança de teste é cobrança de verdade — use valores baixos enquanto integra.

Autenticação#

Toda chamada requer uma chave de API no header Authorization com esquema Bearer.

Gere a chave em Dashboard → API Keys. A chave começa com bp_live_ e aparece UMA VEZ, copie e guarde.

bash
curl https://pagpixhub.com/api/v1/me \
  -H "Authorization: Bearer bp_live_seu_token"

Resposta 401 quando o token é inválido. Resposta 429 com header Retry-After quando excede o rate limit.

Formato de erro#

Erros sempre vêm com este formato. Use o campo error.code pra branching no código (estável); o error.message é pra humanos.

json
{
  "error": {
    "code": "validation_error",
    "message": "One or more fields are invalid",
    "details": { "amount_cents": ["amount_cents min R$5,00 (500 cents)"] }
  }
}

Códigos comuns

unauthorized401 · Token ausente, inválido ou expirado
forbidden403 · Token válido mas sem permissão pro recurso
validation_error422 · Campo com formato/valor inválido (veja details)
rate_limited429 · Só nos saques: mais de 10 por minuto
method_not_supported422 · method diferente de "pix"
internal_error500 · Bug servidor; reportar ao suporte

POST /transactions, Criar cobrança#

O endpoint principal. Cria uma cobrança e devolve o copia-e-cola do PIX. Não há nada pra cadastrar antes.

OBRIGATÓRIO pra rastreamento (UTMify / Pixel / atribuição): VOCÊ precisa enviar os UTMs no campo utm de cada cobrança: quem vê a URL do comprador é a sua página, não a nossa. Capture utm_source, utm_medium, utm_campaign, utm_content, utm_term (+ fbclid/ttclid/gclid) da URL da SUA página de checkout e repasse no body. Sem isso a venda aparece na UTMify SEM origem e não é atribuída ao anúncio/campanha, o tracking não funciona. Basta configurar o token em Integrações > UTMify + mandar os UTMs aqui; o envio à UTMify (aguardando pagamento, pago, reembolsado e recusado) é automático.
POST/transactions

Cria uma cobrança PIX. Retorna o copia-e-cola e o QR.

Request body (JSON)

CampoTipoDescrição
amount_centsinteger (req)Valor em centavos. Mínimo 500 (R$ 5,00).
customer.emailstringEmail do cliente. Default gerado automaticamente.
customer.namestringNome do cliente.
customer.cpfstringCPF/CNPJ (com ou sem máscara).
customer.phonestringTelefone (E.164 ou formato BR).
descriptionstringTexto livre que aparece no extrato/recibo e é o nome do produto na UTMify. Max 300 chars.
external_referencestringSeu ID interno pra correlacionar. Max 120 chars. Volta em todos os webhooks + GET. TAMBEM separa pedidos: duas cobrancas com o MESMO valor e o MESMO cliente em 5 minutos so sao tratadas como retry se a referencia for igual. Referencias diferentes (ou header Idempotency-Key) sempre criam cobrancas diferentes.
metadataobjectChave→valor livre (ex: {"attendant_code":"A123"}). Máx 20 chaves. Volta INTACTA nos webhooks e no GET /transactions.
expires_inintegerSegundos até expirar (PIX). 60-86400. Default 3600.
anti_desviobooleanANTI-DESVIO: quando true, a resposta traz o bloco `anti_desvio` com `upload_url` (onde o comprador manda o comprovante) e `status_url`. Use quando quiser reproduzir na sua tela o "Já paguei" do checkout da PagPix Hub: se a adquirente engolir o pagamento, o comprovante do cliente é a prova que usamos pra cobrar ela e recuperar a venda. Os comprovantes aparecem no seu Financeiro › Entradas, em cada venda.
split.recipientstringEmail OU user id de OUTRA conta PagPix Hub que recebe parte da venda. Pra split/revenue-share (ex: bot de Telegram repassando pro parceiro).
split.amount_centsintegerValor FIXO do split em centavos. Use isto OU split.percent (não os dois).
split.percentnumberPercentual (0.01–100) sobre o LÍQUIDO da venda (após taxas). Use isto OU split.amount_cents.
utm.sourcestringOBRIGATÓRIO p/ UTMify/atribuição. Capture da URL da sua página (ex: "fb").
utm.mediumstringOBRIGATÓRIO p/ UTMify. Capture da URL (ex: "video").
utm.campaignstringOBRIGATÓRIO p/ UTMify. ID/nome da campanha, da URL.
utm.contentstringRecomendado. ID do criativo/anúncio, da URL.
utm.termstringRecomendado. Placement/termo, da URL.
utm.fbclidstringFacebook click ID (da URL). Melhora a atribuição Meta.
utm.gclidstringGoogle click ID (da URL).
utm.ttclidstringTikTok click ID (da URL).

Exemplo cURL, PIX simples

bash
curl -X POST https://pagpixhub.com/api/v1/transactions \
  -H "Authorization: Bearer bp_live_seu_token" \
  -H "Content-Type: application/json" \
  -d '{
    "amount_cents": 1990,
    "method": "pix",
    "customer": {
      "email": "joao@example.com",
      "name": "João Silva",
      "cpf": "11144477735"
    },
    "description": "Mensalidade Plano Pro",
    "external_reference": "order_42",
    "utm": {
      "source": "fb",
      "medium": "video",
      "campaign": "camp-black-friday",
      "content": "criativo-A",
      "term": "feed",
      "fbclid": "IwAR123...",
      "ttclid": "",
      "gclid": ""
    }
  }'

Resposta sucesso (PIX) · HTTP 200

json
{
  "id": "tx_clxabc123",
  "public_id": "pag-pix-1990-4829103746",
  "object": "transaction",
  "status": "PENDING",
  "method": "PIX",
  "amount_cents": 1990,
  "fee_cents": 449,
  "net_cents": 1541,
  "currency": "BRL",
  "pix": {
    "copy_paste": "00020126580014BR.GOV.BCB.PIX...",
    "expires_at": "2026-06-01T16:30:00.000Z"
  },
  "split": null,
  "created_at": "2026-06-01T15:30:00.000Z"
}

Toda transação tem dois ids. id é o interno, estável, usado no cursor da listagem. public_id (formato pag-pix-<valor em centavos>-<10 dígitos>) é o id da venda que aparece no seu painel, e também serve no GET /transactions/{id} no lugar do id.

Exemplo cURL, PIX com split (revenue share / bot Telegram)

bash
curl -X POST https://pagpixhub.com/api/v1/transactions \
  -H "Authorization: Bearer bp_live_seu_token" \
  -H "Content-Type: application/json" \
  -d '{
    "amount_cents": 5000,
    "method": "pix",
    "customer": { "email": "cliente@example.com" },
    "description": "Acesso VIP",
    "split": {
      "recipient": "parceiro@example.com",
      "percent": 30
    }
  }'

Quando esse PIX for pago, 30% do líquido cai automaticamente no saldo da conta parceiro@example.com e o restante no seu. Use amount_cents em vez de percent pra um valor fixo. O recebedor precisa ser uma conta PagPix Hub (identifique por email ou user id). Funciona igual em POST /subscriptions (split aplicado em toda renovação).

Ciclo do PIX e a resposta 202#

Na maioria das cobranças o copia-e-cola sai junto com a resposta da criação (HTTP 200). Quando a adquirente demora ou recusa a primeira tentativa, a criação responde HTTP 202 com pix_status: "generating" e pix.copy_paste: null: a cobrança FOI criada, o id já é válido e nós seguimos tentando gerar o código por conta própria.

Não recrie a cobrança nesse caso. Um novo POST gera uma segunda cobrança para o mesmo pedido. Com 202, guarde o id e consulte.

Resposta 202 (criação aceita, código em geração)

json
{
  "id": "tx_clxabc123",
  "public_id": "pag-pix-1990-4829103746",
  "object": "transaction",
  "status": "PENDING",
  "pix_status": "generating",
  "method": "PIX",
  "amount_cents": 1990,
  "pix": { "copy_paste": null, "expires_at": "2026-06-01T16:30:00.000Z" },
  "message": "PIX em geracao. Faça GET /api/v1/transactions/tx_clxabc123 ate pix.copy_paste ficar disponivel (~5-30s)."
}

Valores de pix_status

generatingCódigo ainda não existe. Continue consultando (a cada 2s é suficiente).
readypix.copy_paste preenchido. Mostre pro comprador e pare de consultar.
paidPago. Estado final.
expiredPassou do expires_at sem pagamento. Estado final.
failedDesistimos de gerar (status FAILED). Estado final: crie uma cobrança nova.
O laço sempre termina. Tentamos gerar por até 45 minutos; passando disso a cobrança vira status: "FAILED" / pix_status: "failed" e aparece assim no GET /transactions/{id}. Nenhuma cobrança fica em generating indefinidamente. Se o seu cliente quiser um teto menor, pare de consultar no seu próprio tempo limite e trate como falha: nada é cobrado sem o comprador pagar.

Consulta até ficar pronto (Node.js)

javascript
async function esperarPix(id, token, limiteMs = 60000) {
  const ate = Date.now() + limiteMs;
  while (Date.now() < ate) {
    const r = await fetch(`https://pagpixhub.com/api/v1/transactions/${id}`, {
      headers: { Authorization: `Bearer ${token}` },
    });
    const tx = await r.json();
    if (tx.pix_status === "ready") return tx.pix.copy_paste;
    if (["failed", "expired", "paid"].includes(tx.pix_status)) {
      throw new Error("cobranca terminou em " + tx.pix_status);
    }
    await new Promise((s) => setTimeout(s, 2000));
  }
  throw new Error("tempo limite esperando o PIX");
}
Isto é a exceção, não o padrão. Consultar em laço vale enquanto pix_status for generating. Para saber que a venda foi PAGA, use o webhook transaction.paid — consultar em laço à espera do pagamento gasta os dois lados e ainda chega depois.

GET /transactions/{id}, Consultar#

GET/transactions/{id}

Estado atual de uma cobrança: status, pix_status, copia-e-cola, E2E, metadata.

O {id} pode ser o id ou o public_id da transação. O public_id é o id da venda que aparece no seu painel: com ele você consulta uma venda que só conhece de lá, sem precisar do id.

bash
curl https://pagpixhub.com/api/v1/transactions/tx_clxabc123 \
  -H "Authorization: Bearer bp_live_seu_token"

# mesma transação, pelo public_id
curl https://pagpixhub.com/api/v1/transactions/pag-pix-1990-4829103746 \
  -H "Authorization: Bearer bp_live_seu_token"

Resposta · HTTP 200

json
{
  "id": "tx_clxabc123",
  "public_id": "pag-pix-1990-4829103746",
  "object": "transaction",
  "status": "PAID",
  "pix_status": "paid",
  "method": "PIX",
  "amount_cents": 1990,
  "fee_cents": 449,
  "net_cents": 1541,
  "currency": "BRL",
  "customer": { "email": "joao@example.com", "name": "João Silva", "cpf": "11144477735", "phone": null },
  "pix": {
    "qr_code": null,
    "copy_paste": "00020126580014BR.GOV.BCB.PIX...",
    "expires_at": "2026-06-01T16:30:00.000Z"
  },
  "external_reference": "order_42",
  "metadata": { "attendant_code": "A123" },
  "end_to_end_id": "E12345678202606011530abcdef12345",
  "paid_at": "2026-06-01T15:32:10.000Z",
  "created_at": "2026-06-01T15:30:00.000Z",
  "updated_at": "2026-06-01T15:32:10.000Z"
}
idId interno da transação. Estável; é o que vai no cursor da listagem.
public_idId da venda que aparece no seu painel (pag-pix-<valor em centavos>-<10 dígitos>). Aceito no lugar do id nesta consulta. Pode vir null só em vendas antigas que ainda não receberam o id.
statusPENDING, PAID, EXPIRED, FAILED, REFUNDED ou CHARGEBACK.
pix_statusEstado da GERAÇÃO do código (tabela acima). status diz da venda; pix_status diz do código.
pix.copy_pasteO EMV. É o que o comprador copia, e é daqui que sai o QR da sua tela.
pix.qr_codeCampo legado. Vem null nas cobranças criadas pela API; não dependa dele.
end_to_end_idE2E do PIX, preenchido depois do pagamento. Use pra conciliar com o extrato e casar um MED.
404O id (ou public_id) não é da sua conta, ou não existe.
Estorno não tem endpoint. A API não devolve dinheiro ao comprador. Reembolso é tratado pelo suporte, caso a caso. Se a sua operação precisa estornar por conta própria, fale com a gente antes de desenhar o fluxo.

GET /transactions, Listar#

GET/transactions

Lista transações. Ordenação created_at DESC (desempate por id), cursor 100% estável.

Query params

CampoTipoDescrição
limitintegerMáx 100. Default 20.
cursorstringID da última transação da página anterior (next_cursor).
statusPENDING|PAID|EXPIRED|REFUNDED|CHARGEBACKFiltra por status.
methodPIX|CARD|APPLE_PAY|GOOGLE_PAYFiltra por método.
external_referencestringFiltra pelo seu external_reference exato.
end_to_end_idstringFiltra pelo EndToEndId do PIX exato. Use pra achar a venda de um MED.
created_at_fromISO 8601Só txs criadas A PARTIR desta data (gte).
created_at_toISO 8601Só txs criadas ATÉ esta data (lte).

Cada item traz public_id, external_reference, metadata, fee_cents, net_cents, status e tracking (UTMs). Reconciliação por janela: ?created_at_from=2026-06-01T00:00:00Z&created_at_to=2026-06-02T00:00:00Z.

bash
curl https://pagpixhub.com/api/v1/transactions?status=PAID&limit=50 \
  -H "Authorization: Bearer bp_live_seu_token"
json
{
  "data": [
    {
      "id": "tx_clxabc123",
      "public_id": "pag-pix-1990-4829103746",
      "object": "transaction",
      "product_id": "prd_xxx",
      "checkout_id": "ck_xxx",
      "customer": { "email": "...", "name": "...", "cpf": "...", "phone": "..." },
      "amount_cents": 1990,
      "fee_cents": 449,
      "net_cents": 1541,
      "currency": "BRL",
      "method": "PIX",
      "status": "PAID",
      "pix": { "qr_code": "...", "copy_paste": "...", "expires_at": "..." },
      "card": null,
      "tracking": { "utm_source": "...", "utm_medium": "...", "fbclid": "..." },
      "split": { "recipient": "parceiro@example.com", "amount_cents": 450 },
      "paid_at": "2026-06-01T15:32:00.000Z",
      "created_at": "2026-06-01T15:30:00.000Z",
      "updated_at": "2026-06-01T15:32:00.000Z"
    }
  ],
  "has_more": true,
  "next_cursor": "tx_clxabc123"
}

GET /me, Conta atual#

GET/me

Retorna info da conta dona da API key.

bash
curl https://pagpixhub.com/api/v1/me -H "Authorization: Bearer bp_live_seu_token"
json
{
  "id": "usr_xxx",
  "email": "voce@example.com",
  "name": "Você",
  "balance_cents": 12345,
  "api_card_enabled": false
}

GET /balance, Saldo#

GET/balance

Saldo da conta dona da chave: disponível para saque, em liberação e saques em aberto.

bash
curl https://pagpixhub.com/api/v1/balance -H "Authorization: Bearer bp_live_seu_token"

Resposta · HTTP 200

json
{
  "object": "balance",
  "currency": "BRL",
  "available_cents": 50000,        // SACÁVEL agora (já liberado)
  "pending_pix_cents": 12000,      // PIX pago, ainda em holding
  "pending_card_cents": 0,         // Cartão pago, ainda em holding (D+X)
  "retained_card_cents": 0,        // Retenção de cartão (libera no fim do período)
  "in_withdrawal_cents": 0,        // Saques abertos já debitados
  "upcoming_releases": [
    { "transaction_id": "tx_xxx", "transaction_public_id": "pag-pix-12000-4829103746", "date": "2026-06-02T10:00:00.000Z", "cents": 12000, "kind": "pix_release", "method": "PIX" }
  ]
}

O valor que você pode sacar via API é sempre available_cents. Os demais campos são informativos (calendário de liberação).

Saques (Withdrawals)#

POST/withdrawals

Solicita um saque PIX. Débito atômico: NUNCA saca mais que o saldo disponível.

GET/withdrawals

Lista os saques da conta (cursor).

GET/withdrawals/{id}

Status de um saque específico.

Segurança. O débito do saldo é feito de forma atômica e condicional no banco (WHERE saldo >= valor), é impossível sacar mais do que você tem. Só pode haver 1 saque em aberto por conta de cada vez, e toda solicitação passa por uma auditoria automática antes de ser aceita. A taxa de saque sai do valor solicitado (você recebe amount_cents − fee_cents).

POST /withdrawals · body

CampoTipoDescrição
amount_centsinteger (req)Valor BRUTO do saque em centavos. PIX mín R$ 100,00 (10000).
method"pix"Default "pix". Só "pix" é aceito: outro valor retorna 422 withdrawal_method_not_supported.
pix_keystringObrigatório. Sua chave Pix.
pix_key_typecpf|cnpj|evp|phone|emailObrigatório. Tipo da chave.

Exemplo cURL, saque PIX

bash
curl -X POST https://pagpixhub.com/api/v1/withdrawals \
  -H "Authorization: Bearer bp_live_seu_token" \
  -H "Content-Type: application/json" \
  -d '{
    "amount_cents": 10000,
    "method": "pix",
    "pix_key": "voce@example.com",
    "pix_key_type": "email"
  }'

Resposta · HTTP 201

json
{
  "id": "wd_clxabc123",
  "object": "withdrawal",
  "status": "PENDING",
  "method": "pix",
  "amount_cents": 10000,
  "fee_cents": 500,
  "net_cents": 9500,
  "pix_key": "voce@example.com",
  "pix_key_type": "email",
  "wallet_address": null,
  "fail_reason": null,
  "paid_at": null,
  "created_at": "2026-06-01T15:30:00.000Z",
  "updated_at": "2026-06-01T15:30:00.000Z"
}

fail_reason só vem preenchido quando o saque termina com status FAILED ou REJECTED: é uma mensagem em português para mostrar ao seu usuário (ex. "Transferência não concluída. O valor voltou para o seu saldo."). Nos outros status é sempre null.

Erros possíveis

CampoTipoDescrição
insufficient_balance422Saldo disponível menor que o valor pedido.
amount_below_minimum422Abaixo do mínimo (PIX R$ 100).
withdrawal_method_not_supported422method diferente de pix. Saque só por PIX.
withdrawal_in_progress409Já existe um saque em aberto. Aguarde finalizar.
audit_blocked422Auditoria automática bloqueou (drift de saldo, refund rate, etc).
blocked403Conta bloqueada para saques.
insufficient_scope403A API key não tem o escopo "withdrawals".

GET /withdrawals, lista

bash
curl "https://pagpixhub.com/api/v1/withdrawals?status=PAID&limit=50" \
  -H "Authorization: Bearer bp_live_seu_token"

Status possíveis: PENDING, PROCESSING, PAID, FAILED, REJECTED.

Webhooks (eventos)#

Eventos são enviados via POST pra URL configurada em Dashboard → Integrações. Cada webhook tem um segredo próprio (whsec_...), que você vê no ícone de escudo da linha do webhook, informando a senha da conta. É com ele que você valida a assinatura HMAC.

Eventos disponíveis

transaction.createdTx criada (PIX gerado)
transaction.paidPagamento confirmado
transaction.refundedReembolsada
transaction.chargebackChargeback
transaction.expiredPIX expirou
transaction.failedFalha no dispatcher do PSP
balance.updatedSaldo da conta mudou (venda liberada, saque pedido ou pago)
withdrawal.paidSaque pago
withdrawal.failedSaque recusado
med.openedMED aberto contra uma venda
med.updatedMED mudou de status ou de bloqueio
transaction.receipt_uploadedLead subiu comprovante
withdrawal.paidSaque pago
withdrawal.failedSaque recusado/falhou (saldo estornado)

Envelope do evento

json
{
  "id": "evt_<deliveryId>",          // ESTÁVEL entre retentativas, dedupe por ele
  "type": "transaction.paid",
  "created": 1730476320,             // unix timestamp (segundos)
  "data": { /* objeto do evento (ver abaixo) */ }
}

data, transaction.* (created / paid / refunded / chargeback / expired)

json
{
  "id": "tx_clxabc123",
  "public_id": "pag-pix-1990-4829103746",
  "product_id": "prd_xxx",
  "checkout_id": null,
  "amount_cents": 1990,
  "fee_cents": 449,
  "net_cents": 1541,
  "currency": "BRL",
  "method": "PIX",
  "status": "PAID",
  "external_reference": "order_42",
  "end_to_end_id": "E18236120202609111335s0000abc123",
  "metadata": { "attendant_code": "A123" },
  "customer": { "email": "...", "name": "...", "cpf": "...", "phone": "..." },
  "tracking": { "utm_source": "fb", "utm_medium": "video", "utm_campaign": "...",
                "utm_content": "...", "utm_term": "...", "fbclid": "...",
                "ttclid": "...", "gclid": "..." },
  "receipt_url": null,
  "paid_at": "2026-06-01T15:32:00.000Z",
  "created_at": "2026-06-01T15:30:00.000Z"
}

external_reference, metadata e tracking (UTMs) voltam em TODOS os eventos de transação, inclusive refunded e chargeback.

public_id é o id da venda que aparece no seu painel, o mesmo que a criação e o GET devolvem. O id continua vindo como antes.

end_to_end_id é o EndToEndId do PIX, o identificador que aparece no extrato e pelo qual o MED chega. Vem preenchido no transaction.paid e nos eventos seguintes, e também no GET /transactions/{id}. É null antes do pagamento e quando a instituição que processou o PIX não informa o E2E.

data, withdrawal.paid / withdrawal.failed

json
{
  "id": "wd_xxx",
  "object": "withdrawal",
  "status": "PAID",
  "method": "pix",
  "amount_cents": 10000,
  "fee_cents": 500,
  "net_cents": 9500,
  "pix_key": "voce@example.com",
  "wallet_address": null,
  "fail_reason": null,
  "paid_at": "2026-06-01T16:00:00.000Z"
}

Assinatura (HMAC-SHA256), header e formato exato

A assinatura vem em dois headers com o MESMO valor: PagPixHub-Signature (canônico) e X-PagPixHub-Signature (alias). Formato:

text
PagPixHub-Signature: t=1730476320,v1=9f86d081884c7d659...
  • t = unix timestamp usado na assinatura.
  • v1 = HMAC-SHA256 (hex) do payload assinado ${t}.${rawBody}, ou seja, o timestamp + ponto + o corpo CRU do request (a string JSON exata, não re-serializada).
  • Anti-replay: rejeite se t estiver fora de uma janela (ex: ±5 min) do horário atual.
  • Algoritmo: HMAC-SHA256. Secret: o whsec_ do webhook.

Verificação de assinatura (Node.js), correta

javascript
import crypto from "node:crypto";

// rawBody = corpo CRU (string), NÃO o objeto re-serializado.
function verifyWebhook(rawBody, headerValue, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(
    headerValue.split(",").map((kv) => kv.split("="))
  ); // { t, v1 }
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false; // replay
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(parts.v1)
  );
}

Retentativas (retry)

SucessoQualquer 2xx (usamos res.ok). Responda 200 rápido (<5s).
TentativasAté 8 no total.
Backoff30s, 2min, 10min, 30min, 1h, 3h, 6h, 24h
evt idMESMO id em todas as retentativas (dedupe seguro). Só muda t/assinatura.
IPs de origemSem IPs fixos (infra serverless). Valide por HMAC, não por IP.
Responda 200 OKrápido (<5s) pra não causar retry. Processe em fila se a lógica for pesada. Como o evt id é estável entre retentativas, use-o pra deduplicar (idempotência no recebedor).

Taxas (referência)#

As taxas variam por conta. Consulte GET /me pra ver os números atuais da sua conta, ou Dashboard → Perfil.

PIXVaria por conta, consulte GET /me
LiberaçãoImediata após o pagamento
Saque PIXR$ 5,00 (fixo)

Quickstart (Node.js)#

javascript
// 1. Cria PIX (sem produto, funciona pra qualquer conta)
const res = await fetch("https://pagpixhub.com/api/v1/transactions", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.PAGPIXHUB_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    amount_cents: 1990,
    method: "pix",
    customer: {
      email: "cliente@example.com",
      name: "Cliente Exemplo",
      cpf: "11144477735",
    },
    description: "Pedido #42",
    external_reference: "order_42",
  }),
});

const tx = await res.json();
if (!res.ok) throw new Error(tx.error.message);

// 2. Mostra QR pro cliente
console.log("Copia-cola PIX:", tx.pix.copy_paste);
console.log("Expira em:", tx.pix.expires_at);

// 3. Espera webhook 'transaction.paid' chegar no seu endpoint
//    OU pollie GET /transactions/{id} periodicamente
//    OU melhor: configure o webhook em Dashboard → Integrações