# PAGUEO — API pública de cobrança Pix

> Versão em texto desta documentação, para pessoas e para agentes de IA. A página com o mesmo conteúdo: https://pagueo.com.br/docs · O contrato OpenAPI 3 (JSON): https://api.pagueo.com.br/api/docs-json

A PAGUEO emite cobranças Pix (imediatas e com vencimento, inclusive carnês), hospeda a página de pagamento, confirma o pagamento com o provedor de liquidação e avisa o seu sistema por webhook. Você integra com uma chave de API; nenhuma credencial de banco passa pelo seu código.

## Regras que valem para tudo

- Base: `https://api.pagueo.com.br/api/v1`. Corpo e resposta em `application/json`. Datas em ISO 8601 (UTC). Dinheiro em **centavos, inteiro** (`amountCents`) — nunca ponto flutuante.
- Autenticação: `Authorization: Bearer <chave>`. Chave de TESTE começa com `vk_test_`, de PRODUÇÃO com `vk_live_`. O ambiente (TEST/LIVE) é decidido pela chave — o campo `environment` no corpo é ignorado.
- A chave pertence a UMA conta (tenant). Não existe `tenantId` na API: o servidor usa a conta da chave. Uma pessoa com várias lojas tem uma chave por loja.
- A API recusa campos desconhecidos com 400. Envie somente o que está documentado.
- Uma cobrança só está paga quando `status` é `PAID` em `GET /charges/:id` ou num webhook `charge.paid` com assinatura válida. Exibir um QR não é confirmação.
- Idempotência: mande `Idempotency-Key` (texto seu, estável por operação) em `POST /charges`, `POST /charges/plans` e em qualquer POST que crie algo. Mesma chave + mesmo corpo dentro de 24 h devolve a MESMA resposta sem criar de novo; mesma chave + corpo diferente responde 409; chave ainda em andamento responde 409 (a reserva expira em 5 minutos se o processo morrer). Em erro de rede, repita com a mesma chave em vez de gerar outra.
- Listagens devolvem `{ "data": [...] }` com os 100 itens mais recentes, sem paginação. Objetos únicos vêm sem envelope.

## Escopos da chave

- `charges:read` — Consultar cobranças, carnês e a linha do tempo de cada uma; enviar a cobrança por e-mail.
- `charges:write` — Criar cobranças e carnês, baixar, conferir no provedor e simular pagamento (TEST).
- `customers:read` — Listar e consultar clientes (pagadores).
- `customers:write` — Cadastrar e editar clientes.
- `webhooks:read` — Listar os endpoints de webhook e o histórico de entregas.
- `webhooks:write` — Cadastrar e remover endpoints, girar o segredo e reenviar entregas.
- `balance:read` — Ler o saldo da conta.
- `transfers:read` — Listar e consultar Pix enviados e pedidos de saque.
- `transfers:write` — Reservado ao painel: envio de Pix e pedido de saque com chave de API respondem 403.
- `bills:read` — Consultar contas pagas e ler um código de barras.
- `bills:write` — Reservado ao painel: pagar conta com chave de API responde 403.

Sem `scopes` no pedido, a chave nasce com `charges:read` e `customers:read`. Peça o mínimo que a integração usa. Crie a chave no painel: Desenvolvedores → Chaves de API (o segredo aparece uma única vez).

## Comece em 5 minutos

1. Crie uma chave `vk_test_` no painel e guarde-a no servidor (nunca no navegador, app ou repositório).
2. Crie uma cobrança:

```bash
curl --request POST 'https://api.pagueo.com.br/api/v1/charges' \
  --header 'Authorization: Bearer vk_test_sua_chave' \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: pedido-1033' \
  --data '{ "amountCents": 14990, "description": "Pedido #1033", "externalId": "pedido-1033", "expiresInSeconds": 3600 }'
```

3. Mostre `pixCopyPaste`, `qrCodeUrl` ou mande o `publicUrl` ao pagador.
4. Em TEST, simule o pagamento: `POST /charges/:id/simulate-payment` (sem corpo). Isso dispara o webhook `charge.paid` exatamente como em produção.
5. Libere o pedido quando `GET /charges/:id` devolver `status: "PAID"` — ou quando o webhook chegar com assinatura válida.

