NewPag

Documentação da API

Integre pagamentos Pix, split entre contas, saldo e saques em uma API REST única. JSON, valores em centavos, webhooks assinados.

Base URLhttps://app.newpag.app/api/v1
RESTJSONPixWebhooks

Introdução

Visão geral da API de pagamentos.

Base URLhttps://app.newpag.app/api/v1
FormatoJSON (UTF-8). Valores monetários em CENTAVOS (inteiro).
DatasISO 8601 (UTC).
MétodosPix (cash-in) + split + saldo + saque. Cartão/boleto em breve.
request_idToda resposta traz req_… no corpo e no header x-request-id — rastreável em Integrações > Logs da API.

Documentação para IA

Uma versão em texto puro, otimizada para LLMs e agentes, está em https://app.newpag.app/llms.txt.

Autenticação

Basic auth: chave pública + segredo.

Gere e revogue credenciais no painel em Desenvolvedores > Chaves de API. Cada credencial tem uma chave pública (pk_live_…, sempre visível) e um segredo (sk_live_…, exibido uma única vez — guarde com segurança e nunca o exponha no navegador nem em repositórios). Autentique com HTTP Basic: usuário = chave pública, senha = segredo.

Header
Authorization: Basic base64(pk_live_...:sk_live_...)
cURL
curl https://app.newpag.app/api/v1/balance -u "pk_live_...:sk_live_..."
Node.js
// Basic base64(chave_pública:segredo) — pk_live_... : sk_live_...
const cred = Buffer.from(
  process.env.NEWPAG_PUBLIC_KEY + ":" + process.env.NEWPAG_SECRET_KEY,
).toString("base64");

const res = await fetch("https://app.newpag.app/api/v1/charges", {
  method: "POST",
  headers: { Authorization: "Basic " + cred, "Content-Type": "application/json" },
  body: JSON.stringify({
    amountCents: 1990,
    customer: { name: "Cliente", email: "cliente@exemplo.com", document: "00000000000" },
    description: "Pedido #1234",
  }),
});
const charge = await res.json();
console.log(charge.pix.copyPaste);

Primeiros passos

  1. 1. Gere uma chave de API no painel (Desenvolvedores > Chaves de API).
  2. 2. Crie uma cobrança com POST /api/v1/charges.
  3. 3. Exiba o pix.copyPaste (QR / copia-e-cola) ao pagador.
  4. 4. Aguarde a confirmação (webhook ou polling do status).
  5. 5. Cobrança paid → o líquido entra no seu saldo.

Modo de teste (sandbox)

Integre sem mover dinheiro real — com chaves pk_test_/sk_test_.

No painel (Chaves de API > Criar chave), escolha o ambiente Teste para gerar credenciais pk_test_…/sk_test_…. Elas usam os MESMOS endpoints e formatos, mas as cobranças ficam num ambiente separado: não chamam o provedor Pix, não aparecem no saldo nem nos dashboards, e toda resposta traz livemode: false. Dá até para criar a chave de teste enquanto seu cadastro ainda está em análise.

POST/api/v1/test/charges/{id}/pay

Simular o pagamento

Crie a cobrança normalmente com a chave de teste e depois chame o endpoint acima (também com a chave de teste). A cobrança vira paid, a taxa é calculada com as taxas REAIS da sua conta e o webhook transaction.paid é disparado com livemode: false no data — filtre por esse campo antes de dar baixa em pedidos reais.
Fluxo completo (cURL)
# 1) criar cobrança de teste (mesma rota, chave pk_test_)
curl -X POST https://app.newpag.app/api/v1/charges \
  -u "pk_test_...:sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{"amountCents":1990,"customer":{"name":"Cliente","email":"c@ex.com","document":"00000000000"}}'

# 2) simular o pagamento → status paid + webhook transaction.paid (livemode: false)
curl -X POST https://app.newpag.app/api/v1/test/charges/{id}/pay \
  -u "pk_test_...:sk_test_..."

Limites do modo de teste

O pix.copyPaste devolvido é um marcador NÃO-pagável. splits retornam 400 e saques retornam 403 test_mode_unsupported; GET /balance responde zeros.

Criar cobrança (Pix)

