# ValidaPay API > API REST para Pix, checkout transparente, links de pagamento, assinaturas, split, subcontas, saques, devoluções e notas fiscais. Valores sempre em reais (BRL), nunca em centavos. Autenticação OAuth2 client_credentials. ## Ambientes | Ambiente | API | OAuth | |---|---|---| | Produção | https://api.validapay.com.br | https://oauth2.validapay.com.br/auth/token | | Sandbox | https://sandbox.validapay.com.br | https://oauth2-sandbox.validapay.com.br/auth/token | ## Recursos para agentes de IA - **Servidor MCP: https://docs.validapay.com.br/mcp** — consulta a documentação sob demanda, sem carregar tudo. Peça ao usuário para adicionar essa URL nos conectores da IA dele. - Contrato OpenAPI 3.1: https://docs.validapay.com.br/openapi.json - Guia de integração (skill): https://docs.validapay.com.br/api/ai-skill - Documentação completa em texto: https://docs.validapay.com.br/llms-full.txt - Collection Postman (JSON válido): https://docs.validapay.com.br/collection.json Markdown de qualquer página: acrescente `.md` à URL. --- # ValidaPay API — skill de integração Guia para agentes de IA implementarem integrações com a API ValidaPay. Siga as regras abaixo; não invente rotas, campos ou status. Como usar esta skill: - **Cursor:** salve em `.cursor/skills/validapay-api/SKILL.md` - **Claude:** cole nas instruções do Project, ou salve como `CLAUDE.md` na raiz (Claude Code) - **ChatGPT:** cole nas instruções de um GPT customizado, no Knowledge do Project, ou no chat - **Lovable:** cole em Knowledge / instruções do projeto - **Outras IAs:** cole o Markdown no chat e peça a integração com a API ValidaPay Credenciais: https://app.validapay.com.br/integracao/api Webhooks: https://app.validapay.com.br/integracao/webhooks Suporte: contato@validapay.com.br · WhatsApp (11) 93623-6133 ## Regras - REST + JSON. Valores monetários em **reais (BRL)**, nunca em centavos. Duas casas, ponto decimal (`10.00`). - **`paymentMethod` muda de caixa entre entrada e saída.** No envio use minúsculo (`pix`, `creditcard`, `boleto`, `pix_automatico`); nas respostas ele volta em maiúsculo (`PIX`, `BOLETO`, `CREDIT_CARD`). Não reenvie o valor lido de uma resposta. - HTTPS obrigatório. Auth: OAuth2 `client_credentials` → `Authorization: Bearer {access_token}`. - Não existe `POST /v1/subscriptions`. Assinaturas nascem via `POST /v1/charges` (itens recorrentes) ou checkout (`POST /v1/checkouts` / `POST /v1/checkout-sessions`). - Idempotência só em `POST /v1/charges`: `externalId` → duplicata vira `409 DUPLICATE_CHARGE`. **`POST /v1/charges/pix` não tem idempotência** — `externalId` é ignorado e chamadas repetidas criam cobranças distintas; controle duplicidade do seu lado. - Cartão no backend: preferir `paymentMethodId` do SDK `@validapay/tokenize`. Não persistir PAN/CVV. - Pix Automático (`pix_automatico`): só conta **PJ**, preço **recorrente**, mínimo **R$ 4,99**. - Saques: mesma titularidade da conta. Split: `type` é `fixed` ou `percentage` (literal, minúsculo); informe `accountNumber` **ou** `publicId` do recebedor. Máximo 20 recebedores; soma dos percentuais até 100%. **Split não funciona em `creditcard` nem `pix_automatico`** — só Pix e boleto. - Webhook: responder **HTTP 200** e não bloquear no handler. A assinatura em `X-Webhook-Signature` é composta — `t=,v1=` — e o HMAC é `HMAC_SHA256(secret, ".")`; use o corpo bruto, sem reserializar. - Sandbox: simular pagamento com `POST /v1/wallet/pay/:chargeId`. ## Ambientes | | API | OAuth | |---|---|---| | Produção | `https://api.validapay.com.br` | `https://oauth2.validapay.com.br/auth/token` | | Sandbox | `https://sandbox.validapay.com.br` | `https://oauth2-sandbox.validapay.com.br/auth/token` | Painel: `https://app.validapay.com.br` Prefixos: `cha_` cobrança · `prod_` produto · `price_` preço · `pl_` link · `cs_` sessão · `cus_` cliente · `pm_` cartão tokenizado · `sub_` assinatura · `item_` item · `ref_` devolução · `wdr_` saque ## Autenticação ```http POST https://oauth2-sandbox.validapay.com.br/auth/token Content-Type: application/x-www-form-urlencoded grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}&scope={scope} ``` Resposta: `{ "access_token", "expires_in", "token_type": "Bearer" }`. **`expires_in` não é fixo em 3600** — o servidor reaproveita tokens já emitidos e devolve o tempo restante. Calcule a validade por `min(expires_in, exp do JWT)` com margem, e não repita a autenticação em laço ao tomar 401: a nova chamada pode devolver o mesmo token. Peça só os scopes necessários, separados por espaço. ### Scopes | Scope | Uso | |---|---| | `pix.cob/write` `pix.cob/read` | QR Pix imediato (`/v1/charges/pix`) e consulta | | `checkouts/write` `checkouts/read` | Links, sessões e checkout transparente (`/v1/charges`) | | `products/write` `products/read` | Produtos e preços | | `customers/write` `customers/read` `customers/delete` | Cadastro de clientes | | `subscriptions/write` `subscriptions/read` | Gestão de assinaturas (não cria) | | `proposals/write` | Onboarding de subcontas | | `subaccounts/read` | Listar subcontas e cobranças | | `wallet/write` `wallet/read` | Saldo, extrato, saque, devolução, pagar sandbox | Nas demais rotas: `Authorization: Bearer {access_token}` e `Content-Type: application/json`. Header opcional: `X-Sub-Account: {numero}` — opera na subconta (ex.: cobrança Pix do seller com split para a master). ## Mapa de rotas ### Pix imediato — `pix.cob/*` | Método | Path | Função | |---|---|---| | POST | `/v1/charges/pix` | QR imediato. Body mínimo `{ "amount": 10.00 }`. Com split, array `split`. | | GET | `/v1/charges/:chargeId` | Status (`PAID`, etc.) | Split para parceiros (na conta master): ```json { "amount": 1.00, "externalTxid": "loja-01-caixa-03", "split": [ { "type": "fixed", "accountNumber": "896532569", "amount": 0.10 } ] } ``` Split para a master a partir do seller: mesmo body **sem** `accountNumber` no split + header `X-Sub-Account`. Resposta da criação: `{ "chargeId", "emv" }` (Pix Copia e Cola). ### Produtos — `products/*` | Método | Path | |---|---| | POST | `/v1/products` | | GET | `/v1/products` · `/v1/products/:id` | | PUT | `/v1/products/:id` | | DELETE | `/v1/products/:id` | | POST | `/v1/products/:id/archive` | `type`: `RECURRING` \| `ONE_TIME`. `prices[].recurrenceType`: `ONE_TIME` `DAILY` `WEEKLY` `MONTHLY` `QUARTERLY` `SEMIANNUAL` `YEARLY`. `recurrenceInterval` mínimo 1 (ex.: 2 = bimestral). `trialDays` opcional. `statementDescriptor` máx. 22 caracteres. ```json { "name": "Plano Premium", "type": "RECURRING", "prices": [ { "title": "Mensal", "amount": 99.9, "recurrenceType": "MONTHLY", "trialDays": 7 } ] } ``` ### Links e sessões — `checkouts/*` | Método | Path | Função | |---|---|---| | POST/GET/PUT | `/v1/checkouts` · `/v1/checkouts/:id` | Link reutilizável (`pl_`). Informe `priceId` **ou** `product`. | | POST/GET | `/v1/checkout-sessions` · `/v1/checkout-sessions/:id` | Sessão única (`cs_`), cliente pré-preenchido. | `allowedPaymentMethods`: `pix` `creditcard` `boleto` `pix_automatico`. ### Checkout transparente — `POST /v1/charges` Campo `paymentMethod` obrigatório. Cliente obrigatório (`name`, `email`, `documentNumber`). Itens via `items[].priceId` **ou** `amount` avulso (exceto Pix Automático: só `items` recorrentes). | `paymentMethod` | Particularidades | Resposta útil | |---|---|---| | `pix` | `expiration` YYYY-MM-DD | `pix.emv`, `pix.qrCode` | | `pix_automatico` | PJ + preço recorrente ≥ 4.99; `billingDay` 1–31 | `pix.emv`, `pix.recurrencyId`; assinatura `PENDING` até o banco autorizar | | `boleto` | `customer.address` completo; `dueDate` / `boletoDueDays`; `boletoInstructions` | `boleto.digitableLine`, `barCode`, `pdfUrl` | | `creditcard` | `card` **ou** `paymentMethodId`; `installments` 1–12 | `status: "paid"` ou 402 recusa | ```json { "paymentMethod": "pix", "externalId": "pedido-2026-0001", "customer": { "name": "João da Silva", "email": "joao@email.com", "documentNumber": "12345678901" }, "items": [{ "priceId": "price_abc123", "quantity": 1 }] } ``` Cartão tokenizado: omita `card` e envie `"paymentMethodId": "pm_abc123"`. ### Emitir nota fiscal junto com a cobrança Envie `nfConfigId` no corpo da cobrança, com o id de uma configuração criada em `POST /v1/invoices/notas/config`. - **`customer.address` passa a ser obrigatório.** Sem ele: `400 INVALID_DATA`. A nota precisa do endereço do tomador, e o `cityCode` (IBGE) é resolvido pelo CEP. - O **momento da emissão vem da configuração**, não da cobrança: `invoiceTiming` aceita `IMMEDIATE` (padrão), `AFTER_CONFIRMATION` e `DAYS_AFTER_CONFIRMATION`; neste último, `daysAfterConfirmation` define o prazo (padrão 1). - O mesmo `nfConfigId` existe em `POST /v1/products` e nas configurações de assinatura, para emitir a cada ciclo sem repetir na cobrança. ```json { "paymentMethod": "pix", "amount": 150.00, "nfConfigId": "nfc_1788364755079_psuecwgdc", "customer": { "name": "João da Silva", "email": "joao@email.com", "documentNumber": "12345678901", "address": { "zipCode": "01310100", "street": "Avenida Paulista", "number": "1000", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP" } } } ``` ### Campos de POST /v1/charges Além de `paymentMethod`, `customer` e `items`/`amount`: | Campo | Regra | |---|---| | `installments` | 1 a 12, só cartão | | `freeInstallments` | 0 a 12, parcelas sem juros ao comprador | | `passFeesToCustomer` | repassa a taxa de parcelamento | | `split` | **não** funciona em `creditcard` nem `pix_automatico` | | `discounts[].type` | `percentage` ou `fixed` (também aceita maiúsculo) | | `allowedPaymentMethods` | subconjunto de `pix` `creditcard` `boleto` `pix_automatico` | | `dueDate` | `YYYY-MM-DD`, precisa ser maior que hoje | | `expirationAfterDueDate` | 0 a 60 dias após o vencimento | | `boletoDueDays` | derivado de `dueDate` quando este é enviado | | `externalId` / `externalTxid` | até 100 caracteres | | `productId` | prefixo `prod_`; `items[].priceId`, prefixo `price_` | | `recurrencyStartDate`, `prorataStartDate`, `prorataDueDate` | `YYYY-MM-DD` | | `mergeWithNextCycle` | junta a pro rata ao próximo ciclo | | `nfConfigId` | emite nota; exige `customer.address` | Com `creditcard`, informe `card`, `tokenId` **ou** `paymentMethodId` — sem um deles a cobrança é recusada. ### Clientes — `customers/*` | Método | Path | Função | |---|---|---| | POST | `/v1/customers` | Cadastra. Já existente → **200** com o cadastro atual (não duplica); com `upsert: true` → **400** `CUSTOMER_ALREADY_EXISTS` | | GET | `/v1/customers` | Lista. Query: `limit`, `lastKey`, `search`, `document`, `status`, `startDate`, `endDate` | | GET | `/v1/customers?lookupDocument=` | Busca 1 cliente pelo CPF/CNPJ exato + endereço padrão | | GET | `/v1/customers/:customerId` | Detalhe com endereços e assinaturas | | PATCH | `/v1/customers/:customerId` | Atualiza. Documento **não** pode ser alterado → **400** `DOCUMENT_UPDATE_NOT_ALLOWED` | | DELETE | `/v1/customers/:customerId` | Remove. Com assinatura recorrente → **400** `CUSTOMER_HAS_ACTIVE_SUBSCRIPTIONS` | `search` faz busca parcial simultânea em **nome, e-mail e documento** — use para autocompletar cliente. `document` é match exato; prefira quando o CPF/CNPJ completo já é conhecido. `lookupDocument` devolve `{ customer, address }` prontos para preencher formulário; documento não cadastrado retorna **200** com ambos `null` (não é erro). Paginação por cursor: repita a chamada com `lastKey` = `pagination.lastKey`, mantendo os mesmos filtros. `lastKey` `null` = fim. `document`: apenas dígitos, CPF (11) ou CNPJ (14). `phone`: E.164 com DDI 55. Com `address`, o `cityCode` (IBGE) é resolvido pelo CEP — necessário para NFS-e. Status: `ACTIVE` `INACTIVE` `BLOCKED`. ```json { "name": "Alexandre Souza", "document": "05154089561", "phone": "5511987654321", "email": "alexandre@exemplo.com.br", "address": { "zipCode": "01310100", "street": "Avenida Paulista", "number": "1000", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP" } } ``` ### Assinaturas — `subscriptions/*` Não criar por esta API. Após o pagamento, liste/filtre (ex. `checkoutId`) e use `GET /v1/subscriptions/:subscriptionId`. | Método | Path | Função | |---|---|---| | GET | `/v1/subscriptions` | Lista. Query: `limit`, `lastKey`, `status`, `paymentMethod`, `document`, `search`, `startDate`, `endDate`, `priceId`, `productId` | | GET | `/v1/subscriptions/:subscriptionId` | Detalhe | | PUT | `/v1/subscriptions/:id/items/:itemId` | Upgrade/downgrade canônico (`priceId` e/ou `quantity`) | | POST | `/v1/subscriptions/:id/items` | Add-on. Assinatura `ACTIVE`/`PAST_DUE`; não no 1º ciclo (`currentCycleNumber === 1`) | | POST | `/v1/subscriptions/:id/prorata` | Preview — **não cobra** | | PATCH | `/v1/subscriptions/:id` | `{ old: { itemId }, new: { priceId } }` upgrade/downgrade; `{ old: { itemId } }` cancela item | | DELETE | `/v1/subscriptions/:id` | Cancela assinatura. Body opcional `{ "reason" }` | Upgrade (`newTotal > currentTotal`): cobra pro rata já (cartão) ou PIX/boleto assíncrono. Downgrade: no próximo ciclo, sem cobrança imediata. Falha de pagamento nestas rotas: **400** `PAYMENT_DECLINED` / `PAYMENT_FAILED` (não 402). Status assinatura: `PENDING` `TRIALING` `ACTIVE` `PAST_DUE` `DEFAULT` `EXPIRED` `CANCELED` `COMPLETED` `ARCHIVED`. Status do item: `PENDING` `TRIALING` `AWAITING_PAYMENT` `ACTIVE` `CHARGED` `FAILED` `CANCELED` `PENDING_UPGRADE` `DEFAULT`. Tipo: `RECURRING` `ONE_TIME`. `paymentType`: `CREDIT_CARD` `PIX` `BOLETO` `PIX_AUTOMATICO`. ### Subcontas — `proposals/write` · `subaccounts/read` | Método | Path | Função | |---|---|---| | POST | `/v1/proposals` | PF ou PJ (campos diferentes). Retorna `formId`. | | GET | `/v1/proposals/:formId` | Status da proposta | | GET | `/v1/accounts/subaccounts` | Lista (`dateFrom`, `dateTo`, `page`, `perPage`) | | GET | `/v1/charges` | Cobranças da conta | | GET | `/v1/wallet/balance?accountId=` | Saldo | Não reutilizar e-mail/telefone da master. `financialDetails` (PF) / `financialOwnerDetails` (PJ) obrigatórios — códigos do apêndice na doc. Número da conta chega no webhook `onboarding.create` (`data.account`). ### Carteira — `wallet/*` | Método | Path | Função | |---|---|---| | POST | `/v1/wallet/pay/:chargeId` | **Só sandbox** — dispara o evento de pagamento. Responde `status: "PROCESSING"`; a confirmação chega pelo webhook. Conta não-sandbox → 400 `NOT_SANDBOX_ACCOUNT` | | POST | `/v1/wallet/withdraw` | Saque Pix. Master: `amount`, `pixKey`, `pixKeyType`. Subconta: + `accountId` | | GET | `/v1/wallet/transactions` | Extrato. Query: `accountId` (sub), `type`, `category`, `dateFrom`, `dateTo`, `limit`, `nextPageToken` | | POST | `/v1/wallet/refunds` | Pix: `endToEndId` + `reason` obrigatório. Cartão: `chargeId` | | GET | `/v1/wallet/refunds?refundId=` | Status da devolução/estorno | `reason` Pix: `CUSTOMER_REQUEST` `FRAUD` `BANK_ERROR` `PIX_CHANGE_ERROR`. Pix costuma nascer `PROCESSING`; cartão pode vir `CONFIRMED` + `success: true`. ### Cartões de teste em sandbox Em conta de sandbox nenhuma cobrança chega ao adquirente: **o número do cartão define o resultado**. | Número | Resultado | |---|---| | `4111111111111111` | aprovado | | `4000000000000002` | recusado pela operadora (`card_declined`) | | `4000000000000004` | saldo insuficiente (`insufficient_funds`) | | `4000000000000006` | cartão expirado (`expired_card`) | | `4000000000000008` | CVV inválido (`invalid_cvv`) | | `4000000000000010` | suspeita de fraude (`fraud_suspected`) | Qualquer outro número de 16 dígitos é aprovado. CVV, validade e nome do titular podem ser quaisquer valores válidos. **Em produção o número não muda nada** — quem decide é o emissor. Os códigos entre parênteses são os `declinedCode` que chegam em `details.declinedCode` no `400 PAYMENT_DECLINED` das rotas de assinatura. Para Pix e boleto, o pagamento em sandbox se dispara com `POST /v1/wallet/pay/:chargeId`. `pixKeyType`: `CPF` `CNPJ` `EMAIL` `PHONE` `EVP`. ## Webhooks Cadastro no painel ou via `POST /v1/users/webhooks`. A ValidaPay envia `POST` JSON. Responda **2xx em até 5s** (timeout do envio). Assinatura HMAC: `X-Webhook-Signature`; token opcional: `x-access-token`. **Não há retry automático** — reenvio manual por `POST /v1/users/webhooks/{webhookEventId}/retry`. Chave da conta: `accountNumber` em `subscription.*`, `charge.created` e no `payment.success` com `subscriptionId`; `accountId` em `payment.failed`, `refund.*`, `onboarding.*`, `med.*` e no `payment.success` avulso. Leia os dois. | Evento | Quando | |---|---| | `payment.success` | Pagamento confirmado (Pix, boleto, ONE_TIME) | | `payment.failed` | Falha em cobrança recorrente. Schema próprio: `accountId`, `failed` (string), sem base de assinatura | | `charge.created` | Cobrança criada. `status` é o da COBRANÇA, não da assinatura | | `subscription.created` | Recorrência criada, 1º pagamento ainda não confirmado | | `subscription.trial` | Trial iniciado. Sem objeto `trial` — prazo em `items[].price.trialDays` | | `subscription.activated` | 1º pagamento ok — ativa | | `subscription.renewed` | Ciclo ≥ 2 pago | | `subscription.canceled` | Cancelada (API ou inadimplência). `currentCycle` continua preenchido | | `subscription.cancel_scheduled` | Cancela no fim do período | | `subscription.upgraded` | Upgrade pago | | `subscription.item_added` | Item adicionado e cobrado | | `subscription.item_removed` | Item removido | | `subscription.downgrade_scheduled` | Downgrade no próximo ciclo | | `onboarding.backgroundcheck` | PENDING → APPROVED/REPROVED | | `onboarding.documentscopy` | Upload de docs | | `onboarding.proposal` | Proposta APPROVED/REPROVED | | `onboarding.create` | Subconta criada (`data.account`), status `CONFIRMED` | | `refund.requested` | Devolução em processamento (`PROCESSING`) | | `refund.confirmed` | Devolução concluída (`CONFIRMED`) | | `refund.failed` | Devolução falhou — status enviado é `ERROR`, não `FAILED` | | `med.*` | Infração e bloqueios do MED. Só assinável via API | Exemplo `payment.success` (Pix avulso): ```json { "event": "payment.success", "chargeId": "cha_1771453171013_fp6iocaxb", "amount": 150.0, "paymentMethod": "PIX", "paymentId": "E1234567820260215120000000000001", "paidAt": "2026-02-15T15:30:00.000Z", "payer": { "name": "Issac Newton", "taxId": "12345678900", "bank": "260", "account": "12345678", "branch": "0001", "accountType": "CACC" } } ``` Eventos de assinatura incluem `subscriptionId`, `customer`, `items`, `currentCycle`, `timestamp`, `accountNumber`. Trate o handler como idempotente. ## Tokenização de cartão ```bash npm install @validapay/tokenize ``` ```js import { tokenize } from '@validapay/tokenize'; const result = await tokenize({ clientId, clientSecret, card: { number, cardHolderName, cvv, expiration: '12/2030' }, customer: { name, document, email }, }); // result.paymentMethodId → POST /v1/charges { paymentMethod: "creditcard", paymentMethodId } ``` ## Fluxos **Pix avulso:** OAuth (`pix.cob/write`) → `POST /v1/charges/pix` `{ amount }` → exibir `emv` → webhook `payment.success` ou GET status. Sandbox: `POST /v1/wallet/pay/:chargeId`. **Checkout + assinatura:** `POST /v1/products` → `POST /v1/charges` com `items` + `paymentMethod` **ou** `POST /v1/checkouts` / `checkout-sessions` → webhook `subscription.activated` → `GET /v1/subscriptions`. **Marketplace:** `POST /v1/proposals` (PF/PJ) → webhooks de onboarding → `onboarding.create` → `POST /v1/charges/pix` com `split` (e `X-Sub-Account` se a cobrança é do seller). **Devolução:** Pix: `endToEndId` do pagamento + `reason`. Cartão: `chargeId`. Poll `GET /v1/wallet/refunds?refundId=` se `PROCESSING`. ## Erros frequentes | HTTP | code | Causa | |---|---|---| | 400 | `INVALID_DATA` `INVALID_PRODUCT_DATA` | Campo inválido | | 400 | `PIX_AUTOMATICO_PJ_ONLY` | Pix Automático em conta PF | | 400 | `PAYMENT_DECLINED` `PAYMENT_FAILED` | Recusa em upgrade/add item | | 400 | `SUBSCRIPTION_ALREADY_CANCELED` | DELETE repetido | | 401/403 | `OWNERSHIP_MISMATCH` `FORBIDDEN` | Subconta/chave de outro titular ou scope | | 402 | — | Cartão recusado no `POST /v1/charges` | | 404 | `PRICE_NOT_FOUND` | `priceId` inexistente | | 409 | `DUPLICATE_CHARGE` | `externalId` repetido; use o `chargeId` retornado | Envelope típico: `{ "error": { "message", "code", "details", "timestamp" } }`. ## Cliente HTTP mínimo ```js async function validapay(method, path, { token, body, headers } = {}) { const res = await fetch(`${process.env.VALIDAPAY_API}${path}`, { method, headers: { Authorization: `Bearer ${token}`, ...(body ? { 'Content-Type': 'application/json' } : {}), ...headers, }, body: body ? JSON.stringify(body) : undefined, }); const data = await res.json().catch(() => ({})); if (!res.ok) { const err = new Error(data?.error?.message || data?.message || res.statusText); err.status = res.status; err.code = data?.error?.code || data?.code; err.body = data; throw err; } return data; } ``` ## Fluxos ponta a ponta Errar o fluxo é mais comum que errar o campo. Siga estas sequências. ### Pix avulso 1. Token com `pix.cob/write`. 2. `POST /v1/charges/pix` com `{ "amount": 10.00 }`. 3. Use `emv` (copia e cola) ou `qrCode` na interface. 4. Sandbox: dispare o pagamento com `POST /v1/wallet/pay/:chargeId` — responde `PROCESSING`, não confirmação. 5. Aguarde o webhook `payment.success` ou consulte `GET /v1/charges/:chargeId`. ### Venda avulsa com checkout transparente 1. Token com `checkouts/write`. 2. `POST /v1/charges` com `paymentMethod`, `customer` e `items` (ou `amount`). 3. Envie `externalId` como idempotência. Duplicata → `409 DUPLICATE_CHARGE`. 4. Pix/boleto: aguarde `payment.success`. Cartão: a resposta já traz `status: "paid"` ou `402`. ### Assinatura 1. `POST /v1/products` com `prices[].recurrenceType` recorrente → guarde o `priceId`. 2. `POST /v1/charges` (ou checkout) com `items: [{ priceId }]`. 3. Webhook `subscription.created` (`PENDING`) chega. 4. Após o pagamento: `charge.created` → `payment.success` → `subscription.activated`. 5. Gerencie por `GET/PATCH/PUT /v1/subscriptions/...`. **Não existe `POST /v1/subscriptions`.** ### Upgrade de plano 1. `POST /v1/subscriptions/:id/prorata` para calcular — **não cobra**, use para mostrar ao cliente. 2. `PUT /v1/subscriptions/:id/items/:itemId` com o novo `priceId`. 3. Cartão: cobrança síncrona. Pix/boleto: assíncrona, aguarde `payment.success`. 4. Recusa nessas rotas retorna **400** `PAYMENT_DECLINED`/`PAYMENT_FAILED`, não 402. ### Subconta com split 1. `POST /v1/proposals` → `formId`. 2. Aguarde `onboarding.create` → o número da conta vem em `data.account`. 3. Cobrança do seller: `POST /v1/charges/pix` com header `X-Sub-Account` e `split` sem `accountNumber`. 4. Cobrança da master para parceiros: `split` com `accountNumber` de cada recebedor. ### Devolução 1. Pix: `POST /v1/wallet/refunds` com `endToEndId` + `reason`. Nasce `PROCESSING`. 2. Cartão: `POST /v1/wallet/refunds` com `chargeId`. Pode vir `CONFIRMED` direto. 3. Aguarde `refund.confirmed` — não trate a resposta da solicitação como conclusão no Pix. ## Sequências de webhook | Cenário | Ordem | |---|---| | Assinatura com cartão | `subscription.created` → `charge.created` → `payment.success` → `subscription.activated` | | Assinatura com trial | `subscription.created` → `subscription.trial` → `charge.created` → `payment.success` → `subscription.activated` | | Renovação | `charge.created` → `payment.success` → `subscription.renewed` | | Inadimplência | `charge.created` → `payment.failed` (por tentativa) → `subscription.canceled` se o dunning esgotar | | Cancelamento agendado | `subscription.cancel_scheduled` → `subscription.canceled` | | Onboarding | `onboarding.backgroundcheck` → `onboarding.documentscopy` → `onboarding.proposal` → `onboarding.create` | Trate os eventos de forma idempotente e ordene por `timestamp` — a ordem de chegada não é garantida. ## Cinco formatos de erro A API não usa um formato único. Trate sempre pelo campo de código, nunca pela mensagem. **1. Envelope (dominante)** — toda exceção lançada nos módulos v1 passa pelo `errorHandler` e sai assim: ```json { "error": { "message": "Cobrança duplicada", "code": "DUPLICATE_CHARGE", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` **2. OAuth2 (`POST /auth/token`)** — segue a RFC 6749; `error` é uma **string**: ```json { "error": "Invalid credentials" } ``` Valores: `Unsupported grant_type`, `Missing client_id, client_secret, or scope` (400), `Invalid credentials` (401), `Unauthorized scope` (403). **3. Cartão recusado no checkout transparente (402)** — `error` é a razão da recusa, em texto: ```json { "success": false, "chargeId": "cha_...", "status": "failed", "error": "Cartão recusado" } ``` **5. Token sem scope (401)** — sem envelope e sem código, e a mensagem engana: o token pode estar válido, faltando só o scope. ```json { "message": "TOKEN EXPIRADO OU INVALIDO" } ``` **4. Propostas de subconta** — recusas de proposta retornam sem envelope: ```json { "message": "Proposta rejeitada", "code": "FORM_NOT_FOUND" } ``` Na mesma rota, erros de validação usam o envelope do formato 1. Trate os dois. ### Recusa de cartão em assinaturas Nas rotas de assinatura a recusa vem como **400** (não 402), com o motivo em `details.declinedCode`: ```json { "error": { "message": "Cartão recusado por saldo insuficiente", "code": "PAYMENT_DECLINED", "details": { "declinedCode": "insufficient_funds" }, "timestamp": "..." } } ``` `declinedCode`: `insufficient_funds` · `card_declined` · `expired_card` · `invalid_cvv` · `fraud_suspected` ### Erro presente em quase toda rota autenticada `404 ACCOUNT_NOT_FOUND` — conta não resolvida a partir das credenciais; vale para praticamente qualquer rota autenticada. Há também `404 NOT_FOUND` genérico, usado quando a exceção é lançada sem código próprio. Trate os dois, com fallback para código desconhecido. Correlação com o pedido, por rota: em `/v1/charges/pix` use `metadata` (persistido, volta no webhook); em `/v1/charges` use `externalId` — ali `metadata` é aceito mas descartado. Guarde sempre um índice local `chargeId` → pedido. ## Cliente HTTP mínimo (continuação) O cliente acima já cobre os dois formatos: `data?.error?.code || data?.code`. ## Recursos para agentes | Recurso | URL | |---|---| | Contrato OpenAPI 3.1 | `/openapi.json` | | Índice para IA | `/llms.txt` | | Documentação completa em texto | `/llms-full.txt` | | Markdown de qualquer página | acrescente `.md` à URL | | Collection Postman (JSON válido) | `/collection.json` | | Environment sandbox | `/ValidaPay-Sandbox.postman_environment.json` | Prefira `/openapi.json` para gerar código: ele traz tipos, campos obrigatórios, scopes por rota e os payloads de webhook. --- # Referência completa de endpoints # Autenticação `POST /auth/token` ### Resposta 200 — 200 ```json { "access_token": "eyJraWQiOiJleGVtcGxvIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAiLCJ0b2tlbl91c2UiOiJhY2Nlc3MiLCJzY29wZSI6ImFjY291bnQvcmVhZCIsImNsaWVudF9pZCI6ImV4ZW1wbG9jbGllbnRpZDEyMzQ1Njc4OTAiLCJpc3MiOiJodHRwczovL2NvZ25pdG8taWRwLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tL3VzLWVhc3QtMV9FWEVNUExPIiwiZXhwIjoxOTAwMDAwMDAwLCJpYXQiOjE4OTk5OTY0MDB9.ASSINATURA_DE_EXEMPLO", "expires_in": 3600, "token_type": "Bearer" } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-autenticacao Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Status de cobrança `GET /v1/charges/:chargeId` **Área:** Pix **Scopes necessários:** `pix.cob/read` ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `chargeId` | **sim** | Identificador retornado no ato da geraçao da cobrança | ### Resposta 200 — 200 ```json { "chargeId": "cha_1771453171013_fp6iocaxb", "status": "PAID", "amount": 0.2, "paymentType": "PIX", "emv": "00020101021226910014br.gov.bcb.pix…", "paidAt": "2026-02-18T22:22:50.031Z", "createdAt": "2026-02-18T22:19:31.013Z" } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-status-de-cobranca Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Cobrança imediata `POST /v1/charges/pix` **Área:** Pix **Scopes necessários:** `pix.cob/write` Com esta funcionalidade você pode criar um QR Code de cobrança imediata. **Case de uso:** _Como SaaS, quero gerar cobranças preenchendo apenas o valor do produto e nada mais_ **Regras condicionais (COBV):** `name` e `cep` do `customer` só são aceitos junto com `expiration`. Havendo `expiration` e `customer`, o trio `documentNumber`, `name` e `cep` passa a ser obrigatório em bloco. **Resposta:** os campos vêm na raiz — `emv` e `qrCode`, não aninhados sob `pix`. O `qrCode` já é uma data URL PNG pronta para exibir; não é preciso gerar a imagem no seu lado. **Correlação com o pedido:** envie `metadata` na criação e ele volta na resposta e no payload do webhook `payment.success`. É a forma recomendada de amarrar o pagamento ao seu pedido. > ⚠️ **Esta rota não tem idempotência.** `externalId` é aceito e descartado; duas chamadas iguais criam **duas cobranças**. Controle duplicidade no seu lado (índice `pedido → cobrança`) ou use `POST /v1/charges`, que responde `409 DUPLICATE_CHARGE`. O campo `externalTxid` documentado aqui identifica loja, caixa ou vendedor — não serve como chave de idempotência. ### Request body ```json { "amount": 10.00, "paymentMethod": "pix", "expiration": "2026-12-31", "externalTxid": "loja-01-caixa-03", "metadata": { "orderId": "pedido-1001" }, "customer": { "documentNumber": "12345678901", "name": "Joao da Silva", "cep": "01310100", "phone": "+5511999998888", "email": "joao@email.com" }, "split": [ { "type": "fixed", "accountNumber": "896532569", "amount": 0.10 } ] } ``` ### Campos do body **Obrigatórios:** `amount`, `split.type`, `split.amount` | Campo | Descrição | |---|---| | `amount` | Valor em reais, nunca em centavos (mín.: 0.01) | | `split.type` | Tipo da divisao (valores: percentage, fixed) | | `split.amount` | Valor em reais quando fixed; percentual de 0 a 100 quando percentage (mín.: 0.01) | **Opcionais** | Campo | Descrição | |---|---| | `paymentMethod` | Fixo "pix"; o padrao ja e pix (valores: pix) | | `expiration` | Vencimento (COBV). Nao aceita data passada | | `externalTxid` | Identifica loja, caixa ou vendedor | | `customer` | Dados do pagador. Com expiration, vira COBV | | `customer.documentNumber` | CPF ou CNPJ do pagador | | `customer.name` | Exige expiration (COBV) | | `customer.cep` | Exige expiration (COBV) | | `customer.phone` | Telefone no formato E.164 | | `customer.email` | E-mail do pagador | | `split` | Divisao do valor entre recebedores | | `split.accountNumber` | Conta do recebedor; ou informe publicId | ### Resposta 200 — 200 ```json { "chargeId": "cha_1771511282731_9p1wo3tql", "emv": "00020101021226910014br.gov.bcb.pix…", "qrCode": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", "metadata": { "orderId": "pedido-1001" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-cobranca-imediata Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Cobrança imediata com split `POST /v1/charges/pix` **Área:** Split de pagamentos **Scopes necessários:** `pix.cob/write` Com esta funcionalidade você pode criar um QR Code de cobrança na sua conta e fazer split para outras contas ValidaPay. **Case de uso:** _Como SaaS, tenho parceiros/afiliados PF ou PJ. Quero gerar cobranças na minha conta preenchendo apenas o valor do produto e fazer split para as contas dos meus parceiros._ Use `externalTxid` para identificar a **loja**, o **caixa** ou o **vendedor** responsável pela cobrança. ### Request body ```json { "amount": 1.00, "externalTxid": "loja-01-caixa-03", "split": [ { "type": "fixed", "accountNumber": "896532569", "amount": 0.10 }, { "type": "fixed", "accountNumber": "125485692", "amount": 0.10 } ] } ``` ### Campos do body **Obrigatórios:** `amount`, `type` | Campo | Descrição | |---|---| | `amount` | Valor com precisão de duas casas decimais separado por ponto | | `type` | Valor fixo ou porcentagem | **Opcionais** | Campo | Descrição | |---|---| | `externalTxid` | Identifica a loja, o caixa ou o vendedor responsável pela cobrança | ### Resposta 200 — 200 ```json { "chargeId": "cha_1881511282731_9p1wo5plk", "emv": "00020101021226910014br.gov.bcb.pix…" } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-cobranca-imediata-com-split Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Split para Conta Master `POST /v1/charges/pix` **Área:** Split de pagamentos **Scopes necessários:** `pix.cob/write` Com esta funcionalidade você pode criar um QR Code de cobrança na conta de um _Seller_ e fazer split para a sua conta. **Case de uso:** _Como SaaS tenho vários Sellers, cada um deles possui uma subconta ValidaPay. Quero gerar cobranças para qualquer subconta preenchendo apenas o valor do produto e fazer split para a minha conta Master_ > ⚠️ **Atenção:** O número da subconta é retornado via webhook quando a subconta é aprovada. Use `externalTxid` para identificar a **loja**, o **caixa** ou o **vendedor** responsável pela cobrança. ### Request body ```json { "amount": 1.00, "externalTxid": "loja-01-caixa-03", "split": [ { "type": "fixed", "amount": 0.10 } ] } ``` ### Campos do body **Obrigatórios:** `amount`, `type` | Campo | Descrição | |---|---| | `amount` | Valor com precisão de duas casas decimais separado por ponto | | `type` | Valor fixo ou porcentagem | **Opcionais** | Campo | Descrição | |---|---| | `externalTxid` | Identifica a loja, o caixa ou o vendedor responsável pela cobrança | ### Resposta 200 — 200 ```json { "chargeId": "cha_15631511282731_9p1wo5ghu", "emv": "00020101021226910014br.gov.bcb.pix…" } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-split-para-conta-master Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Status de cobrança com split `GET /v1/charges/:chargeId` **Área:** Split de pagamentos **Scopes necessários:** `pix.cob/read` ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `chargeId` | **sim** | Identificador retornado no ato da geraçao da cobrança | ### Resposta 200 — 200 ```json { "chargeId": "cha_1771453171013_fp6iocaxb", "status": "PAID", "amount": 0.2, "paymentType": "PIX", "masterAccointId": "2345567893", "subaccountId": "987654322", "emv": "00020101021226910014br.gov.bcb.pix…", "paidAt": "2026-02-18T22:22:50.031Z", "createdAt": "2026-02-18T22:19:31.013Z" } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-status-de-cobranca-com-split Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Criar subconta PF `POST /v1/proposals` **Área:** Subcontas ValidaPay **Scopes necessários:** `proposals/write` Com esta funcionalidade você pode criar subcontas Pessoa Física na ValidaPay. Ao criar a subconta ela ficará associada à sua conta (chamaremos de conta Master). Case de uso: _Como SaaS tenho vários Sellers, preciso gerar cobranças para esses Sellers e receber split em cada venda._ > ⚠️ **Atenção:** Não é possivel criar uma subconta com mesmo email e telefone da _master account._ > ⚠️ **Atenção:** Dados de renda/faturamento no campo financialDetails são obrigatórios. Os respectivos códigos estão descritos no apêndice Campos Financeiros ao final da sessão Subcontas ValidaPay ### Request body ```json { "documentNumber": "11122233396", "phoneNumber": "+5511912345678", "email": "empresa@exemplo.com.br", "motherName": "Teste Mãe", "fullName": "Richard Feynman", "socialName": "", "birthDate": "31-12-2000", "address": { "postalCode": "06455030", "street": "Alameda Xingu", "number": "350", "addressComplement": "", "neighborhood": "Alphaville Industrial", "city": "Barueri", "state": "SP" }, "isPoliticallyExposedPerson": false, "financialDetails": { "declaredIncome": "1DINP02", "occupation": "ONP07", "netWorth": "NWNP02" }, "webhookUrl": "https://api.teste.com.br" } ``` ### Campos do body **Obrigatórios:** `documentNumber`, `phoneNumber`, `email`, `motherName`, `fullName`, `birthDate`, `postalCode`, `street`, `number`, `addressComplement`, `neighborhood`, `city`, `state`, `isPoliticallyExposedPerson`, `declaredIncome`, `occupation`, `netWorth` | Campo | Descrição | |---|---| | `documentNumber` | CPF do titular | | `phoneNumber` | Número de telefone do titular | | `email` | email do titular | | `motherName` | | | `fullName` | Nome completo do titular | | `birthDate` | Data de nascimento do titular | | `postalCode` | CEP do titular | | `street` | | | `number` | | | `addressComplement` | | | `neighborhood` | | | `city` | | | `state` | | | `isPoliticallyExposedPerson` | | | `declaredIncome` | Renda declarada do titular | | `occupation` | Profissão do titular | | `netWorth` | Patrimônio do titular | **Opcionais** | Campo | Descrição | |---|---| | `socialName` | | | `webhookUrl` | URL onde você gostaria de receber a notificação de criação de conta | ### Resposta 201 — 201 ```json { "status": "UNFINISHED", "message": "Formulário criado com sucesso", "formId": "a6358673-dd00-4c6d-9592-df393513a78a" } ``` ### Resposta 200 — 200 ```json { "status": "FINISHED", "message": "Formulário atualizado com sucesso", "formId": "cda0e605-44f7-4cbc-850c-ef3a2073c685" } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-criar-subconta-pf Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Criar subconta PJ `POST /v1/proposals` **Área:** Subcontas ValidaPay **Scopes necessários:** `proposals/write` Com esta funcionalidade você pode criar subcontas Pessoa Jurídica na ValidaPay. Ao criar a subconta ela ficará associada à sua conta (chamaremos de conta Master). Case de uso: _Como SaaS tenho vários Sellers, preciso gerar cobranças para esses Sellers e receber split em cada venda._ > ⚠️ **Atenção:** Não é possivel criar uma subconta com mesmo email e telefone da _master account_ > ⚠️ **Atenção:** Dados de renda/faturamento no campo financialDetails são obrigatórios. Os respectivos códigos estão descritos no apêndice Campos Financeiros ao final da sessão Subcontas ValidaPay ### Request body ```json { "contactNumber": "+5511912345678", "documentNumber": "99665544000130", "businessEmail": "empresa@exemplo.com.br", "businessName": "Empresa Exemplo LTDA", "tradingName": "Empresa Exemplo", "companyType": "PJ", "owner": [ { "ownerType": "SOCIO", "documentNumber": "22233344405", "fullName": "Cesar Lattes ", "phoneNumber": "+5511912345128", "email": "socio@exemplo.com.br", "motherName": "Marie Curie", "socialName": "Nome", "birthDate": "02-02-1990", "address": { "postalCode": "06455030", "street": "Alameda Xingu", "number": "50", "addressComplement": "", "neighborhood": "Alphaville Industrial", "city": "Barueri", "state": "SP" }, "isPoliticallyExposedPerson": false, "financialOwnerDetails": { "ownerDeclaredIncome": "ODIB02", "ownerDeclaredRevenue": "ODRB02" } } ], "businessAddress": { "postalCode": "06455030", "street": "Alamed Xingu", "number": "350", "addressComplement": "", "neighborhood": "Alphaville Industrial", "city": "Barueri", "state": "SP" }, "webhookUrl": "https://api.teste.com.br" } ``` ### Campos do body **Obrigatórios:** `contactNumber`, `documentNumber`, `businessEmail`, `businessName`, `tradingName`, `companyType`, `ownerType`, `fullName`, `phoneNumber`, `email`, `motherName`, `socialName`, `birthDate`, `postalCode`, `street`, `number`, `addressComplement`, `neighborhood`, `city`, `state`, `isPoliticallyExposedPerson`, `ownerDeclaredIncome`, `ownerDeclaredRevenue` | Campo | Descrição | |---|---| | `contactNumber` | Telefone da empresa | | `documentNumber` | CPF do sócio | | `businessEmail` | email da empresa | | `businessName` | Razão social | | `tradingName` | Nome fantasia | | `companyType` | PJ, MEI ou ME | | `ownerType` | | | `fullName` | Nome completo do sócio | | `phoneNumber` | Telefone celular do sócio | | `email` | email do sócio | | `motherName` | | | `socialName` | | | `birthDate` | Data de nascimento do sócio | | `postalCode` | CEP da empresa | | `street` | | | `number` | | | `addressComplement` | | | `neighborhood` | | | `city` | | | `state` | | | `isPoliticallyExposedPerson` | | | `ownerDeclaredIncome` | Renda do sócio | | `ownerDeclaredRevenue` | Faturamento da empresa | **Opcionais** | Campo | Descrição | |---|---| | `webhookUrl` | URL onde você gostaria de receber a notificação de criação de conta | ### Resposta 201 — 201 ```json { "status": "UNFINISHED", "message": "Formulário criado com sucesso", "formId": "fb8cbb9d-d376-4604-940c-957e76e3dcbb" } ``` ### Resposta 200 — 200 ```json { "status": "FINISHED", "message": "Formulário criado com sucesso", "formId": "8f82a068-ff1a-45b7-8f98-71f07176e0dd" } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-criar-subconta-pj Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Status de subconta `GET /v1/proposals/:formId` **Área:** Subcontas ValidaPay **Scopes necessários:** `proposals/write` @botton Quando a conta for aprovada, será enviado um evento na URL de webhook cadastrada nas rotas de criação de conta PF e PJ. O evento segue o seguinte layout: ``` json { "event": "account_approved", "status": "CONFIRMED", "account": { "account": "123456", "branch": "0001", "documentNumber": "123456789", "ispb": "13935893", "name": "Werner Heisenberg" }, "onboardingId": "fc0e6dab-8210-4f2d-8fce-2e94990b63ef", "documentNumber": "1234567889", "formId": "7b83fcb4-fe9c-4ad3-8d3a-621fe9c9ffc1", "createdAt": "2025-06-02T17:46:10.1120909" } ``` ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `formId` | **sim** | Identificador único retornado no ato do envio da proposta | ### Resposta 200 — PF 200 ```json { "phoneNumber": "+5511912345678", "isPoliticallyExposedPerson": false, "documentNumber": "98765432100", "motherName": "Teste Mãe", "fullName": "Teste teste", "type": "PF", "birthDate": "31-12-2000", "email": "cliente@exemplo.com.br", "socialName": "", "address": { "number": "12", "addressComplement": "", "city": "Barueri", "street": "Alameda Xingu", "postalCode": "", "neighborhood": "Alphaville Industrial", "state": "SP" }, "metaData": { "formId": "a6358673-dd00-4c6d-9592-df393513a78a", "createdAt": "2025-11-21T21:52:49.155Z", "updatedAt": "2025-11-21T21:53:43.213Z" }, "proposalStatus": { "form": "UNFINISHED", "proposal": "PENDING", "documents": "PENDING", "urlDocumentscopy": "https://validapay.cadastro.io/0336bdddcd087923e2d0249b4cdd268d" } } ``` ### Resposta 200 — PJ 200 ```json { "documentNumber": "99776655000113", "type": "PJ", "businessName": "FULANO SILVA PUBLICIDADE, PROMOCAO E PRODUCAO DE EVENTOS ESPORTIVOS LTDA", "tradingName": "NEY SILVA", "businessEmail": "titular@exemplo.com.br", "contactNumber": "+558145630249", "businessAddress": { "number": "10", "addressComplement": "CXPST 2", "city": "CHA GRANDE", "street": "ANTONIO", "postalCode": "55636000", "neighborhood": "CAMELA", "state": "PE" }, "financialCompanyDetails": { "declaredCompanyRevenue": "DCRB02" }, "owner": [ { "ownerType": "SOCIO", "address": { "number": "10", "city": "CHA GRANDE", "street": "Av. Sao Jose", "postalCode": "55636000", "neighborhood": "Chã Grande", "state": "PE", "complement": "" }, "financialOwnerDetails": { "ownerDeclaredIncome": "ODIB04" }, "phoneNumber": "+558112345689", "isPoliticallyExposedPerson": false, "documentNumber": "55566677720", "motherName": "SELMA MARIA DA SILVA", "fullName": "FUNANO CRISTOVAO DA SILVA", "type": "PF", "birthDate": "30-11-1991", "email": "contato@exemplo.com.br" } ], "proposalId": "d0c39afa-d034-4330-8d57-527eacca88c6", "metaData": { "formId": "31aa2217-a149-40ba-847f-c23500a635c7", "createdAt": "2026-02-24T02:18:55.257Z", "updatedAt": "2026-02-24T02:29:04.911Z", "origin": "API" }, "proposalStatus": { "form": "FINISHED", "sendStatus": "SENT", "proposal": "PENDING", "documents": "PENDING", "urlDocumentscopy": null } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-status-de-subconta Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Listar subcontas `GET /v1/accounts/subaccounts` **Área:** Subcontas ValidaPay **Scopes necessários:** `subaccounts/read` Com esta rota você poderá listar todas as subcontas associadas à sua _master account_ ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `dateFrom` | não | | | `dateTo` | não | | | `page` | não | | | `perPage` | não | | ### Request body ```json { "amount": 1.00, "split": [ { "type": "fixed", "amount": 0.10 } ] } ``` ### Campos do body **Obrigatórios:** `amount`, `type` | Campo | Descrição | |---|---| | `amount` | Valor com precisão de duas casas decimais separado por ponto | | `type` | Valor fixo ou porcentagem | ### Resposta 200 — 200 ```json { "masterAccountId": "SANDBOX_0438f4c8-0031-7051-16d4-5a23704756b6", "subAccounts": [ { "documentNumber": "66677788830", "createdAt": "2026-02-23T22:29:52.537Z", "accountNumber": "4960589", "status": "CONFIRMED", "onboardingId": "b9790268-a770-4aec-8fe5-d891f17e8007", "name": "Friedrich Nietzsche", "dailyWithdrawalLimit": 3000, "balance": 0 }, { "documentNumber": "33344455508", "createdAt": "2026-02-17T20:38:45.664Z", "accountNumber": "4949228", "status": "CONFIRMED", "onboardingId": "30608b18-7258-437d-a6cb-63e5882e4fb7", "name": "Tales de Mileto", "dailyWithdrawalLimit": 3000, "balance": 170.9 } ], "page": 1, "perPage": 15, "hasMore": false, "dateFrom": "2026-02-01T00:00:00.000Z", "dateTo": "2026-02-23T23:59:59.999Z" } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-listar-subcontas Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Listar cobranças `GET /v1/charges` **Área:** Subcontas ValidaPay **Scopes necessários:** `subaccounts/read` Com esta rota você poderá listar todas as cobranças que a sua _master account_ gerou em uma subcontas ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `dateFrom` | não | | | `dateTo` | não | | | `page` | não | | | `perPage` | não | | ### Resposta 200 — 200 ```json { "data": [ { "status": "PENDING", "createdAt": "2026-02-23T18:46:22.652Z", "chargeId": "cha_1771872382645_qe5j0ohge", "updatedAt": "2026-02-23T18:46:22.652Z", "masterAccountId": "SANDBOX_0438f4c8-0031-7051-16d4-5a23704756b6", "amount": 39.9, "attempts": 1, "emvQrCode": "00020101021226930014br.gov.bcb.pix…", "paymentType": "PIX", "subAccountId": "4949228" }, { "status": "PENDING", "createdAt": "2026-02-23T18:34:13.130Z", "chargeId": "cha_1771871653130_pzzsyzeha", "updatedAt": "2026-02-23T18:34:13.130Z", "masterAccountId": "SANDBOX_0438f4c8-0031-7051-16d4-5a23704756b6", "amount": 39.9, "attempts": 1, "emvQrCode": "00020101021226930014br.gov.bcb.pix…", "paymentType": "PIX", "subAccountId": "4949228" }, { "status": "PENDING", "createdAt": "2026-02-23T18:34:09.892Z", "chargeId": "cha_1771871649852_mm0luemzr", "updatedAt": "2026-02-23T18:34:09.892Z", "masterAccountId": "SANDBOX_0438f4c8-0031-7051-16d4-5a23704756b6", "amount": 39.9, "attempts": 1, "emvQrCode": "00020101021226930014br.gov.bcb.pix…", "paymentType": "PIX", "subAccountId": "4949228" } ], "totalItems": 23, "totalPages": 2, "page": 1, "limit": 15, "dateFrom": "2026-02-01T00:00:00.000Z", "dateTo": "2026-02-23T23:59:59.999Z" } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-listar-cobrancas Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Saldo subcontas `GET /v1/wallet/balance` **Área:** Subcontas ValidaPay **Scopes necessários:** `wallet/read` Com esta funcionalidade você pode verificar o saldo de uma ou várias subcontas > ⚠️ **Atenção:** Para consultar o saldo de várias subcontas envie o header acoountId com o número das subcontas separado por vírgula, por exemplo: 9489623,9489624,9489625 ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `accountId` | **sim** | Número da subconta. Para consultar o saldo de várias subcontas envie separado por virgula | ### Resposta 200 — Sucesso ```json { "masterAccountId": "429131313", "balances": [ { "accountNumber": "459013888", "name": "VALIDAPAY PAGAMENTOS TECNOLOGIA E SERVICOS", "balance": 54.81 }, { "accountNumber": "460851986", "name": "VALIDA PIX", "balance": 196.82 } ] } ``` ### Resposta 401 — Acesso negado ```json { "error": { "message": "Subconta 436514888 nao pertence a esta conta master", "code": "UNAUTHORIZED_SUBACCOUNT", "details": null, "timestamp": "2026-03-17T03:45:53.738Z" } } ``` ### Resposta 404 — Subconta não encontrada ```json { "error": { "message": "Subconta 459013666 nao encontrada", "code": "SUBACCOUNT_NOT_FOUND", "details": null, "timestamp": "2026-03-17T03:46:49.577Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-saldo-subcontas Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Criar Produto `POST /v1/products` **Área:** Produtos **Scopes necessários:** `products/write` Cria um novo produto ou serviço com nome, descrição, preço e configurações de recorrência. Os produtos criados ficam disponíveis no painel administrativo e podem ser utilizados tanto no checkout transparente (via API) quanto no checkout pro (link de pagamento). Tipos de recorrência em prices[].recurrenceType: - ONE_TIME → Avulsa - WEEKLY → Semanal - MONTHLY → Mensal - QUARTERLY → Trimestral - SEMIANNUAL → Semestral - YEARLY → Anual Case de uso: _Como SaaS, quero cadastrar meus planos como produtos com preços recorrentes, para que meus clientes possam assinar diretamente pelo checkout pro ou pela minha própria interface._ ### Request body ```json { "name": "Plano Premium", "description": "Acesso completo à plataforma", "type": "RECURRING", "statementDescriptor": "VALIDAPAY PREMIUM", "isActive": true, "metadata": {}, "prices": [ { "title": "Mensal", "amount": 99.9, "currency": "BRL", "recurrenceType": "MONTHLY", "recurrenceInterval": 1, "trialDays": 7, "compareAtPrice": 129.9 }, { "title": "Anual", "amount": 899.0, "currency": "BRL", "recurrenceType": "YEARLY", "recurrenceInterval": 1 } ] } ``` ### Campos do body **Obrigatórios:** `name`, `prices`, `prices.title`, `prices.amount`, `prices.recurrenceType` | Campo | Descrição | |---|---| | `name` | Nome do produto | | `prices` | | | `prices.title` | | | `prices.amount` | Valor em reais (> 0) | | `prices.recurrenceType` | WEEKLY, MONTHLY, QUARTERLY, SEMIANNUAL, YEARLY ou ONE_TIME | **Opcionais** | Campo | Descrição | |---|---| | `description` | | | `type` | RECURRING ou ONE_TIME (default RECURRING) | | `statementDescriptor` | max 22 caracteres | | `isActive` | | | `prices.currency` | | | `prices.recurrenceInterval` | min 1 (ex: 2 = bimestral) | | `prices.trialDays` | | | `prices.compareAtPrice` | Preço "de" | ### Resposta 200 — 200 ```json { "productId": "prod_xxx", "name": "Plano Premium", "prices": [ { "priceId": "price_xxx", "amount": 99.9, "checkoutUrl": "https://app.validapay.com.br/pagamento/pl_xxx" } ] } ``` ### Resposta 400 — 400 ```json { "error": { "message": "O campo name é obrigatório", "code": "INVALID_PRODUCT_DATA", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-criar-produto Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Listar Produtos `GET /v1/products` **Área:** Produtos **Scopes necessários:** `products/read` Lista todos os produtos cadastrados com suporte a filtros por status e paginação. ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `lastKey` | **sim** | base64 - optional | | `status` | **sim** | active \| inactive - optional | | `search` | **sim** | busca por nome - optional | | `limit` | não | Quantidade de itens por página (default 50) - optional | ### Resposta 200 — 200 ```json { "items": [ { "productId": "prod_xxx", "name": "Plano Premium" } ], "pagination": { "total": 10, "hasMore": false, "lastKey": null } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-listar-produtos Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Buscar Produto `GET /v1/products/:id` **Área:** Produtos **Scopes necessários:** `products/read` Retorna todos os detalhes de um produto específico, incluindo preço e configurações. ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `id` | **sim** | Id | ### Resposta 200 — 200 ```json { "productId": "prod_xxx", "name": "Plano Premium", "prices": [ { "priceId": "price_xxx", "amount": 99.9 } ] } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Produto não encontrado", "code": "PRODUCT_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-buscar-produto Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Atualizar Produto `PUT /v1/products/:id` **Área:** Produtos **Scopes necessários:** `products/write` Atualiza as informações de um produto, como nome, descrição ou preço. Mesmos campos de POST (todos opcionais). Para atualizar preço existente, inclua `priceId` no item de `prices[]`. ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `id` | **sim** | Id | ### Request body ```json { "name": "Plano Premium Plus", "description": "Acesso completo à plataforma", "type": "RECURRING", "statementDescriptor": "VALIDAPAY PREMIUM", "isActive": true, "metadata": {}, "prices": [ { "priceId": "price_xxx", "amount": 109.9, "recurrenceType": "MONTHLY", "recurrenceInterval": 1, "trialDays": 7, "compareAtPrice": 129.9 }, { "title": "Trimestral", "amount": 279.0, "recurrenceType": "QUARTERLY", "recurrenceInterval": 1 } ] } ``` ### Campos do body **Opcionais** | Campo | Descrição | |---|---| | `name` | | | `description` | | | `type` | | | `statementDescriptor` | | | `isActive` | | | `prices` | Para atualizar preço existente, inclua priceId no item | | `prices.priceId` | ID do preço existente | | `prices.amount` | | | `prices.recurrenceType` | | | `prices.recurrenceInterval` | | | `prices.trialDays` | | | `prices.compareAtPrice` | | | `prices.title` | Novo preço | ### Resposta 200 — 200 ```json { "productId": "prod_xxx", "name": "Plano Premium Plus", "newPrices": [ { "priceId": "price_yyy" } ] } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Produto não encontrado", "code": "PRODUCT_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/put-atualizar-produto Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Remover Produto `DELETE /v1/products/:id` **Área:** Produtos **Scopes necessários:** `products/write` Remove um produto que não esteja vinculado a assinaturas ativas. ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `id` | **sim** | Id | ### Resposta 200 — 200 ```json { "deleted": true, "productId": "prod_xxx" } ``` ### Resposta 400 — 400 ```json { "error": { "message": "Não é possível deletar um produto que possui assinaturas vinculadas", "code": "PRODUCT_HAS_SUBSCRIPTIONS", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Produto não encontrado", "code": "PRODUCT_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/delete-remover-produto Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Arquivar Produto `POST /v1/products/:id/archive` **Área:** Produtos **Scopes necessários:** `products/write` Guarda o produto sem excluí-lo, mantendo o histórico de cobranças vinculadas. ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `id` | **sim** | Id | ### Resposta 200 — 200 ```json { "productId": "prod_xxx", "archivedAt": "2024-01-20T10:00:00Z", "checkoutsDeactivated": 3 } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Produto não encontrado", "code": "PRODUCT_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-arquivar-produto Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Criar link de pagamento `POST /v1/checkouts` **Área:** Links de pagamento **Scopes necessários:** `checkouts/write` Cria uma página de pagamento (payment link) configurável, com produtos, formas de pagamento aceitas, cupons e aparência personalizada. O link é reutilizável e não fica vinculado a um cliente específico. É obrigatório informar `priceId` (preço já cadastrado) ou `product` (produto com preços inline). Formas de pagamento suportadas: pix, creditcard, boleto e pix_automatico. **Pix Automático** está disponível apenas para **contas PJ** (conta ValidaPay cadastrada com CNPJ) e só é aceito em preços recorrentes (`recurrenceType` WEEKLY, MONTHLY, QUARTERLY, SEMIANNUAL ou YEARLY). O cliente autoriza a recorrência uma única vez no aplicativo do banco e as cobranças seguintes são debitadas automaticamente, sem novo QR Code a cada ciclo. Até o banco do pagador confirmar a autorização, a assinatura fica com status `PENDING`. O valor mínimo por cobrança é de **R$ 4,99**. Erros: `400 PIX_AUTOMATICO_PJ_ONLY` (conta PF) e `400 PIX_AUTOMATICO_MIN_AMOUNT` (valor abaixo do mínimo). Ao informar `termsOfServiceUrl` e/ou `privacyPolicyUrl`, o checkout exibe um aceite obrigatório com os links: o cliente só consegue finalizar a compra depois de marcar que leu e concorda. O texto do aceite se adapta a um ou aos dois links. Sem esses campos, nenhum aceite é exibido. Case de uso: _Como SaaS, quero criar um link de pagamento reutilizável para uma oferta — definindo cores, parcelamento e order bumps — e compartilhá-lo com vários clientes._ ### Request body ```json { "priceId": "price_xxx", "allowedPaymentMethods": [ "pix", "creditcard", "boleto", "pix_automatico" ], "successUrl": "https://meusite.com/obrigado", "cancelUrl": "https://meusite.com/cancelado", "redirectAfterPaymentUrl": "https://meusite.com/redirect", "termsOfServiceUrl": "https://meusite.com/termos-de-servico", "privacyPolicyUrl": "https://meusite.com/politica-de-privacidade", "successMessage": "Obrigado pela compra!", "maxInstallments": 12, "freeInstallments": 1, "passFeesToCustomer": false, "checkoutName": "Oferta Black Friday", "primaryColor": "#7C3AED", "secondaryColor": "#EDE9FE", "fontColor": "#1F2937", "showProductImage": true, "metadata": {}, "orderBumps": [ { "priceId": "price_yyy", "label": "Adicionar suporte premium", "displayMode": "checkbox" } ] } ``` ### Campos do body **Obrigatórios:** `priceId`, `allowedPaymentMethods`, `orderBumps.priceId` | Campo | Descrição | |---|---| | `priceId` | ID do preço já cadastrado (obrigatório priceId OU product) | | `allowedPaymentMethods` | Formas de pagamento aceitas: pix, creditcard, boleto, pix_automatico (só conta PJ, em preço recorrente) | | `orderBumps.priceId` | priceId do produto adicional | **Opcionais** | Campo | Descrição | |---|---| | `successUrl` | Redireciona após pagamento aprovado | | `cancelUrl` | Redireciona ao cancelar | | `redirectAfterPaymentUrl` | URL de redirecionamento pós-pagamento | | `termsOfServiceUrl` | Termos de serviço exibidos no checkout para aceite do cliente | | `privacyPolicyUrl` | Política de privacidade exibida no checkout para aceite do cliente | | `successMessage` | Mensagem exibida após o pagamento | | `maxInstallments` | Limite de parcelas (1 a 12) | | `freeInstallments` | Parcelas sem juros (1 a 12, default 1) | | `passFeesToCustomer` | Repassa as taxas ao cliente (default false) | | `checkoutName` | Nome interno do checkout | | `primaryColor` | Cor primária em hex | | `secondaryColor` | Cor secundária em hex | | `fontColor` | Cor do texto em hex | | `showProductImage` | Exibir imagem do produto (default true) | | `orderBumps` | Produtos adicionais oferecidos no checkout | | `orderBumps.label` | Texto exibido | | `orderBumps.displayMode` | Modo de exibição | ### Resposta 200 — 200 ```json { "id": "pl_xxx", "url": "https://app.validapay.com.br/pagamento/pl_xxx", "priceId": "price_xxx" } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-criar-link-de-pagamento Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Listar links de pagamento `GET /v1/checkouts` **Área:** Links de pagamento **Scopes necessários:** `checkouts/read` Lista todas as páginas de pagamento (checkouts) criadas, com seus status e configurações. Suporta paginação e filtros por status e busca textual. ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `lastKey` | **sim** | base64 - optional | | `status` | **sim** | Filtra por status do checkout - optional | | `search` | **sim** | Busca por texto - optional | | `limit` | não | Quantidade de itens por página (default 15) - optional | ### Resposta 200 — 200 ```json { "items": [ { "id": "pl_xxx", "url": "https://app.validapay.com.br/pagamento/pl_xxx" } ], "pagination": { "total": 5, "hasMore": false } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-listar-links-de-pagamento Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Buscar link de pagamento `GET /v1/checkouts/:id` **Área:** Links de pagamento **Scopes necessários:** `checkouts/read` Retorna os detalhes completos de uma página de pagamento, incluindo produtos e formas de pagamento aceitas. O identificador aceita diferentes prefixos: `cha_` (cobrança), `cs_` (sessão), `price_` (preço) e `pl_` (payment link). A autenticação é opcional — o checkout pode ser consultado publicamente. ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `id` | **sim** | ID do checkout / payment link (ex: pl_xxx) - required | ### Resposta 200 — 200 ```json { "id": "pl_xxx", "status": "ACTIVE", "priceId": "price_xxx" } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Checkout não encontrado", "code": "CHECKOUT_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-buscar-link-de-pagamento Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Atualizar link de pagamento `PUT /v1/checkouts/:id` **Área:** Links de pagamento **Scopes necessários:** `checkouts/write` Atualiza as configurações de uma página de pagamento, como preço vinculado, parcelamento ou aparência. Todos os campos são opcionais — envie apenas o que deseja alterar. ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `id` | **sim** | ID do checkout / payment link (ex: pl_xxx) - required | ### Request body ```json { "priceId": "price_yyy", "discounts": [], "maxInstallments": 6, "primaryColor": "#FF0000", "showProductImage": false, "termsOfServiceUrl": "https://meusite.com/termos-de-servico", "privacyPolicyUrl": "https://meusite.com/politica-de-privacidade", "applyBrandingToAllPrices": true } ``` ### Campos do body **Opcionais** | Campo | Descrição | |---|---| | `priceId` | Novo preço vinculado ao checkout | | `maxInstallments` | Limite de parcelas (1 a 12) | | `primaryColor` | Cor primária em hex | | `showProductImage` | Exibir imagem do produto | | `termsOfServiceUrl` | Termos de serviço exibidos no checkout para aceite do cliente | | `privacyPolicyUrl` | Política de privacidade exibida no checkout para aceite do cliente | | `applyBrandingToAllPrices` | Aplica a identidade visual a todos os preços | ### Resposta 200 — 200 ```json { "id": "pl_xxx", "priceId": "price_yyy" } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Checkout não encontrado", "code": "CHECKOUT_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/put-atualizar-link-de-pagamento Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Criar sessão de pagamento `POST /v1/checkout-sessions` **Área:** Links de pagamento **Scopes necessários:** `checkouts/write` Cria um acesso temporário e seguro a uma página de pagamento, com cliente e configurações pré-preenchidos. É de uso único: expira após o pagamento. Informe o `priceId` de um preço já cadastrado. Opcionalmente, envie os dados do cliente, restrinja as formas de pagamento e personalize a aparência. A resposta inclui o `id` da sessão e a `url` de pagamento hospedada pela ValidaPay. Formas de pagamento aceitas em `allowedPaymentMethods`: pix, creditcard, boleto e pix_automatico. O **Pix Automático** está disponível apenas para **contas PJ** (conta ValidaPay cadastrada com CNPJ) e exige um preço recorrente (`recurrenceType` WEEKLY, MONTHLY, QUARTERLY, SEMIANNUAL ou YEARLY): o cliente autoriza a recorrência uma única vez no aplicativo do banco e os ciclos seguintes são debitados automaticamente. Enquanto a autorização não é confirmada pelo banco do pagador, a assinatura fica com status `PENDING`. O valor mínimo por cobrança é de **R$ 4,99**. Erros: `400 PIX_AUTOMATICO_PJ_ONLY` (conta PF) e `400 PIX_AUTOMATICO_MIN_AMOUNT` (valor abaixo do mínimo). Ao informar `termsOfServiceUrl` e/ou `privacyPolicyUrl`, o checkout exibe um aceite obrigatório com os links: o cliente só consegue finalizar a compra depois de marcar que leu e concorda. O texto do aceite se adapta a um ou aos dois links. Sem esses campos, nenhum aceite é exibido. Case de uso: _Como SaaS, quero gerar um link de pagamento nominal para cada cliente no momento da contratação, com uso único para evitar cobranças duplicadas._ ### Request body ```json { "priceId": "price_abc123", "allowedPaymentMethods": [ "pix", "creditcard", "boleto", "pix_automatico" ], "customer": { "name": "João Silva", "email": "joao@email.com", "documentNumber": "12345678901", "phone": "51999999999", "address": { "type": "BILLING", "street": "Rua das Flores", "number": "123", "complement": "Apto 4", "neighborhood": "Centro", "city": "Porto Alegre", "state": "RS", "zipCode": "90010000", "country": "BR", "cityCode": "4314902" } }, "items": [ { "priceId": "price_abc123", "quantity": 1 } ], "billingDay": 15, "prorataStartDate": "2026-06-11", "installments": 1, "dueDate": "2026-07-30", "boletoDueDays": 7, "expirationAfterDueDate": 30, "discounts": [ { "type": "PERCENTAGE", "value": 10, "paymentMethod": "pix", "fromCycle": 1, "toCycle": 3, "durationMonths": 3 } ], "passFeesToCustomer": false, "freeInstallments": 1, "maxInstallments": 12, "boletoInstructions": { "fine": 2.0, "interest": 1.0, "discount": { "amount": 10.00, "modality": "fixed", "limitDate": "2026-07-28" } }, "orderBumps": [ { "priceId": "price_bump123", "callToAction": "Adicionar ao pedido", "title": "Produto adicional", "description": "Descrição do order bump", "showImage": true } ], "primaryColor": "#6366f1", "secondaryColor": "#818cf8", "fontColor": "#ffffff", "companyName": "Minha Empresa", "successUrl": "https://meusite.com/sucesso", "failureUrl": "https://meusite.com/falha", "termsOfServiceUrl": "https://meusite.com/termos-de-servico", "privacyPolicyUrl": "https://meusite.com/politica-de-privacidade", "metadata": { "referencia": "pedido-001" } } ``` ### Campos do body **Obrigatórios:** `priceId`, `items.priceId`, `discounts.type`, `discounts.value`, `orderBumps.priceId` | Campo | Descrição | |---|---| | `priceId` | Preço da sessão (deve começar com price_) | | `items.priceId` | priceId do item | | `discounts.type` | PERCENTAGE ou FIXED | | `discounts.value` | Valor do desconto | | `orderBumps.priceId` | priceId do produto adicional | **Opcionais** | Campo | Descrição | |---|---| | `allowedPaymentMethods` | Métodos exibidos: pix, creditcard, boleto, pix_automatico (só conta PJ; omitir usa o padrão do price) | | `customer` | Pré-preenche os dados do cliente no checkout | | `customer.name` | Nome exibido | | `customer.email` | Usado para localizar cliente existente | | `customer.documentNumber` | CPF (11) ou CNPJ (14 dígitos) | | `customer.phone` | Telefone | | `customer.address` | Endereço (obrigatório para boleto no pagamento) | | `customer.address.type` | Tipo do endereço | | `customer.address.street` | | | `customer.address.number` | | | `customer.address.complement` | | | `customer.address.neighborhood` | | | `customer.address.city` | | | `customer.address.state` | | | `customer.address.zipCode` | | | `customer.address.country` | | | `customer.address.cityCode` | Código IBGE (necessário para nota fiscal) | | `items` | Lista de { priceId, quantity } (sobrescreve o item principal) | | `items.quantity` | Quantidade (default 1) | | `billingDay` | Dia do mês das cobranças recorrentes (1 a 31) | | `prorataStartDate` | Início do cálculo de pró-rata (YYYY-MM-DD) | | `installments` | Parcelas fixas da sessão (1 a 12) | | `dueDate` | Vencimento do boleto (YYYY-MM-DD, maior que hoje) | | `boletoDueDays` | Dias até o vencimento (mín. 1; ignorado se dueDate informado) | | `expirationAfterDueDate` | Dias após o vencimento que o boleto aceita pagamento (0 a 60) | | `discounts` | Descontos aplicados à sessão | | `discounts.paymentMethod` | Restringe a um método | | `discounts.fromCycle` | Ciclo inicial | | `discounts.toCycle` | Ciclo final | | `discounts.durationMonths` | Duração em meses | | `passFeesToCustomer` | Repassa as taxas ao cliente (default false) | | `freeInstallments` | Parcelas sem juros (1 a 12, default 1) | | `maxInstallments` | Limite máximo de parcelas exibido (1 a 12) | | `boletoInstructions` | Regras de multa/juros/desconto do boleto | | `boletoInstructions.fine` | Multa em % (0.1 a 100; fine + interest <= 60) | | `boletoInstructions.interest` | Juros mensais em % (0.1 a 100) | | `boletoInstructions.discount` | Desconto antecipado | | `boletoInstructions.discount.amount` | Valor do desconto | | `boletoInstructions.discount.modality` | fixed (R$) ou percent (%) | | `boletoInstructions.discount.limitDate` | Data limite (antes de dueDate) | | `orderBumps` | Produtos adicionais exibidos no checkout | | `orderBumps.callToAction` | Texto do botão | | `orderBumps.title` | Título exibido | | `orderBumps.description` | Descrição exibida | | `orderBumps.showImage` | Exibir imagem | | `primaryColor` | Cor primária em hex | | `secondaryColor` | Cor secundária em hex | | `fontColor` | Cor do texto em hex | | `companyName` | Nome da empresa exibido no checkout | | `successUrl` | Redireciona após pagamento aprovado | | `failureUrl` | Redireciona após pagamento recusado | | `termsOfServiceUrl` | Termos de serviço exibidos no checkout para aceite do cliente | | `privacyPolicyUrl` | Política de privacidade exibida no checkout para aceite do cliente | ### Resposta 200 — 200 ```json { "id": "cs_abc123", "url": "https://app.validapay.com.br/pagamento/cs_abc123", "priceId": "price_abc123" } ``` ### Resposta 400 — 400 ```json { "error": { "code": "INVALID_DATA", "message": "Campo inválido", "details": [] } } ``` ### Resposta 401 — 401 ```json { "error": { "message": "Você não tem permissão para usar este produto", "code": "FORBIDDEN", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Preço não encontrado", "code": "PRICE_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-criar-sessao-de-pagamento Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Buscar sessão de pagamento `GET /v1/checkout-sessions/:id` **Área:** Links de pagamento **Scopes necessários:** `checkouts/read` Retorna os dados de uma sessão de checkout ativa, como produtos disponíveis e formas de pagamento. ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `id` | **sim** | ID da sessão de checkout (ex: cs_xxx) - required | ### Resposta 200 — 200 ```json { "id": "cs_xxx", "status": "PENDING", "priceId": "price_xxx" } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Sessão não encontrada", "code": "SESSION_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-buscar-sessao-de-pagamento Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Gerar cobrança PIX `POST /v1/charges` **Área:** Checkout Transparente **Scopes necessários:** `checkouts/write` Gera uma cobrança **PIX** pelo checkout transparente. O cliente informa os dados diretamente na sua própria interface e você os envia para a API. Envie os dados do comprador e os itens da compra. A resposta traz o código `emv` (copia e cola) e o QR Code para pagamento. Produto ou valor: envie `items` com os produtos OU `amount` para uma cobrança avulsa. Notificações por e-mail: use `notifications` para escolher quais e-mails saem nesta cobrança. Eventos aceitos aqui: `oneoff.pix.generated` (envia o QR Code ao comprador assim que a cobrança é criada), `oneoff.payment.success` (confirmação ao comprador quando o Pix compensa) e `new.sale` (avisa você, vendedor, da venda paga). Os eventos destinados ao comprador exigem `customer.email`. Sem o campo, uma cobrança avulsa (enviada com `amount`) não dispara e-mail nenhum; com `items` de um produto, vale a configuração de notificações do produto, e `notifications` no payload tem precedência sobre ela. > ⚠️ **Atenção:** envie o campo `externalId` como chave de idempotência (idempotencyKey). Se duas cobranças forem enviadas com o mesmo `externalId`, a segunda é recusada com `409 DUPLICATE_CHARGE`, retornando o `chargeId` da cobrança original. Erros comuns: `409 DUPLICATE_CHARGE` (externalId já utilizado), `404 PRICE_NOT_FOUND` (preço inexistente) e `400 INVALID_DATA` (campo inválido). Use `externalTxid` para identificar a **loja**, o **caixa** ou o **vendedor** responsável pela cobrança. **Correlação com o pedido:** use `externalId` — ele é persistido e devolvido. O campo `metadata` é aceito nesta rota mas **não é gravado na cobrança** nem volta no webhook; ele só é persistido em `POST /v1/charges/pix`. ### Emitindo nota fiscal na cobrança Envie `nfConfigId` com o identificador de uma configuração fiscal criada em `POST /v1/invoices/notas/config`. Com ele presente: - `customer.address` passa a ser **obrigatório** — a nota precisa do endereço do tomador. Sem ele: `400 INVALID_DATA`. - O momento da emissão vem da configuração, não da cobrança: `invoiceTiming` aceita `IMMEDIATE` (padrão), `AFTER_CONFIRMATION` e `DAYS_AFTER_CONFIRMATION`; neste último, `daysAfterConfirmation` define em quantos dias (padrão 1). - O `cityCode` (IBGE) do endereço é resolvido a partir do CEP e é necessário para a NFS-e. O mesmo campo existe em produtos (`POST /v1/products`) e nas configurações de assinatura, para emitir nota a cada ciclo sem repetir o `nfConfigId` em cada cobrança. ### Request body ```json { "paymentMethod": "pix", "externalId": "pedido-2026-0001", "externalTxid": "loja-01-caixa-03", "customer": { "name": "João da Silva", "email": "joao@email.com", "documentNumber": "12345678901", "phone": "+5511999998888", "cep": "01310100" }, "items": [ { "priceId": "price_abc123", "quantity": 1 } ], "expiration": "2026-07-30", "couponCode": "PROMO10", "metadata": { "referencia": "pedido-001" }, "description": "Assinatura Premium", "split": [ { "type": "fixed", "accountNumber": "896532569", "amount": 0.10 } ], "installments": 1, "freeInstallments": 1, "passFeesToCustomer": false, "allowedPaymentMethods": ["pix", "creditcard"], "nfConfigId": "nfc_1788364755079_psuecwgdc", "notifications": ["oneoff.pix.generated", "oneoff.payment.success", "new.sale"], "discounts": [ { "type": "percentage", "value": 10, "paymentMethod": "pix", "fromCycle": 1, "toCycle": 3, "durationMonths": 3 } ], "tokenId": "tok_abc123", "productId": "prod_123456_example", "recurrencyStartDate": "2026-10-01", "prorataStartDate": "2026-09-15", "prorataDueDate": "2026-09-20", "mergeWithNextCycle": false } ``` ### Campos do body **Obrigatórios:** `paymentMethod`, `customer`, `customer.name`, `customer.email`, `customer.documentNumber`, `items.priceId`, `discounts.type`, `discounts.value` | Campo | Descrição | |---|---| | `paymentMethod` | Forma de pagamento (fixo: pix) | | `customer` | Dados do comprador | | `customer.name` | Nome completo | | `customer.email` | E-mail | | `customer.documentNumber` | CPF (11) ou CNPJ (14 dígitos) | | `items.priceId` | ID do preço do produto | | `discounts.type` | Tipo do desconto: percentual sobre o valor ou abatimento fixo em reais | | `discounts.value` | Percentual de 0 a 100 quando type e percentage; valor em reais quando fixed | **Opcionais** | Campo | Descrição | |---|---| | `externalId` | Identificador único do pedido no seu sistema; usado como idempotencyKey (evita cobrança duplicada) | | `externalTxid` | Identifica a loja, o caixa ou o vendedor responsável pela cobrança | | `customer.phone` | Telefone | | `customer.cep` | CEP (necessário para PIX com dados do pagador) | | `items` | Produtos da compra (ou use amount para cobrança avulsa) | | `items.quantity` | Quantidade (default 1) | | `expiration` | Expiração do QR Code PIX (YYYY-MM-DD) | | `couponCode` | Código de cupom de desconto | | `description` | Descricao livre da cobranca | | `split` | Divisao do valor. Nao suportado em creditcard nem pix_automatico | | `installments` | Parcelas no cartao, de 1 a 12 | | `freeInstallments` | Parcelas sem juros para o comprador, de 0 a 12 | | `passFeesToCustomer` | Repassa a taxa de parcelamento ao comprador | | `nfConfigId` | Emite nota fiscal com esta configuracao. Exige customer.address | | `discounts` | Descontos aplicados a cobranca | | `discounts.paymentMethod` | Aplica o desconto so neste metodo de pagamento | | `discounts.fromCycle` | Primeiro ciclo em que o desconto vale, em cobrancas recorrentes | | `discounts.toCycle` | Ultimo ciclo; null mantem o desconto ate o fim da assinatura | | `discounts.durationMonths` | Alternativa a toCycle: por quantos meses o desconto vale | | `tokenId` | Alternativa a card e a paymentMethodId no cartao | | `productId` | Cria a cobranca a partir de um produto | | `recurrencyStartDate` | Primeira cobranca da recorrencia (YYYY-MM-DD) | | `prorataStartDate` | Inicio do calculo pro rata | | `prorataDueDate` | Vencimento da cobranca pro rata (YYYY-MM-DD) | | `mergeWithNextCycle` | Junta a pro rata com o proximo ciclo em vez de cobrar agora | ### Resposta 200 — 200 ```json { "success": true, "customerId": "cus_xxx", "chargeId": "cha_abc123", "pix": { "emv": "00020126330014br.gov.bcb.pix...5204000053039865802BR6304ABCD", "qrCode": "data:image/png;base64,iVBORw0KGgo..." } } ``` ### Resposta 404 — 404 PRICE_NOT_FOUND ```json { "error": { "message": "Preço não encontrado", "code": "PRICE_NOT_FOUND" } } ``` ### Resposta 409 — 409 DUPLICATE_CHARGE ```json { "error": { "message": "Cobrança duplicada: já existe uma cobrança para este pedido", "code": "DUPLICATE_CHARGE", "details": { "chargeId": "cha_1784065113577_5dw2oyfic" }, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-gerar-cobranca-pix Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Gerar cobrança Pix Automático `POST /v1/charges` **Área:** Checkout Transparente **Scopes necessários:** `checkouts/write` Inicia uma assinatura com **Pix Automático** pelo checkout transparente. O cliente informa os dados na sua própria interface e você os envia para a API. A resposta traz `pix.emv` (copia e cola) e `pix.recurrencyId`. Enquanto o banco do pagador não confirma a autorização, a assinatura fica com status `PENDING`. Requisitos: - conta ValidaPay cadastrada como **PJ** (CNPJ) - `items` com preço **recorrente** (`recurrenceType` WEEKLY, MONTHLY, QUARTERLY, SEMIANNUAL ou YEARLY); não use `amount` avulso - valor mínimo de **R$ 4,99** por cobrança Notificações por e-mail: use `notifications` para escolher quais e-mails saem nesta cobrança. Eventos aceitos aqui: `oneoff.payment.success` (confirmação ao comprador quando o Pix compensa) e `new.sale` (avisa você, vendedor, da venda paga). Os eventos destinados ao comprador exigem `customer.email`. Sem o campo, uma cobrança avulsa (enviada com `amount`) não dispara e-mail nenhum; com `items` de um produto, vale a configuração de notificações do produto, e `notifications` no payload tem precedência sobre ela. > ⚠️ **Atenção:** envie o campo `externalId` como chave de idempotência (idempotencyKey). Se duas cobranças forem enviadas com o mesmo `externalId`, a segunda é recusada com `409 DUPLICATE_CHARGE`, retornando o `chargeId` da cobrança original. Erros comuns: `400 PIX_AUTOMATICO_PJ_ONLY` (conta PF), `400 PIX_AUTOMATICO_MIN_AMOUNT` (valor abaixo do mínimo), `409 DUPLICATE_CHARGE` (externalId já utilizado) e `404 PRICE_NOT_FOUND` (preço inexistente). Use `externalTxid` para identificar a **loja**, o **caixa** ou o **vendedor** responsável pela cobrança. **Correlação com o pedido:** use `externalId` — ele é persistido e devolvido. O campo `metadata` é aceito nesta rota mas **não é gravado na cobrança** nem volta no webhook; ele só é persistido em `POST /v1/charges/pix`. ### Request body ```json { "paymentMethod": "pix_automatico", "externalId": "assinatura-2026-0001", "externalTxid": "loja-01-caixa-03", "customer": { "name": "João da Silva", "email": "joao@email.com", "documentNumber": "12345678901", "phone": "+5511999998888" }, "items": [ { "priceId": "price_abc123", "quantity": 1 } ], "billingDay": 15, "couponCode": "PROMO10", "metadata": { "referencia": "assinatura-001" }, "description": "Assinatura Premium", "split": [ { "type": "fixed", "accountNumber": "896532569", "amount": 0.10 } ], "installments": 1, "freeInstallments": 1, "passFeesToCustomer": false, "allowedPaymentMethods": ["pix", "creditcard"], "nfConfigId": "nfc_1788364755079_psuecwgdc", "notifications": ["oneoff.pix.generated", "new.sale"], "discounts": [ { "type": "percentage", "value": 10, "paymentMethod": "pix", "fromCycle": 1, "toCycle": 3, "durationMonths": 3 } ], "tokenId": "tok_abc123", "productId": "prod_123456_example", "recurrencyStartDate": "2026-10-01", "prorataStartDate": "2026-09-15", "prorataDueDate": "2026-09-20", "mergeWithNextCycle": false } ``` ### Campos do body **Obrigatórios:** `paymentMethod`, `customer`, `customer.name`, `customer.email`, `customer.documentNumber`, `items`, `items.priceId`, `discounts.type`, `discounts.value` | Campo | Descrição | |---|---| | `paymentMethod` | Forma de pagamento (fixo: pix_automatico) | | `customer` | Dados do comprador | | `customer.name` | Nome completo | | `customer.email` | E-mail | | `customer.documentNumber` | CPF (11) ou CNPJ (14 dígitos) | | `items` | Itens da assinatura; o preço precisa ser recorrente | | `items.priceId` | ID do preço recorrente (valor mínimo de R$ 4,99) | | `discounts.type` | Tipo do desconto: percentual sobre o valor ou abatimento fixo em reais | | `discounts.value` | Percentual de 0 a 100 quando type e percentage; valor em reais quando fixed | **Opcionais** | Campo | Descrição | |---|---| | `externalId` | Identificador único do pedido no seu sistema; usado como idempotencyKey (evita cobrança duplicada) | | `externalTxid` | Identifica a loja, o caixa ou o vendedor responsável pela cobrança | | `customer.phone` | Telefone | | `items.quantity` | Quantidade (default 1) | | `billingDay` | Dia do mês das cobranças seguintes (1 a 31) | | `couponCode` | Código de cupom de desconto | | `description` | Descricao livre da cobranca | | `split` | Divisao do valor. Nao suportado em creditcard nem pix_automatico | | `installments` | Parcelas no cartao, de 1 a 12 | | `freeInstallments` | Parcelas sem juros para o comprador, de 0 a 12 | | `passFeesToCustomer` | Repassa a taxa de parcelamento ao comprador | | `nfConfigId` | Emite nota fiscal com esta configuracao. Exige customer.address | | `discounts` | Descontos aplicados a cobranca | | `discounts.paymentMethod` | Aplica o desconto so neste metodo de pagamento | | `discounts.fromCycle` | Primeiro ciclo em que o desconto vale, em cobrancas recorrentes | | `discounts.toCycle` | Ultimo ciclo; null mantem o desconto ate o fim da assinatura | | `discounts.durationMonths` | Alternativa a toCycle: por quantos meses o desconto vale | | `tokenId` | Alternativa a card e a paymentMethodId no cartao | | `productId` | Cria a cobranca a partir de um produto | | `recurrencyStartDate` | Primeira cobranca da recorrencia (YYYY-MM-DD) | | `prorataStartDate` | Inicio do calculo pro rata | | `prorataDueDate` | Vencimento da cobranca pro rata (YYYY-MM-DD) | | `mergeWithNextCycle` | Junta a pro rata com o proximo ciclo em vez de cobrar agora | ### Resposta 200 — 200 ```json { "success": true, "customerId": "cus_xxx", "chargeId": "cha_abc123", "pix": { "emv": "00020126330014br.gov.bcb.pix...5204000053039865802BR6304ABCD", "recurrencyId": "RN1234567890abcdef" } } ``` ### Resposta 400 — 400 PIX_AUTOMATICO_PJ_ONLY ```json { "error": { "message": "Pix Automático está disponível apenas para contas PJ", "code": "PIX_AUTOMATICO_PJ_ONLY" } } ``` ### Resposta 400 — 400 PIX_AUTOMATICO_MIN_AMOUNT ```json { "error": { "message": "Pix Automático exige valor mínimo de R$ 4,99", "code": "PIX_AUTOMATICO_MIN_AMOUNT" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-gerar-cobranca-pix-automatico Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Gerar cobrança Boleto `POST /v1/charges` **Área:** Checkout Transparente **Scopes necessários:** `checkouts/write` Gera uma cobrança via **boleto** pelo checkout transparente. O cliente informa os dados na sua própria interface e você os envia para a API. Para boleto, o **endereço completo do comprador é obrigatório**. Você pode personalizar vencimento, multa, juros e desconto por meio de `boletoInstructions`. Produto ou valor: envie `items` com os produtos OU `amount` para uma cobrança avulsa. Notificações por e-mail: use `notifications` para escolher quais e-mails saem nesta cobrança. Eventos aceitos aqui: `oneoff.boleto.generated` (envia o boleto ao comprador assim que a cobrança é criada), `oneoff.payment.success` (confirmação ao comprador quando o boleto compensa) e `new.sale` (avisa você, vendedor, da venda paga). Os eventos destinados ao comprador exigem `customer.email`. Sem o campo, uma cobrança avulsa (enviada com `amount`) não dispara e-mail nenhum; com `items` de um produto, vale a configuração de notificações do produto, e `notifications` no payload tem precedência sobre ela. > ⚠️ **Atenção:** envie o campo `externalId` como chave de idempotência (idempotencyKey). Se duas cobranças forem enviadas com o mesmo `externalId`, a segunda é recusada com `409 DUPLICATE_CHARGE`, retornando o `chargeId` da cobrança original. Erros comuns: `409 DUPLICATE_CHARGE` (externalId já utilizado), `404 PRICE_NOT_FOUND` (preço inexistente) e `400 INVALID_DATA` (campo inválido — inclui endereço ausente). Use `externalTxid` para identificar a **loja**, o **caixa** ou o **vendedor** responsável pela cobrança. **Correlação com o pedido:** use `externalId` — ele é persistido e devolvido. O campo `metadata` é aceito nesta rota mas **não é gravado na cobrança** nem volta no webhook; ele só é persistido em `POST /v1/charges/pix`. ### Request body ```json { "paymentMethod": "boleto", "externalId": "pedido-2026-0001", "externalTxid": "loja-01-caixa-03", "customer": { "name": "João da Silva", "email": "joao@email.com", "documentNumber": "12345678901", "phone": "+5511999998888", "address": { "street": "Av. Paulista", "number": "1000", "complement": "Apto 52", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP", "zipCode": "01310100", "country": "BR", "cityCode": "3550308" } }, "items": [ { "priceId": "price_abc123", "quantity": 1 } ], "dueDate": "2026-07-30", "boletoDueDays": 7, "expirationAfterDueDate": 30, "boletoInstructions": { "fine": 2.0, "interest": 1.0, "discount": { "amount": 10.0, "modality": "fixed", "limitDate": "2026-07-28" } }, "couponCode": "PROMO10", "metadata": { "referencia": "pedido-001" }, "description": "Assinatura Premium", "split": [ { "type": "fixed", "accountNumber": "896532569", "amount": 0.10 } ], "installments": 1, "freeInstallments": 1, "passFeesToCustomer": false, "allowedPaymentMethods": ["pix", "creditcard"], "nfConfigId": "nfc_1788364755079_psuecwgdc", "notifications": ["oneoff.pix.generated", "oneoff.payment.success", "new.sale"], "discounts": [ { "type": "percentage", "value": 10, "paymentMethod": "pix", "fromCycle": 1, "toCycle": 3, "durationMonths": 3 } ], "tokenId": "tok_abc123", "productId": "prod_123456_example", "recurrencyStartDate": "2026-10-01", "prorataStartDate": "2026-09-15", "prorataDueDate": "2026-09-20", "mergeWithNextCycle": false } ``` ### Campos do body **Obrigatórios:** `paymentMethod`, `customer`, `customer.name`, `customer.email`, `customer.documentNumber`, `customer.address`, `customer.address.street`, `customer.address.number`, `customer.address.neighborhood`, `customer.address.city`, `customer.address.state`, `customer.address.zipCode`, `items.priceId`, `discounts.type`, `discounts.value` | Campo | Descrição | |---|---| | `paymentMethod` | Forma de pagamento (fixo: boleto) | | `customer` | Dados do comprador | | `customer.name` | Nome completo | | `customer.email` | E-mail | | `customer.documentNumber` | CPF (11) ou CNPJ (14 dígitos) | | `customer.address` | Endereço do comprador (obrigatório para boleto) | | `customer.address.street` | Rua ou logradouro | | `customer.address.number` | Número | | `customer.address.neighborhood` | Bairro | | `customer.address.city` | Cidade | | `customer.address.state` | UF com 2 letras | | `customer.address.zipCode` | CEP com 8 dígitos | | `items.priceId` | ID do preço do produto | | `discounts.type` | Tipo do desconto: percentual sobre o valor ou abatimento fixo em reais | | `discounts.value` | Percentual de 0 a 100 quando type e percentage; valor em reais quando fixed | **Opcionais** | Campo | Descrição | |---|---| | `externalId` | Identificador único do pedido no seu sistema; usado como idempotencyKey (evita cobrança duplicada) | | `externalTxid` | Identifica a loja, o caixa ou o vendedor responsável pela cobrança | | `customer.phone` | Telefone | | `customer.address.complement` | Complemento | | `customer.address.country` | País (default BR) | | `customer.address.cityCode` | Código IBGE (necessário para nota fiscal) | | `items` | Produtos da compra (ou use amount para cobrança avulsa) | | `items.quantity` | Quantidade (default 1) | | `dueDate` | Vencimento do boleto (YYYY-MM-DD, maior que hoje) | | `boletoDueDays` | Dias até o vencimento (mín. 1; ignorado se dueDate informado) | | `expirationAfterDueDate` | Dias para cancelar o boleto após o vencimento (0 a 60) | | `boletoInstructions` | Regras de multa/juros/desconto do boleto | | `boletoInstructions.fine` | Multa por atraso em % (0.1 a 100; fine + interest <= 60) | | `boletoInstructions.interest` | Juros mensais por atraso em % (0.1 a 100) | | `boletoInstructions.discount` | Desconto para pagamento antecipado | | `boletoInstructions.discount.amount` | Valor do desconto | | `boletoInstructions.discount.modality` | fixed (R$) ou percent (%) | | `boletoInstructions.discount.limitDate` | Data limite do desconto (antes de dueDate) | | `couponCode` | Código de cupom de desconto | | `description` | Descricao livre da cobranca | | `split` | Divisao do valor. Nao suportado em creditcard nem pix_automatico | | `installments` | Parcelas no cartao, de 1 a 12 | | `freeInstallments` | Parcelas sem juros para o comprador, de 0 a 12 | | `passFeesToCustomer` | Repassa a taxa de parcelamento ao comprador | | `nfConfigId` | Emite nota fiscal com esta configuracao. Exige customer.address | | `discounts` | Descontos aplicados a cobranca | | `discounts.paymentMethod` | Aplica o desconto so neste metodo de pagamento | | `discounts.fromCycle` | Primeiro ciclo em que o desconto vale, em cobrancas recorrentes | | `discounts.toCycle` | Ultimo ciclo; null mantem o desconto ate o fim da assinatura | | `discounts.durationMonths` | Alternativa a toCycle: por quantos meses o desconto vale | | `tokenId` | Alternativa a card e a paymentMethodId no cartao | | `productId` | Cria a cobranca a partir de um produto | | `recurrencyStartDate` | Primeira cobranca da recorrencia (YYYY-MM-DD) | | `prorataStartDate` | Inicio do calculo pro rata | | `prorataDueDate` | Vencimento da cobranca pro rata (YYYY-MM-DD) | | `mergeWithNextCycle` | Junta a pro rata com o proximo ciclo em vez de cobrar agora | ### Resposta 200 — 200 ```json { "success": true, "customerId": "cus_xxx", "chargeId": "cha_abc123", "boleto": { "digitableLine": "23793.38128 60007.827136 95000.063305 9 84410000010000", "barCode": "23799844100000100003381260007827139500006330", "dueDate": "2026-07-30", "pdfUrl": "https://app.validapay.com.br/boletos/cha_abc123.pdf" } } ``` ### Resposta 404 — 404 PRICE_NOT_FOUND ```json { "error": { "message": "Preço não encontrado", "code": "PRICE_NOT_FOUND" } } ``` ### Resposta 409 — 409 DUPLICATE_CHARGE ```json { "error": { "message": "Cobrança duplicada: já existe uma cobrança para este pedido", "code": "DUPLICATE_CHARGE", "details": { "chargeId": "cha_1784065113577_5dw2oyfic" }, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-gerar-cobranca-boleto Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Gerar cobrança Cartão `POST /v1/charges` **Área:** Checkout Transparente **Scopes necessários:** `checkouts/write` Gera uma cobrança via **cartão de crédito** pelo checkout transparente. O cliente informa os dados na sua própria interface e você os envia para a API. Envie os dados do cartão no objeto `card` (dados brutos) ou use `paymentMethodId`/`tokenId` de um cartão tokenizado. É possível parcelar (`installments`) e repassar as taxas ao comprador. Produto ou valor: envie `items` com os produtos OU `amount` para uma cobrança avulsa. Notificações por e-mail: use `notifications` para escolher quais e-mails saem nesta cobrança. Eventos aceitos aqui: `oneoff.payment.success` (confirmação ao comprador quando o cartão é aprovado), `oneoff.payment.failed` (aviso ao comprador quando o cartão é recusado) e `new.sale` (avisa você, vendedor, da venda paga). Os eventos destinados ao comprador exigem `customer.email`. Sem o campo, uma cobrança avulsa (enviada com `amount`) não dispara e-mail nenhum; com `items` de um produto, vale a configuração de notificações do produto, e `notifications` no payload tem precedência sobre ela. > ⚠️ **Atenção:** envie o campo `externalId` como chave de idempotência (idempotencyKey). Se duas cobranças forem enviadas com o mesmo `externalId`, a segunda é recusada com `409 DUPLICATE_CHARGE`, retornando o `chargeId` da cobrança original. Erros comuns: `409 DUPLICATE_CHARGE` (externalId já utilizado), `402` (pagamento recusado pelo banco), `400 MISSING_CARD_DATA` (faltam dados do cartão) e `404 PRICE_NOT_FOUND` (preço inexistente). **Cartões de teste (sandbox):** em conta de sandbox nenhuma cobrança chega ao adquirente — o número do cartão é que define o resultado: - `4111111111111111` — pagamento aprovado - `4000000000000002` — recusado pela operadora (`card_declined`) - `4000000000000004` — saldo insuficiente (`insufficient_funds`) - `4000000000000006` — cartão expirado (`expired_card`) - `4000000000000008` — CVV inválido (`invalid_cvv`) - `4000000000000010` — suspeita de fraude (`fraud_suspected`) Qualquer outro número de 16 dígitos é aprovado. CVV, validade e nome do titular podem ser quaisquer valores válidos. Em produção o número não muda nada: quem decide é o emissor do cartão. Use `externalTxid` para identificar a **loja**, o **caixa** ou o **vendedor** responsável pela cobrança. **Correlação com o pedido:** use `externalId` — ele é persistido e devolvido. O campo `metadata` é aceito nesta rota mas **não é gravado na cobrança** nem volta no webhook; ele só é persistido em `POST /v1/charges/pix`. ### Request body ```json { "paymentMethod": "creditcard", "externalId": "pedido-2026-0001", "externalTxid": "loja-01-caixa-03", "customer": { "name": "João da Silva", "email": "joao@email.com", "documentNumber": "12345678901", "phone": "+5511999998888" }, "card": { "number": "4111111111111111", "cvv": "123", "name": "JOAO DA SILVA", "expiration": "12/2027" }, "paymentMethodId": "pm_abc123", "items": [ { "priceId": "price_abc123", "quantity": 1 } ], "installments": 1, "passFeesToCustomer": false, "freeInstallments": 1, "couponCode": "PROMO10", "metadata": { "referencia": "pedido-001" }, "description": "Assinatura Premium", "split": [ { "type": "fixed", "accountNumber": "896532569", "amount": 0.10 } ], "installments": 1, "freeInstallments": 1, "passFeesToCustomer": false, "allowedPaymentMethods": ["pix", "creditcard"], "nfConfigId": "nfc_1788364755079_psuecwgdc", "notifications": ["oneoff.pix.generated", "oneoff.payment.success", "new.sale"], "discounts": [ { "type": "percentage", "value": 10, "paymentMethod": "pix", "fromCycle": 1, "toCycle": 3, "durationMonths": 3 } ], "tokenId": "tok_abc123", "productId": "prod_123456_example", "recurrencyStartDate": "2026-10-01", "prorataStartDate": "2026-09-15", "prorataDueDate": "2026-09-20", "mergeWithNextCycle": false } ``` ### Campos do body **Obrigatórios:** `paymentMethod`, `customer`, `customer.name`, `customer.email`, `customer.documentNumber`, `card`, `card.number`, `card.cvv`, `card.name`, `card.expiration`, `items.priceId`, `discounts.type`, `discounts.value` | Campo | Descrição | |---|---| | `paymentMethod` | Forma de pagamento (fixo: creditcard) | | `customer` | Dados do comprador | | `customer.name` | Nome completo | | `customer.email` | E-mail | | `customer.documentNumber` | CPF (11) ou CNPJ (14 dígitos) | | `card` | Dados do cartão (ou use paymentMethodId/tokenId de um cartão salvo) | | `card.number` | Número do cartão (13 a 19 dígitos) | | `card.cvv` | Código de segurança (3 ou 4 dígitos) | | `card.name` | Nome como está no cartão | | `card.expiration` | Validade no formato MM/YYYY | | `items.priceId` | ID do preço do produto | | `discounts.type` | Tipo do desconto: percentual sobre o valor ou abatimento fixo em reais | | `discounts.value` | Percentual de 0 a 100 quando type e percentage; valor em reais quando fixed | **Opcionais** | Campo | Descrição | |---|---| | `externalId` | Identificador único do pedido no seu sistema; usado como idempotencyKey (evita cobrança duplicada) | | `externalTxid` | Identifica a loja, o caixa ou o vendedor responsável pela cobrança | | `customer.phone` | Telefone | | `paymentMethodId` | Cartão tokenizado (alternativa ao objeto card) | | `items` | Produtos da compra (ou use amount para cobrança avulsa) | | `items.quantity` | Quantidade (default 1) | | `installments` | Parcelas no cartao, de 1 a 12 | | `passFeesToCustomer` | Repassa a taxa de parcelamento ao comprador | | `freeInstallments` | Parcelas sem juros para o comprador, de 0 a 12 | | `couponCode` | Código de cupom de desconto | | `description` | Descricao livre da cobranca | | `split` | Divisao do valor. Nao suportado em creditcard nem pix_automatico | | `nfConfigId` | Emite nota fiscal com esta configuracao. Exige customer.address | | `discounts` | Descontos aplicados a cobranca | | `discounts.paymentMethod` | Aplica o desconto so neste metodo de pagamento | | `discounts.fromCycle` | Primeiro ciclo em que o desconto vale, em cobrancas recorrentes | | `discounts.toCycle` | Ultimo ciclo; null mantem o desconto ate o fim da assinatura | | `discounts.durationMonths` | Alternativa a toCycle: por quantos meses o desconto vale | | `tokenId` | Alternativa a card e a paymentMethodId no cartao | | `productId` | Cria a cobranca a partir de um produto | | `recurrencyStartDate` | Primeira cobranca da recorrencia (YYYY-MM-DD) | | `prorataStartDate` | Inicio do calculo pro rata | | `prorataDueDate` | Vencimento da cobranca pro rata (YYYY-MM-DD) | | `mergeWithNextCycle` | Junta a pro rata com o proximo ciclo em vez de cobrar agora | ### Resposta 200 — 200 ```json { "success": true, "customerId": "cus_xxx", "chargeId": "cha_abc123", "status": "paid" } ``` ### Resposta 402 — 402 ```json { "success": false, "chargeId": "cha_1784065113577_5dw2oyfic", "status": "failed", "error": "Cartão recusado" } ``` ### Resposta 400 — 400 MISSING_CARD_DATA ```json { "error": { "message": "tokenId, card ou paymentMethodId é obrigatório", "code": "MISSING_CARD_DATA" } } ``` ### Resposta 404 — 404 PRICE_NOT_FOUND ```json { "error": { "message": "Preço não encontrado", "code": "PRICE_NOT_FOUND" } } ``` ### Resposta 409 — 409 DUPLICATE_CHARGE ```json { "error": { "message": "Cobrança duplicada: já existe uma cobrança para este pedido", "code": "DUPLICATE_CHARGE", "details": { "chargeId": "cha_1784065113577_5dw2oyfic" }, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-gerar-cobranca-cartao Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Pagar em sandbox `POST /v1/wallet/pay/:chargeId` **Área:** Simular pagamentos **Scopes necessários:** `wallet/write` Confirma o pagamento de uma cobrança do **sandbox** sem dinheiro de verdade. A ValidaPay envia ao seu webhook o mesmo evento de PIX recebido que um pagamento real dispararia, então o seu fluxo de baixa é exercitado ponta a ponta. **Case de uso:** _Como desenvolvedor integrando a API, quero marcar uma cobrança do sandbox como paga, para testar meu webhook de confirmação sem transferir dinheiro._ Informe no path o `chargeId` devolvido na criação da cobrança. A resposta é imediata e traz `status: PROCESSING` — a confirmação chega pelo webhook; consulte a cobrança depois para vê-la como `PAID`. Disponível **apenas em contas de sandbox**: em produção a chamada é recusada com `400 NOT_SANDBOX_ACCOUNT`. Cobrança já paga responde `200` com a mensagem "Cobranca ja foi paga" e cobrança inexistente, `404 CHARGE_NOT_FOUND`. **Cartão de crédito não passa por esta rota.** No sandbox o resultado da cobrança no cartão é decidido pelo número enviado: **Cartões de teste (sandbox):** em conta de sandbox nenhuma cobrança chega ao adquirente — o número do cartão é que define o resultado: - `4111111111111111` — pagamento aprovado - `4000000000000002` — recusado pela operadora (`card_declined`) - `4000000000000004` — saldo insuficiente (`insufficient_funds`) - `4000000000000006` — cartão expirado (`expired_card`) - `4000000000000008` — CVV inválido (`invalid_cvv`) - `4000000000000010` — suspeita de fraude (`fraud_suspected`) Qualquer outro número de 16 dígitos é aprovado. CVV, validade e nome do titular podem ser quaisquer valores válidos. Em produção o número não muda nada: quem decide é o emissor do cartão. ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `chargeId` | **sim** | Identificador retornado no ato da geraçao da cobrança | --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-pagar-em-sandbox Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Saque subconta `POST /v1/wallet/withdraw` **Área:** Saques **Scopes necessários:** `wallet/write` Com esta funcionalidade você pode criar um saque em uma subconta associada à sua _master account._ > ⚠️ **Atenção:** Só é possível fazer saques para contas de mesma titularidade ### Request body ```json { "amount": 1.00, "pixKey": "12345678925", "pixKeyType": "CPF", "accountId": "258965356" } ``` ### Campos do body **Obrigatórios:** `amount`, `pixKey`, `pixKeyType`, `accountId` | Campo | Descrição | |---|---| | `amount` | Valor do saque | | `pixKey` | Chave Pix de destino | | `pixKeyType` | tipo de chave Pix | | `accountId` | Número da subconta de destino | ### Resposta 200 — Sucesso ```json { "withdrawalId": "wdr_1772883158760_tdhomd8xe", "status": "PROCESSING", "amount": 1, "accountNumber": "258965356" } ``` ### Resposta 401 — Acesso negado ```json { "error": { "message": "Subconta nao pertence a esta conta", "code": "OWNERSHIP_MISMATCH", "details": null, "timestamp": "2026-03-17T04:01:14.653Z" } } ``` ### Resposta 400 — Bloqueio por titularidade ```json { "error": { "message": "A chave PIX nao pertence ao titular da conta", "code": "OWNERSHIP_MISMATCH", "details": null, "timestamp": "2026-03-17T04:01:57.811Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-saque-subconta Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Saque master account `POST /v1/wallet/withdraw` **Área:** Saques **Scopes necessários:** `wallet/write` Com esta funcionalidade você pode criar um saque da sua _conta ValidaPay._ > ⚠️ **Atenção:** Só é possível fazer saques para contas de mesma titularidade ### Request body ```json { "amount": 1.00, "pixKey": "12345678925", "pixKeyType": "CPF" } ``` ### Campos do body **Obrigatórios:** `amount`, `pixKey`, `pixKeyType` | Campo | Descrição | |---|---| | `amount` | Valor do saque | | `pixKey` | Chave Pix de destino | | `pixKeyType` | tipo de chave Pix | ### Resposta 200 — Sucesso ```json { "withdrawalId": "wdr_1772883158760_tdhomd8xe", "status": "PROCESSING", "amount": 1, "accountNumber": "258965356" } ``` ### Resposta 400 — Bloqueio por titularidade ```json { "error": { "message": "A chave PIX nao pertence ao titular da conta", "code": "OWNERSHIP_MISMATCH", "details": null, "timestamp": "2026-03-17T04:01:57.811Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-saque-master-account Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Extrato subconta `GET /v1/wallet/transactions` **Área:** Extratos **Scopes necessários:** `wallet/read` Com esta funcionalidade você pode isualizar movimentações em uma subconta associada a sua _master account_ ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `accountId` | **sim** | - ID da subconta a consultar | | `type` | não | - CREDIT ou DEBIT | | `category` | não | - PAYMENT, PIX_IN, WITHDRAWAL, etc. | | `dateFrom` | não | - Data início (ISO 8601) | | `dateTo` | não | - Data fim (ISO 8601) | | `limit` | não | - 1-100, default 50 | | `nextPageToken` | não | - Token de paginação | ### Resposta 200 — Sucesso ```json { "accountId": "429134563", "transactions": [ { "transactionId": "txn_1773694940975_r10b6fyzm", "type": "CREDIT", "category": "PIX_IN", "amount": 2.56, "balanceAfter": 901.6, "title": "PIX recebido de Empresa Exemplo LTDA", "paymentMethod": "PIX", "chargeId": null, "subscriptionId": null, "endToEndId": "E13935893202603162102IfDcitXf0zO", "counterparty": { "name": "Empresa Exemplo LTDA", "bank": "13935893", "taxId": "37134852000458", "account": "410900056" }, "referenceId": "E139389320260316202IfDyytXf0zO", "description": "PIX recebido direto", "createdAt": "2026-03-16T21:02:20.975Z" }, { "transactionId": "txn_1773718528326_449bqmhm7", "type": "DEBIT", "category": "WITHDRAWAL", "amount": 1, "balanceAfter": 929.85, "title": "Saque PIX", "paymentMethod": "PIX", "chargeId": null, "subscriptionId": null, "endToEndId": "E13935893202563270335KF9O0GDVVIz", "counterparty": null, "referenceId": "f7d1e875-7096-4fa8-992d-0c81a09f91c0", "description": "Saque / transferência PIX", "createdAt": "2026-03-17T03:35:28.326Z" } ], "nextPageToken": "eyJTSyI6IjIwMjYtMDMtMTVUMjM6NTk6MzMuMDcxWiN0eG5fMTc3MzYxOTE3MzA3MV8zb3JpcjNjYnciLCJhY2NvdW50SWQiOiI0MjkxMzEyMTIifQ", "hasMore": true } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-extrato-subconta Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Extrato conta master `GET /v1/wallet/transactions` **Área:** Extratos **Scopes necessários:** `wallet/read` Com esta funcionalidade você pode isualizar movimentações na sua conta ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `type` | não | - CREDIT ou DEBIT | | `category` | não | - PAYMENT, PIX_IN, WITHDRAWAL, etc. | | `dateFrom` | não | - Data início (ISO 8601) | | `dateTo` | não | - Data fim (ISO 8601) | | `limit` | não | - 1-100, default 50 | | `nextPageToken` | não | - Token de paginação | ### Resposta 200 — Sucesso ```json { "accountId": "429134563", "transactions": [ { "transactionId": "txn_1773694940975_r10b6fyzm", "type": "CREDIT", "category": "PIX_IN", "amount": 2.56, "balanceAfter": 901.6, "title": "PIX recebido de Empresa Exemplo LTDA", "paymentMethod": "PIX", "chargeId": null, "subscriptionId": null, "endToEndId": "E13935893202603162102IfDcitXf0zO", "counterparty": { "name": "Empresa Exemplo LTDA", "bank": "13935893", "taxId": "37134852000458", "account": "410900056" }, "referenceId": "E139389320260316202IfDyytXf0zO", "description": "PIX recebido direto", "createdAt": "2026-03-16T21:02:20.975Z" }, { "transactionId": "txn_1773718528326_449bqmhm7", "type": "DEBIT", "category": "WITHDRAWAL", "amount": 1, "balanceAfter": 929.85, "title": "Saque PIX", "paymentMethod": "PIX", "chargeId": null, "subscriptionId": null, "endToEndId": "E13935893202563270335KF9O0GDVVIz", "counterparty": null, "referenceId": "f7d1e875-7096-4fa8-992d-0c81a09f91c0", "description": "Saque / transferência PIX", "createdAt": "2026-03-17T03:35:28.326Z" } ], "nextPageToken": "eyJTSyI6IjIwMjYtMDMtMTVUMjM6NTk6MzMuMDcxWiN0eG5fMTc3MzYxOTE3MzA3MV8zb3JpcjNjYnciLCJhY2NvdW50SWQiOiI0MjkxMzEyMTIifQ", "hasMore": true } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-extrato-conta-master Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Criar devolução PIX `POST /v1/wallet/refunds` **Área:** Devolução Pix **Scopes necessários:** `wallet/write` Cria uma **devolução PIX** a partir do `endToEndId` da transação original. A devolução pode ser parcial ou total. > ⚠️ **Atenção:** o campo `reason` (motivo da devolução) é **obrigatório**. Valores aceitos para `reason`: - `CUSTOMER_REQUEST` — solicitação do cliente - `FRAUD` — suspeita de fraude - `BANK_ERROR` — erro bancário - `PIX_CHANGE_ERROR` — erro na transação A devolução nasce em geral como `PROCESSING`. Guarde o `refundId` retornado e acompanhe a confirmação pela rota **Consultar status da devolução PIX** (`GET /v1/wallet/refunds`). ### Request body ```json { "accountId": "459013777", "endToEndId": "E003603052026032511186a4f4cdf139", "amount": 1.00, "reason": "CUSTOMER_REQUEST", "chargeId": "cha_1774437468463_4hj927ips" } ``` ### Campos do body **Obrigatórios:** `endToEndId`, `amount`, `reason` | Campo | Descrição | |---|---| | `endToEndId` | EndToEndId da transação PIX original. | | `amount` | Valor da devolução (parcial ou total). | | `reason` | Um de: BANK_ERROR, FRAUD, CUSTOMER_REQUEST, PIX_CHANGE_ERROR. | **Opcionais** | Campo | Descrição | |---|---| | `accountId` | Número da subconta. Se omitido, opera na conta principal. | | `chargeId` | ID da charge associada. | ### Resposta 201 — Sucesso ```json { "refundId": "ref_1774437918293_jm2hen5y7", "status": "PROCESSING", "amount": 1, "reason": "CUSTOMER_REQUEST", "endToEndId": "E003603052026032511186a4f4cdf139", "returnIdentification": "D13935893202603251125zbRSLI3lqPH", "chargeId": "cha_1774437468463_4hj927ips", "createdAt": "2026-03-25T11:25:18.293Z" } ``` ### Resposta 401 — Não autorizado ```json { "error": { "message": "Subconta nao pertence a esta conta", "code": "OWNERSHIP_MISMATCH", "details": null, "timestamp": "2026-03-25T11:28:25.397Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-criar-devolucao-pix Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Consultar status da devolução PIX `GET /v1/wallet/refunds` **Área:** Devolução Pix **Scopes necessários:** `wallet/read` Consulta se uma **devolução PIX** foi confirmada. Não use o status da cobrança (`REFUNDED` / `PARTIALLY_REFUNDED`) para saber se o estorno foi confirmado — use o refund: - `status === "CONFIRMED"` (ou `success === true`): estorno confirmado - `status === "PROCESSING"`: ainda aguardando - `status === "ERROR"`: falhou (`error` pode vir preenchido) Modos de uso: - Informe `refundId` (ou `returnIdentification`) para o detalhe/polling de uma devolução específica. - Informe `endToEndId` do PIX original para consultar as devoluções daquele pagamento. - MasterAccounts podem consultar uma subconta informando `accountId`. Precedência: `refundId` > `returnIdentification` > `endToEndId` > `chargeId`. > ℹ️ Polling sugerido: 2–5s com timeout (60–120s). ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `refundId` | não | - Detalhe/polling de uma devolução específica | ### Resposta 200 — Item único (por refundId) ```json { "refundId": "ref_1774531490865_bq4e8v12x", "accountId": "429131212", "status": "CONFIRMED", "success": true, "amount": 100.00, "reason": "CUSTOMER_REQUEST", "chargeId": "cha_1774530966959_frgj3ptax", "originalEndToEndId": "E0036030520260326132336e2f8787c4", "returnIdentification": "D13935893202603261324C5jA3zE3V6J", "providerChargeId": null, "paymentType": null, "splitReversals": [], "error": null, "createdAt": "2026-03-26T13:24:52.106Z", "updatedAt": "2026-03-26T13:24:57.553Z" } ``` ### Resposta 404 — 404 REFUND_NOT_FOUND ```json { "error": { "message": "Refund não encontrado", "code": "REFUND_NOT_FOUND", "details": null, "timestamp": "2026-08-05T12:00:00.000Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-consultar-status-da-devolucao-pix Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Criar estorno de cartão `POST /v1/wallet/refunds` **Área:** Estorno Cartão **Scopes necessários:** `wallet/write` Cria um **estorno de cartão de crédito** a partir do `chargeId` da cobrança original. O estorno pode ser parcial ou total. > ℹ️ Para cartão, o estorno pode retornar `CONFIRMED` na hora, quando a confirmação vem imediatamente — nesse caso o polling não é necessário (`success` já vem `true`). Se vier `PROCESSING`, guarde o `refundId` e acompanhe pela rota **Consultar status do estorno** (`GET /v1/wallet/refunds`). ### Request body ```json { "accountId": "459013777", "chargeId": "cha_1774530966959_frgj3ptax", "amount": 100.00, "reason": "CUSTOMER_REQUEST" } ``` ### Campos do body **Obrigatórios:** `chargeId`, `amount` | Campo | Descrição | |---|---| | `chargeId` | ID da cobrança de cartão a ser estornada. | | `amount` | Valor do estorno (parcial ou total). | **Opcionais** | Campo | Descrição | |---|---| | `accountId` | Número da subconta. Se omitido, opera na conta principal. | | `reason` | Motivo do estorno. | ### Resposta 201 — Sucesso ```json { "refundId": "ref_1774531490865_bq4e8v12x", "status": "CONFIRMED", "success": true, "amount": 100, "reason": "CUSTOMER_REQUEST", "chargeId": "cha_1774530966959_frgj3ptax", "providerChargeId": "prov_ch_9f8a7b6c", "paymentType": "CREDIT_CARD", "createdAt": "2026-03-26T13:24:52.106Z" } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-criar-estorno-de-cartao Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Consultar status do estorno `GET /v1/wallet/refunds` **Área:** Estorno Cartão **Scopes necessários:** `wallet/read` Consulta se um **estorno de cartão** foi confirmado. Use o refund (não o status da cobrança) para confirmar: - `status === "CONFIRMED"` (ou `success === true`): estorno confirmado - `status === "PROCESSING"`: ainda aguardando - `status === "ERROR"`: falhou (`error` pode vir preenchido) Modos de uso: - Informe `refundId` para o detalhe/polling de um estorno específico. - Informe `chargeId` para consultar os estornos daquela cobrança de cartão. - MasterAccounts podem consultar uma subconta informando `accountId`. > ℹ️ No estorno de cartão a resposta traz `paymentType: "CREDIT_CARD"` e o `providerChargeId` da transação. ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `refundId` | não | - Detalhe/polling de um estorno específico | ### Resposta 200 — Item único (por refundId) ```json { "refundId": "ref_1774531490865_bq4e8v12x", "accountId": "429131212", "status": "CONFIRMED", "success": true, "amount": 100.00, "reason": "CUSTOMER_REQUEST", "chargeId": "cha_1774530966959_frgj3ptax", "originalEndToEndId": null, "returnIdentification": null, "providerChargeId": "prov_ch_9f8a7b6c", "paymentType": "CREDIT_CARD", "splitReversals": [], "error": null, "createdAt": "2026-03-26T13:24:52.106Z", "updatedAt": "2026-03-26T13:24:57.553Z" } ``` ### Resposta 404 — 404 REFUND_NOT_FOUND ```json { "error": { "message": "Refund não encontrado", "code": "REFUND_NOT_FOUND", "details": null, "timestamp": "2026-08-05T12:00:00.000Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-consultar-status-do-estorno Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Criar Cliente `POST /v1/customers` **Área:** Clientes **Scopes necessários:** `customers/write` Cadastra um cliente na sua conta a partir do CPF/CNPJ, com endereço opcional. O documento é a chave do cliente dentro da conta e não pode ser alterado depois. Por padrão, se já existir um cliente com o mesmo documento, a API devolve 200 com o cadastro existente em vez de duplicar. Envie upsert: true para que a tentativa de recadastrar retorne erro 400 (CUSTOMER_ALREADY_EXISTS). Quando o endereço é informado, o código IBGE do município (cityCode) é resolvido automaticamente a partir do CEP — necessário para emissão de NFS-e. Case de uso: _Como plataforma, quero cadastrar meus clientes junto com o endereço de cobrança, para depois gerar assinaturas e cobranças sem redigitar os dados a cada venda._ ### Request body ```json { "name": "Alexandre Souza", "document": "11144477735", "phone": "5511987654321", "email": "alexandre@exemplo.com.br", "upsert": false, "address": { "zipCode": "01310100", "street": "Avenida Paulista", "number": "1000", "complement": "Sala 5", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP" } } ``` ### Campos do body **Obrigatórios:** `name`, `document`, `phone`, `address.zipCode`, `address.street`, `address.number`, `address.neighborhood`, `address.city`, `address.state` | Campo | Descrição | |---|---| | `name` | Nome completo ou razão social | | `document` | CPF (11) ou CNPJ (14), apenas dígitos | | `phone` | E.164 com DDI 55 | | `address.zipCode` | 8 dígitos, apenas números | | `address.street` | | | `address.number` | | | `address.neighborhood` | | | `address.city` | | | `address.state` | UF com 2 letras | **Opcionais** | Campo | Descrição | |---|---| | `email` | | | `upsert` | true retorna erro 400 se o documento já existir (default false) | | `address` | | | `address.complement` | | ### Resposta 201 — 201 ```json { "customer": { "customerId": "cus_xxx", "id": "cus_xxx", "name": "Alexandre Souza", "document": "11144477735", "email": "alexandre@exemplo.com.br", "phone": "5511987654321", "accountId": "460851686", "status": "ACTIVE", "createdAt": "2026-08-28T12:00:00.000Z" } } ``` ### Resposta 200 — 200 ```json { "customer": { "customerId": "cus_xxx", "document": "11144477735", "name": "Alexandre Souza" } } ``` ### Resposta 400 — 400 ```json { "error": { "message": "Já existe um cliente cadastrado com este documento", "code": "CUSTOMER_ALREADY_EXISTS", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-criar-cliente Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Listar Clientes `GET /v1/customers` **Área:** Clientes **Scopes necessários:** `customers/read` Lista os clientes cadastrados na sua conta, com busca por texto e paginação por cursor. O parâmetro search faz busca parcial simultânea em nome, e-mail e documento — é o filtro indicado para uma tela de seleção de cliente, onde o usuário pode digitar qualquer um dos três. Já document faz correspondência exata e deve ser usado quando o CPF/CNPJ completo já é conhecido. A paginação é por cursor: quando houver mais páginas, pagination.lastKey vem preenchido; repita a chamada enviando esse valor em lastKey, mantendo os mesmos filtros. Quando lastKey vier null, não há mais páginas. Case de uso: _Como integrador, quero buscar um cliente já cadastrado por nome, e-mail ou CPF/CNPJ, para preencher automaticamente os dados na hora de criar uma nova cobrança._ ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `lastKey` | **sim** | Cursor da próxima página, em base64, retornado em pagination.lastKey - optional | | `search` | **sim** | Busca parcial por nome, e-mail ou documento - optional | | `document` | **sim** | Filtro por CPF/CNPJ exato, apenas dígitos - optional | | `status` | **sim** | ACTIVE \| INACTIVE \| BLOCKED - optional | | `startDate` | **sim** | Data inicial de criação (ISO 8601) - optional | | `endDate` | **sim** | Data final de criação (ISO 8601) - optional | | `limit` | não | Quantidade de itens por página (default 15) - optional | ### Resposta 200 — 200 ```json { "items": [ { "customerId": "cus_xxx", "name": "Alexandre Souza", "document": "11144477735", "email": "alexandre@exemplo.com.br", "phone": "5511987654321", "status": "ACTIVE", "createdAt": "2026-08-28T12:00:00.000Z", "subscriptions": [] } ], "pagination": { "total": 128, "totalPages": 9, "limit": 15, "hasMore": true, "lastKey": "eyJQSyI6...=" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-listar-clientes Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Buscar Cliente por Documento `GET /v1/customers` **Área:** Clientes **Scopes necessários:** `customers/read` Busca direta de um único cliente pelo CPF/CNPJ exato, retornando junto o endereço padrão dele. Diferente de Listar Clientes, esta chamada não devolve lista nem paginação: retorna o objeto do cliente e o endereço em uma única resposta, pronto para preencher um formulário. Quando o documento não está cadastrado, a resposta é 200 com customer e address em null — não é erro. Case de uso: _Como checkout próprio, quero consultar o CPF digitado pelo comprador e, se ele já for cliente, preencher nome, e-mail, telefone e endereço automaticamente._ ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `lookupDocument` | não | CPF (11) ou CNPJ (14), apenas dígitos - required | ### Resposta 200 — 200 ```json { "customer": { "customerId": "cus_xxx", "name": "Alexandre Souza", "document": "11144477735", "email": "alexandre@exemplo.com.br", "phone": "5511987654321", "status": "ACTIVE" }, "address": { "zipCode": "01310100", "street": "Avenida Paulista", "number": "1000", "complement": "Sala 5", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP", "cityCode": "3550308" } } ``` ### Resposta 200 — 200 (não encontrado) ```json { "customer": null, "address": null } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-buscar-cliente-por-documento Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Detalhar Cliente `GET /v1/customers/:customerId` **Área:** Clientes **Scopes necessários:** `customers/read` Retorna os dados completos de um cliente, incluindo todos os endereços cadastrados e o histórico de assinaturas. Cada assinatura vem acompanhada dos itens, dos ciclos de cobrança e das faturas e cobranças de cada ciclo. É a visão consolidada usada na tela de detalhe do cliente. Case de uso: _Como atendente, quero ver tudo que um cliente possui — assinaturas, ciclos e faturas — em uma única consulta, para responder a um contato de suporte._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `customerId` | **sim** | Customerid | ### Resposta 200 — 200 ```json { "customer": { "customerId": "cus_xxx", "name": "Alexandre Souza", "document": "11144477735", "status": "ACTIVE" }, "addresses": [ { "zipCode": "01310100", "street": "Avenida Paulista", "number": "1000", "city": "São Paulo", "state": "SP", "isDefault": true } ], "subscriptions": [] } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Cliente não encontrado", "code": "CUSTOMER_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-detalhar-cliente Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Atualizar Cliente `PATCH /v1/customers/:customerId` **Área:** Clientes **Scopes necessários:** `customers/write` Atualiza os dados de um cliente. Envie apenas os campos que deseja alterar. O documento não pode ser alterado: enviar um CPF/CNPJ diferente do atual retorna erro 400 (DOCUMENT_UPDATE_NOT_ALLOWED). Quando o endereço é enviado, ele substitui o endereço padrão do cliente. Case de uso: _Como plataforma, quero atualizar o e-mail e o telefone de um cliente que mudou de contato, sem recriar o cadastro._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `customerId` | **sim** | Customerid | ### Request body ```json { "name": "Alexandre Souza Silva", "email": "novo@exemplo.com.br", "additionalEmails": ["financeiro@exemplo.com.br"], "phone": "5511987654321", "address": { "zipCode": "01310100", "street": "Avenida Paulista", "number": "2000", "complement": "Andar 3", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP" } } ``` ### Campos do body **Obrigatórios:** `address.zipCode`, `address.street`, `address.number`, `address.neighborhood`, `address.city`, `address.state` | Campo | Descrição | |---|---| | `address.zipCode` | | | `address.street` | | | `address.number` | | | `address.neighborhood` | | | `address.city` | | | `address.state` | | **Opcionais** | Campo | Descrição | |---|---| | `name` | | | `email` | | | `phone` | E.164 com DDI 55 | | `address` | substitui o endereço padrão | | `address.complement` | | ### Resposta 200 — 200 ```json { "customer": { "customerId": "cus_xxx", "name": "Alexandre Souza Silva", "email": "novo@exemplo.com.br", "phone": "5511987654321" } } ``` ### Resposta 400 — 400 ```json { "error": { "message": "O documento do cliente não pode ser alterado", "code": "DOCUMENT_UPDATE_NOT_ALLOWED", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/patch-atualizar-cliente Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Remover Cliente `DELETE /v1/customers/:customerId` **Área:** Clientes **Scopes necessários:** `customers/delete` Remove um cliente da sua conta. A exclusão é bloqueada quando o cliente possui assinaturas recorrentes vinculadas, retornando erro 400 (CUSTOMER_HAS_ACTIVE_SUBSCRIPTIONS). Cancele as assinaturas antes de excluir. Case de uso: _Como plataforma, quero remover um cadastro criado por engano, garantindo que clientes com assinaturas ativas não sejam apagados por acidente._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `customerId` | **sim** | Customerid | ### Resposta 200 — 200 ```json { "success": true } ``` ### Resposta 400 — 400 ```json { "error": { "message": "Cliente possui assinaturas vinculadas e não pode ser excluído", "code": "CUSTOMER_HAS_ACTIVE_SUBSCRIPTIONS", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/delete-remover-cliente Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Listar Assinaturas `GET /v1/subscriptions` **Área:** Assinaturas **Scopes necessários:** `subscriptions/read` Lista todas as assinaturas da conta com suporte a filtros por status, cliente, método de pagamento, produto e período. Utilize o campo `lastKey` retornado na resposta para navegar entre as páginas. Status possíveis: `PENDING`, `AWAITING_PAYMENT`, `ACTIVE`, `TRIALING`, `PAST_DUE`, `PAUSED`, `CANCELED`, `INCOMPLETE`. > Assinaturas com `interval: ONE_TIME` são excluídas automaticamente do resultado. Case de uso: _Como SaaS, quero listar todas as assinaturas ativas dos meus clientes para exibir no meu painel administrativo._ ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `lastKey` | **sim** | Cursor de paginação em base64 retornado na resposta anterior - optional | | `startDate` | **sim** | Filtro por createdAt. ISO 8601 recomendado (ex: 2026-03-10T00:00:00.000Z). YYYY-MM-DD aceito - optional | | `endDate` | **sim** | Filtro por createdAt. ISO 8601 com fim do dia (ex: 2026-03-10T23:59:59.999Z). YYYY-MM-DD pode excluir registros do mesmo dia com horário - optional | | `status` | **sim** | Filtro por status (lista separada por vírgula): PENDING, AWAITING_PAYMENT, ACTIVE, TRIALING, PAST_DUE, PAUSED, CANCELED, INCOMPLETE - optional | | `search` | **sim** | Busca por nome ou documento do cliente - optional | | `document` | **sim** | Filtro por CPF ou CNPJ do cliente - optional | | `paymentMethod` | **sim** | Filtro por método: CREDIT_CARD, PIX, BOLETO ou PIX_AUTOMATICO. Alias aceito: paymentType - optional | | `priceId` | **sim** | Filtro por ID do preço - optional | | `productId` | **sim** | Filtro por ID do produto - optional | | `limit` | não | Quantidade de itens por página (default 15) - optional | ### Resposta 200 — 200 ```json { "items": [ { "subscriptionId": "sub_xxx", "status": "ACTIVE", "interval": "MONTHLY", "billingDay": 15, "currentCycleNumber": 3, "currentCycleAmount": 99.9, "nextCycleChargeDate": "2024-02-15", "customer": { "customerId": "cus_xxx", "name": "João Silva", "email": "joao@email.com" }, "lastCharge": { "netAmount": 98.91, "status": "PAID" } } ], "pagination": { "total": 50, "hasMore": true, "lastKey": "eyJ..." } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-listar-assinaturas Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Buscar Assinatura `GET /v1/subscriptions/:subscriptionId` **Área:** Assinaturas **Scopes necessários:** `subscriptions/read` Retorna os detalhes completos de uma assinatura específica. A resposta inclui: `customer` (dados do cliente), `items` (itens da assinatura), `upgrades` (mudanças de plano pendentes), `billingCycles` (histórico de ciclos) e `coupon` (cupom aplicado, se houver). Case de uso: _Como SaaS, quero consultar o status e os itens de uma assinatura específica para exibir na área do cliente._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `subscriptionId` | **sim** | ID da assinatura (ex: sub_xxx) - required | ### Resposta 200 — 200 ```json { "subscriptionId": "sub_xxx", "status": "ACTIVE", "customer": {}, "items": [], "upgrades": [], "billingCycles": [], "coupon": null } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Assinatura não encontrada", "code": "SUBSCRIPTION_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-buscar-assinatura Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Atualizar Assinatura (Item) `PATCH /v1/subscriptions/:subscriptionId` **Área:** Assinaturas **Scopes necessários:** `subscriptions/write` Realiza **upgrade ou downgrade** de um item da assinatura. Envie `old.itemId` do item atual e `new.priceId` (e opcionalmente `new.quantity`) do novo plano. > Rota **canônica** para upgrade/downgrade: **Atualizar Item** (PUT). Este PATCH delega para a mesma lógica. - **Upgrade:** gera cobrança de pro rata imediatamente (cartão) ou de forma assíncrona via webhook (PIX/boleto). O item antigo só é substituído após confirmação do pagamento. - **Downgrade:** a mudança é agendada para o próximo ciclo de cobrança, sem cobrança imediata. Pré-condições: assinatura `ACTIVE`, `PAST_DUE` ou `AWAITING_PAYMENT`; item com status `ACTIVE`. Case de uso: _Como SaaS, quero permitir que meu cliente faça upgrade do plano Básico para o Pro no meio do ciclo, cobrando apenas a diferença proporcional._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `subscriptionId` | **sim** | ID da assinatura (ex: sub_xxx) - required | ### Request body ```json { "old": { "itemId": "item_xxx" }, "new": { "priceId": "price_yyy", "quantity": 2 } } ``` ### Campos do body **Obrigatórios:** `old`, `old.itemId`, `new`, `new.priceId` | Campo | Descrição | |---|---| | `old` | | | `old.itemId` | ID do item atual | | `new` | | | `new.priceId` | ID do novo preço | **Opcionais** | Campo | Descrição | |---|---| | `new.quantity` | Nova quantidade (default 1) | ### Resposta 200 — 200 ```json { "success": true, "type": "UPGRADE", "chargeId": "cha_xxx", "prorataAmount": 45.0, "newAmount": 100.0 } ``` ### Resposta 400 — 400 ```json { "error": { "message": "Cartão recusado por saldo insuficiente", "code": "PAYMENT_DECLINED", "details": { "declinedCode": "insufficient_funds" }, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/patch-atualizar-assinatura-item Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Cancelar Item `PATCH /v1/subscriptions/:subscriptionId` **Área:** Assinaturas **Scopes necessários:** `subscriptions/write` Remove um **item** da assinatura sem cancelar a assinatura inteira. Envie apenas `old.itemId` — **não informe** o campo `new`. A ausência de `new` indica cancelamento de item. Case de uso: _Como SaaS, quero remover um add-on da assinatura do cliente mantendo o plano principal ativo._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `subscriptionId` | **sim** | ID da assinatura (ex: sub_xxx) - required | ### Request body ```json { "old": { "itemId": "item_xxx" } } ``` ### Campos do body **Obrigatórios:** `old`, `old.itemId` | Campo | Descrição | |---|---| | `old` | | | `old.itemId` | ID do item a remover | ### Resposta 200 — 200 ```json { "success": true, "type": "ITEM_CANCELED", "itemId": "item_xxx" } ``` ### Resposta 400 — 400 ```json { "error": { "message": "old.itemId é obrigatório", "code": "MISSING_ITEM_ID", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Item não encontrado", "code": "ITEM_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/patch-cancelar-item Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Cancelar Assinatura `DELETE /v1/subscriptions/:subscriptionId` **Área:** Assinaturas **Scopes necessários:** `subscriptions/write` Cancela uma assinatura ativa, interrompendo todas as cobranças futuras. **Rota recomendada** para cancelamento (preferir em relação ao PATCH com `action: "cancel"`). A assinatura é marcada como `CANCELED` imediatamente. Ciclos futuros pendentes (`PENDING`, `AWAITING_PAYMENT`) são cancelados. O campo `reason` é opcional e pode ser usado para registrar o motivo do cancelamento. Case de uso: _Como SaaS, quero cancelar a assinatura de um cliente que solicitou encerramento do serviço._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `subscriptionId` | **sim** | ID da assinatura (ex: sub_xxx) - required | ### Request body ```json { "reason": "Cliente solicitou" } ``` ### Campos do body **Opcionais** | Campo | Descrição | |---|---| | `reason` | Motivo do cancelamento | ### Resposta 200 — 200 ```json { "success": true, "message": "Assinatura cancelada com sucesso", "status": "CANCELED", "canceledCycles": 2 } ``` ### Resposta 400 — 400 ```json { "error": { "message": "Assinatura já está cancelada", "code": "SUBSCRIPTION_ALREADY_CANCELED", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Assinatura não encontrada", "code": "SUBSCRIPTION_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/delete-cancelar-assinatura Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Adicionar Item `POST /v1/subscriptions/:subscriptionId/items` **Área:** Assinaturas **Scopes necessários:** `subscriptions/write` Adiciona um novo produto ou serviço a uma assinatura já existente. Informe o `priceId` de um preço previamente cadastrado. Para assinaturas com cartão de crédito, a cobrança é processada imediatamente. Para PIX ou boleto, a resposta inclui `payment.transactionId` — a confirmação chega via **webhook**. Pré-condições: assinatura `ACTIVE` ou `PAST_DUE`. Antes do 1º pagamento confirmado (`currentCycleNumber === 1`), add item retorna `400`. > `billOnNextCycle` adia a cobrança para o próximo ciclo (apenas boleto/PIX; incompatível com cartão ou `ONE_TIME`). Case de uso: _Como SaaS, quero adicionar um módulo extra (add-on) à assinatura de um cliente que já possui um plano base._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `subscriptionId` | **sim** | ID da assinatura (ex: sub_xxx) - required | ### Request body ```json { "priceId": "price_xxx", "quantity": 1, "type": "RECURRING", "billOnNextCycle": false, "dueDate": "2026-04-06", "boletoInstructions": { "fine": 2.0, "interest": 1.0 }, "expirationAfterDueDate": 30 } ``` ### Campos do body **Obrigatórios:** `priceId` | Campo | Descrição | |---|---| | `priceId` | ID do preço do item | **Opcionais** | Campo | Descrição | |---|---| | `quantity` | Quantidade (default 1, mínimo 1) | | `type` | RECURRING ou ONE_TIME (default RECURRING) | | `billOnNextCycle` | Adia cobrança para próximo ciclo (boleto/PIX apenas) | | `dueDate` | Vencimento do boleto/PIX de pro-rata (YYYY-MM-DD) | | `boletoInstructions` | Para assinaturas com boleto | | `expirationAfterDueDate` | Dias após vencimento (0 a 60, default 30) | ### Resposta 200 — 200 cartão ```json { "success": true, "type": "ADD_ITEM", "chargeId": "cha_xxx", "amount": 49.9, "newAmount": 149.8 } ``` ### Resposta 200 — 200 PIX ```json { "success": true, "type": "ADD_ITEM", "paymentMethod": "PIX", "chargeId": "cha_xxx", "payment": { "emvQrCode": "..." } } ``` ### Resposta 400 — 400 pagamento ```json { "error": { "message": "Cartão recusado pela operadora", "code": "PAYMENT_DECLINED", "details": { "declinedCode": "card_declined" }, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` ### Resposta 400 — 400 ```json { "error": { "message": "Assinatura não está ativa", "code": "SUBSCRIPTION_NOT_ACTIVE", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-adicionar-item Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Atualizar Item `PUT /v1/subscriptions/:subscriptionId/items/:itemId` **Área:** Assinaturas **Scopes necessários:** `subscriptions/write` **Rota canônica** para upgrade ou downgrade de plano. Altera o `priceId` ou `quantity` de um item específico. O `subscriptionId` e `itemId` vão na URL. Informe pelo menos `priceId` ou `quantity`. - **Upgrade** (`newTotal > currentTotal`): cobra pro-rata imediatamente (cartão) ou gera boleto/PIX assíncrono. - **Downgrade** (`newTotal <= currentTotal`): efetivado no próximo ciclo, sem cobrança imediata. Pré-condições: assinatura `ACTIVE`, `PAST_DUE` ou `AWAITING_PAYMENT`; item `ACTIVE`. > Falha de pagamento retorna **400** com `PAYMENT_DECLINED` ou `PAYMENT_FAILED` (não 402). ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `subscriptionId` | **sim** | ID da assinatura (ex: sub_xxx) - required | | `itemId` | **sim** | ID do item da assinatura (ex: item_xxx) - required | ### Request body ```json { "priceId": "price_yyy", "quantity": 2, "dueDate": "2026-04-06", "boletoInstructions": { "fine": 2.0, "interest": 1.0 }, "expirationAfterDueDate": 30 } ``` ### Campos do body **Opcionais** | Campo | Descrição | |---|---| | `priceId` | Pelo menos priceId ou quantity é obrigatório | | `quantity` | | | `dueDate` | Vencimento do boleto/PIX de pro-rata (YYYY-MM-DD) | | `boletoInstructions` | Juros, multa e desconto do boleto | | `expirationAfterDueDate` | Dias após vencimento (0 a 60, default 30) | ### Resposta 200 — 200 upgrade ```json { "success": true, "type": "UPGRADE", "chargeId": "cha_xxx", "prorataAmount": 33.5, "newAmount": 199.9 } ``` ### Resposta 200 — 200 downgrade ```json { "success": true, "type": "DOWNGRADE", "effectiveAt": "2024-02-01", "newAmount": 59.9 } ``` ### Resposta 400 — 400 pagamento ```json { "error": { "message": "Cartão recusado por saldo insuficiente", "code": "PAYMENT_DECLINED", "details": { "declinedCode": "insufficient_funds" }, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Item não encontrado", "code": "ITEM_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/put-atualizar-item Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Calcular Pro Rata `POST /v1/subscriptions/:subscriptionId/prorata` **Área:** Assinaturas **Scopes necessários:** `subscriptions/read` Calcula o valor de pro rata para uma troca de plano **sem efetuar cobrança**. Útil para exibir ao cliente o valor exato da mudança antes de confirmar o upgrade. O cálculo considera os dias restantes do ciclo atual. Envie `old` com o preço/quantidade atuais e `new` com o preço/quantidade desejados. Case de uso: _Como SaaS, quero mostrar na interface "Você pagará R$ 45,48 hoje pela diferença proporcional" antes do cliente confirmar o upgrade._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `subscriptionId` | **sim** | ID da assinatura (ex: sub_xxx) - required | ### Request body ```json { "old": { "priceId": "price_xxx", "quantity": 1 }, "new": { "priceId": "price_yyy", "quantity": 1 } } ``` ### Campos do body **Obrigatórios:** `old`, `old.priceId`, `new`, `new.priceId` | Campo | Descrição | |---|---| | `old` | | | `old.priceId` | Preço atual | | `new` | | | `new.priceId` | Novo preço | **Opcionais** | Campo | Descrição | |---|---| | `old.quantity` | | | `new.quantity` | | ### Resposta 200 — 200 ```json { "subscriptionId": "sub_xxx", "currentAmount": 99.9, "newAmount": 199.9, "prorataAmount": 45.48, "remainingDays": 15, "cycleDays": 31, "currentCredit": 48.34, "nextCycleChargeDate": "2024-02-15" } ``` ### Resposta 404 — 404 old ```json { "error": { "message": "Preço antigo não encontrado", "code": "OLD_PRICE_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` ### Resposta 404 — 404 new ```json { "error": { "message": "Preço novo não encontrado", "code": "NEW_PRICE_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` ### Resposta 404 — 404 sub ```json { "error": { "message": "Assinatura não encontrada", "code": "SUBSCRIPTION_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-calcular-pro-rata Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Listar Notas Fiscais `GET /v1/invoices/notas` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/read` Lista as notas fiscais da conta, da mais recente para a mais antiga. Inclui todas as origens: notas geradas por cobranças e assinaturas e também as avulsas, emitidas por POST nesta mesma rota. ### O identificador da nota O campo `invoiceId` é o identificador usado nas demais rotas — consultar, cancelar, reemitir, reenviar e emitir. Na nota avulsa ele é o `ref` que você informou na emissão; nas notas geradas por cobrança, é o identificador da própria cobrança. Não o confunda com o `ref` da resposta, que traz o identificador interno da nota e serve apenas para suporte. ### Status - `PROCESSING` — enviada, a prefeitura ainda não respondeu - `ISSUED` ou `AUTHORIZED` — autorizada. Os dois valores são equivalentes: o primeiro vem da emissão síncrona, o segundo da confirmação assíncrona da prefeitura - `FAILED` ou `ERROR` — recusada. `nf.errors` traz as mensagens da prefeitura - `CANCELED` — cancelada - `REPLACED` — substituída por uma reemissão No filtro `status` os pares são intercambiáveis: `AUTHORIZED` traz também as `ISSUED`, e `ERROR` traz também as `FAILED`. ### Paginação Por cursor: envie em `lastKey` o valor devolvido em `pagination.lastKey`. Enquanto `pagination.hasMore` for `true`, ainda há páginas. `emissor` identifica de qual empresa a nota saiu, útil quando a conta tem mais de uma configuração fiscal. `feeAmount` e `feeStatus` descrevem a taxa de emissão cobrada pela ValidaPay, não um tributo da nota. Case de uso: _Como plataforma, quero conciliar as notas do mês e conferir quais foram autorizadas antes de fechar o faturamento._ ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `lastKey` | **sim** | Cursor da próxima página, de pagination.lastKey - optional | | `search` | **sim** | Busca parcial por nome do tomador ou documento - optional | | `taxId` | **sim** | CPF/CNPJ exato do tomador, apenas dígitos - optional | | `customerName` | **sim** | Nome do tomador - optional | | `status` | **sim** | AUTHORIZED (ou ISSUED), PROCESSING, ERROR (ou FAILED), CANCELED ou REPLACED - optional | | `startDate` | **sim** | Data inicial da emissão, ISO 8601 - optional | | `endDate` | **sim** | Data final da emissão, ISO 8601 - optional | | `limit` | não | Itens por página (default 20) - optional | ### Resposta 200 — 200 ```json { "items": [ { "emissor": { "configId": "unc_1788193720141_65g0zh12p", "cnpj": "99988877000108", "nome": "EMPRESA EXEMPLO LTDA" }, "type": "NFSE", "invoiceId": "nf_1788101026585_uqaspo7bn", "chargeId": null, "customerId": null, "customerName": "Alexandre Souza", "taxId": "11144477735", "amount": 150.00, "emitidaEm": "2026-08-30T14:43:49.719Z", "ref": "2109541", "status": "AUTHORIZED", "feeStatus": "COMPLETED", "feeAmount": 0.37, "nf": { "id": "2109541", "number": "7814", "status": "AUTHORIZED", "url": "https://…", "pdfUrl": "https://…", "xmlPath": "/arquivos/…-nfse.xml", "xmlUrl": "https://…", "verificationCode": "PGRW-2TFA", "rpsNumber": "5053", "rpsSeries": "1", "cnpj": "99988877000108", "issuedAt": "2026-08-30T14:43:49.719Z", "errors": null } } ], "pagination": { "total": 1, "totalPages": 1, "limit": 20, "hasMore": false, "lastKey": null } } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Conta não encontrada", "code": "ACCOUNT_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-listar-notas-fiscais Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Resumo de Notas Fiscais `GET /v1/invoices/notas/summary` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/read` Totais de notas da conta por status, em quantidade e em valor. Sem `startDate` e `endDate`, o resumo cobre todas as notas da conta. Os pares de status são somados juntos: `authorized` inclui as notas `ISSUED` e `AUTHORIZED`, e `error` inclui as `FAILED` e `ERROR`. Case de uso: _Como plataforma, quero mostrar no painel quantas notas foram autorizadas e quantas falharam no mês, sem paginar a listagem inteira._ ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `startDate` | **sim** | Data inicial da emissão, ISO 8601 - optional | | `endDate` | **sim** | Data final da emissão, ISO 8601 - optional | ### Resposta 200 — 200 ```json { "authorizedCount": 128, "authorizedAmount": 45320.75, "canceledCount": 3, "canceledAmount": 890.00, "errorCount": 2, "errorAmount": 450.00, "processingCount": 1, "processingAmount": 150.00, "replacedCount": 2, "replacedAmount": 300.00 } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-resumo-de-notas-fiscais Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Consultar Nota Fiscal `GET /v1/invoices/notas/:notaid` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/read` Retorna uma nota pelo `invoiceId` devolvido na listagem — que na nota avulsa é o `ref` informado na emissão, e na nota de cobrança é o identificador da cobrança. Traz os links do PDF e do XML e o código de verificação quando a nota já está autorizada. Quando a prefeitura recusou, `nf.errors` traz as mensagens do que precisa ser corrigido. Nota inexistente, excluída ou de outra conta responde 404 com `NOTA_NOT_FOUND`. Case de uso: _Como plataforma, quero buscar o PDF de uma nota para anexar ao e-mail que envio ao meu cliente._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `notaid` | **sim** | Notaid | ### Resposta 200 — 200 ```json { "emissor": { "configId": "unc_1788193720141_65g0zh12p", "cnpj": "99988877000108", "nome": "EMPRESA EXEMPLO LTDA" }, "type": "NFSE", "invoiceId": "nf_1788101026585_uqaspo7bn", "chargeId": null, "customerId": null, "customerName": "Alexandre Souza", "taxId": "11144477735", "amount": 150.00, "emitidaEm": "2026-08-30T14:43:49.719Z", "ref": "2109541", "status": "ERROR", "feeStatus": null, "feeAmount": null, "nf": { "id": "2109541", "number": null, "status": "ERROR", "url": null, "pdfUrl": null, "xmlPath": null, "xmlUrl": null, "verificationCode": null, "rpsNumber": null, "rpsSeries": null, "cnpj": "99988877000108", "issuedAt": null, "errors": [ { "mensagem": "Código de tributação nacional do ISS inválido para o município" } ] } } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Nota fiscal não encontrada", "code": "NOTA_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-consultar-nota-fiscal Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Emitir Nota Fiscal `POST /v1/invoices/notas` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/write` Emite uma nota fiscal de serviço avulsa, sem vínculo com cobrança ou assinatura. A emissão é imediata: o `invoiceTiming` da configuração fiscal vale apenas para as notas geradas a partir de cobranças, não para a avulsa. Informe em `configId` qual configuração fiscal usar — uma conta pode ter configurações de mais de uma empresa, e a nota sai no CNPJ da configuração escolhida. Liste as disponíveis em `GET /v1/invoices/notas/config`. O `ref` que você enviar passa a ser o identificador da nota nas demais rotas: consultar, cancelar, reemitir e reenviar. Omitido, a API gera um identificador próprio e o devolve na resposta. O campo `type` indica o modelo do documento fiscal. O único valor aceito hoje é `NFSE` (nota fiscal de serviço), que também é o assumido quando o campo é omitido — qualquer outro valor retorna 400 com o código `NOTA_TYPE_NOT_SUPPORTED`. Outros tipos de nota estarão disponíveis em breve. Envie `type` explicitamente desde já: quando cada modelo for liberado, nenhuma alteração no payload será necessária. O tomador não precisa estar cadastrado. Se o endereço não trouxer `cityCode`, o código IBGE do município é resolvido a partir do CEP — assim como logradouro e bairro, quando faltarem. A resposta volta com status `PROCESSING`: a prefeitura responde de forma assíncrona. Não há evento de webhook para nota fiscal — acompanhe o desfecho em `GET /v1/invoices/notas/{notaId}`, que passa a `AUTHORIZED` ou a `ERROR` com as mensagens da prefeitura. Case de uso: _Como prestador, quero emitir uma nota para um serviço cobrado fora da plataforma, informando apenas o tomador, o valor e a descrição._ ### Request body ```json { "configId": "unc_1776888897617_ppwgo7oef", "type": "NFSE", "amount": 150.00, "descricao": "Consultoria em tecnologia da informação", "ref": "pedido-2026-0912", "customer": { "document": "11144477735", "name": "Alexandre Souza", "email": "alexandre@exemplo.com.br", "phone": "5511987654321", "address": { "zipCode": "01310100", "street": "Avenida Paulista", "number": "1000", "complement": "Sala 5", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP", "cityCode": "3550308" } } } ``` ### Campos do body **Obrigatórios:** `configId`, `amount`, `descricao`, `customer`, `customer.document`, `customer.name`, `customer.address`, `customer.address.zipCode`, `customer.address.street`, `customer.address.number`, `customer.address.neighborhood`, `customer.address.city`, `customer.address.state` | Campo | Descrição | |---|---| | `configId` | Configuração fiscal, de GET /v1/invoices/notas/config | | `amount` | Valor do serviço em reais | | `descricao` | Discriminação do serviço na nota | | `customer` | | | `customer.document` | CPF (11) ou CNPJ (14), apenas dígitos | | `customer.name` | Nome completo ou razão social do tomador | | `customer.address` | | | `customer.address.zipCode` | 8 dígitos, apenas números | | `customer.address.street` | | | `customer.address.number` | | | `customer.address.neighborhood` | | | `customer.address.city` | | | `customer.address.state` | UF com 2 letras | **Opcionais** | Campo | Descrição | |---|---| | `type` | Modelo do documento fiscal; único valor aceito hoje, outros tipos em breve. Padrão: NFSE | | `ref` | Vira o identificador da nota nas demais rotas; se omitida, a API gera uma | | `customer.email` | | | `customer.phone` | | | `customer.address.complement` | | | `customer.address.cityCode` | Código IBGE; resolvido pelo CEP quando ausente | ### Resposta 200 — 200 ```json { "success": true, "status": "PROCESSING", "ref": "nf_1788101026585_uqaspo7bn", "id": "nf_1788101026585_uqaspo7bn", "nfStatus": "processando_autorizacao", "tipo": "nacional", "issuedAt": "2026-08-30T14:43:49.719Z", "internalStatus": "PROCESSING" } ``` ### Resposta 400 — 400 - campos obrigatórios ```json { "error": { "message": "customer.document, amount, descricao e configId são obrigatórios", "code": "MISSING_FIELDS", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` ### Resposta 400 — 400 - configuração inválida ```json { "error": { "message": "Configuração não encontrada ou desabilitada", "code": "NOTA_CONFIG_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-emitir-nota-fiscal Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Emitir Nota de uma Cobrança `POST /v1/invoices/notas/:notaid/emitir` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/write` Emite a nota de uma cobrança que já existe — a que nunca emitiu e também a que falhou. O identificador na URL é o da cobrança: `invoiceId` de uma fatura de assinatura ou `chargeId` de uma cobrança avulsa. Diferente da emissão avulsa, a nota nasce ligada à cobrança: herda cliente, valor e, quando existe, assinatura e ciclo. ### De onde vem a configuração fiscal Na ordem: o `configId` do corpo, depois o da nota anterior, o `nfConfigId` da cobrança e o da assinatura. Não achando nenhum, a resposta é `NF_CONFIG_REQUIRED` e nada é emitido. ### Quando a emissão é recusada - `INVOICE_NOT_FOUND` (404) — cobrança inexistente ou de outra conta - `INVOICE_STATUS_NOT_EMITTABLE` — só emite cobrança pendente, aguardando pagamento ou paga - `NOTA_ALREADY_ISSUED` — já existe nota autorizada, vinculada ou agendada para essa cobrança - `NOTA_PROCESSING` — há uma emissão em andamento aguardando o retorno da prefeitura - `NF_INCOMPLETE_DATA` — faltam dados do tomador; `details` lista exatamente o que falta - `NF_CONFIG_NOT_FOUND` — a configuração informada não existe ou está desabilitada Para conferir os dados antes sem emitir nada, use `POST /v1/invoices/notas/{notaId}/verificar-emissao`. Case de uso: _Como prestador, quero emitir a nota de uma cobrança que ficou sem nota, sem precisar refazer a cobrança._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `notaid` | **sim** | Notaid | ### Request body ```json { "configId": "unc_1776888897617_ppwgo7oef" } ``` ### Campos do body **Opcionais** | Campo | Descrição | |---|---| | `configId` | Configuração fiscal a usar; sem ela vale a da cobrança ou da assinatura | ### Resposta 200 — 200 ```json { "success": true, "invoiceId": "inv_1788101026585_uqaspo7bn", "subscriptionId": "sub_1788101026585_a1b2c3d4e", "cycleNumber": 3, "type": "NFSE", "status": "PROCESSING", "numero": null, "tipo": "nacional" } ``` ### Resposta 400 — 400 - dados incompletos ```json { "error": { "message": "Dados incompletos para emitir a nota fiscal: CEP do cliente, Município do cliente (código IBGE)", "code": "NF_INCOMPLETE_DATA", "details": [ "CEP do cliente", "Município do cliente (código IBGE)" ], "timestamp": "2026-07-14T21:39:36.322Z" } } ``` ### Resposta 400 — 400 - sem emissor ```json { "error": { "message": "Informe o emissor (configId) para emitir a nota fiscal", "code": "NF_CONFIG_REQUIRED", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Cobrança não encontrada", "code": "INVOICE_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-emitir-nota-de-uma-cobranca Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Verificar Dados para Emissão `POST /v1/invoices/notas/:notaid/verificar-emissao` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/write` Confere se uma cobrança tem tudo o que a nota fiscal exige, sem emitir nada. O identificador na URL é o da cobrança, como em `POST /v1/invoices/notas/{notaId}/emitir`. `ready` diz se a emissão passaria agora; `pendencias` lista em português o que falta — CPF ou CNPJ, nome, valor, endereço, CEP, município (código IBGE), logradouro ou bairro do cliente. `configId` traz a configuração fiscal que seria usada, ou `null` quando nenhuma foi encontrada. Diferente da emissão, aqui a ausência de configuração não é erro. A conferência é uma rota própria em vez de um parâmetro na rota de emissão: um flag ignorado por engano emitiria a nota de verdade. Case de uso: _Como plataforma, quero avisar o usuário sobre o cadastro incompleto do cliente antes de tentar emitir a nota e receber a recusa._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `notaid` | **sim** | Notaid | ### Request body ```json { "configId": "unc_1776888897617_ppwgo7oef" } ``` ### Campos do body **Opcionais** | Campo | Descrição | |---|---| | `configId` | Configuração fiscal a conferir; sem ela vale a da cobrança ou da assinatura | ### Resposta 200 — 200 - pronta para emitir ```json { "invoiceId": "inv_1788101026585_uqaspo7bn", "ready": true, "pendencias": [], "configId": "unc_1788193720141_65g0zh12p", "amount": 150.00 } ``` ### Resposta 200 — 200 - com pendências ```json { "invoiceId": "inv_1788101026585_uqaspo7bn", "ready": false, "pendencias": [ "CEP do cliente", "Município do cliente (código IBGE)" ], "configId": "unc_1788193720141_65g0zh12p", "amount": 150.00 } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-verificar-dados-para-emissao Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Cancelar Nota Fiscal `DELETE /v1/invoices/notas/:notaid` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/write` Cancela na prefeitura uma nota fiscal já autorizada. O identificador é o `invoiceId` da listagem. O motivo vai na query string, e não no corpo: parte dos clientes HTTP descarta body em requisições DELETE. Só é possível cancelar notas da própria conta e que estejam autorizadas. O status é reconferido antes do cancelamento: nota em processamento ou já cancelada é recusada com `NF_NOT_AUTHORIZED`. O prazo de cancelamento é definido pela prefeitura do município emissor. Passada essa janela, o cancelamento é recusado com `NF_CANCEL_FAILED` e a correção passa a exigir substituição da nota. Case de uso: _Como prestador, quero cancelar uma nota emitida com valor errado, dentro do prazo permitido pelo município._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `notaid` | **sim** | Notaid | ### Query parameters | Campo | Obrigatório | Descrição | |---|---|---| | `motivo` | não | Justificativa enviada à prefeitura - required | ### Resposta 200 — 200 ```json { "success": true, "invoiceId": "nf_1788101026585_uqaspo7bn" } ``` ### Resposta 400 — 400 - não autorizada ```json { "error": { "message": "Nota fiscal não está autorizada para cancelamento", "code": "NF_NOT_AUTHORIZED", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Nota fiscal não encontrada", "code": "NOTA_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/delete-cancelar-nota-fiscal Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Reemitir Nota Fiscal `POST /v1/invoices/notas/:notaid/reemitir` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/write` Gera uma nova nota para uma emissão que falhou na prefeitura. O identificador é o `invoiceId` da listagem. Só vale para notas que não foram autorizadas: uma nota já autorizada é recusada com `NOTA_ALREADY_ISSUED` — nesse caso o caminho é cancelar e emitir de novo. A nota anterior fica com status `REPLACED` e a nova assume o lugar dela. A configuração fiscal usada é a mesma da nota anterior. Corrija a causa da recusa antes de reemitir: a mensagem da prefeitura está em `nf.errors`, na consulta da nota. Case de uso: _Como prestador, quero reprocessar uma nota recusada por erro de cadastro, depois de corrigir a configuração fiscal._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `notaid` | **sim** | Notaid | ### Resposta 200 — 200 ```json { "success": true, "invoiceId": "nf_1788101026585_uqaspo7bn", "subscriptionId": null, "cycleNumber": null, "type": "NFSE", "status": "PROCESSING", "numero": null, "tipo": "nacional" } ``` ### Resposta 400 — 400 - já autorizada ```json { "error": { "message": "Nota já autorizada — não pode ser reemitida", "code": "NOTA_ALREADY_ISSUED", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-reemitir-nota-fiscal Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Reenviar Nota por E-mail `POST /v1/invoices/notas/:notaid/reenviar` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/write` Reenvia por e-mail uma nota já autorizada. O identificador é o `invoiceId` da listagem. Aceita até 10 destinatários por chamada — acima disso a resposta é `TOO_MANY_EMAILS`. Notas que ainda não foram autorizadas são recusadas com `NOTA_NOT_ISSUED`. A nota segue anexada em PDF e XML. Case de uso: _Como prestador, quero reenviar a nota para um segundo e-mail do cliente, sem precisar baixar e anexar o PDF manualmente._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `notaid` | **sim** | Notaid | ### Request body ```json { "emails": [ "financeiro@exemplo.com.br", "contabilidade@exemplo.com.br" ] } ``` ### Campos do body **Obrigatórios:** `emails` | Campo | Descrição | |---|---| | `emails` | No máximo 10 destinatários | ### Resposta 200 — 200 ```json { "success": true, "emails": [ "financeiro@exemplo.com.br", "contabilidade@exemplo.com.br" ] } ``` ### Resposta 400 — 400 - sem e-mail ```json { "error": { "message": "Informe ao menos um e-mail", "code": "EMAILS_REQUIRED", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-reenviar-nota-por-e-mail Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Listar Configurações Fiscais `GET /v1/invoices/notas/config` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/read` Lista as configurações fiscais da conta. Use o `id` de cada uma como `configId` ao emitir uma nota avulsa, e como `nfConfigId` em cobranças, produtos e assinaturas. A resposta traz também `defaults`: os valores que a API preencheria sozinha a partir do cadastro da conta — CNPJ, endereço, contato e código IBGE do município — úteis para montar a tela de cadastro já preenchida. Segredos nunca são devolvidos. De `prefeitura` vêm o `login`, `has_senha` e a numeração do RPS; do certificado, se existe e a validade. Case de uso: _Como plataforma, quero listar as empresas emissoras da conta para escolher por qual emitir cada nota._ ### Resposta 200 — 200 ```json { "configs": [ { "id": "unc_1788193720141_65g0zh12p", "accountId": "460851686", "config_name": "Matriz", "enabled": true, "invoiceTiming": "IMMEDIATE", "codigo_tributacao_nacional_iss": "010701", "tributacao_iss": 1, "tipo_retencao_iss": 1, "serie_dps": "1", "prestador": { "cnpj": "99988877000108", "nome_fantasia": "EMPRESA EXEMPLO LTDA", "inscricao_municipal": "1234567", "codigo_municipio": "4205407", "codigo_municipio_prestacao": "4205407", "codigo_opcao_simples_nacional": 1, "regime_especial_tributacao": 0 }, "prefeitura": { "login": "usuario-do-portal", "has_senha": true, "serie_rps": "1", "proximo_numero_rps": 145 }, "certificate": { "has_certificate": true, "expiry_date": "2026-11-18T11:01:15.000Z" }, "createdAt": "2026-08-31T16:28:43.167Z", "updatedAt": "2026-08-31T16:28:43.167Z" } ], "defaults": { "prestador": { "cnpj": "99988877000108", "nome_fantasia": "EMPRESA EXEMPLO LTDA", "email": "fiscal@exemplo.com.br", "telefone": "5548999999999", "codigo_municipio": "4205407", "codigo_municipio_prestacao": "4205407", "endereco": { "logradouro": "RUA DAS PALMEIRAS", "numero": "110", "bairro": "CENTRO", "cep": "88010000", "uf": "SC" } }, "responsavel": { "nome": "Maria Souza", "cpf": "11144477735" } } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-listar-configuracoes-fiscais Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Consultar Configuração Fiscal `GET /v1/invoices/notas/config/:configid` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/read` Retorna uma configuração fiscal pelo `id`. Segredos nunca são devolvidos: a senha do certificado e a senha da prefeitura ficam de fora. `certificate.expiry_date` traz o vencimento do certificado, e `prefeitura.has_senha` diz se há credencial gravada. Configuração inexistente ou de outra conta responde `{}`, e não 404. Case de uso: _Como plataforma, quero conferir a validade do certificado de uma empresa antes que ela pare de emitir._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `configid` | **sim** | Configid | ### Resposta 200 — 200 ```json { "id": "unc_1788193720141_65g0zh12p", "accountId": "460851686", "config_name": "Matriz", "enabled": true, "invoiceTiming": "IMMEDIATE", "codigo_tributacao_nacional_iss": "010701", "tributacao_iss": 1, "tipo_retencao_iss": 1, "serie_dps": "1", "descricao_servico": "Prestação de Serviços", "prestador": { "cnpj": "99988877000108", "nome_fantasia": "EMPRESA EXEMPLO LTDA", "inscricao_municipal": "1234567", "codigo_municipio": "4205407", "codigo_municipio_prestacao": "4205407", "codigo_opcao_simples_nacional": 1, "regime_especial_tributacao": 0 }, "prefeitura": { "login": "usuario-do-portal", "has_senha": true, "serie_rps": "1", "proximo_numero_rps": 145 }, "certificate": { "has_certificate": true, "expiry_date": "2026-11-18T11:01:15.000Z" }, "createdAt": "2026-08-31T16:28:43.167Z", "updatedAt": "2026-08-31T16:28:43.167Z" } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/get-consultar-configuracao-fiscal Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Criar Configuração Fiscal `POST /v1/invoices/notas/config` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/write` Cadastra a empresa emissora: CNPJ, regime tributário, certificado digital e os tributos que entram na nota. O `id` devolvido aqui é o `configId` da emissão avulsa e o `nfConfigId` de cobranças, produtos e assinaturas. Uma conta pode ter mais de uma configuração — o CNPJ do prestador define de qual empresa a nota sai. O que não for enviado é preenchido a partir do cadastro da conta: CNPJ, endereço, contato e código IBGE do município. Enviar explicitamente evita depender desses dados. A criação valida e registra a empresa emissora, incluindo o certificado. Se essa etapa falhar, nada é gravado e o certificado enviado é descartado — não sobra configuração pela metade. Não envie `id` no corpo: com ele a chamada vira atualização da configuração existente. ### Municipal ou nacional: quem decide é o município O código IBGE em `prestador.codigo_municipio` determina por qual padrão a nota sai, e isso muda quais campos tributários são lidos: - **NFS-en nacional** — padrão nacional da NFS-e, adotado pela maior parte dos municípios. Usa `codigo_tributacao_nacional_iss`, `tributacao_iss`, `tipo_retencao_iss`, `serie_dps` e os campos de PIS/COFINS ou do Simples, conforme o regime. - **NFS-e municipal** — municípios com sistema próprio. Usa `item_lista_servico`, `aliquota_iss`, `iss_retido`, `natureza_operacao` e, quando o município exige, `codigo_cnae` e `codigo_tributario_municipio`. Você não precisa escolher: a rota é resolvida na emissão, a partir do município do prestador. `tipo_nf` força um dos dois padrões e só faz sentido quando o município aceita ambos. Na dúvida sobre em qual padrão o seu município está, preencha os dois conjuntos — o que não se aplica é ignorado. ### Credencial da prefeitura e numeração do RPS O certificado digital A1 basta na maior parte dos municípios. Os que têm sistema próprio podem exigir também uma credencial do portal, enviada em `prefeitura` — nem todos pedem `login`, e há municípios em que só a senha é necessária. Confira o portal do seu município antes de preencher. Em parte deles o que vai em `senha` é uma chave digital gerada no perfil do usuário, e não a senha de acesso ao portal — usar a senha errada só aparece como falha de autenticação na primeira emissão. ### Numeração Cada padrão tem a sua, e as duas continuam a sequência que a prefeitura já registrou para a empresa — em branco, a numeração começa do início. - **NFS-e municipal** — `prefeitura.serie_rps` e `prefeitura.proximo_numero_rps`. - **NFS-en nacional** — `serie_dps`, no primeiro nível do corpo. A série declarada no cadastro é a mesma que vai em cada emissão e precisa bater com a registrada na prefeitura; a sequência dos números é mantida pela ValidaPay. ### Quando a nota é emitida `invoiceTiming` define o momento da emissão das notas geradas por cobrança: - `IMMEDIATE` — junto com a cobrança. É o padrão. - `AFTER_CONFIRMATION` — somente após a confirmação do pagamento. - `DAYS_AFTER_CONFIRMATION` — `daysAfterConfirmation` dias depois da confirmação (padrão 1). A emissão avulsa por `POST /v1/invoices/notas` sai sempre na hora, qualquer que seja o valor configurado. > ⚠️ **Atenção:** configurações criadas pelo painel trazem também `quando_emitir`, com os mesmos três valores. Ele é apenas o espelho gravado pela tela — quem define o agendamento é `invoiceTiming`. ### Campos exigidos pelo regime O regime vem de `prestador.codigo_opcao_simples_nacional`: - **1, não optante** — exige `situacao_tributaria_pis_cofins`, `aliquota_pis` e `aliquota_cofins`. - **2 (MEI) e 3 (ME/EPP)** — exigem `percentual_total_tributos_simples_nacional`. Faltando um deles, a configuração não é gravada e a resposta traz a mensagem da validação com o código `INTERNAL_ERROR`. Case de uso: _Como plataforma, quero cadastrar a empresa emissora e o certificado digital por API, para habilitar a emissão de notas sem passar pelo painel._ ### Request body ```json { "config_name": "Matriz", "enabled": true, "razao_social": "EMPRESA EXEMPLO LTDA", "invoiceTiming": "IMMEDIATE", "daysAfterConfirmation": 1, "tipo_nf": "nacional", "descricao_servico": "Prestação de Serviços", "enviar_email_destinatario": true, "codigo_tributacao_nacional_iss": "010701", "tributacao_iss": 1, "tipo_retencao_iss": 1, "serie_dps": "1", "situacao_tributaria_pis_cofins": "01", "aliquota_pis": 0.65, "aliquota_cofins": 3, "aliquota_csll": 0, "aliquota_irrf": 0, "tipo_retencao_pis_cofins": 0, "percentual_total_tributos_federais": 5.65, "percentual_total_tributos_estaduais": 0, "percentual_total_tributos_municipais": 2, "percentual_total_tributos_simples_nacional": 6, "regime_tributario_simples_nacional": 1, "item_lista_servico": "07.02", "aliquota_iss": 2, "iss_retido": false, "natureza_operacao": "1", "codigo_cnae": "6201500", "codigo_tributario_municipio": "620150001", "prestador": { "cnpj": "99988877000108", "inscricao_municipal": "1234567", "inscricao_estadual": "", "nome_fantasia": "EMPRESA EXEMPLO LTDA", "email": "fiscal@exemplo.com.br", "telefone": "5548999999999", "codigo_municipio": "4205407", "codigo_municipio_prestacao": "4205407", "codigo_opcao_simples_nacional": 1, "regime_especial_tributacao": 0, "endereco": { "logradouro": "RUA DAS PALMEIRAS", "numero": "110", "complemento": "", "bairro": "CENTRO", "municipio": "Florianópolis", "cep": "88010000", "uf": "SC" } }, "prefeitura": { "login": "usuario-do-portal", "senha": "chave-ou-senha-do-portal", "serie_rps": "1", "proximo_numero_rps": 1 }, "responsavel": { "nome": "Maria Souza", "cpf": "11144477735" }, "certificate": { "pfx_base64": "MIIQ…", "password": "senha-do-certificado" } } ``` ### Campos do body **Obrigatórios:** `codigo_tributacao_nacional_iss`, `tributacao_iss`, `tipo_retencao_iss`, `situacao_tributaria_pis_cofins`, `aliquota_pis`, `aliquota_cofins`, `percentual_total_tributos_simples_nacional`, `prestador`, `prestador.cnpj`, `prestador.codigo_municipio`, `prestador.codigo_opcao_simples_nacional`, `prestador.regime_especial_tributacao`, `certificate.pfx_base64`, `certificate.password` | Campo | Descrição | |---|---| | `codigo_tributacao_nacional_iss` | NFS-en: código de tributação nacional do ISS, 6 dígitos | | `tributacao_iss` | NFS-en: 1 tributável, 2 imunidade, 3 exportação, 4 não incidência | | `tipo_retencao_iss` | NFS-en: 1 não retido, 2 retido pelo tomador, 3 pelo intermediário | | `situacao_tributaria_pis_cofins` | se não optante pelo Simples - NFS-en | | `aliquota_pis` | se não optante - Percentual aplicado sobre o valor do serviço | | `aliquota_cofins` | se não optante - Percentual aplicado sobre o valor do serviço | | `percentual_total_tributos_simples_nacional` | se optante pelo Simples (MEI ou ME/EPP) | | `prestador` | | | `prestador.cnpj` | 14 dígitos, apenas números | | `prestador.codigo_municipio` | Código IBGE do município, 7 dígitos; define o padrão de emissão | | `prestador.codigo_opcao_simples_nacional` | NÚMERO, não string. 1 não optante, 2 MEI, 3 ME/EPP | | `prestador.regime_especial_tributacao` | 0 nenhum | | `certificate.pfx_base64` | Certificado A1 em base64; anda junto com password | | `certificate.password` | | **Opcionais** | Campo | Descrição | |---|---| | `config_name` | Nome para diferenciar as configurações da conta | | `enabled` | Default true; configuração desabilitada não emite | | `razao_social` | Razão social da empresa emissora; sem ela vale o nome_fantasia | | `invoiceTiming` | Momento da emissão nas notas geradas por cobrança. Default IMMEDIATE (valores: IMMEDIATE, AFTER_CONFIRMATION, DAYS_AFTER_CONFIRMATION) | | `daysAfterConfirmation` | Dias após a confirmação, quando invoiceTiming for DAYS_AFTER_CONFIRMATION. Default 1 (mín.: 1) | | `tipo_nf` | Força o padrão de emissão; por padrão quem decide é o município do prestador (valores: municipal, nacional) | | `descricao_servico` | Discriminação padrão do serviço, usada quando a cobrança não traz o nome do item | | `enviar_email_destinatario` | Default true; a nota é enviada ao tomador por e-mail na autorização | | `serie_dps` | NFS-en: série da DPS, declarada no cadastro e enviada em cada emissão. Default 1 | | `aliquota_csll` | Percentual; vira o valor de CSLL da nota | | `aliquota_irrf` | Percentual; vira o valor de IRRF da nota | | `tipo_retencao_pis_cofins` | 0 não retido | | `percentual_total_tributos_federais` | Percentual informado na nota | | `percentual_total_tributos_estaduais` | Percentual informado na nota | | `percentual_total_tributos_municipais` | Percentual informado na nota | | `regime_tributario_simples_nacional` | 1 federais e municipal pelo SN. Default 1 | | `item_lista_servico` | Obrigatório na NFS-e municipal: item da lista de serviços, formato NN.NN | | `aliquota_iss` | Obrigatório na NFS-e municipal: alíquota do ISS em percentual | | `iss_retido` | NFS-e municipal: ISS retido pelo tomador. Default false | | `natureza_operacao` | NFS-e municipal. Default 1 | | `codigo_cnae` | NFS-e municipal; exigido por parte dos municípios | | `codigo_tributario_municipio` | NFS-e municipal; exigido por parte dos municípios | | `prestador.inscricao_municipal` | | | `prestador.inscricao_estadual` | | | `prestador.nome_fantasia` | | | `prestador.email` | | | `prestador.telefone` | | | `prestador.codigo_municipio_prestacao` | Default igual a codigo_municipio | | `prestador.endereco` | Preenchido pelo cadastro da conta quando ausente | | `prestador.endereco.logradouro` | | | `prestador.endereco.numero` | | | `prestador.endereco.complemento` | | | `prestador.endereco.bairro` | | | `prestador.endereco.municipio` | | | `prestador.endereco.cep` | | | `prestador.endereco.uf` | | | `prefeitura` | Credencial do portal e numeração do RPS, na NFS-e municipal | | `prefeitura.login` | Só nos municípios que pedem login | | `prefeitura.senha` | Em parte dos municípios é a chave digital, não a senha de acesso | | `prefeitura.serie_rps` | Série do RPS registrada na prefeitura | | `prefeitura.proximo_numero_rps` | Número do próximo RPS a emitir (mín.: 1) | | `responsavel` | Guardado no cadastro; não vai para a nota | | `responsavel.nome` | | | `responsavel.cpf` | | | `certificate` | Sem certificado a prefeitura normalmente recusa a empresa | ### Resposta 201 — 201 ```json { "id": "unc_1788193720141_65g0zh12p", "accountId": "460851686", "config_name": "Matriz", "enabled": true, "invoiceTiming": "IMMEDIATE", "codigo_tributacao_nacional_iss": "010701", "tributacao_iss": 1, "tipo_retencao_iss": 1, "serie_dps": "1", "descricao_servico": "Prestação de Serviços", "prestador": { "cnpj": "99988877000108", "nome_fantasia": "EMPRESA EXEMPLO LTDA", "inscricao_municipal": "1234567", "codigo_municipio": "4205407", "codigo_municipio_prestacao": "4205407", "codigo_opcao_simples_nacional": 1, "regime_especial_tributacao": 0 }, "prefeitura": { "login": "usuario-do-portal", "has_senha": true, "serie_rps": "1", "proximo_numero_rps": 145 }, "certificate": { "has_certificate": true, "expiry_date": "2026-11-18T11:01:15.000Z" }, "createdAt": "2026-08-31T16:28:43.167Z", "updatedAt": "2026-08-31T16:28:43.167Z" } ``` ### Resposta 400 — 400 - sincronização ```json { "error": { "message": "Mensagem devolvida pela prefeitura", "code": "NF_CONFIG_SYNC_FAILED", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` ### Resposta 500 — 500 - regime incompleto ```json { "error": { "message": "aliquota_pis é obrigatório para regime Não Optante", "code": "INTERNAL_ERROR", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/post-criar-configuracao-fiscal Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Atualizar Configuração Fiscal `PUT /v1/invoices/notas/config/:configid` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/write` Atualiza uma configuração fiscal. Envie apenas os campos que mudam — os demais são preservados. > ⚠️ **Atenção:** o merge é por campo do primeiro nível, não por campo aninhado. Enviar `prestador` com dois campos substitui o objeto `prestador` inteiro, apagando o que não veio. O mesmo vale para `endereco` e `certificate`: monte o objeto completo antes de enviar. `prefeitura` é a exceção: os campos enviados são mesclados com os já gravados, então dá para alterar só a série do RPS sem reenviar a senha. Enviar `null` em um campo o remove da configuração. `certificate` com `pfx_base64` e `password` substitui o certificado e revalida a empresa emissora; o certificado anterior é apagado, a menos que outra configuração da conta use o mesmo arquivo. Qualquer alteração revalida a empresa emissora. Se essa etapa falhar, nada é gravado. Case de uso: _Como plataforma, quero trocar o certificado digital antes do vencimento, sem recriar a configuração._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `configid` | **sim** | Configid | ### Request body ```json { "config_name": "Matriz", "enabled": true, "invoiceTiming": "AFTER_CONFIRMATION", "daysAfterConfirmation": 3, "descricao_servico": "Consultoria em tecnologia da informação", "codigo_tributacao_nacional_iss": "010701", "tributacao_iss": 1, "tipo_retencao_iss": 1, "aliquota_iss": 2, "item_lista_servico": "07.02", "serie_dps": "1", "prefeitura": { "login": "usuario-do-portal", "senha": "chave-ou-senha-do-portal", "serie_rps": "1", "proximo_numero_rps": 145 }, "certificate": { "pfx_base64": "MIIQ…", "password": "senha-do-certificado" } } ``` ### Campos do body **Obrigatórios:** `certificate.pfx_base64`, `certificate.password` | Campo | Descrição | |---|---| | `certificate.pfx_base64` | | | `certificate.password` | | **Opcionais** | Campo | Descrição | |---|---| | `config_name` | | | `enabled` | false desliga a emissão sem apagar a configuração | | `invoiceTiming` | Momento da emissão nas notas geradas por cobrança (valores: IMMEDIATE, AFTER_CONFIRMATION, DAYS_AFTER_CONFIRMATION) | | `daysAfterConfirmation` | Só com invoiceTiming DAYS_AFTER_CONFIRMATION (mín.: 1) | | `descricao_servico` | | | `codigo_tributacao_nacional_iss` | | | `tributacao_iss` | | | `tipo_retencao_iss` | | | `aliquota_iss` | NFS-e municipal | | `item_lista_servico` | NFS-e municipal | | `serie_dps` | NFS-en: série da DPS | | `prefeitura` | Mesclado com o que já está gravado; envie só o que muda | | `prefeitura.login` | | | `prefeitura.senha` | Só quando a credencial muda | | `prefeitura.serie_rps` | Série do RPS registrada na prefeitura | | `prefeitura.proximo_numero_rps` | Número do próximo RPS a emitir (mín.: 1) | | `certificate` | Só para substituir o certificado | ### Resposta 200 — 200 ```json { "id": "unc_1788193720141_65g0zh12p", "accountId": "460851686", "config_name": "Matriz", "enabled": true, "invoiceTiming": "IMMEDIATE", "codigo_tributacao_nacional_iss": "010701", "tributacao_iss": 1, "tipo_retencao_iss": 1, "serie_dps": "1", "descricao_servico": "Prestação de Serviços", "prestador": { "cnpj": "99988877000108", "nome_fantasia": "EMPRESA EXEMPLO LTDA", "inscricao_municipal": "1234567", "codigo_municipio": "4205407", "codigo_municipio_prestacao": "4205407", "codigo_opcao_simples_nacional": 1, "regime_especial_tributacao": 0 }, "prefeitura": { "login": "usuario-do-portal", "has_senha": true, "serie_rps": "1", "proximo_numero_rps": 145 }, "certificate": { "has_certificate": true, "expiry_date": "2026-11-18T11:01:15.000Z" }, "createdAt": "2026-08-31T16:28:43.167Z", "updatedAt": "2026-08-31T16:28:43.167Z" } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Configuração não encontrada", "code": "NOTA_CONFIG_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/put-atualizar-configuracao-fiscal Contrato OpenAPI: https://docs.validapay.com.br/openapi.json --- # Excluir Configuração Fiscal `DELETE /v1/invoices/notas/config/:configid` **Área:** Notas Fiscais **Scopes necessários:** `nota.fiscal/write` Remove uma configuração fiscal da conta. A exclusão vale para a plataforma. As notas já emitidas por ela não são afetadas. Case de uso: _Como plataforma, quero remover a configuração de uma empresa que deixou de operar._ ### Path parameters | Campo | Obrigatório | Descrição | |---|---|---| | `configid` | **sim** | Configid | ### Resposta 200 — 200 ```json { "success": true } ``` ### Resposta 404 — 404 ```json { "error": { "message": "Configuração não encontrada", "code": "NOTA_CONFIG_NOT_FOUND", "details": null, "timestamp": "2026-07-14T21:39:36.322Z" } } ``` --- Página: https://docs.validapay.com.br/documentacao-validapay2/delete-excluir-configuracao-fiscal Contrato OpenAPI: https://docs.validapay.com.br/openapi.json