## Cobranças Pix — `POST /charges` (escopo charges:write)

| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| `amountCents` | integer | sim | Valor em centavos de BRL, de 1 a 100.000.000 (R$ 0,01 a R$ 1.000.000,00). Ex.: 14990 = R$ 149,90. |
| `description` | string ≤ 140 | sim | O que está sendo cobrado; aparece na cobrança e para o pagador. Obrigatória, exceto quando vier chargeItemId. Descrição que indique atividade proibida (apostas, armas, drogas, pirâmide…) é recusada com 400 PROHIBITED_BUSINESS_CATEGORY. |
| `externalId` | string ≤ 100 | não | O id do pedido no SEU sistema. Volta em toda resposta e em todo webhook: é a sua chave de conciliação. |
| `customerId` | string | não | Cliente cadastrado na conta (POST /customers). Nome, documento e e-mail dele vão ao provedor. Inexistente responde 404. |
| `expiresInSeconds` | integer | não | Validade do QR, de 60 a 2.592.000 segundos (30 dias). Sem o campo: 3600 (1 hora). |
| `payerName` | string ≤ 120 | não | Nome do pagador quando não há customerId. |
| `payerDocument` | string ≤ 20 | não | CPF ou CNPJ do pagador quando não há customerId. Máscara é aceita e descartada. |
| `chargeItemId` | string | não | Item do catálogo da conta (cadastrado no painel). Dispensa description. O VALOR não vem do item: mande amountCents sempre. |
| `environment` | TEST | LIVE | não | Aceito por compatibilidade e IGNORADO: o ambiente vem da credencial. vk_test_ cria em TEST; vk_live_ cria em LIVE. |

Resposta 201 (a mesma forma em `GET /charges/:id` e dentro dos webhooks):

```json
{
  "id": "cmtyv7fek000bpc018ulijzjg",
  "status": "PENDING",
  "environment": "TEST",
  "amountCents": 14990,
  "currency": "BRL",
  "description": "Pedido #1033",
  "reference": null,
  "externalId": "pedido-1033",
  "pixCopyPaste": "00020126580014br.gov.bcb.pix…",
  "qrCodeUrl": "data:image/png;base64,…",
  "expiresAt": "2026-09-12T22:00:00.000Z",
  "paidAt": null,
  "feeCents": null,
  "netAmountCents": null,
  "publicUrl": "https://pagueo.com.br/p/<token>",
  "customer": null,
  "chargeItem": null,
  "installmentNumber": null,
  "paymentPlanId": null,
  "createdAt": "2026-09-12T21:00:00.000Z"
}
```

| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| `id` | string | não | Identificador da cobrança. Guarde junto do pedido. |
| `status` | enum | não | Ver a tabela de status. Liberar o pedido só em PAID. |
| `environment` | TEST | LIVE | não | Em TEST o Pix NÃO é pagável e qrCodeUrl vem null; use simulate-payment. |
| `pixCopyPaste` | string | null | não | O código Pix copia e cola (BR Code). |
| `qrCodeUrl` | string | null | não | A imagem do QR pronta para <img src>: data URI em produção; null em TEST. |
| `publicUrl` | string | não | Página de pagamento hospedada pela PAGUEO, para mandar por WhatsApp ou e-mail. |
| `expiresAt` | ISO 8601 | null | não | Quando o QR deixa de valer. |
| `paidAt` | ISO 8601 | null | não | Quando o provedor confirmou o pagamento. |
| `feeCents / netAmountCents` | integer | null | não | Tarifa da PAGUEO e valor líquido. null até a liquidação; 0 é tarifa zero. |
| `customer` | objeto | null | não | { id, name, email, phone } quando a cobrança tem cliente. |
| `chargeItem` | objeto | null | não | { id, name, category } quando veio do catálogo. null em tudo que entra pela API sem chargeItemId. |
| `installmentNumber / paymentPlanId` | integer | string | null | não | Preenchidos quando a cobrança é parcela de um carnê. |

### Status da cobrança

