Introdução
Visão geral da API de pagamentos.
| Base URL | https://app.newpag.app/api/v1 | |
| Formato | JSON (UTF-8). Valores monetários em CENTAVOS (inteiro). | |
| Datas | ISO 8601 (UTC). | |
| Métodos | Pix (cash-in) + split + saldo + saque. Cartão/boleto em breve. | |
| request_id | Toda resposta traz req_… no corpo e no header x-request-id — rastreável em Integrações > Logs da API. |
Documentação para IA
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.
Authorization: Basic base64(pk_live_...:sk_live_...)curl https://app.newpag.app/api/v1/balance -u "pk_live_...:sk_live_..."// 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. Gere uma chave de API no painel (Desenvolvedores > Chaves de API).
- 2. Crie uma cobrança com
POST /api/v1/charges. - 3. Exiba o
pix.copyPaste(QR / copia-e-cola) ao pagador. - 4. Aguarde a confirmação (webhook ou polling do status).
- 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.
/api/v1/test/charges/{id}/paySimular o pagamento
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.# 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
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.
/api/v1/chargesIdempotência
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)
| amountCents | integerobrigatório | Valor em centavos (ex.: 1990 = R$ 19,90). |
| customer.name | stringobrigatório | Nome do pagador. |
| customer.email | stringobrigatório | E-mail do pagador. |
| customer.document | stringobrigatório | CPF/CNPJ (só dígitos). |
| customer.phone | string | Telefone do pagador, DDD + número (ex.: 11987654321). Recomendado: alguns adquirentes exigem; sem ele, usamos o telefone do titular da conta. |
| description | string | Sua referência (ex.: “Pedido #1234”), guardada na cobrança. |
| external_reference | string | ID do pedido no SEU sistema (até 120 chars) — volta nas respostas e é pesquisável em GET /charges?external_reference=. |
| splits | array | Split entre sellers (ver seção Split). |
Limites de valor
400 validation com a mensagem indicando o limite; nada é criado no provider.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"
}'{
"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..."
}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
400."splits": [
{ "recipient_id": "id-do-seller-B", "type": "PERCENTAGE", "percent": 40 },
{ "recipient_id": "id-do-seller-C", "type": "FIXED", "amount": 1500 }
]Objeto cobrança
| id | string | Identificador da cobrança. |
| livemode | boolean | true = produção; false = modo de teste (sandbox). |
| status | string | Situação atual — ver Ciclo de status. |
| amountCents | integer | Valor em centavos. |
| pix.copyPaste | string | Có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.qrCodeBase64 | string | QR em PNG data-URL, pronto para <img src>. Vem no 201 e no GET por id (não na listagem). |
| createdAt | string | Data de criação (ISO 8601, UTC). |
| refund | object|null | Estorno 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).
/api/v1/charges/{id}Faça polling do status até paid, ou use webhooks.
curl https://app.newpag.app/api/v1/charges/{id} \
-u "pk_live_...:sk_live_..."{
"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.
/api/v1/charges?limit=50{ "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).
/api/v1/balancecurl https://app.newpag.app/api/v1/balance \
-u "pk_live_...:sk_live_..."{ "available": 73992, "reserved": 0, "currency": "BRL" }Dados da conta
Dados cadastrais + taxas + saldo.
/api/v1/companycurl https://app.newpag.app/api/v1/company \
-u "pk_live_...:sk_live_..."Solicitar saque
Saque o saldo disponível via Pix.
/api/v1/transfersSaque automático
pending_approval: true). Se estiver ligado, é processado na hora.Parâmetros (body)
| amount | integer | Valor 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_key | string | Chave Pix do destinatário. Obrigatória sem qr_code. Não combine com qr_code. |
| pix_key_type | string | CPF, CNPJ, EMAIL, PHONE ou EVP (chave aleatória, no formato UUID). Obrigatório sem qr_code. |
| qr_code | string | Código copia-e-cola do QR Code Pix (payload EMV). No lugar de pix_key. A taxa é cobrada por cima do valor do QR. |
| message | string | Mensagem opcional. |
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"
}'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..."
}'{
"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
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.
/api/v1/transfers/{id}Liste todos com GET /api/v1/transfers. Status: requested processing completed rejected.
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.
/api/v1/charges/{id}/refundO 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.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"}'{ "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).
/api/v1/charges/{id}/refundMesmo 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
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.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.pending | Aguardando pagamento | ativo |
| transaction.paid | Pago | ativo |
| transaction.refunded | Reembolsado | ativo |
| transaction.refund_failed | Estorno recusado pelo PSP | ativo |
| withdrawal.processing | Saque processando | ativo |
| withdrawal.completed | Saque concluído | ativo |
| withdrawal.failed | Saque falhou | ativo |
| dispute.opened | Disputa aberta | ativo |
| dispute.accepted | Disputa aceita | ativo |
| dispute.rejected | Disputa rejeitada | ativo |
MED — contestações Pix
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.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árioimport { 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
| 200 | Requisição bem-sucedida |
| 201 | Recurso criado com sucesso |
| 400 | Erro de validação nos parâmetros |
| 401 | Chave de API inválida ou ausente |
| 403 | Conta em análise ou bloqueada |
| 404 | Recurso não encontrado |
| 409 | Idempotency-Key reusada com corpo diferente |
| 422 | Saque recusado (ex.: saldo insuficiente) |
| 429 | Limite de requisições excedido |
| 502 | Falha ao gerar a cobrança no provedor |
Erros
Erros retornam JSON { "error": "<codigo>", "message": "..." }.
| unauthorized | Chave ausente, inválida, revogada — ou IP fora da allowlist da conta (401). |
| validation | Corpo inválido — confira o campo details (400). |
| account_inactive | Conta em análise ou bloqueada (403). |
| api_withdrawal_disabled | Saque via API desabilitado para esta conta (403). |
| not_found | Cobrança/saque não encontrado (404). |
| idempotency_conflict | Idempotency-Key já usada com um corpo DIFERENTE — use uma chave nova por pedido (409). |
| invalid_url | URL de webhook inacessível ou apontando para rede interna (400). |
| endpoint_limit | Máximo de 20 endpoints de webhook por conta (400). |
| transfer_failed | Saque recusado, ex.: saldo insuficiente (422). |
| charge_not_refundable | Estorno de cobrança que não está paid (422). |
| refund_window_expired | Estorno pedido mais de 90 dias após o pagamento (422). |
| insufficient_balance | Saldo disponível não cobre o estorno — o corpo traz shortfallCents (422). |
| refund_not_supported | O provider desta cobrança não oferece estorno via API (422). |
| refund_failed | O PSP recusou ou não respondeu ao pedido de estorno; a retenção foi liberada (502). |
| rate_limited | Muitas 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_failed | Falha ao gerar a cobrança no provedor (502). |
request_id e Logs da API
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.