Gera uma cobrança e retorna o copia-e-cola Pix.

POST/api/v1/charges

Idempotência

Envie o header Idempotency-Key (único por pedido): num retry, devolvemos a MESMA cobrança em vez de gerar outro Pix. Recomendado sempre. Reusar a chave com um corpo diferente retorna 409 idempotency_conflict (igual no modo de teste).

Parâmetros (body)

amountCentsintegerobrigatórioValor em centavos (ex.: 1990 = R$ 19,90).
customer.namestringobrigatórioNome do pagador.
customer.emailstringobrigatórioE-mail do pagador.
customer.documentstringobrigatórioCPF/CNPJ (só dígitos).
customer.phonestringTelefone do pagador, DDD + número (ex.: 11987654321). Recomendado: alguns adquirentes exigem; sem ele, usamos o telefone do titular da conta.
descriptionstringSua referência (ex.: “Pedido #1234”), guardada na cobrança.
external_referencestringID do pedido no SEU sistema (até 120 chars) — volta nas respostas e é pesquisável em GET /charges?external_reference=.
splitsarraySplit entre sellers (ver seção Split).

Limites de valor

Cada conta tem um valor mínimo e máximo por cobrança (o padrão da plataforma, ou um limite personalizado da sua conta — veja em Empresa → Limites e taxas). Valor fora da faixa retorna 400 validation com a mensagem indicando o limite; nada é criado no provider.
Requisição
curl -X POST https://app.newpag.app/api/v1/charges \
  -u "pk_live_...:sk_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pedido-1234" \
  -d '{
    "amountCents": 1990,
    "customer": {
      "name": "Cliente Exemplo",
      "email": "cliente@exemplo.com",
      "document": "00000000000",
      "phone": "11987654321"
    },
    "description": "Pedido #1234"
  }'
Resposta 201
{
  "id": "clx7a9...",
  "livemode": true,
  "status": "pending",
  "amountCents": 1990,
  "external_reference": "pedido-1234",
  "pix": {
    "copyPaste": "00020101br.gov.bcb.pix...",
    "qrCodeBase64": "data:image/png;base64,iVBORw0..."
  },
  "createdAt": "2026-07-20T00:00:00.000Z",
  "request_id": "req_kJ2m9..."
}
Listar com filtros + paginação por cursor
curl "https://app.newpag.app/api/v1/charges?status=paid&external_reference=pedido-1234&starting_after=<id>" \
  -u "pk_live_...:sk_live_..."
# filtros opcionais: limit (1–100), status, external_reference, from/to (ISO),
# starting_after (cursor = id do último item). Resposta traz "has_more" —
# enquanto true, repita com starting_after. Mesmos parâmetros em /transfers.

Split de pagamentos

Divida o líquido entre sellers do sistema (marketplace).

Envie splits ao criar a cobrança. Quando o pagamento confirma, cada recebedor é creditado no saldo dele; a reserva incide só sobre o que sobra para você. recipient_id = id da empresa recebedora. PERCENTAGE usa percent; FIXED usa amount (centavos).

Regras

A soma dos percentuais não pode exceder 100%. Destinatário precisa ser uma conta ativa e diferente do emissor. Split inválido retorna 400.
Trecho do body
"splits": [
  { "recipient_id": "id-do-seller-B", "type": "PERCENTAGE", "percent": 40 },
  { "recipient_id": "id-do-seller-C", "type": "FIXED", "amount": 1500 }
]

Objeto cobrança

idstringIdentificador da cobrança.
livemodebooleantrue = produção; false = modo de teste (sandbox).
statusstringSituação atual — ver Ciclo de status.
amountCentsintegerValor em centavos.
pix.copyPastestringCódigo Pix copia-e-cola (BR Code) para o pagador. É um payload EMV: sequência de campos id (2 dígitos) + tamanho (2 dígitos) + valor. O campo 54 é o valor, quando o QR é de valor fixo.
pix.qrCodeBase64stringQR em PNG data-URL, pronto para <img src>. Vem no 201 e no GET por id (não na listagem).
createdAtstringData de criação (ISO 8601, UTC).
refundobject|nullEstorno da cobrança, se houver: { id, status: pending|completed|failed, amountCents, reason, createdAt, completedAt, failureReason }. Só no GET por id.