- `CREATED` — Registrada, sem o QR confirmado pelo provedor ainda. Passageiro.
- `PENDING` — QR emitido, aguardando o pagador. É o status normal logo depois de criar.
- `PAID` — Pagamento confirmado pelo provedor. SÓ AQUI o pedido pode ser liberado.
- `EXPIRED` — Venceu sem pagamento. Não volta: crie outra cobrança.
- `CANCELLED` — Baixada por você (POST /charges/:id/cancel) ou junto do carnê.
- `REFUNDED` — Devolvida ao pagador. Reservado para conciliação: hoje nenhuma rota da API devolve.
- `FAILED` — O provedor recusou a emissão. Nada foi cobrado.

### Outras rotas de cobrança

- `GET /charges/:id/events` — `{ data: [{ id, type, fromStatus, toStatus, payload, occurredAt }] }`, em ordem cronológica.
- `POST /charges/:id/cancel` — corpo opcional `{ "reason": "…" }`. Só CREATED/PENDING; cobrança paga responde 409.
- `POST /charges/:id/reconcile` — pergunta ao provedor agora (LIVE). Responde `{ ok, mudou, status, message }`.
- `POST /charges/:id/simulate-payment` — só cobrança de TEST. Responde `{ ok, mudou, status: "PAID", message }`.
- `POST /charges/:id/send-email` — corpo opcional `{ "email" }`; sem ele usa o e-mail do cliente.

## Carnês — `POST /charges/plans` (escopo charges:write)

Um carnê é N cobranças com vencimento (Boleto Pix), emitidas de uma vez. Cada parcela continua pagável depois do vencimento, com multa e juros calculados pelo provedor, como um boleto.

| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| `title` | string ≤ 140 | sim | Nome do carnê. Cada parcela sai como "<title> - parcela N/T". |
| `installmentAmountCents` | integer | sim | Valor de CADA parcela, em centavos (1 a 100.000.000). |
| `installmentCount` | integer | sim | Quantidade de parcelas, de 1 a 60. Uma cobrança com vencimento por parcela, todas emitidas de uma vez. |
| `firstDueDate` | YYYY-MM-DD | sim | Vencimento da primeira parcela; as seguintes vencem no mesmo dia dos meses seguintes. |
| `description` | string ≤ 140 | não | Texto livre sobre o contrato ou plano. |
| `customerId` | string | não | Obrigatório NA PRÁTICA: cobrança com vencimento exige CPF/CNPJ do pagador (regra do arranjo Pix), e é do cliente cadastrado que ele vem. Sem cliente com documento, o provedor recusa. |
| `environment` | TEST | LIVE | não | Aceito e ignorado: o ambiente vem da credencial. |

Resposta: `{ id, title, description, status: ACTIVE|COMPLETED|CANCELLED, environment, installmentAmountCents, installmentCount, totalAmountCents, publicUrl, customer, installments: [{ number, amountCents, dueDate, status: PENDING|PAID|EXPIRED|CANCELLED, charge }] }` — cada `charge` tem a forma da cobrança acima, com `installmentNumber` e `paymentPlanId`.

## Clientes — `POST /customers` (escopo customers:write)

| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| `name` | string 3–120 | sim | Nome completo, como no documento. |
| `document` | string ≤ 20 | sim | CPF ou CNPJ. Máscara é aceita e descartada. É o que permite emitir carnê para este cliente. |
| `phone` | string ≤ 30 | sim | Telefone com DDD. Aceita máscara e o 55 na frente. |
| `email` | e-mail ≤ 160 | não | Para onde a cobrança pode ser enviada por e-mail. |
| `externalCode` | string ≤ 100 | não | O código deste cliente no seu sistema. |
| `identityDocument` | string ≤ 40 | não | RG ou outro documento de identidade. |
| `gender` | FEMALE | MALE | OTHER | UNDISCLOSED | não | Opcional. |
| `addressStreet, addressNumber, addressComplement, addressNeighborhood, addressCity` | string | não | Endereço, campo a campo. Todos opcionais. |
| `addressState` | UF (2 letras) | não | Sigla do estado. |
| `addressPostalCode` | string ≤ 9 | não | CEP, com ou sem hífen. |

Documento duplicado na mesma conta responde 409. `GET /customers` devolve também `podeReceberCarne` (true quando há documento).

## Seus webhooks — a PAGUEO avisa o seu sistema

Cadastre um endereço e a PAGUEO faz POST nele a cada evento da conta.

`POST /webhook-endpoints` (escopo webhooks:write):

| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| `url` | https, 8–500 | sim | Endereço PÚBLICO que vai receber os POSTs. Só https; endereços internos ou privados são recusados; redirecionamentos não são seguidos. |
| `description` | string ≤ 120 | não | Só para você reconhecer depois (ex.: "ERP produção"). |
| `events` | string[] | não | Quais eventos assinar. Em branco, assina todos. Valores: charge.paid, charge.expired, charge.cancelled, charge.refunded. |

A resposta traz `secret` (`whsec_…`) UMA única vez. Guarde-o no servidor; é com ele que você confere a assinatura. Perdeu? `POST /webhook-endpoints/:id/rotate-secret` gera outro.

### Eventos

- `charge.paid` — O provedor confirmou o pagamento. data.charge.status é PAID e paidAt está preenchido.
- `charge.expired` — A cobrança venceu sem pagamento.
- `charge.cancelled` — A cobrança foi baixada.
- `charge.refunded` — A cobrança foi devolvida (reservado; ver o status REFUNDED).

### O que chega no seu endpoint

`POST` com `Content-Type: application/json` e estes cabeçalhos:

- `x-pagueo-signature: t=<unix em segundos>,v1=<HMAC-SHA256 em hex>`
- `x-pagueo-event-id` — identificador do evento; o MESMO em toda reentrega (use para não processar duas vezes)
- `x-pagueo-event-type` — o tipo, igual ao `type` do corpo
- `x-pagueo-delivery-attempt` — número da tentativa, começando em 1
- `user-agent: PAGUEO-Webhooks/1`

Corpo:

```json
{
  "id": "evt_charge_paid_cmtyv7fek000bpc018ulijzjg",
  "type": "charge.paid",
  "createdAt": "2026-09-12T21:05:10.000Z",
  "data": {
    "charge": {
      "id": "cmtyv7fek000bpc018ulijzjg",
      "status": "PAID",
      "environment": "TEST",
      "amountCents": 14990,
      "currency": "BRL",
      "description": "Pedido #1033",
      "reference": null,
      "externalId": "pedido-1033",
      "pixCopyPaste": "00020126580014br.gov.bcb.pix…",
      "qrCodeUrl": "data:image/png;base64,…",
      "expiresAt": "2026-09-12T22:00:00.000Z",
      "paidAt": "2026-09-12T21:05:08.000Z",
      "feeCents": 178,
      "netAmountCents": 14812,
      "publicUrl": "https://pagueo.com.br/p/<token>",
      "customer": null,
      "chargeItem": null,
      "installmentNumber": null,
      "paymentPlanId": null,
      "createdAt": "2026-09-12T21:00:00.000Z"
    }
  }
}
```

### Conferir a assinatura (obrigatório)

1. Leia o corpo CRU (bytes, antes de qualquer parse). Reserializar o JSON muda espaços e derruba a assinatura.
2. Separe `t` e `v1` do cabeçalho.
3. Calcule `HMAC-SHA256(secret, "<t>.<corpo cru>")` em hex e compare com `v1` em tempo constante.
4. Recuse se `|agora − t|` passar de 300 segundos (repetição de notificação capturada).
5. Responda 2xx só depois de gravar o evento. Qualquer outra resposta, ou demora, vira reentrega.

Node.js (Express — leia o corpo cru com `express.raw({ type: 'application/json' })`):

```javascript
import { createHmac, timingSafeEqual } from 'node:crypto';

export function assinaturaValida(cabecalho, corpoCru, segredo) {
  const partes = Object.fromEntries(cabecalho.split(',').map((p) => p.split('=')));
  const t = Number(partes.t);
  if (!partes.v1 || !Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > 300) return false;
  const esperada = createHmac('sha256', segredo).update(`${t}.${corpoCru}`).digest('hex');
  const a = Buffer.from(esperada);
  const b = Buffer.from(partes.v1);
  return a.length === b.length && timingSafeEqual(a, b);
}

app.post('/webhooks/pagueo', express.raw({ type: 'application/json' }), (req, res) => {
  const corpoCru = req.body.toString('utf8');
  if (!assinaturaValida(req.header('x-pagueo-signature') ?? '', corpoCru, process.env.PAGUEO_WEBHOOK_SECRET)) {
    return res.status(400).end();
  }
  const evento = JSON.parse(corpoCru);
  // Idempotência: ignore se evento.id já foi processado.
  if (evento.type === 'charge.paid') liberarPedido(evento.data.charge.externalId, evento.data.charge.id);
  res.status(200).end();
});
```