Ciclo de status

A cobrança nasce pending e muda conforme o pagamento.

  • pendingAguardando pagamento do cliente.
  • paidPago e confirmado — o líquido entra no seu saldo.
  • expiredExpirou sem pagamento.
  • refundedEstornado.
  • canceledCancelada.
  • under_reviewEm análise.
  • blockedBloqueada.

Consultar cobrança

Retorna a cobrança pelo id (mesmo formato).

GET/api/v1/charges/{id}

Faça polling do status até paid, ou use webhooks.

Requisição
curl https://app.newpag.app/api/v1/charges/{id} \
  -u "pk_live_...:sk_live_..."
Resposta 200 (paga)
{
  "id": "clx7a9...",
  "livemode": true,
  "status": "paid",
  "amountCents": 1990,
  "description": "Pedido #1234",
  "external_reference": "pedido-1234",
  "customer": { "name": "Cliente Exemplo", "email": "cliente@exemplo.com", "document": "00000000000" },
  "payer":    { "name": "Fulano de Tal", "document": "10900327570", "bank": "NU PAGAMENTOS - IP" },
  "pix": {
    "copyPaste": "00020101br.gov.bcb.pix...",
    "qrCodeBase64": "data:image/png;base64,iVBORw0...",
    "endToEnd": "E18236120202609130426s1894658118"
  },
  "paidAt": "2026-09-13T04:26:13.927Z",
  "createdAt": "2026-09-13T04:25:54.018Z",
  "request_id": "req_kJ2m9..."
}

customer é o que você informou ao cobrar; payer é quem de fato pagou (nome, CPF/CNPJ e banco informados pelo PSP na confirmação — null enquanto pendente). Use pix.endToEnd + payer para conciliar com o extrato.

Listar cobranças

Lista as cobranças da sua conta.

GET/api/v1/charges?limit=50
Resposta 200
{ "data": [ { "id": "clx...", "status": "paid", "amountCents": 1990, "customer": { "name": "...", "email": "...", "document": "..." }, "payer": { "name": "...", "document": "...", "bank": "..." }, "pix": { "endToEnd": "E..." }, "paidAt": "...", "createdAt": "..." } ], "has_more": false }

Saldo

Saldo disponível e reservado da sua conta (centavos).

GET/api/v1/balance
Requisição
curl https://app.newpag.app/api/v1/balance \
  -u "pk_live_...:sk_live_..."
Resposta 200
{ "available": 73992, "reserved": 0, "currency": "BRL" }

Dados da conta

Dados cadastrais + taxas + saldo.

GET/api/v1/company
Requisição
curl https://app.newpag.app/api/v1/company \
  -u "pk_live_...:sk_live_..."

Solicitar saque

Saque o saldo disponível via Pix.

POST/api/v1/transfers

Saque automático

Se o “saque automático” estiver desligado na sua conta, o saque nasce pendente de aprovação (pending_approval: true). Se estiver ligado, é processado na hora.

Parâmetros (body)

amountintegerValor em centavos. Obrigatório com pix_key. Com qr_code é opcional: o QR de valor fixo define o valor (se informado, tem que bater com o QR); QR de valor variável exige amount.
pix_keystringChave Pix do destinatário. Obrigatória sem qr_code. Não combine com qr_code.
pix_key_typestringCPF, CNPJ, EMAIL, PHONE ou EVP (chave aleatória, no formato UUID). Obrigatório sem qr_code.
qr_codestringCódigo copia-e-cola do QR Code Pix (payload EMV). No lugar de pix_key. A taxa é cobrada por cima do valor do QR.
messagestringMensagem opcional.
Requisição (chave Pix)
curl -X POST https://app.newpag.app/api/v1/transfers \
  -u "pk_live_...:sk_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: saque-1234" \
  -d '{
    "amount": 500,
    "pix_key": "12345678909",
    "pix_key_type": "CPF"
  }'
Requisição (QR Code)
curl -X POST https://app.newpag.app/api/v1/transfers \
  -u "pk_live_...:sk_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: saque-qr-1234" \
  -d '{
    "qr_code": "00020126580014br.gov.bcb.pix0136...520400005303986540510.005802BR..."
  }'