Python:

```python
import hmac, hashlib, time

def assinatura_valida(cabecalho: str, corpo_cru: bytes, segredo: str) -> bool:
    partes = dict(p.split('=', 1) for p in cabecalho.split(','))
    t = int(partes.get('t', '0'))
    if 'v1' not in partes or abs(time.time() - t) > 300:
        return False
    esperada = hmac.new(segredo.encode(), f"{t}.".encode() + corpo_cru, hashlib.sha256).hexdigest()
    return hmac.compare_digest(esperada, partes['v1'])
```

### Reentregas

Sem 2xx, a PAGUEO tenta de novo com estas esperas, em minutos: 0, 1, 5, 30, 120, 360, 1440 (7 tentativas em 24 h). Depois disso a entrega fica como `DEAD_LETTER` no histórico (`GET /webhook-endpoints/deliveries`) e pode ser reenviada por `POST /webhook-endpoints/deliveries/:id/resend`. O mesmo evento redescoberto por dois caminhos (webhook do provedor e conciliação) gera UM `id` — o seu sistema recebe uma vez, ou a repetição com o mesmo `x-pagueo-event-id`.

### Segurança do destino

Só https. Endereços privados ou internos são recusados no cadastro; redirecionamentos não são seguidos. O corpo do webhook é uma notificação: se quiser a certeza final, consulte `GET /charges/:id` ao receber.

## Saldo e saída de dinheiro

Pela API se LÊ: saldo (`GET /charges/balance`, `GET /charges/withdrawals/balance`), Pix enviados (`GET /charges/transfers`, `GET /charges/transfers/:id` — que confere no banco na hora e devolve nome, documento mascarado e banco de quem recebeu depois da liquidação) e contas pagas (`GET /charges/bill-payments`). Enviar Pix, pedir saque e pagar conta são operações do PAINEL, com senha de transferência e código por e-mail: com chave de API respondem 403 — por desenho.

## Erros

A API não usa envelope `{ "error": … }`. O corpo de erro é:

```json
{ "statusCode": 401, "message": "Sessao invalida.", "code": "SESSION_EXPIRED" }
```

Em validação (400), `message` é uma LISTA de frases: `{ "statusCode": 400, "message": ["amountCents must be an integer number", "property foo should not exist"], "error": "Bad Request" }`. Alguns erros trazem `code` estável — os que existem estão na tabela.

| HTTP | code | Quando | O que fazer |
|---|---|---|---|
| 400 | — | Corpo inválido | Campo faltando, tipo errado ou campo DESCONHECIDO — a API recusa propriedades que não existem no contrato. message vem como lista de frases, uma por problema. Corrija e repita com a mesma Idempotency-Key. |
| 400 | `PROHIBITED_BUSINESS_CATEGORY` | Categoria proibida | A descrição indica atividade que a PAGUEO não cobra (apostas, armas, drogas, pirâmide…). O corpo traz category. Não repita sem mudar o produto. |
| 401 | `SESSION_EXPIRED` | Sem credencial, ou credencial inválida | Falta o Authorization, ou a chave é inválida ou foi revogada. O code é o mesmo da sessão do painel: com chave de API não há o que renovar — confira a chave. Nunca tente outra conta. |
| 403 | — | Escopo ou operação não permitida | "Escopo X não concedido": crie a chave com o escopo certo. Ou a rota só aceita sessão do painel (toda saída de dinheiro). |
| 404 | — | Não encontrado | O id não é desta conta ou não existe. Rota inexistente responde { "message": "Cannot GET /api/v1/…", "statusCode": 404 }. |
| 409 | — | Conflito | Idempotency-Key reutilizada com corpo diferente, ou a mesma requisição ainda em andamento; ou transição impossível (baixar cobrança paga, cliente com documento já cadastrado). |
| 429 | — | Teto de requisições | Espere e repita com backoff exponencial, mantendo a mesma Idempotency-Key para a mesma operação. |
| 503 | — | Provedor ou função indisponível | O provedor de liquidação não respondeu, ou a função está desligada na plataforma. A operação PODE ter sido recebida: consulte (GET) antes de criar de novo. |