Resposta 201
{
  "data": {
    "id": "b8d1eaa3-...",
    "status": "requested",
    "amount": 500,
    "net_amount": 465,
    "fee": 35,
    "pix_key": "12345678909",
    "pix_key_type": "cpf",
    "pending_approval": true,
    "failure_reason": null,
    "created_at": "2026-07-20T00:00:00.000Z"
  }
}

Débito no saque por QR Code

No QR, o destinatário recebe exatamente o valor do QR (ou o amount informado, se o QR for de valor variável) e a taxa é debitada por cima: o saldo sai pelo valor + taxa. No saque por chave, a taxa sai do próprio amount. Hoje só alguns provedores aceitam QR; em outro, a API responde 422 transfer_failed sem debitar. No retorno, pix_key traz o código do QR e pix_key_type é qrcode.

No painel: Recebimentos > Solicitar saque.

Consultar saque

Detalhes de um saque pelo id.

GET/api/v1/transfers/{id}

Liste todos com GET /api/v1/transfers. Status: requested processing completed rejected.

Requisição
curl https://app.newpag.app/api/v1/transfers/{id} \
  -u "pk_live_...:sk_live_..."

Estornar cobrança

Devolve o valor ao pagador via Pix. Total, uma vez por cobrança.

POST/api/v1/charges/{id}/refund

O estorno é assíncrono

202 com status: "pending" significa que o PSP aceitou o pedido — o dinheiro ainda não voltou. Ouça transaction.refunded (voltou) ou transaction.refund_failed (recusado). O valor fica retido do seu saldo enquanto pendente.
Requisição
curl -X POST https://app.newpag.app/api/v1/charges/{id}/refund \
  -u "pk_live_...:sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"reason":"Cliente desistiu"}'
Resposta 202
{ "id": "clx...", "chargeId": "clx...", "livemode": true, "status": "pending", "amountCents": 1990, "reason": "Cliente desistiu", "createdAt": "...", "completedAt": null, "failureReason": null }

Regras: só cobrança paid, até 90 dias após o pagamento, valor total, uma vez por cobrança (repetir devolve o mesmo estorno). Recusas: charge_not_refundable, refund_window_expired, insufficient_balance (traz shortfallCents), refund_not_supported (provider da cobrança sem devolução via API).

GET/api/v1/charges/{id}/refund

Mesmo objeto; 404 se não houver estorno. A cobrança (GET /api/v1/charges/{id}) também traz o campo refund. Em modo de teste o estorno conclui na hora, sem PSP.

Webhooks

Receba uma notificação assinada na sua URL a cada evento — sem polling.

Cadastre endpoints em Integrações > Webhooks. A cada evento assinado, enviamos um POST com corpo JSON para a sua URL. Cada entrega leva o header x-webhook-event e uma assinatura x-webhook-signature: sha256=… (HMAC-SHA256 do corpo cru, com o segredo do endpoint). Reenviamos até 3 vezes; responda 2xx para confirmar.

Gerenciar endpoints via API

Além do painel, dá para gerir endpoints pela própria API (chave de produção ou de teste): GET/POST /api/v1/webhooks e PATCH/DELETE /api/v1/webhooks/{id}. O POST devolve o segredo de assinatura UMA única vez. URL precisa ser HTTPS pública; máx. 20 endpoints por conta.
Criar endpoint via API
curl -X POST https://app.newpag.app/api/v1/webhooks \
  -u "pk_live_...:sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"url":"https://seusistema.com.br/webhooks","events":["transaction.paid","transaction.refunded","transaction.refund_failed"]}'
# 201 → { id, url, events, status, ..., "secret": "whsec..." }  ← guarde o secret (só aparece aqui)

Eventos

transaction.pendingAguardando pagamentoativo
transaction.paidPagoativo
transaction.refundedReembolsadoativo
transaction.refund_failedEstorno recusado pelo PSPativo
withdrawal.processingSaque processandoativo
withdrawal.completedSaque concluídoativo
withdrawal.failedSaque falhouativo
dispute.openedDisputa abertaativo
dispute.acceptedDisputa aceitaativo
dispute.rejectedDisputa rejeitadaativo