Tetos de requisições (429):

- `GET /public/*`: 60 por minuto, por origem
- `GET /charges/transfers/:id`: 60 por minuto, por usuário
- `POST /charges/:id/send-email`: 30 por hora, por usuário
- `POST /charges/transfers/key-lookup`: 30 por minuto, por usuário

## Referência de endpoints

Caminhos relativos a `https://api.pagueo.com.br/api/v1`.

### Cobranças Pix

| Método | Caminho | Acesso | O que faz |
|---|---|---|---|
| POST | `/charges` | charges:write | Cria uma cobrança Pix imediata: QR, copia e cola e link público. Aceita Idempotency-Key. |
| GET | `/charges` | charges:read | As 100 cobranças mais recentes da conta, da mais nova para a mais antiga. Sem paginação. |
| GET | `/charges/:id` | charges:read | Uma cobrança. É ESTA consulta que decide se o pedido pode ser liberado (status PAID). |
| GET | `/charges/:id/events` | charges:read | Linha do tempo: cada transição de status, com origem, payload e horário. |
| POST | `/charges/:id/cancel` | charges:write | Baixa uma cobrança CREATED ou PENDING, no provedor e aqui. Corpo opcional: { "reason" }. |
| POST | `/charges/:id/reconcile` | charges:write | Pergunta ao provedor o status real agora (cobrança LIVE). Para quando o pagador diz que pagou e a cobrança segue PENDING. |
| POST | `/charges/:id/simulate-payment` | charges:write | Só TEST: marca a cobrança como paga pelo MESMO caminho da produção — tarifa, eventos e webhook charge.paid incluídos. |
| POST | `/charges/:id/send-email` | charges:read | Envia a cobrança por e-mail ao cliente. Corpo opcional: { "email" }. Teto: 30 por hora. |
| GET | `/public/charges/:token` | público | O que a página de pagamento mostra (dados do pagador mascarados). Teto: 60 por minuto. |

### Carnês (Boleto Pix parcelado)

| Método | Caminho | Acesso | O que faz |
|---|---|---|---|
| POST | `/charges/plans` | charges:write | Cria o carnê inteiro: uma cobrança com vencimento por parcela, todas emitidas de uma vez. Aceita Idempotency-Key. |
| GET | `/charges/plans` | charges:read | Carnês da conta, com as parcelas e a cobrança de cada uma. |
| POST | `/charges/plans/:id/cancel` | charges:write | Baixa o carnê e todas as parcelas ainda abertas. Parcelas pagas ficam no histórico. |
| GET | `/public/plans/:token` | público | A página do carnê: parcelas, vencimentos e status. |

### Clientes (pagadores)

| Método | Caminho | Acesso | O que faz |
|---|---|---|---|
| GET | `/customers?q=` | customers:read | Até 100 clientes. q busca por nome e e-mail; com 3 ou mais dígitos, também por documento e telefone. |
| GET | `/customers/:id` | customers:read | Um cliente. |
| POST | `/customers` | customers:write | Cadastra um pagador. name, document e phone são obrigatórios. |
| PATCH | `/customers/:id` | customers:write | Edita o cadastro; todos os campos são opcionais aqui. |

### Seus webhooks (a PAGUEO avisa o seu sistema)

| Método | Caminho | Acesso | O que faz |
|---|---|---|---|
| POST | `/webhook-endpoints` | webhooks:write | Cadastra um endereço https. A resposta traz o secret (whsec_…) UMA única vez. |
| GET | `/webhook-endpoints` | webhooks:read | Endpoints cadastrados, sem o segredo. |
| DELETE | `/webhook-endpoints/:id` | webhooks:write | Remove o endpoint; entregas pendentes param. |
| POST | `/webhook-endpoints/:id/rotate-secret` | webhooks:write | Gira o segredo. O anterior para de valer no mesmo instante. |
| GET | `/webhook-endpoints/deliveries?endpointId=` | webhooks:read | As 50 entregas mais recentes, com as últimas 5 tentativas de cada (status HTTP, latência, erro). |
| POST | `/webhook-endpoints/deliveries/:id/resend` | webhooks:write | Reenvia uma entrega agora — inclusive as que já viraram DEAD_LETTER. |

### Saldo e saída de dinheiro (somente leitura pela API)

| Método | Caminho | Acesso | O que faz |
|---|---|---|---|
| GET | `/charges/balance` | balance:read | Saldo da conta no provedor. |
| GET | `/charges/withdrawals/balance` | transfers:read | Saldo disponível para sacar, já descontados os pedidos em aberto. |
| GET | `/charges/transfers` | transfers:read | Os 100 Pix enviados mais recentes: status, quem recebeu, liquidação e motivo quando não realizado. |
| GET | `/charges/transfers/:id` | transfers:read | Um Pix enviado, conferido no banco na hora enquanto estiver PROCESSING. Teto: 60 por minuto. |
| GET | `/charges/withdrawals` | transfers:read | Pedidos de saque da conta. |
| GET | `/charges/bill-payments` | bills:read | Contas (boletos) pagas com o saldo. |
| POST | `/charges/bill-payments/details` | bills:read | Lê um código de barras ou linha digitável: beneficiário, vencimento, valor final e se pode ser pago. |
| POST | `/charges/transfers · /charges/withdrawals · /charges/bill-payments` | sessão do painel | Movimentam dinheiro e exigem senha de transferência e código por e-mail. Chave de API responde 403 — por desenho, não por falta. |

### Painel (sessão) — não use na integração

| Método | Caminho | Acesso | O que faz |
|---|---|---|---|
| POST | `/auth/login` | sessão | Login do painel: senha e depois código por e-mail (/auth/verify-otp). Integração usa chave de API, nunca sessão. |
| GET | `/auth/me` | sessão | Usuário, conta ativa e permissões. |
| GET | `/tenants` | sessão | As contas do usuário e a ativa. Uma chave de API pertence a UMA conta. |
| POST | `/api-keys` | sessão | Cria uma chave (TEST ou LIVE) com escopos; o segredo aparece uma vez. Mais simples pelo painel, em Desenvolvedores. |
| POST | `/api-keys/:id/revoke · /api-keys/:id/rotate` | sessão | Revoga (para de valer, fica na lista) ou gira o segredo (o anterior para de valer). |
| DELETE | `/api-keys/:id` | sessão | Exclui a chave de vez, ativa ou revogada. A auditoria guarda nome, prefixo e ambiente. |

## Páginas públicas

`publicUrl` (cobrança) e o `publicUrl` do carnê são páginas hospedadas pela PAGUEO. Por trás delas estão `GET /public/charges/:token` e `GET /public/plans/:token` (sem autenticação; dados do pagador mascarados). Não exponha ids internos nem dados de cliente em páginas próprias.

## Segurança — o que precisa estar no seu código

- Chave de API só no servidor, em variável de ambiente ou cofre. Nunca em frontend, aplicativo ou repositório. Uma chave vazada se revoga no painel (Desenvolvedores) e se recria — não há "desativar temporário".
- Confira a assinatura de TODO webhook e trate `x-pagueo-event-id` como chave de idempotência.
- Nunca marque um pedido como pago a partir do navegador ou de um corpo que não veio assinado da PAGUEO.
- Guarde `id`, `externalId`, `status` e a hora de cada resposta: é o que permite conciliar e abrir um chamado com fatos.
- Comece em TEST. Troque para `vk_live_` só no servidor de produção, e nunca misture dados dos dois ambientes.

## Suporte

Central de ajuda: https://pagueo.com.br/help · Painel: https://pagueo.com.br/dashboard · Esta página: https://pagueo.com.br/llms.txt (regerada a cada publicação; a referência viva é https://api.pagueo.com.br/api/docs-json).