MED — contestações Pix

Os eventos dispute.* notificam infrações de MED (contestação Pix): dispute.opened ao abrir, dispute.accepted/dispute.rejected no desfecho. A defesa é respondida no painel em Disputas (dentro do prazo). Sellers no plano sem MED não precisam agir — a nossa equipe cuida.
Exemplo de entrega
POST https://seusistema.com.br/webhooks
x-webhook-event: transaction.paid
x-webhook-signature: sha256=9f86d081...    ← HMAC-SHA256 do corpo
content-type: application/json

{
  "event": "transaction.paid",
  "data": {
    "id": "b8d1eaa3-...",
    "livemode": true,
    "amount": 5000,
    "net": 4670,
    "fee": 330,
    "method": "pix",
    "status": "paid",
    "external_reference": "pedido-1234",
    "description": "Pedido #1234",
    "customer": { "name": "Cliente Exemplo", "email": "cliente@exemplo.com", "document": "00000000000" },
    "payer":    { "name": "Fulano de Tal", "document": "10900327570", "bank": "NU PAGAMENTOS - IP" },
    "pix": { "endToEnd": "E18236120202609130426s1894658118" },
    "paidAt": "2026-09-13T04:26:13.927Z"
  },
  "createdAt": "2026-09-13T04:26:14.100Z"
}

// customer = o que você informou ao cobrar · payer = quem DE FATO pagou (do PSP)
// pix.endToEnd + payer = chaves para conciliar com o extrato bancário
Validar a assinatura (Node.js)
import { createHmac, timingSafeEqual } from "node:crypto";

// raw = corpo CRU da requisição (não faça JSON.parse antes de validar)
function isValid(raw, header, secret) {
  const expected = "sha256=" + createHmac("sha256", secret).update(raw).digest("hex");
  const a = Buffer.from(expected), b = Buffer.from(header ?? "");
  return a.length === b.length && timingSafeEqual(a, b);
}

Códigos de status HTTP

200Requisição bem-sucedida
201Recurso criado com sucesso
400Erro de validação nos parâmetros
401Chave de API inválida ou ausente
403Conta em análise ou bloqueada
404Recurso não encontrado
409Idempotency-Key reusada com corpo diferente
422Saque recusado (ex.: saldo insuficiente)
429Limite de requisições excedido
502Falha ao gerar a cobrança no provedor

Erros

Erros retornam JSON { "error": "<codigo>", "message": "..." }.

unauthorizedChave ausente, inválida, revogada — ou IP fora da allowlist da conta (401).
validationCorpo inválido — confira o campo details (400).
account_inactiveConta em análise ou bloqueada (403).
api_withdrawal_disabledSaque via API desabilitado para esta conta (403).
not_foundCobrança/saque não encontrado (404).
idempotency_conflictIdempotency-Key já usada com um corpo DIFERENTE — use uma chave nova por pedido (409).
invalid_urlURL de webhook inacessível ou apontando para rede interna (400).
endpoint_limitMáximo de 20 endpoints de webhook por conta (400).
transfer_failedSaque recusado, ex.: saldo insuficiente (422).
charge_not_refundableEstorno de cobrança que não está paid (422).
refund_window_expiredEstorno pedido mais de 90 dias após o pagamento (422).
insufficient_balanceSaldo disponível não cobre o estorno — o corpo traz shortfallCents (422).
refund_not_supportedO provider desta cobrança não oferece estorno via API (422).
refund_failedO PSP recusou ou não respondeu ao pedido de estorno; a retenção foi liberada (502).
rate_limitedMuitas requisições — aguarde o header retry-after (segundos) e use backoff (429). Monitore x-ratelimit-limit / x-ratelimit-remaining / x-ratelimit-reset em toda resposta autenticada.
charge_failedFalha ao gerar a cobrança no provedor (502).

request_id e Logs da API

Toda resposta (sucesso ou erro) traz um request_id (req_…) no corpo JSON e no header x-request-id. Guarde-o nos seus logs: no painel, em Integrações > Logs da API, cada requisição autenticada aparece com status, duração e código de erro (retenção de 30 dias) — e o suporte localiza qualquer chamada por esse id.