# Introdução (/guias) O que a API faz, por onde começar e onde estão as URLs da sua integração. A API da Gates2b recebe pagamentos por PIX, boleto e cartão e cripto, cobra assinaturas recorrentes e avisa o seu sistema, por webhook, quando o dinheiro entra. Esta documentação cobre tudo o que você precisa para integrar pelo backend. ## Comece por aqui Uma integração completa passa por quatro etapas, nesta ordem: *Figura: Do cadastro à primeira cobrança confirmada: as quatro etapas de uma integração.* - Libere o IP do servidor: Só IPs cadastrados podem usar a chave. - Gere a chave de API: No painel, em Integração. - Inscreva-se nos webhooks: Uma URL do seu backend recebe charge.paid. - Crie cobranças: POST /charge e o cliente paga. - [Autenticação](/guias/autenticacao): Gere a chave de API e envie no header `Authorization`. - [Liberação de IP](/guias/liberacao-de-ip): Cadastre os IPs dos seus servidores antes da primeira chamada. - [Primeira cobrança](/guias/primeira-cobranca): Crie uma cobrança PIX e receba a confirmação do pagamento. - [Webhooks](/guias/webhooks): Receba eventos assinados em vez de consultar a API. ## Qual endpoint usar | Para | Use | | --- | --- | | Cobrança avulsa, em qualquer meio de pagamento | [`POST /charge`](/api-reference/endpoint/charge/create) | | Cobrança recorrente | [`POST /plan`](/api-reference/endpoint/subscription/plan/create) e [`POST /subscription`](/api-reference/endpoint/subscription/subscription/create) | | Consultar uma cobrança pelo seu número de pedido | [`GET /charge?externalReference=`](/api-reference/endpoint/charge/find-by-reference) | | Reembolsar uma cobrança | [`POST /charge/{chargeId}/refund`](/api-reference/endpoint/charge/refund) | | Saber quando uma cobrança foi paga | [`POST /webhook-subscriptions`](/api-reference/endpoint/webhook-subscription/create) | | Testar se a chave de API está válida | [`GET /api-key/validate`](/api-reference/endpoint/api-key-validate) | Os endpoints de **invoices** (`/invoices`, `/refunds/invoice`) atendem integrações antigas. Integração nova usa `/charge`. ## URL base Todas as chamadas vão para: ```text "https://api.gates2b.com" ``` O painel, onde você gera a chave e cadastra IPs, fica em [https://painel.gates2b.com](https://painel.gates2b.com). ## Convenções [#convenções] - Toda requisição e toda resposta é JSON. Envie `Content-Type: application/json`. - Não envie corpo em `GET`: a requisição é recusada com `403`. - Valores em dinheiro de cobranças e reembolsos são **strings com duas casas decimais** (`"10.00"`). Planos usam **inteiro em centavos** (`amountCents: 9990`). - Datas seguem ISO 8601. Os endpoints de cobrança e assinatura respondem em UTC; os de invoice, no horário de Brasília (UTC−3). - Ids de cobrança, assinatura e inscrição de webhook são strings (ULID ou UUID). Ids de invoice são inteiros. ## Integração com assistentes de IA [#integração-com-assistentes-de-ia] A doc inteira está disponível em texto para Cursor, Claude Code, Copilot e afins: - [`/llms.txt`](/llms.txt): índice das páginas. - [`/llms-full.txt`](/llms-full.txt): todo o conteúdo, com o contrato de cada endpoint. - Qualquer página em markdown: acrescente `.md` ao endereço (por exemplo, [`/guias/autenticacao.md`](/guias/autenticacao.md)). --- # Assinatura por cartão (/guias/assinatura-por-cartao) Do checkout à cobrança de cada ciclo, o cancelamento e como colocar de volta em sincronia uma assinatura de cartão. A assinatura por cartão usa os mesmos endpoints do Pix Automático. O que muda é o plano: com `paymentMethods: ["CREDIT_CARD"]`, a criação devolve um link de checkout no lugar do código Pix. O pagador cadastra o cartão nessa página; os dados do cartão não passam pela Gates2b. *Figura: Assinatura por cartão: o pagador cadastra o cartão no checkout, cada ciclo pago chega como charge.paid e a reconciliação corrige o que ficou fora de sincronia.* - Seu servidor → API Gates2b: POST /subscription - API Gates2b → Seu servidor: activation.checkout.url - Seu servidor → Pagador: envia o link (24 h) - Pagador → Checkout do cartão: cadastra o cartão - Checkout do cartão → API Gates2b: checkout concluído - API Gates2b → API Gates2b: status ACTIVE + nextBillingAt - Checkout do cartão → API Gates2b: ciclo pago - API Gates2b → Seu servidor: webhook charge.paid - Seu servidor → API Gates2b: reconcile, se preciso O primeiro ciclo é cobrado quando o pagador conclui o checkout; os seguintes, no mesmo dia a cada período (`MONTHLY`: todo mês nessa data). Se algum aviso entre a operadora e a Gates2b se perder, o último passo, a reconciliação, coloca o registro de volta em ordem. ## 1. Criar o plano e a assinatura Crie um plano de cartão em [Criar plano](../api-reference/endpoint/subscription/plan/create.mdx): ```json { "name": "Plano Mensal Premium", "amountCents": 9990, "frequency": "MONTHLY", "type": "RECURRENT", "paymentMethods": ["CREDIT_CARD"] } ``` Depois chame [Criar assinatura](../api-reference/endpoint/subscription/subscription/create.mdx). Do cliente, o cartão exige só `name` e `email`; documento e endereço são opcionais, o que permite assinante de fora do Brasil. ```json { "planId": "01JB7Y9C8D7E6F5G4H3J2K1M0N", "dayGenerateCharge": 25, "customer": { "name": "Maria Souza", "email": "cliente@example.com" }, "gatewayOptions": { "redirectUrl": "https://sualoja.example.com/assinatura/obrigado", "cancelUrl": "https://sualoja.example.com/assinatura/cancelada" } } ``` A assinatura nasce em `AWAITING_PAYER_AUTHORIZATION` e **nada é cobrado** nesse momento. A resposta traz o link em `activation.checkout.url`: ```json "activation": { "status": "open", "pixRecurring": null, "checkout": { "url": "https://checkout.example.com/session/a1B2c3D4", "expiresAt": 1780059900 }, "nextBillingAt": null, "postCancelCycles": null } ``` | Campo | O que é | | --- | --- | | `checkout.url` | O link que o pagador abre para cadastrar o cartão. O domínio pode mudar; não fixe no seu código. | | `checkout.expiresAt` | Expiração da sessão, em segundos desde 1970 (epoch). A sessão dura 24 horas. | | `status` | Estado da sessão: `open` na criação, `complete` depois que o pagador conclui. | | `nextBillingAt` | Próxima cobrança. `null` até o pagador concluir o checkout. | ### Erros na criação [#erros-na-criação] | Status | Quando | O que fazer | | --- | --- | --- | | `400` | Falta `name` ou `email` no cliente. | A `message` diz o que falta. O cliente fica cadastrado: complete os dados com [Atualizar cliente](../api-reference/endpoint/subscription/customer/update.mdx) e repita a chamada com `customerId`. | | `400` | O plano tem `installmentCount`. | Use um plano sem `installmentCount`. No cartão a recorrência é contínua até o cancelamento. | | `400` | `redirectUrl` ou `cancelUrl` não é URL absoluta com `http` ou `https`. | Envie a URL completa, como `https://sualoja.example.com/obrigado`. | | `501` | O plano tem `["PIX", "CREDIT_CARD"]`, ou `passthroughFees: true`. | Use só `["CREDIT_CARD"]`, sem repasse de tarifa. | Assinatura de cartão nunca fica em `PENDING_CUSTOMER`: cadastro incompleto é recusado na criação. ## 2. Autorização pelo pagador [#2-autorização-pelo-pagador] Envie `activation.checkout.url` ao pagador. Enquanto ele não conclui o checkout, a assinatura fica em `AWAITING_PAYER_AUTHORIZATION` e `needsPayerAuthorization` vem `true`. A sessão expira em 24 horas e não é renovada. Se o pagador não concluir a tempo, [cancele a assinatura](../api-reference/endpoint/subscription/subscription/status.mdx) e crie outra. Depois do checkout, o pagador volta para `gatewayOptions.redirectUrl`; se desistir, para `gatewayOptions.cancelUrl`. Sem essas URLs, valem os endereços padrão da conta. `cancelUrl` não herda `redirectUrl`, para quem desistiu não cair na sua página de sucesso. As URLs ficam gravadas na assinatura. ## 3. Ativação [#3-ativação] Quando o pagador conclui o checkout, a assinatura vai para `ACTIVE` e `activation.nextBillingAt` passa a trazer a data da próxima cobrança. O ciclo conta a partir do dia em que o pagador concluiu o checkout, **não** do `dayGenerateCharge`. No cartão, `dayGenerateCharge` é só informativo: para mostrar a próxima cobrança, use `activation.nextBillingAt`. Se o aviso de conclusão do checkout se perder, a assinatura já cobra o cartão mas continua em `AWAITING_PAYER_AUTHORIZATION` do nosso lado. A [reconciliação](#colocando-a-assinatura-de-volta-em-sincronia) corrige isso. ## 4. Ciclos de cobrança [#4-ciclos-de-cobrança] A cada ciclo pago no cartão: - uma cobrança `PAID` é criada, com o `externalReference` da assinatura. O mesmo ciclo nunca gera duas cobranças; - o valor é creditado no seu saldo e o evento `charge.paid` é enviado às suas [inscrições de webhook](/guias/webhooks); - ciclos de valor zero (período de teste, ajuste proporcional) não geram cobrança. Quando um ciclo falha, a operadora do cartão faz as novas tentativas. Nesta versão, a falha de um ciclo não muda o status da assinatura nem gera aviso. ## 5. Cancelamento Uma assinatura chega a `CANCELLED` por três caminhos: - **Por você**: [Cancelar assinatura](../api-reference/endpoint/subscription/subscription/status.mdx). - **Pelo pagador**, no portal do assinante. - **Pela operadora**, quando as tentativas de cobrança se esgotam ou o contrato é encerrado fora da Gates2b. Se esse aviso se perder, a assinatura segue `ACTIVE` do nosso lado, com uma próxima cobrança que não vai acontecer. `CANCELLED` é definitivo: tentar reativar responde `409`. Quando você ou o pagador cancelam, o status muda mesmo que o aviso à operadora falhe. O `200` não garante que o cartão parou de ser cobrado. Depois de cancelar uma assinatura de cartão, chame a [reconciliação](../api-reference/endpoint/subscription/subscription/reconcile.mdx). ### Ciclos cobrados depois do cancelamento Se o cartão for cobrado depois do cancelamento, o ciclo **não** vira cobrança nem crédito no saldo: ele fica registrado para reembolso e o cancelamento é reenviado à operadora. O resumo aparece em `activation.postCancelCycles`: ```json "postCancelCycles": { "count": 1, "lastAt": "2026-07-28T13:05:00.000Z", "lastAmountCents": 9990, "totalAmountCents": 9990 } ``` O reembolso desses ciclos é manual e não é feito por esta API. ## Colocando a assinatura de volta em sincronia Todos os casos abaixo se resolvem com [Reconciliar assinatura](../api-reference/endpoint/subscription/subscription/reconcile.mdx). Ela pode ser chamada quantas vezes for preciso, até 10 por minuto. | Situação | O que fazer | Como confirmar | | --- | --- | --- | | `CANCELLED` aqui, mas o cartão continua sendo cobrado | Reconcilie. | `cancelledAtGateway: true` (ou `gatewayStatus` encerrado) e `errors` vazio. Os ciclos indevidos aparecem em `postCancelInvoices`. | | `AWAITING_PAYER_AUTHORIZATION` aqui, o cartão já é cobrado, e você quer manter | Reconcilie. | Status `ACTIVE`, cobranças dos ciclos pagos criadas e saldo creditado. | | `AWAITING_PAYER_AUTHORIZATION` aqui, o cartão já é cobrado, e você quer parar | Cancele primeiro e reconcilie depois. | Os ciclos pagos vão para `postCancelInvoices` em vez de virar receita. | | `ACTIVE` aqui, mas encerrada na operadora | Reconcilie. | Status `CANCELLED` com a data de hoje e um aviso em `warnings`. | Para parar uma assinatura que já cobra, não inverta a ordem. Reconciliar antes de cancelar ativa a assinatura e credita os ciclos pagos no saldo, e cancelar depois não desfaz o crédito. Se a listagem de ciclos falhar durante a reconciliação, o cancelamento ainda é enviado, mas `postCancelInvoices` volta `0`. Confira `errors` antes de concluir que não houve cobrança indevida. --- # Autenticação (/guias/autenticacao) Gere a chave de API no painel e envie em toda chamada no header Authorization. A API identifica a sua conta pela **chave de API**. Toda chamada leva a chave no header `Authorization`, no formato `Bearer`. Sem a chave, ou com uma chave inválida, a API responde `401`. ## Gerar a chave Cadastre ao menos um IP de servidor em **Integração**. A chave só é gerada para contas com IP cadastrado; veja [Liberação de IP](/guias/liberacao-de-ip). No [painel](https://painel.gates2b.com), abra **Integração** e gere a chave de API. Copie a chave e guarde no cofre de segredos da sua aplicação. Ela não é exibida de novo. ## Enviar a chave Envie estes headers em todas as chamadas: ```http Authorization: Bearer Content-Type: application/json ``` Antes de executar qualquer operação, a API confere duas coisas, nesta ordem: *Figura: O que a API confere em cada chamada antes de executar a operação.* - A chave é válida?: 1ª checagem — Se faltar, estiver fora do formato Bearer ou for inválida: 401. - O IP está liberado?: 2ª checagem — Se a chamada vier de IP fora da lista: 403 API_KEY_IP_NOT_ALLOWED. - Operação executada: liberada — A chamada segue para o endpoint pedido. Para confirmar que a chave funciona antes de integrar o resto: ```bash curl "https://api.gates2b.com/api-key/validate" \ -H "Authorization: Bearer $API_KEY" ``` A resposta e os campos estão em [Validar chave de API](/api-reference/endpoint/api-key-validate). ## Erros de autenticação [#erros-de-autenticação] | Status | `code` | Quando | | --- | --- | --- | | `401` | `UNAUTHORIZED` | Header ausente, fora do formato `Bearer ` ou chave inválida/revogada. | | `403` | `API_KEY_IP_NOT_ALLOWED` | A chave é válida, mas a chamada saiu de um IP fora da lista da conta. | ## Guarde a chave como senha **A chave de API movimenta a sua conta** Quem tem a chave cria cobranças e reembolsos em seu nome. Trate como senha de produção. - Guarde em cofre de segredos ou variável de ambiente, nunca no código-fonte nem no repositório. - Use só no backend. Não coloque no front-end, no app mobile nem em URL. - Não registre a chave em log e não envie por e-mail, chat ou atendimento. - Se a chave vazar, gere uma nova no painel, troque nos seus servidores e avise o [suporte](https://t.me/Gates2b) para invalidar a anterior. --- # Códigos HTTP e erros (/guias/codigos-http) O que cada status significa e o formato do corpo de erro. A API usa os status HTTP convencionais: `2xx` é sucesso, `4xx` é problema na requisição que você enviou e `5xx` é falha do nosso lado. ## Formato do erro Todo erro tem o mesmo corpo: ```json { "statusCode": 400, "code": "VALIDATION", "message": ["grossAmount must be a string"], "traceId": "3b9c6f2a-71d4-4e0b-b8a5-0c2e9f41d7a6" } ``` | Campo | Descrição | | --- | --- | | `statusCode` | O mesmo status HTTP da resposta. | | `code` | Código estável para o seu sistema tratar o erro. Use este campo nas decisões, não a mensagem. | | `message` | Texto para pessoas. Pode ser string ou lista (erros de validação trazem um item por campo). Pode mudar sem aviso. | | `traceId` | Identificador do erro nos nossos registros. Informe ao suporte para localizar o caso. | | `missing` | Opcional. Lista dos dados que faltam para concluir a operação. | ## Status | Status | `code` | Significado | | --- | --- | --- | | `200`, `201` | — | Sucesso. `201` quando um recurso é criado. | | `400` | `BAD_REQUEST`, `VALIDATION` | Campo obrigatório ausente ou inválido. A `message` diz qual. | | `401` | `UNAUTHORIZED` | Chave de API ausente ou inválida. Veja [Autenticação](/guias/autenticacao). | | `403` | `FORBIDDEN`, `API_KEY_IP_NOT_ALLOWED` | Operação não permitida para a conta, chamada de IP não liberado, ou `GET` enviado com corpo. | | `404` | `NOT_FOUND` | O endpoint ou o recurso não existe (ou não pertence à sua conta). | | `409` | `CONFLICT` | O estado atual impede a operação: cliente duplicado, assinatura já cancelada, cobrança já reembolsada. | | `422` | `VALIDATION` | Os dados têm o formato certo, mas não passam numa regra de negócio. | | `429` | — | Limite de requisições excedido. Veja [Limites](/guias/limites). | | `500` | `INTERNAL` | Erro do nosso lado. A `message` é genérica de propósito; guarde o `traceId`. | | `501` | — | Combinação não suportada, por exemplo um plano que mistura PIX e cartão. | | `503` | `UNAVAILABLE` | Serviço temporariamente indisponível. Tente de novo com espera crescente. | **GET com corpo é recusado** Chamadas `GET` com qualquer conteúdo no corpo recebem `403`. Envie filtros na query string. ## Quando tentar de novo - `429`, `500`, `503` e timeouts: tente de novo com espera crescente (1 s, 2 s, 4 s…). - Na criação de cobrança, envie `attemptIdempotencyKey`. Se a nova tentativa responder `409`, a primeira chegou a ser criada: consulte a cobrança pelo seu `externalReference` em vez de criar outra. - `4xx` (exceto `429`): não repita a mesma requisição. Corrija o que a `message` aponta. --- # Cripto na cobrança (/guias/cripto-no-charge) Como cobrar em cripto pelo POST /charge, escolher as moedas, ler a cotação e saber quando o pagamento foi feito. Uma cobrança em cripto é uma cobrança comum de [Criar cobrança](../api-reference/endpoint/charge/create.mdx) com `paymentMethod: "CRYPTO"`. O valor é definido na moeda da cobrança (`BRL`, `USD` ou `EUR`) e o pagador transfere o equivalente em cripto. O que muda em relação a PIX e boleto está nesta página. ```bash curl -X POST "https://api.gates2b.com/charge" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "grossAmount": "35.00", "currency": "BRL", "paymentMethod": "CRYPTO", "externalReference": "pedido-0004", "gatewayOptions": { "cryptoTickers": ["ETH_USDT"] } }' ``` `passthroughFees: true` não é aceito em cripto e responde `400`. ## Moedas `gatewayOptions.cryptoTickers` lista as moedas aceitas. Cada item é um ticker no formato `REDE_ATIVO`; moedas nativas usam só o ativo. | Ativo | Rede | Ticker | | --- | --- | --- | | USDT | Ethereum | `ETH_USDT` | | USDT | BNB Smart Chain | `BSC_USDT` | | USDT | Polygon | `MATIC_USDT` | | USDC | Ethereum | `ETH_USDC` | | USDC | Polygon | `MATIC_USDC` | | ETH | Ethereum | `ETH` | | BNB | BNB Smart Chain | `BNB` | | MATIC | Polygon | `MATIC` | - A oferta real é a das moedas habilitadas na sua conta. `cryptoTickers` só restringe esse conjunto: pedir um ticker não habilitado não o adiciona. - Omitir o campo equivale a aceitar todas as moedas habilitadas. Lista vazia responde `400`. - De 1 a 20 tickers, sem repetição. ## Um ticker ou vários [#um-ticker-ou-vários] A quantidade de tickers muda o fluxo, não só a lista de moedas. **Um ticker: moeda travada.** A cotação e a carteira são reservadas na criação. A resposta já traz endereço, valor exato e QR Code em `checkoutMeta.crypto` e `checkoutMeta.qr_image`, e o pagador não escolhe moeda. **Com um ticker, a reserva de 20 minutos começa na criação** Use um ticker só quando o pagador vai pagar em seguida. Para link enviado por mensagem e aberto mais tarde, use vários tickers ou omita o campo, senão a reserva pode vencer antes de o pagador abrir o link. **Dois ou mais tickers, ou o campo omitido: moeda aberta.** Nada é reservado. O pagador escolhe a moeda no checkout e a reserva começa a contar depois da escolha. A resposta vem sem `checkoutMeta.crypto` e sem `qr_image`. **Um ticker** *Figura: Moeda travada: a reserva de 20 minutos começa na criação, e a resposta já traz endereço e valor.* - Seu servidor → API Gates2b: POST /charge (1 ticker) - API Gates2b → API Gates2b: reserva 20 min começa - API Gates2b → Seu servidor: endereço, valor, QR Code - Seu servidor → Pagador: mostra QR ou checkoutUrl - Pagador → Rede: transfere amountFormatted - Rede → API Gates2b: transação confirmada - API Gates2b → Seu servidor: webhook charge.paid **Vários tickers** *Figura: Moeda aberta: nada é reservado na criação; a reserva começa quando o pagador escolhe a moeda no checkout.* - Seu servidor → API Gates2b: POST /charge (vários tickers) - API Gates2b → Seu servidor: checkoutUrl, sem endereço - Seu servidor → Pagador: envia checkoutUrl - Pagador → API Gates2b: escolhe a moeda - API Gates2b → Pagador: endereço e valor; reserva começa - Pagador → Rede: transfere - Rede → API Gates2b: transação confirmada - API Gates2b → Seu servidor: webhook charge.paid ## Resposta da criação [#resposta-da-criação] A resposta é a tentativa de pagamento. O id da cobrança vem em `chargeId`. ```json { "id": "0192f4c6-7d1e-7a3b-9c2d-4e5f6a7b8c9f", "chargeId": "01JC8Z3R5W7Y9A1C3E5G7J9K2Q", "status": "PROCESSING", "paymentMethod": "CRYPTO", "checkoutMeta": { "url": "https://pay.gates2b.com/01JC8Z3R5W7Y9A1C3E5G7J9K2Q", "paymentMethod": "CRYPTO", "redirectUrl": "https://pay.provider.example/p/6f1c2a90", "crypto": { "ticker": "ETH_USDT", "symbol": "USDT", "network": "Ethereum", "networkKey": "ethereum", "address": "0x9f1C4b2E8a7D3c6F5e0B1a2C3d4E5f6A7b8CE4a2", "paymentUri": "ethereum:0x9f1C4b2E8a7D3c6F5e0B1a2C3d4E5f6A7b8CE4a2?amount=6.875105", "amount": "6875105", "amountFormatted": "6.875105", "expiresAt": "2026-10-22T14:20:00.000Z", "expirationDurationMin": 20 }, "qr_image": "data:image/png;base64,iVBORw0KGgo..." }, "checkoutUrl": "https://pay.gates2b.com/01JC8Z3R5W7Y9A1C3E5G7J9K2Q" } ``` | Campo | O que é | | --- | --- | | `checkoutUrl` | Checkout onde o pagador vê endereço, valor, QR Code e prazo. Mande o pagador para cá. | | `checkoutMeta.redirectUrl` | Página de pagamento alternativa para esta tentativa. Não é a URL de retorno de `gatewayOptions.redirectUrl`. | | `crypto.amount` | Valor na menor unidade do token, inteiro em string. | | `crypto.amountFormatted` | Valor na unidade do ativo. É o que o pagador transfere. | | `crypto.paymentUri` | Conteúdo do QR Code, com o valor exato. | | `crypto.expiresAt`, `crypto.expirationDurationMin` | Fim e duração da reserva. Podem não vir; sem eles, a tela só perde o contador. | Os valores em cripto são strings de propósito: um token de 18 casas decimais convertido para número de ponto flutuante perde dígitos. Guarde e compare como string ou com uma biblioteca decimal. ## Exibir o valor Se você mostrar o valor na sua própria tela, arredonde `amountFormatted` **para cima** nas casas do ativo. O número na tela é instrução de pagamento: arredondar para baixo pede menos do que a reserva e a transferência fica incompleta. | Ativo | Casas | Exemplo | | --- | --- | --- | | USDT, USDC, DAI, DOGE | 2 | `6.88` | | ETH, LTC, BCH | 6 | `0.004312` | | BTC | 8 | `0.00012345` | | SHIB | 0 | `1240918` | | Demais ativos | 4 | `12.3457` | Deixe o valor exato acessível para copiar. O QR Code (`paymentUri`) já carrega o valor exato. ## Status e prazo O status da cobrança segue o mesmo ciclo das outras, com um status a mais, `PARTIAL`, para pagamento abaixo do cotado. *Figura: Status de uma cobrança em cripto: PARTIAL fica aberta até o restante chegar; só PAID significa pago.* - PENDING: aguardando a transferência — (transferência abaixo do valor) - PARTIAL: aberta, não expira, não é paga — (restante recebido) - PAID: dispara charge.paid - undefined → undefined: PAID: (valor cheio recebido) - undefined → undefined: EXPIRED: ainda aceita transferência atrasada — (prazo vence sem transferência) Cripto tem três particularidades: - **Pagamento a menor.** O pagador pode transferir menos que o cotado. A cobrança vai para `PARTIAL`: continua aberta, não é paga e não expira pelo prazo. Ela vira `PAID` quando o restante chega. Não libere o pedido em `PARTIAL`. - **Prazo ancorado na reserva.** Com moeda travada, o `expiresAt` da cobrança passa a ser o fim da reserva de 20 minutos, não o valor enviado na criação. - **Pagamento depois do prazo.** Uma cobrança `EXPIRED` que recebe a transferência depois do prazo ainda é creditada: vira `PAID` com o valor cheio, ou `PARTIAL` com valor menor. ## Saber que foi pago Assine o evento `charge.paid` numa inscrição de webhook. Ele é enviado quando a cobrança vira `PAID`, também em cripto, e traz o `externalReference`. Veja [Webhooks](./webhooks.mdx). Os eventos `crypto_payment.*` não são enviados para cobranças de `/charge`. Eles valem só para pagamentos criados em [Criar pagamento em cripto](../api-reference/endpoint/crypto-payments.mdx). ## Dados da liquidação [#dados-da-liquidação] Depois do pagamento, a cobrança ganha um bloco `crypto` com os números da transação: moeda e rede pagas, valores bruto e líquido em cripto e tarifas. ```json "crypto": { "currency": "ETH_USDT", "blockchain": "ETH", "grossAmount": "6.512300", "netAmount": "6.317931", "fee": "0.194369", "feePercent": 2.985, "networkFee": "0.900000" } ``` O bloco aparece em `lastConfirmedAttempt.crypto` no detalhe da cobrança (`GET /charge/me/{id}`), em `crypto` em cada item da listagem (`GET /charge/list`) e em `crypto` nas consultas de tentativa (`GET /charge/{chargeId}/attempts` e `GET /charge/attempts/{attemptId}`). Trate todos os campos do bloco como opcionais. O conteúdo varia conforme a rede e o momento da consulta, e campos como `txHash`, `senderAddress`, `paidAt` e `confirmations` podem não vir. Use o bloco para conciliação e exibição, não como condição para dar o pedido por pago: essa decisão é do status `PAID`. --- # Liberação de IP (/guias/liberacao-de-ip) Cadastre os IPs dos servidores que chamam a API. Chamada de IP fora da lista é recusada. A API só aceita chamadas com chave de API vindas de IPs cadastrados na sua conta. Mesmo que a chave vaze, ela não funciona fora dos seus servidores. | Conta | Liberação de IP | | --- | --- | | Brasileira | Obrigatória | | Uruguaia | Opcional, recomendada | ## Cadastrar um IP No [painel](https://painel.gates2b.com), abra **Integração**. Adicione o IP público de saída de cada servidor que vai chamar a API. Repita para cada IP. Salve. A liberação vale para as chamadas seguintes, sem trocar a chave. **Cadastre o IP antes de gerar a chave** O painel só gera chave de API para contas com pelo menos um IP cadastrado. ## Quando a chamada é recusada [#quando-a-chamada-é-recusada] Uma chamada com chave válida vinda de IP fora da lista recebe `403`: ```json { "statusCode": 403, "code": "API_KEY_IP_NOT_ALLOWED", "message": "Este IP não está na whitelist de IP da conta (Integrações).", "traceId": "8f0c2a4e-3d7b-4c1e-9a52-6b1f0e7d2c91" } ``` Se toda chamada de uma integração nova falha com `403`, confira primeiro: - O IP cadastrado é o de **saída** do servidor, como a internet o vê, e não o IP interno da rede. Em nuvem, é o IP do NAT ou do balanceador de saída. - Servidores com IP dinâmico (autoscaling, serverless) precisam de um IP de saída fixo para funcionar com a liberação. Ainda com dúvida, fale com o [suporte](https://t.me/Gates2b) e informe o `traceId` da resposta. --- # Limites (/guias/limites) Quantas requisições a API aceita e o que acontece quando você passa do limite. Cada conta pode fazer até **1.000 requisições por segundo**. Acima disso, as requisições excedentes recebem `429 Too Many Requests` até a janela seguinte. ## Ao receber `429` - Espere e tente de novo com intervalo crescente (1 s, 2 s, 4 s…). - Não consulte a API em laço para saber se uma cobrança foi paga. Assine os [webhooks](/guias/webhooks): o evento chega assim que o status muda. - Distribua tarefas em lote (conciliação, relatórios) ao longo do tempo em vez de disparar tudo de uma vez. ## Precisa de mais? Se a sua operação precisa de mais de 1.000 requisições por segundo, fale com o [suporte](https://t.me/Gates2b) informando o volume esperado e os endpoints envolvidos. --- # Primeira cobrança (/guias/primeira-cobranca) Crie uma cobrança PIX, mostre o QR Code ao cliente e confirme o pagamento por webhook. Este guia leva uma integração do zero até a primeira cobrança paga. Antes, gere a chave de API e cadastre o IP do servidor ([Autenticação](/guias/autenticacao) e [Liberação de IP](/guias/liberacao-de-ip)). *Figura: O caminho de uma cobrança PIX: você cria, o cliente paga, a Gates2b avisa o seu servidor.* - Seu servidor → API Gates2b: POST /charge - API Gates2b → Seu servidor: QR Code + checkoutUrl - Seu servidor → Cliente: mostra o QR Code - Cliente → Banco do cliente: paga o PIX - Banco do cliente → API Gates2b: confirma o pagamento - API Gates2b → Seu servidor: webhook charge.paid - Seu servidor → API Gates2b: responde 2xx ### Inscreva-se para receber o pagamento Cadastre uma URL do seu backend para receber o evento `charge.paid`. Faça isso uma vez, não a cada cobrança. ```bash curl -X POST "https://api.gates2b.com/webhook-subscriptions" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "subscribedEvents": ["charge.paid"], "callbackUrl": "https://minhaloja.com.br/webhooks/pagamentos" }' ``` Guarde o `secret` da resposta: ele aparece só agora e serve para verificar a assinatura de cada entrega. Detalhes em [Webhooks](/guias/webhooks). ### Crie a cobrança [#crie-a-cobrança] ```bash curl -X POST "https://api.gates2b.com/charge" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "grossAmount": "49.90", "currency": "BRL", "paymentMethod": "PIX", "externalReference": "pedido-1042", "description": "Pedido 1042" }' ``` `grossAmount` é string com duas casas decimais. `externalReference` é o seu identificador do pedido: ele volta no webhook e evita que você precise guardar o id da cobrança para conciliar. ### Mostre o pagamento ao cliente Com `paymentMethod: "PIX"`, a resposta é a **tentativa de pagamento** já criada: o `id` é da tentativa e o id da cobrança vem em `chargeId`. Use um dos dois caminhos: - **Checkout pronto:** redirecione o cliente para `checkoutUrl`. - **Na sua tela:** exiba `checkoutMeta.qr_image` (imagem em base64) e ofereça o copia e cola de `checkoutMeta.emv`. ```json { "id": "8d3f2a61-4c0b-4e7a-9b15-2f6e1c9a7d40", "chargeId": "01JC8Z3R5W7Y9A1C3E5G7J9K2M", "status": "PROCESSING", "paymentMethod": "PIX", "checkoutMeta": { "url": "https://pay.gates2b.com/01JC8Z3R5W7Y9A1C3E5G7J9K2M", "emv": "00020101021226810014br.gov.bcb.pix...", "qr_image": "data:image/png;base64,iVBORw0KGgo..." }, "checkoutUrl": "https://pay.gates2b.com/01JC8Z3R5W7Y9A1C3E5G7J9K2M" } ``` ### Confirme pelo webhook Quando o cliente paga, a sua URL recebe um `POST` com o evento `charge.paid`. Verifique a assinatura, marque o pedido como pago e responda `2xx`. Qualquer outra resposta faz a entrega ser repetida. Use o webhook como fonte da verdade. Não libere o pedido pelo retorno do navegador do cliente. ## Próximos passos [#próximos-passos] - [Criar cobrança](/api-reference/endpoint/charge/create): Todos os campos: boleto, cartão, vencimento, split e repasse de tarifa. - [Webhooks](/guias/webhooks): Catálogo de eventos, verificação da assinatura e política de reenvio. --- # Regras de negócio (/guias/regras-de-negocio) Valor mínimo de cobrança, tarifas e prazos padrão de liberação e de saque. Os valores abaixo são o padrão da plataforma. Tarifas, limites e prazos são configurados por conta e podem ter sido negociados de outro jeito no seu contrato: os valores que valem para você estão no [painel](https://painel.gates2b.com). ## Valor mínimo de cobrança [#valor-mínimo-de-cobrança] O valor mínimo depende da tarifa da conta. O padrão é **R$ 3,00**, em qualquer meio de pagamento; nenhuma conta tem mínimo menor que esse. Cobrança abaixo do mínimo da conta é recusada com `400`. Planos de assinatura têm piso próprio: `amountCents` a partir de `100` (R$ 1,00). ## Cobranças [#cobranças] | Tarifa por cobrança paga | Liberação do saldo | | --- | --- | | R$ 2,99 | 1 dia após o pagamento | Com `passthroughFees: true` na [criação da cobrança](/api-reference/endpoint/charge/create), a tarifa é somada ao valor pago pelo cliente em vez de descontada do seu recebimento. ## Saques | Tipo | Quando o dinheiro sai | Mínimo | Tarifa padrão | | --- | --- | --- | --- | | Normal | Às 10h do segundo dia corrido após o pedido | R$ 5,00 | R$ 2,99 | | Emergencial | Em até 30 minutos | R$ 5,00 | 0,99% do valor | Prazos em dias corridos, incluindo fins de semana. Pelo painel, cada saque é limitado a R$ 15.000,00; limites diários, semanais e mensais da conta valem para o painel e para a API. Detalhes, exceções e exemplos em [Quando o dinheiro fica disponível](/ajuda/liberacao-de-saldo) e [Como as taxas são aplicadas](/ajuda/taxas). --- # Webhooks (/guias/webhooks) Receba no seu servidor, com assinatura HMAC, os eventos de pagamento, reembolso e saque da sua conta. Um webhook avisa o seu sistema quando algo muda na sua conta: uma cobrança foi paga, um reembolso saiu, um saque foi concluído. Você cadastra uma URL com uma **inscrição de webhook**, escolhe os eventos e a Gates2b faz um `POST` assinado nessa URL a cada evento. Assim você não precisa consultar a API em loop. ## Como receber eventos Publique um endpoint `https` que aceite `POST` com corpo JSON e responda `2xx` em até 10 segundos. Crie a inscrição com [Criar inscrição](../api-reference/endpoint/webhook-subscription/create.mdx), informando a `callbackUrl` e os eventos em `subscribedEvents`. Guarde o `secret` da resposta em um cofre de segredos. Ele só aparece nessa resposta. Em cada entrega, [verifique a assinatura](#verificar-a-assinatura), descarte duplicatas pelo [id do evento](#idempotencia) e responda `2xx`. ```bash curl -X POST "https://api.gates2b.com/webhook-subscriptions" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "callbackUrl": "https://loja.example.com/webhooks/pagamentos", "subscribedEvents": ["charge.paid", "charge.refunded", "payout.paid", "payout.failed"] }' ``` *Figura: Uma entrega: a Gates2b assina e envia o evento, o seu servidor valida e responde 2xx; sem 2xx, a mesma entrega volta mais tarde.* - Gates2b → Gates2b: evento charge.paid - Gates2b → Seu servidor: POST assinado (x-Webhook-Signature) - Seu servidor → Seu servidor: valida assinatura e janela de 5 min - Seu servidor → Seu servidor: ignora x-Webhook-Event-Id repetido - Seu servidor → Gates2b: 2xx em até 10 s - Gates2b → Seu servidor: sem 2xx: mesma entrega, nova tentativa Cada inscrição tem uma URL. Para mandar eventos diferentes para URLs diferentes, crie uma inscrição por URL. Um evento assinado por mais de uma inscrição é entregue a cada uma delas, com assinatura e id próprios. Para gerenciar as inscrições: [Listar](../api-reference/endpoint/webhook-subscription/list.mdx), [Consultar](../api-reference/endpoint/webhook-subscription/get.mdx), [Atualizar](../api-reference/endpoint/webhook-subscription/update.mdx), [Rotacionar segredo](../api-reference/endpoint/webhook-subscription/rotate-secret.mdx), [Pausar](../api-reference/endpoint/webhook-subscription/pause.mdx), [Ativar](../api-reference/endpoint/webhook-subscription/activate.mdx) e [Revogar](../api-reference/endpoint/webhook-subscription/revoke.mdx). ### Status da inscrição [#status-da-inscrição] A inscrição nasce `active` e só recebe eventos nesse status. Você pausa para manutenção do endpoint e revoga para desligar a URL. A Gates2b também pausa a inscrição sozinha quando, na hora da entrega, a URL aponta para um endereço não permitido. *Figura: Status de uma inscrição de webhook: só active recebe eventos; paused volta com Ativar; revoked desliga a URL.* - active: recebe eventos — (Pausar ou URL recusada na entrega) - paused: nada é entregue nem guardado - undefined → undefined: revoked: para todas as entregas — (Revogar) - undefined → undefined: active: volta a receber eventos novos — (Ativar) O que acontece com os eventos em cada mudança: - **Pausar:** eventos gerados durante a pausa não são criados para a inscrição, e uma nova tentativa que vencer nesse intervalo é descartada. Ao ativar, a entrega recomeça só com eventos novos. - **Revogar:** as tentativas pendentes são descartadas. Para usar outra URL, crie uma inscrição nova. - **Pausa automática:** corrija a `callbackUrl` com [Atualizar](../api-reference/endpoint/webhook-subscription/update.mdx) antes de [Ativar](../api-reference/endpoint/webhook-subscription/activate.mdx); senão a próxima entrega pausa a inscrição de novo. ## Eventos Use em `subscribedEvents` o nome exato da primeira coluna. A API aceita um nome com erro de grafia, mas nenhum evento com esse nome existe, e a inscrição não recebe nada. | Evento | Quando é enviado | `x-Webhook-Correlation-Id` | | --- | --- | --- | | `charge.paid` | A cobrança passou para `PAID`. | `id` da cobrança | | `charge.refunded` | Um reembolso da cobrança foi processado, parcial ou total. | `id` da cobrança | | `invoice.paid` | Uma invoice foi paga. | `id` da invoice | | `invoice.refunded` | Uma invoice foi reembolsada. | `id` da invoice | | `payout.completed` | O saque foi aceito e debitado do saldo. O dinheiro **ainda não saiu**. | `id` do saque | | `payout.paid` | O dinheiro do saque saiu. | `id` do saque | | `payout.failed` | O saque foi recusado na criação ou falhou depois de aceito. | `id` do saque | | `auto_payout.skipped` | O saque automático configurado na cobrança não chegou a ser agendado. | `id` da cobrança | | `auto_payout.failed` | O saque automático foi agendado, mas não saiu. | `id` da cobrança | Sobre os saques: *Figura: Eventos de um saque: payout.completed quando é aceito, depois payout.paid ou payout.failed; o desfecho ainda pode mudar.* - payout.completed: aceito e debitado; o dinheiro não saiu — (dinheiro enviado) - payout.paid: o dinheiro saiu - undefined → undefined: payout.failed: (falha depois de aceito) - undefined → undefined: payout.failed: (revertido pela operação) - A sequência normal é `payout.completed` e depois `payout.paid` ou `payout.failed`. Alguns meios de saque pulam o `payout.completed` e enviam só o desfecho; um saque recusado na criação recebe só `payout.failed`. - O desfecho pode mudar: um saque dado como falho pode ser confirmado depois, e um saque pago pode ser revertido. Os dois eventos chegam. Vale o que tiver o `payout.updatedAt` mais recente. - Saques automáticos (`settlementConfig` na cobrança) não enviam `payout.*`; eles têm os eventos `auto_payout.*`. ### Pagamentos em cripto Há um evento por status do pagamento. O `x-Webhook-Correlation-Id` é o id do pagamento em cripto. | Evento | Quando é enviado | | --- | --- | | `crypto_payment.waiting` | Aguardando o pagamento na rede. | | `crypto_payment.confirming` | Transação vista, aguardando confirmações da rede. | | `crypto_payment.confirmed` | Confirmado na rede. **Intermediário**: o valor ainda não foi liquidado. | | `crypto_payment.sending` | Fundos em processamento. | | `crypto_payment.partially_paid` | Pago abaixo do valor esperado. | | `crypto_payment.finished` | Liquidado. É o único evento de sucesso final. | | `crypto_payment.failed` | O pagamento falhou. | | `crypto_payment.refunded` | O pagamento foi reembolsado. | | `crypto_payment.expired` | O prazo para pagar acabou sem pagamento. | Libere o pedido só em `crypto_payment.finished`. `crypto_payment.confirmed` não é pagamento concluído. ## Formato da entrega A Gates2b faz um `POST` na `callbackUrl` com `Content-Type: application/json`. O corpo é o objeto do evento; os headers abaixo vêm em toda entrega. | Header | Conteúdo | | --- | --- | | `x-Webhook-Signature` | Assinatura no formato `t=,v1=`. Veja [Verificar a assinatura](#verificar-a-assinatura). | | `x-Webhook-Event-Id` | Id da entrega. O mesmo em todas as tentativas; use para [idempotência](#idempotencia). | | `x-Webhook-Event-Type` | Nome do evento, por exemplo `charge.paid`. | | `x-Webhook-Timestamp` | Momento da assinatura, em segundos Unix. Igual ao `t` da assinatura. | | `x-Webhook-Correlation-Id` | Id do recurso do evento (veja a tabela de eventos). Ausente quando o evento não tem um. | | `X-Gates2b-Environment` | `production` ou `sandbox`. | Nomes de header não diferenciam maiúsculas de minúsculas. A maioria dos frameworks os entrega em minúsculas (`x-webhook-signature`). Use o header `x-Webhook-Event-Type` para decidir como tratar a entrega. O corpo muda de evento para evento, e nem todo corpo traz o nome do evento. **charge.paid** ```json { "event": "charge.paid", "charge": { "id": "019ecb7a-2ab0-7744-982f-e9d951d61746", "status": "PAID", "grossAmount": "100.00", "currency": "BRL", "externalReference": "pedido-123", "description": "Assinatura mensal", "customer": { "name": "Maria Silva", "email": "cliente@example.com", "document": "12345678909", "phone": "11999998888", "country": null }, "paymentMethod": { "type": "PIX", "brand": null, "authorizationCode": null, "expMonth": null, "expYear": null, "funding": null, "last4": null, "bankIspb": "00000000" }, "paidAt": "2026-06-15T14:10:05.094Z", "createdAt": "2026-06-15T14:00:00.000Z" }, "attempt": { "id": "019ecb7b-0c41-7a5e-8d0f-3c2a9e1b7f42", "paymentMethod": "PIX", "idempotencyKey": "pedido-123-tentativa-1", "payer": { "name": "Maria Silva", "email": null, "document": "12345678909", "phone": null, "country": null } } } ``` `charge.customer` é quem você (ou o comprador, no checkout) informou. `attempt.payer` é quem de fato pagou, segundo a instituição de origem. Os dois podem ser pessoas diferentes, e isso não é erro. Os três blocos vêm sempre com todas as chaves; o que não se sabe vem `null`. **charge.refunded** ```json { "event": "charge.refunded", "charge": { "id": "019ecb7a-2ab0-7744-982f-e9d951d61746", "status": "REFUNDED", "grossAmount": "100.00", "refundedAmount": "100.00", "currency": "BRL", "externalReference": "pedido-123", "description": "Assinatura mensal" }, "refund": { "id": "019ed0c4-5b1e-7d22-a6f3-91e0b4c8d2aa", "amount": "100.00", "status": "PROCESSED", "reason": "Pedido cancelado pelo cliente", "externalRefundId": null, "gateway": null, "createdAt": "2026-06-16T10:00:00.000Z" } } ``` **payout.failed** ```json { "event": "payout.failed", "payout": { "id": "8f0e6c1a-3b2d-4e5f-9a8b-7c6d5e4f3a2b", "invoiceId": 4242, "idempotencyKey": "saque-123", "status": "failed", "grossAmount": 100, "netAmount": -102.5, "currency": "BRL", "type": "PIX", "destination": "cliente@example.com", "gateway": null, "updatedAt": "2026-10-08T12:00:00.000Z", "reason": "Chave PIX inválida", "failureReason": "Chave PIX inválida" } } ``` Em `payout.*`, `grossAmount` é o valor pedido e `netAmount` o total debitado do saldo (negativo), ambos em reais. `reason` só vem em `payout.failed`. Os eventos `invoice.*` trazem o mesmo objeto da [notificação legada](#webhook-legado-configurado-no-painel). O corpo de cada evento, campo a campo, está em [Eventos de webhook](../api-reference/endpoint/webhook-events.mdx). ## Verificar a assinatura Toda entrega é assinada com HMAC-SHA256 usando o `secret` da inscrição. Verifique antes de confiar no corpo: 1. Leia `t` e `v1` do header `x-Webhook-Signature` (`t=1718460605,v1=5f2b…`). 2. Rejeite a entrega se `t` estiver a mais de 300 segundos (5 minutos) do relógio do seu servidor, para cima ou para baixo. Isso barra o reenvio de uma entrega capturada. 3. Calcule `HMAC-SHA256(secret, t + "." + corpo)` em hexadecimal minúsculo. `corpo` são os bytes exatos recebidos, **antes** de qualquer parse de JSON. 4. Compare o resultado com `v1` em tempo constante. Reserializar o JSON muda espaços e ordem das chaves e quebra a assinatura. Configure o framework para entregar o corpo cru nessa rota. Mantenha o relógio do servidor sincronizado (NTP), ou a janela de 5 minutos rejeita entregas válidas. **Node.js** ```js import crypto from 'node:crypto'; import express from 'express'; const TOLERANCE_SECONDS = 300; function verifySignature(rawBody, header, secret) { const parts = Object.fromEntries( header.split(',').map((part) => { const [key, ...value] = part.trim().split('='); return [key, value.join('=')]; }), ); const timestamp = Number.parseInt(parts.t, 10); if (!Number.isFinite(timestamp) || !parts.v1) return false; if (Math.abs(Math.floor(Date.now() / 1000) - timestamp) > TOLERANCE_SECONDS) return false; const expected = crypto .createHmac('sha256', secret) .update(`${parts.t}.`) .update(rawBody) // Buffer com o corpo cru .digest(); const received = Buffer.from(parts.v1, 'hex'); return received.length === expected.length && crypto.timingSafeEqual(received, expected); } const app = express(); // express.raw: req.body chega como Buffer, sem parse app.post('/webhooks/pagamentos', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.get('x-webhook-signature') ?? ''; if (!verifySignature(req.body, signature, process.env.WEBHOOK_SECRET)) { return res.sendStatus(401); } const eventId = req.get('x-webhook-event-id'); const eventType = req.get('x-webhook-event-type'); const payload = JSON.parse(req.body.toString('utf8')); // Grave eventId como processado e trate o evento fora da requisição. res.sendStatus(200); }); ``` **Python** ```python import hashlib import hmac import os import time from flask import Flask, abort, request TOLERANCE_SECONDS = 300 def verify_signature(raw_body: bytes, header: str, secret: str) -> bool: parts = dict(p.strip().split("=", 1) for p in header.split(",") if "=" in p) timestamp, received = parts.get("t", ""), parts.get("v1", "") if not timestamp.isdigit() or not received: return False if abs(int(time.time()) - int(timestamp)) > TOLERANCE_SECONDS: return False expected = hmac.new( secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, received) app = Flask(__name__) @app.post("/webhooks/pagamentos") def receive_webhook(): raw_body = request.get_data() # bytes, sem parse signature = request.headers.get("x-webhook-signature", "") if not verify_signature(raw_body, signature, os.environ["WEBHOOK_SECRET"]): abort(401) event_id = request.headers["x-webhook-event-id"] event_type = request.headers["x-webhook-event-type"] payload = request.get_json() # Grave event_id como processado e trate o evento fora da requisição. return "", 200 ``` ## Guardar o segredo O `secret` vem em texto puro só na resposta de [Criar inscrição](../api-reference/endpoint/webhook-subscription/create.mdx) e de [Rotacionar segredo](../api-reference/endpoint/webhook-subscription/rotate-secret.mdx). Nenhuma outra rota o devolve. Guarde-o em um cofre de segredos ou variável de ambiente, nunca no repositório. Se perder o segredo ou suspeitar de vazamento, rotacione. O anterior deixa de valer na hora, inclusive para novas tentativas de eventos já gerados. A página de [Rotacionar segredo](../api-reference/endpoint/webhook-subscription/rotate-secret.mdx) mostra como trocar sem rejeitar entregas. ## Novas tentativas A entrega conta como recebida quando a sua URL responde `2xx` em até 10 segundos. Qualquer outro caso é falha: status `3xx` (redirecionamentos não são seguidos), `4xx`, `5xx`, tempo esgotado ou erro de conexão. Depois de uma falha, a Gates2b tenta de novo com intervalo crescente: *Figura: Novas tentativas de uma entrega: o intervalo dobra a partir de 30 s até 6 h; depois da 15ª tentativa ou de 7 dias, a entrega é abandonada.* - Tentativa 1: na hora — logo depois do evento - Tentativas 2 a 4: +30 s, +1 min, +2 min — cada espera conta da tentativa anterior - Tentativas 5 a 8: +4, +8, +16, +32 min - Tentativas 9 a 11: +1 h 4, +2 h 8, +4 h 16 - Tentativas 12 a 15: +6 h cada — cerca de 32 h após o evento - Entrega abandonada: 15 tentativas ou 7 dias — sem nova tentativa automática Cada espera varia até 25% para mais ou para menos. Depois da 15ª tentativa (cerca de 32 horas após o evento), ou 7 dias após o evento, o que vier primeiro, a entrega é abandonada e não há nova tentativa automática. Nesse caso, consulte o estado do recurso pela API. - `failureCount` da inscrição soma cada tentativa que falha e volta a `0` na primeira entrega aceita. - Pausar ou revogar a inscrição descarta as tentativas pendentes. Eventos gerados enquanto ela não está `active` não são entregues depois. - Se, no momento da entrega, a URL apontar para um endereço não permitido (IP privado, porta fora de 80, 443, 8080 e 8443), a entrega é abandonada e a inscrição passa para `paused`. Responda `2xx` assim que validar a assinatura e processe o evento depois. Um processamento lento que estoura os 10 segundos vira falha e gera nova tentativa. ## Idempotência [#idempotência] A entrega é *pelo menos uma vez*: o mesmo evento pode chegar mais de uma vez, e a ordem de chegada não é garantida. - Guarde o `x-Webhook-Event-Id` de cada entrega processada e ignore as que repetirem o id. Novas tentativas da mesma entrega usam o mesmo id. - Torne a ação do seu lado idempotente também pelo recurso (`id` da cobrança, do saque…). Um reenvio manual gera uma entrega nova, com outro `x-Webhook-Event-Id`. - Não confie só no valor do webhook para liberar um pedido. Compare com o pedido do seu lado ou consulte a cobrança pela API. Para pedir de novo a notificação de uma invoice paga, use [Reenviar webhook](../api-reference/endpoint/resend-webhook.mdx). O reenvio chega às inscrições que assinam `invoice.paid`. ## Webhook legado configurado no painel Contas antigas podem ter uma URL de notificação cadastrada no [painel](https://painel.gates2b.com), em **Integração**. Essa URL recebe um `POST` quando o status de uma invoice muda, criada pelos endpoints legados de `/invoices`. Ela continua funcionando, mas tem limites que a inscrição de webhook não tem: - **Sem assinatura.** Não há `x-Webhook-Signature`; você não consegue provar que a chamada veio da Gates2b. - **Sem a política de novas tentativas.** Se o seu servidor falhar, a notificação pode se perder. Confira o status pela API ou use [Reenviar webhook](../api-reference/endpoint/resend-webhook.mdx). - **Sem escolha de eventos.** Toda mudança de status chega na mesma URL. Para integração nova, use inscrição de webhook com `invoice.paid` e `invoice.refunded`. Se você já usa a URL do painel, mantenha as duas até migrar o seu endpoint para a verificação de assinatura; depois apague a URL do painel para não processar o mesmo pagamento duas vezes. Exemplo de corpo, com a invoice paga: ```json { "id": 72276, "id_transaction": "26182891-7569-414f-aa60-4f2b8e1c9d3a", "transaction_pix_id": "e3c1a2b4-50d3-4de7-911d-8a7b6c5d4e3f", "external_reference": "pedido-123", "emv": "00020101021226...6304ABCD", "amount": 120, "status": "Pagamento realizado", "international_status": "PAYMENT_RECEIVED", "name_client": "MARIA SILVA", "document_client": "12345678909", "createdAt": "2026-06-15T12:24:49.056Z", "user": {} } ``` `international_status` é o campo estável para o seu código. Valores: `WAITING_PAYMENT`, `WAITING_PROCESSING`, `REVIEW_REQUIRED`, `PAYMENT_RECEIVED`, `PARTIALLY_PAID`, `PAYMENT_EXPIRED`, `PAYMENT_FAILED`, `WITHDRAWAL_IN_PROGRESS`, `WITHDRAWAL_IN_PROCESSING`, `WITHDRAWAL_COMPLETED`, `WITHDRAWAL_FAILED`, `REFUND_REQUESTED` e `BALANCE_REMOVED`. O pagamento confirmado é `PAYMENT_RECEIVED`. `status` é o mesmo estado em texto, em português, e pode mudar. --- # Visão geral (/api-reference) URL base, autenticação e convenções que valem para todos os endpoints. Cada página desta seção descreve um endpoint: campos da requisição, respostas, erros e um exemplo pronto para copiar. O botão de testar envia a chamada de verdade para a API, com a chave de API que você informar. ## Base | | | | --- | --- | | URL base | https://api.gates2b.com | | Autenticação | `Authorization: Bearer ` — veja [Autenticação](/guias/autenticacao) | | Formato | JSON na requisição e na resposta (`Content-Type: application/json`) | | Erros | Corpo padrão com `statusCode`, `code`, `message` e `traceId` — veja [Códigos HTTP e erros](/guias/codigos-http) | | Limite | 1.000 requisições por segundo — veja [Limites](/guias/limites) | ## Dinheiro e datas - Cobranças e reembolsos: valor em reais como **string** com duas casas (`"49.90"`). Não envie número: `49.9` em ponto flutuante perde precisão. - Planos: valor como **inteiro em centavos** (`amountCents: 4990`). - Datas em ISO 8601. Cobranças e assinaturas respondem em UTC; invoices, no horário de Brasília (UTC−3). ## Contrato em OpenAPI O contrato de todos os endpoints também está em texto, junto com os guias, em [`/llms-full.txt`](/llms-full.txt), pronto para colar num assistente de código. --- # Validar chave de API (/api-reference/endpoint/api-key-validate) Confirma que a chave de API é aceita, sem efeito colateral. Use para testar a credencial antes da integração. ```yaml GET /api-key/validate: tags: - Chave de API operationId: validateApiKey summary: Validar chave de API description: | Confirma que a chave de API enviada no header `Authorization` é aceita. Não altera nada; serve para testar a credencial antes da primeira chamada real ou em um health check. responses: "200": description: A chave é válida. content: application/json: schema: $ref: "#/components/schemas/ApiKeyValidation" example: status: success message: API Key válida "401": $ref: "#/components/responses/Unauthorized" "429": description: | Mais de 30 chamadas por minuto vindas do mesmo IP. O limite conta também as chamadas recusadas com `401`. content: application/json: schema: $ref: "#/components/schemas/Error" ``` ## Regras - A resposta `200` só confirma que a chave é aceita. Ela não diz se o IP de origem está liberado: chamadas de IP não liberado podem ser recusadas nos outros endpoints. Veja [Liberação de IP](../../guias/liberacao-de-ip.mdx). - O limite é de 30 chamadas por minuto por IP, contando as recusadas com `401`. Não use este endpoint antes de cada requisição; trate o `401` dos endpoints reais. --- # Criar cobrança (/api-reference/endpoint/charge/create) Cria uma cobrança avulsa em PIX, boleto ou cartão e devolve o link de checkout para o pagador. ```yaml POST /charge: tags: - Cobranças operationId: createCharge summary: Criar cobrança description: | Cria uma cobrança e devolve o link de checkout em `checkoutUrl`. Com `paymentMethod` igual a `PIX` ou `BANK_SLIP`, as instruções de pagamento (QR Code, boleto) já vêm na resposta. Sem `paymentMethod`, o pagador escolhe o meio no checkout. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateChargeRequest" examples: pix: summary: PIX value: grossAmount: "49.90" currency: BRL paymentMethod: PIX externalReference: pedido-0001 description: Assinatura mensal expiresAt: 2026-11-30T23:59:59Z bankSlip: summary: Boleto value: grossAmount: "150.00" currency: BRL paymentMethod: BANK_SLIP externalReference: pedido-0002 customerMeta: name: Maria da Silva document: "12345678909" document_type: CPF email: cliente@example.com address: zipcode: "01310100" street: Avenida Paulista number: "1000" neighborhood: Bela Vista city: São Paulo state: SP checkout: summary: Sem meio definido (checkout) value: grossAmount: "89.90" currency: BRL externalReference: pedido-0003 gatewayOptions: redirectUrl: https://loja.example.com/obrigado maxInstallments: 6 split: summary: Com split value: grossAmount: "200.00" currency: BRL paymentMethod: PIX split: - email: parceiro@example.com kind: PERCENT percent: 10 - email: fornecedor@example.com kind: FIXED amount: "25.00" crypto: summary: Cripto com moeda travada value: grossAmount: "35.00" currency: BRL paymentMethod: CRYPTO externalReference: pedido-0004 gatewayOptions: cryptoTickers: - ETH_USDT responses: "201": description: | Cobrança criada. O formato depende de `paymentMethod`: com `PIX` ou `BANK_SLIP` (ou `CRYPTO`) a resposta é a tentativa de pagamento (`ChargeAttempt`, com `chargeId`); sem `paymentMethod` ou com `CREDIT_CARD`, é a cobrança (`Charge`). As duas trazem `checkoutUrl`. content: application/json: schema: oneOf: - $ref: "#/components/schemas/ChargeAttempt" - $ref: "#/components/schemas/Charge" examples: pix: summary: PIX value: id: 0192f4c6-7d1e-7a3b-9c2d-4e5f6a7b8c9d chargeId: 01JC8Z3R5W7Y9A1C3E5G7J9K2M status: PROCESSING paymentMethod: PIX checkoutMeta: url: https://pay.gates2b.com/01JC8Z3R5W7Y9A1C3E5G7J9K2M paymentMethod: PIX emv: 00020101021226810014br.gov.bcb.pix2559qr.example.com/v2/cobv/9d36b84f...6304A1B2 qr_image: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA... checkoutUrl: https://pay.gates2b.com/01JC8Z3R5W7Y9A1C3E5G7J9K2M createdAt: 2026-10-22T14:00:00.000Z updatedAt: 2026-10-22T14:00:00.000Z bankSlip: summary: Boleto value: id: 0192f4c6-7d1e-7a3b-9c2d-4e5f6a7b8c9e chargeId: 01JC8Z3R5W7Y9A1C3E5G7J9K2N status: PROCESSING paymentMethod: BANK_SLIP checkoutMeta: url: https://pay.gates2b.com/01JC8Z3R5W7Y9A1C3E5G7J9K2N paymentMethod: BANK_SLIP expiresAt: 2026-10-25T23:59:59.000Z bankSlip: barcode: "34191151500000150001092324575250772982609000" digitableLine: "34191092302457525077429826090002115150000015000" status: CREATED value: 15000 fee: 199 pix: brCode: 00020101021226810014br.gov.bcb.pix... qrCodeImage: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA... txId: 70e451d6aa994cfb96229e5b74933540 qr_image: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA... checkoutUrl: https://pay.gates2b.com/01JC8Z3R5W7Y9A1C3E5G7J9K2N createdAt: 2026-10-22T14:00:00.000Z updatedAt: 2026-10-22T14:00:00.000Z checkout: summary: Sem meio definido ou CREDIT_CARD value: id: 01JC8Z3R5W7Y9A1C3E5G7J9K2P kind: SALE status: PENDING grossAmount: "89.90" netAmount: "85.31" refundedAmount: "0.00" currency: BRL externalReference: pedido-0003 description: null expiresAt: null customerMeta: null passthroughFees: false splitConfig: null splitSettlement: null canRefund: false canRefundPartial: false checkoutUrl: https://pay.gates2b.com/01JC8Z3R5W7Y9A1C3E5G7J9K2P createdAt: 2026-10-22T14:00:00.000Z updatedAt: 2026-10-22T14:00:00.000Z cryptoLocked: summary: Cripto, um ticker (moeda travada) value: id: 0192f4c6-7d1e-7a3b-9c2d-4e5f6a7b8c9f chargeId: 01JC8Z3R5W7Y9A1C3E5G7J9K2Q status: PROCESSING paymentMethod: CRYPTO checkoutMeta: url: https://pay.gates2b.com/01JC8Z3R5W7Y9A1C3E5G7J9K2Q paymentMethod: CRYPTO redirectUrl: https://pay.provider.example/p/6f1c2a90 crypto: ticker: ETH_USDT symbol: USDT network: Ethereum networkKey: ethereum address: "0x9f1C4b2E8a7D3c6F5e0B1a2C3d4E5f6A7b8CE4a2" paymentUri: ethereum:0x9f1C4b2E8a7D3c6F5e0B1a2C3d4E5f6A7b8CE4a2?amount=6.875105 amount: "6875105" amountFormatted: "6.875105" expiresAt: 2026-10-22T14:20:00.000Z expirationDurationMin: 20 qr_image: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA... checkoutUrl: https://pay.gates2b.com/01JC8Z3R5W7Y9A1C3E5G7J9K2Q createdAt: 2026-10-22T14:00:00.000Z updatedAt: 2026-10-22T14:00:00.000Z cryptoOpen: summary: Cripto, vários tickers (moeda aberta) value: id: 0192f4c6-7d1e-7a3b-9c2d-4e5f6a7b8ca0 chargeId: 01JC8Z3R5W7Y9A1C3E5G7J9K2R status: PROCESSING paymentMethod: CRYPTO checkoutMeta: url: https://pay.gates2b.com/01JC8Z3R5W7Y9A1C3E5G7J9K2R paymentMethod: CRYPTO redirectUrl: https://pay.provider.example/p/7a2d3b01 checkoutUrl: https://pay.gates2b.com/01JC8Z3R5W7Y9A1C3E5G7J9K2R createdAt: 2026-10-22T14:00:00.000Z updatedAt: 2026-10-22T14:00:00.000Z "400": description: | Campo inválido, dados do pagador faltando no boleto, combinação não permitida (por exemplo, `passthroughFees: true` sem `paymentMethod`) ou meio de pagamento não habilitado na conta. content: application/json: schema: $ref: "#/components/schemas/Error" examples: validation: summary: Campo inválido value: statusCode: 400 code: BAD_REQUEST message: - "currency must be one of the following values: BRL, USD, EUR" traceId: 3b7c1f0e-8a2d-4c4e-9f1a-6d2b5e8c9a10 bankSlipPayer: summary: Boleto sem dados do pagador value: statusCode: 400 code: BAD_REQUEST message: "BANK_SLIP requires payer data: document, address.zipcode, address.number." traceId: 6a1d0c2e-4b3f-4e9a-8c7d-2f5e1a0b9c84 notEnabled: summary: Boleto não habilitado value: statusCode: 400 code: BAD_REQUEST message: BANK_SLIP is not enabled for this account. traceId: 9e2f4a6b-1c3d-4e5f-8a7b-0c1d2e3f4a5b "401": $ref: "#/components/responses/Unauthorized" "403": description: | A conta ainda não concluiu a verificação cadastral (`code` `KYC_PENDING`) ou a chamada veio de um IP não liberado. content: application/json: schema: $ref: "#/components/schemas/Error" example: statusCode: 403 code: KYC_PENDING message: Conclua a verificação da conta para criar cobranças. traceId: 1f2e3d4c-5b6a-4798-8a9b-0c1d2e3f4a5b "409": description: A `attemptIdempotencyKey` já foi usada nesta conta nos últimos 30 dias. content: application/json: schema: $ref: "#/components/schemas/Error" example: statusCode: 409 code: CONFLICT message: Idempotency key already used. Use a different key or omit it. traceId: 2a4c6e8f-0b1d-4f3a-8c5e-7a9b1d3f5e7c "500": $ref: "#/components/responses/InternalError" ``` **O formato da resposta depende de paymentMethod** Com `PIX` ou `BANK_SLIP` (ou `CRYPTO`), a resposta é a tentativa de pagamento: o `id` é da tentativa e o id da cobrança vem em `chargeId`. Sem `paymentMethod` ou com `CREDIT_CARD`, a resposta é a própria cobrança e o `id` é o da cobrança. Guarde o id da cobrança: é ele que o reembolso e as consultas pedem. ## Como funciona Uma **cobrança** guarda o que você vende: valor, moeda, `externalReference`, prazo e status. O pagamento em si acontece numa **tentativa de pagamento**, ligada à cobrança. Uma cobrança pode ter várias tentativas (um PIX que venceu, depois um cartão no checkout), mas só é paga uma vez. *Figura: Uma cobrança e suas tentativas de pagamento: a cobrança tem o status que importa; cada tentativa é um jeito de pagá-la.* - Cobrança - Tentativa na criação - Tentativa no checkout - Nova tentativa Por isso o formato da resposta muda. Com `PIX` ou `BANK_SLIP`, a API cria a cobrança e a tentativa na mesma chamada e devolve a tentativa, que é onde estão o QR Code e o boleto. Sem `paymentMethod`, ou com `CREDIT_CARD`, nenhuma tentativa é criada agora: a resposta é a cobrança, e a tentativa nasce quando o pagador escolhe o meio e paga em `checkoutUrl`. Dados de cartão nunca passam por esta API. *Figura: Cobrança PIX: a resposta já traz o QR Code; o pagamento é confirmado depois, pelo webhook charge.paid.* - Seu servidor → API Gates2b: POST /charge (PIX) - API Gates2b → API Gates2b: cria cobrança e tentativa - API Gates2b → Seu servidor: tentativa: QR Code + chargeId - Seu servidor → Pagador: mostra QR ou checkoutUrl - Pagador → API Gates2b: paga o PIX - API Gates2b → Seu servidor: webhook charge.paid ## Status da cobrança [#status-da-cobrança] *Figura: Ciclo de vida da cobrança: PENDING até o pagamento, PAID quando pago e REFUNDED só depois do reembolso total.* - PENDING: aguardando pagamento — (pagamento confirmado) - PAID: dispara charge.paid — (reembolso do valor total) - REFUNDED: todo o valor devolvido - undefined → undefined: EXPIRED: (prazo vence sem pagamento) - undefined → undefined: RETAINED: (valor retido pela plataforma) - Libere o pedido em `PAID`. Esse é o único status de cobrança paga. - Cada reembolso, parcial ou total, dispara `charge.refunded`. O parcial mantém a cobrança em `PAID` e aumenta `refundedAmount`; ela só vai a `REFUNDED` quando o total reembolsado chega a `grossAmount`. - Uma tentativa recusada (cartão negado, por exemplo) não muda a cobrança: ela continua `PENDING` e aceita nova tentativa até o prazo. - Nas consultas, uma cobrança `PENDING` com `expiresAt` vencido já aparece como `EXPIRED`. - `CANCELED` e `FAILED` também existem. Trate os dois como cobrança encerrada sem pagamento. Em cripto há mais um status, `PARTIAL`: o pagador transferiu menos que o cotado. A cobrança continua aberta e vira `PAID` quando o restante chega. Detalhes em [Cripto na cobrança](../../../guias/cripto-no-charge.mdx). ## Regras - A conta precisa ter a verificação cadastral concluída. Antes disso, a criação responde `403` com `code` `KYC_PENDING`. - `grossAmount` é string com ponto e duas casas decimais: `"49.90"`. Não envie vírgula nem notação científica. - O pagamento é confirmado pelo evento `charge.paid`, entregue às suas inscrições de webhook. O campo `webhookUrl` é gravado na cobrança, mas hoje não recebe notificação. Veja [Webhooks](../../../guias/webhooks.mdx). - Use `externalReference` para ligar a cobrança ao pedido no seu sistema. Ela volta no `charge.paid`. - `attemptIdempotencyKey` impede tentativa duplicada: a mesma chave usada de novo na conta, em até 30 dias, responde `409` e nada novo é criado. Depois de um timeout, [busque a cobrança pelo `externalReference`](./find-by-reference.mdx) antes de criar outra com chave nova. ## Boleto - `customerMeta.name`, `customerMeta.document` e o `customerMeta.address` completo (`zipcode`, `street`, `number`, `neighborhood`, `city`, `state`) são obrigatórios. Faltando algum, a resposta é `400` com todos os campos ausentes na mensagem, e a cobrança não é criada. - O boleto é emitido na hora. A resposta traz o boleto em `checkoutMeta.bankSlip` e um QR Code PIX que paga o mesmo valor em `checkoutMeta.pix`. - `bankSlip.value` e `bankSlip.fee` são inteiros em centavos de real (`15000` = R$ 150,00), enquanto `grossAmount` é string em unidades da moeda. Em cobrança `USD` ou `EUR`, o boleto cobra o valor convertido em reais. - A API não devolve imagem do boleto. Gere o código de barras a partir de `barcode` (padrão Interleaved 2 of 5) e mostre `digitableLine` para copiar. - Se o boleto não estiver habilitado na conta, a resposta é `400` com `BANK_SLIP is not enabled for this account.` ## Repasse de tarifas Com `passthroughFees: true`, `grossAmount` é o valor que você quer receber; o pagador paga esse valor mais as tarifas. A opção exige `paymentMethod` definido e não vale para `CRYPTO`. Sem ela, o pagador paga `grossAmount` e as tarifas saem do seu valor (`netAmount`). ## Split - O split divide o `netAmount`, não o `grossAmount`. `PERCENT` é um percentual dele; `FIXED`, um valor fixo em string com duas casas. - Cada parte vai para a conta dona do `email`. Se não houver conta com esse e-mail, a parte fica com você. - `splitSettlement` mostra a divisão efetiva, em centavos, depois que a cobrança é paga. ## Cripto Com `paymentMethod: "CRYPTO"`, a quantidade de itens em `gatewayOptions.cryptoTickers` muda o comportamento: - Um ticker trava a moeda. A resposta já traz endereço, valor e QR Code em `checkoutMeta.crypto`, e a reserva de 20 minutos começa a contar na criação. - Dois ou mais tickers, ou o campo omitido, deixam a escolha para o pagador no checkout. A resposta vem sem `checkoutMeta.crypto` e sem `qr_image`. Em `CRYPTO`, `checkoutMeta.redirectUrl` é uma página de pagamento alternativa para a tentativa, não a URL de retorno que você enviou em `gatewayOptions.redirectUrl`. Mande o pagador para `checkoutUrl`. Tickers aceitos, reserva, status e exibição do valor: [Cripto na cobrança](../../../guias/cripto-no-charge.mdx). --- # Buscar cobrança pela referência (/api-reference/endpoint/charge/find-by-reference) Retorna a cobrança da sua conta que tem o externalReference informado, para ligar o pedido à cobrança. ```yaml GET /charge: tags: - Cobranças operationId: findChargeByExternalReference summary: Buscar cobrança pela referência description: | Retorna a cobrança da sua conta com o `externalReference` informado. Use para reconciliar um pedido com a cobrança, por exemplo depois de um timeout na criação. parameters: - name: externalReference in: query required: true description: O `externalReference` enviado na criação. Comparação exata, com maiúsculas e minúsculas. schema: type: string maxLength: 255 example: pedido-0001 responses: "200": description: | A cobrança encontrada. Quando nenhuma cobrança da conta tem essa referência, a resposta também é `200`, com corpo vazio. content: application/json: schema: $ref: "#/components/schemas/Charge" example: id: 01JC8Z3R5W7Y9A1C3E5G7J9K2M kind: SALE status: PAID grossAmount: "49.90" netAmount: "47.35" refundedAmount: "0.00" currency: BRL externalReference: pedido-0001 description: Assinatura mensal expiresAt: 2026-11-30T23:59:59.000Z customerMeta: name: Maria da Silva document: 123******09 email: cl*****@example.com phone: null passthroughFees: false splitConfig: null splitSettlement: null canRefund: true canRefundPartial: true createdAt: 2026-10-22T14:00:00.000Z updatedAt: 2026-10-22T14:03:12.000Z "400": description: "`externalReference` ausente ou vazio." content: application/json: schema: $ref: "#/components/schemas/Error" example: statusCode: 400 code: BAD_REQUEST message: Query parameter externalReference is required traceId: 1a3c5e7b-9d1f-4b3d-8f5a-7c9e1b3d5f7a "401": $ref: "#/components/responses/Unauthorized" ``` **Não encontrada é 200 com corpo vazio** Quando nenhuma cobrança da conta tem a referência, a resposta é `200` sem corpo, não `404`. Verifique se o corpo está vazio antes de ler o JSON. ## Regras - A comparação é exata: `Pedido-1` não encontra `pedido-1`. Para busca parcial, use `search` em [Listar cobranças](./list.mdx). - A busca só olha as cobranças da conta da chave de API. - A API não impede duas cobranças com o mesmo `externalReference`. Se houver mais de uma, a resposta traz só uma, sem ordem garantida. Use uma referência única por cobrança, ou liste com `search` para ver todas. - Para ver o pagamento confirmado (quem pagou, identificador PIX), consulte o `id` retornado em [Consultar cobrança](./get.mdx). --- # Consultar cobrança (/api-reference/endpoint/charge/get) Retorna uma cobrança da sua conta com valores, tarifas, situação do reembolso e os dados do pagamento confirmado. ```yaml GET /charge/me/{id}: tags: - Cobranças operationId: getCharge summary: Consultar cobrança description: | Retorna uma cobrança da sua conta com valores, tarifas, situação do reembolso e o resumo do pagamento confirmado (quem pagou, identificador PIX, código de autorização do cartão). parameters: - name: id in: path required: true description: Id da cobrança (o `chargeId` da criação). schema: type: string example: 01JC8Z3R5W7Y9A1C3E5G7J9K2M responses: "200": description: A cobrança. content: application/json: schema: $ref: "#/components/schemas/ChargeDetail" example: id: 01JC8Z3R5W7Y9A1C3E5G7J9K2M kind: SALE status: PAID grossAmount: "49.90" netAmount: "47.35" refundedAmount: "0.00" currency: BRL externalReference: pedido-0001 description: Assinatura mensal expiresAt: 2026-11-30T23:59:59.000Z subscriptionId: null splitConfig: null feesMeta: percentSalesFee: 0.0399 amountPerSale: 0.56 totalFeeAmount: 2.55 customerMeta: name: Maria da Silva document: 123******09 email: cl*****@example.com phone: null canRefund: true canRefundPartial: true attemptIds: - 0192f4c6-7d1e-7a3b-9c2d-4e5f6a7b8c9d lastConfirmedAttempt: id: 0192f4c6-7d1e-7a3b-9c2d-4e5f6a7b8c9d status: CONFIRMED paymentMethod: PIX providerTransactionId: 70e451d6aa994cfb96229e5b74933540 endToEndId: E18236120202610221403s0123456789 payer: name: Maria da Silva document: "12345678909" createdAt: 2026-10-22T14:00:00.000Z updatedAt: 2026-10-22T14:03:12.000Z createdAt: 2026-10-22T14:00:00.000Z updatedAt: 2026-10-22T14:03:12.000Z "401": $ref: "#/components/responses/Unauthorized" "404": description: A cobrança não existe ou é de outra conta. content: application/json: schema: $ref: "#/components/schemas/Error" example: statusCode: 404 code: NOT_FOUND message: Charge 01JC8Z3R5W7Y9A1C3E5G7J9K2M not found traceId: 5c7e9a1b-3d5f-4a7c-9e1b-3d5f7a9c1e3d ``` ## Regras - Use o id da cobrança. Na criação com `PIX` ou `BANK_SLIP` (ou `CRYPTO`), ele vem em `chargeId`, não em `id`. - Cobrança de outra conta responde `404`, igual a uma que não existe. - Uma cobrança `PENDING` com prazo vencido aparece como `EXPIRED`. `checkoutUrl` só vem enquanto a cobrança pode ser paga (`PENDING` ou `PARTIAL`). - `lastConfirmedAttempt` é `null` até o pagamento ser confirmado. Depois, traz `endToEndId` em PIX e `authorizationCode` em cartão, quando o processador informa. - `lastConfirmedAttempt.payer` vem sem máscara: são os dados de quem efetivamente pagou, que podem ser diferentes de `customerMeta`. Trate como dado pessoal. - `canRefund` considera só o status e o prazo de 7 dias. O saldo disponível é verificado no [reembolso](./refund.mdx). - `feesMeta` pode trazer chaves além das documentadas. Dependa só de `totalFeeAmount`, `percentSalesFee`, `amountPerSale` e `fxLock`. --- # Listar cobranças (/api-reference/endpoint/charge/list) Lista as cobranças da sua conta com paginação e filtros por status, data, valor, meio de pagamento e texto. ```yaml GET /charge/list: tags: - Cobranças operationId: listCharges summary: Listar cobranças description: | Lista as cobranças da sua conta, paginadas, da mais recente para a mais antiga por padrão. Todos os filtros são opcionais e se combinam. parameters: - name: page in: query description: Página, a partir de `1`. schema: type: integer minimum: 1 default: 1 example: 1 - name: limit in: query description: Itens por página, até `100`. schema: type: integer minimum: 1 maximum: 100 default: 20 example: 50 - name: search in: query description: | Busca parcial, sem diferenciar maiúsculas, no id da cobrança, no `externalReference`, na descrição e nos ids das tentativas. schema: type: string maxLength: 255 example: pedido-00 - name: status in: query description: | Um ou mais status, separados por vírgula (`PAID,REFUNDED`) ou com o parâmetro repetido. Valores desconhecidos são ignorados. schema: type: string example: PAID,REFUNDED - name: kind in: query description: | Tipo da cobrança, mesmo formato de `status`. `SALE` é a cobrança normal; `DISCOUNT_MED_APPLY` é o lançamento de desconto por devolução PIX (MED). Omitido, a lista traz os dois. schema: type: string example: SALE - name: from in: query description: Início do intervalo de criação, em ISO 8601. schema: type: string format: date-time example: 2026-10-01T00:00:00-03:00 - name: to in: query description: Fim do intervalo de criação, em ISO 8601. schema: type: string format: date-time example: 2026-10-31T23:59:59-03:00 - name: minAmount in: query description: Valor mínimo de `grossAmount`, em unidades da moeda (`10.5` = 10,50). schema: type: number minimum: 0 example: 10 - name: maxAmount in: query description: Valor máximo de `grossAmount`, em unidades da moeda. schema: type: number minimum: 0 example: 500 - name: amount in: query description: | Valor exato de `grossAmount`, em **centavos** (`4990` = 49,90). Ignorado se `minAmount` ou `maxAmount` vier junto. schema: type: integer minimum: 0 example: 4990 - name: currency in: query description: Moeda da cobrança. schema: type: string enum: - BRL - USD - EUR example: BRL - name: paymentMethod in: query description: Meio de pagamento da tentativa, ou o meio fixado na criação. schema: type: string enum: - PIX - BANK_SLIP - CREDIT_CARD - CRYPTO example: PIX - name: subscriptionId in: query description: Só as cobranças geradas por esta assinatura. schema: type: string maxLength: 36 - name: sortField in: query description: Campo de ordenação. schema: type: string enum: - createdAt - grossAmount default: createdAt - name: sortDirection in: query description: Direção da ordenação, em minúsculas. schema: type: string enum: - desc - asc default: desc responses: "200": description: Página de cobranças. O total também vem no header `X-Total-Count`. headers: X-Total-Count: description: Total de cobranças com os filtros aplicados, igual a `total` no corpo. schema: type: integer example: 1 content: application/json: schema: $ref: "#/components/schemas/ChargeListResponse" example: items: - id: 01JC8Z3R5W7Y9A1C3E5G7J9K2M kind: SALE status: PAID grossAmount: "49.90" refundedAmount: "0.00" currency: BRL externalReference: pedido-0001 description: Assinatura mensal expiresAt: 2026-11-30T23:59:59.000Z subscriptionId: null paymentMethod: PIX customerMeta: name: Maria da Silva document: 123******09 email: cl*****@example.com phone: null canRefund: true canRefundPartial: true attemptIds: - 0192f4c6-7d1e-7a3b-9c2d-4e5f6a7b8c9d createdAt: 2026-10-22T14:00:00.000Z updatedAt: 2026-10-22T14:03:12.000Z actualPage: 1 pagesQuantity: 1 total: 1 "400": description: Parâmetro inválido, como `limit` acima de `100` ou data fora do ISO 8601. content: application/json: schema: $ref: "#/components/schemas/Error" "401": $ref: "#/components/responses/Unauthorized" ``` ## Regras - A paginação usa `page` e `limit` (até `100` por página). A resposta traz `total`, `pagesQuantity` e `actualPage`; o total também vem no header `X-Total-Count`. - Para reconciliar um período, filtre por `from` e `to` e percorra as páginas até `actualPage` igual a `pagesQuantity`. Ordene por `createdAt` para a paginação ficar estável. - `minAmount` e `maxAmount` são em unidades da moeda (`49.9`); `amount` é o valor exato em centavos (`4990`). - `sortDirection` aceita só minúsculas: `asc` ou `desc`. - Uma cobrança `PENDING` com prazo vencido aparece como `EXPIRED`, mesmo antes de o status ser gravado. - Os itens são um resumo: não trazem `netAmount`, tarifas nem o pagamento confirmado. Para isso, use [Consultar cobrança](./get.mdx). --- # Reembolsar cobrança (/api-reference/endpoint/charge/refund) Devolve ao pagador o valor total ou parcial de uma cobrança paga, descontando do seu saldo disponível. ```yaml POST /charge/{chargeId}/refund: tags: - Cobranças operationId: refundCharge summary: Reembolsar cobrança description: | Devolve ao pagador todo o valor de uma cobrança paga, ou parte dele. O reembolso é processado na hora: a resposta já traz o resultado em `status`, e o valor sai do seu saldo disponível. parameters: - name: chargeId in: path required: true description: Id da cobrança, como veio em `id` (ou `chargeId`) na criação. schema: type: string example: 01JC8Z3R5W7Y9A1C3E5G7J9K2M requestBody: required: false content: application/json: schema: $ref: "#/components/schemas/CreateChargeRefundRequest" examples: partial: summary: Reembolso parcial value: value: "20.00" reason: Item fora de estoque full: summary: Reembolso do restante value: reason: Pedido cancelado pelo cliente responses: "201": description: Reembolso processado. content: application/json: schema: $ref: "#/components/schemas/ChargeRefund" example: id: 0192f4d0-2b1a-7c3d-8e4f-5a6b7c8d9e0f chargeId: 01JC8Z3R5W7Y9A1C3E5G7J9K2M amount: "20.00000000" status: PROCESSED reason: Item fora de estoque gateway: null externalRefundId: e2e-7c1a9b3f createdAt: 2026-10-22T15:30:00.000Z "400": description: | A cobrança não está paga, tem mais de 7 dias, o valor passa do que resta reembolsar, o saldo disponível não cobre o valor, ou o reembolso foi recusado ao ser processado. content: application/json: schema: $ref: "#/components/schemas/Error" examples: notPaid: summary: Cobrança não paga value: statusCode: 400 code: BAD_REQUEST message: Charge precisa estar PAID para refund (status=PENDING). traceId: 2c4e6a8b-0d1f-4a3b-9c5d-7e9f1a3b5c7d balance: summary: Saldo insuficiente value: statusCode: 400 code: BAD_REQUEST message: "Saldo insuficiente para refund. Disponível: 12.30; necessário: 20.00." traceId: 5d7f9b1c-3e5a-4c7d-8f1b-3d5f7a9c1e3b "401": $ref: "#/components/responses/Unauthorized" "403": description: A cobrança é de outra conta. content: application/json: schema: $ref: "#/components/schemas/Error" "404": $ref: "#/components/responses/NotFound" ``` ## Como funciona O reembolso é síncrono: a mesma chamada valida o pedido, devolve o dinheiro ao pagador e debita o seu saldo. Quando a resposta chega com `status: "PROCESSED"`, o reembolso está feito. *Figura: Um reembolso de cobrança, do pedido à resposta, numa única chamada.* Exemplo: numa cobrança paga de `100.00`, um reembolso de `30.00` deixa a cobrança em `PAID` com `refundedAmount: "30.00"`. Um segundo pedido sem `value` reembolsa os `70.00` restantes e a cobrança passa a `REFUNDED`. ## Regras - A cobrança precisa ter sido paga e criada há no máximo 7 dias. Fora disso, a resposta é `400`. - Sem `value`, o reembolso cobre tudo o que ainda não foi reembolsado. Com `value`, a soma dos reembolsos não pode passar de `grossAmount`. - O valor sai do seu saldo disponível. Se o saldo não cobrir, a resposta é `400` com o disponível e o necessário na mensagem. - O reembolso sai só do seu saldo. As partes de split já distribuídas não são debitadas. - Alguns meios de pagamento só aceitam reembolso do valor total. Nesses casos, um `value` menor que `grossAmount` responde `400` pedindo o valor integral. - O processamento é síncrono: `status: "PROCESSED"` na resposta significa reembolso feito. Se o processamento falhar, a resposta é `400` com mensagem genérica; tente de novo ou fale com o suporte. - Cada reembolso processado gera o evento `charge.refunded` nas suas inscrições de webhook. --- # Criar pagamento em cripto (/api-reference/endpoint/crypto-payments) Cria um pagamento em cripto a partir de um valor em moeda fiduciária e devolve carteira e QR Code. ```yaml POST /payments/v2/crypto: tags: - Cripto operationId: createCryptoPayment summary: Criar pagamento em cripto description: | Cria um pagamento em cripto com o valor definido em moeda fiduciária e devolve o endereço da carteira e o QR Code. Para integrações novas, prefira `POST /charge` com `paymentMethod: "CRYPTO"`. servers: - url: https://api-gateway.gates2b.com requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateCryptoPaymentRequest" example: amount: 500 fiat_currency: BRL pay_currency: USDTBSC customer_name: Maria da Silva customer_email: cliente@example.com external_reference: pedido-0005 responses: "201": description: Pagamento criado, aguardando a transferência. content: application/json: schema: $ref: "#/components/schemas/CryptoPayment" example: id: 68d2fa97b30181b2d2f13600 id_transaction: d615bb9b-e935-47c4-ac19-ad046e4b5f1a status: WAITING_PAYMENT payment_id: "6043353044" qr_code: iVBORw0KGgoAAAANSUhEUgAA... pay_address: 0x1CEfB8730786f34af8B10dC4e5B8028F79a63abd?amount=91.24 amount: 500 currency: BRL expires_at: 2026-10-23T14:00:00.000Z redirect_url: null "400": description: Campo inválido ou campo desconhecido no corpo. content: application/json: schema: $ref: "#/components/schemas/GatewayError" example: statusCode: 400 message: Validation failed errors: - property: pay_currency errors: - Pay currency must be a valid crypto currency code "401": description: Chave de API ausente ou inválida. content: application/json: schema: $ref: "#/components/schemas/GatewayError" example: statusCode: 401 message: Unauthorized "500": description: Falha ao criar o pagamento. O corpo não traz detalhes. content: application/json: schema: $ref: "#/components/schemas/GatewayError" example: message: Internal server error ``` **Outro endereço base e outro formato de erro** Este endpoint responde em https://api-gateway.gates2b.com, não no endereço principal da API. Os erros também têm outro corpo: sem `code` e sem `traceId`. ## Regras - Para integrações novas, prefira [Criar cobrança](./charge/create.mdx) com `paymentMethod: "CRYPTO"`: ela devolve link de checkout, status de cobrança e o evento `charge.paid`. - Só `amount` é obrigatório, mas envie sempre `fiat_currency` e `pay_currency`. Sem eles, valem `USD` e `USDTBSC`. - `amount` é número na moeda fiduciária (`500.00`), não string. - `pay_currency` usa os códigos deste endpoint (`USDTBSC`, `BTC`…), não os tickers `REDE_ATIVO` de `/charge`. - Campo desconhecido no corpo responde `400`. - `qr_code` é a imagem PNG em base64 sem o prefixo `data:`. Para usar em ``, prefixe com `data:image/png;base64,`. - Consulte o andamento com [Consultar pagamento em cripto](./invoices/payment-gateway-detail.mdx), usando o `id` da resposta. --- # Consultar pagamento em cripto (/api-reference/endpoint/invoices/payment-gateway-detail) Retorna um pagamento criado pelo endpoint de cripto, com valores, status e dados da carteira. ```yaml GET /invoices/payment-gateway/{id}: tags: - Cripto operationId: getCryptoInvoice summary: Consultar pagamento em cripto description: | Retorna um pagamento criado por `POST /payments/v2/crypto`, no mesmo formato de um item da listagem. parameters: - name: id in: path required: true description: Id do pagamento, como veio em `id` na criação (24 caracteres hexadecimais). schema: type: string example: 68d2fa97b30181b2d2f13600 responses: "200": description: | O pagamento. Quando o id não existe ou é de outra conta, a resposta também é `200`, mas sem corpo. content: application/json: schema: $ref: "#/components/schemas/CryptoInvoice" example: id: 68d2fa97b30181b2d2f13600 type: PAYMENT amount: total: 500 final: 88.5 currency: BRL pay_currency: USDTBSC fiat_currency: BRL dollar: base: 91.24 effective: 88.5 transaction: id: d615bb9b-e935-47c4-ac19-ad046e4b5f1a gatewayId: "6043353044" status: PAYMENT_RECEIVED extra: image: iVBORw0KGgoAAAANSUhEUgAA... text: 0x1CEfB8730786f34af8B10dC4e5B8028F79a63abd?amount=91.24 externalReference: pedido-0005 fees: value: 15 client: name: Maria da Silva email: cliente@example.com options: redirectUrl: null expireAt: 2026-10-23T14:00:00.000Z createdAt: 2026-10-22T14:00:00.000Z updatedAt: 2026-10-22T14:12:41.000Z "401": $ref: "#/components/responses/Unauthorized" "500": description: O id não tem o formato de 24 caracteres hexadecimais. content: application/json: schema: $ref: "#/components/schemas/Error" ``` ## Regras - Use o `id` devolvido por [Criar pagamento em cripto](../crypto-payments.mdx) (24 caracteres hexadecimais), não o `id_transaction`. - Id inexistente ou de outra conta responde `200` com corpo vazio. Trate corpo vazio como "não encontrado". - Id fora do formato de 24 caracteres hexadecimais responde `500`. - O pagamento está pago quando `transaction.status` é `PAYMENT_RECEIVED`. --- # Listar pagamentos em cripto (/api-reference/endpoint/invoices/payment-gateway-list) Lista os pagamentos criados pelo endpoint de cripto, com paginação e filtros por status, data e valor. ```yaml GET /invoices/payment-gateway: tags: - Cripto operationId: listCryptoInvoices summary: Listar pagamentos em cripto description: | Lista os pagamentos criados por `POST /payments/v2/crypto` na conta da chave, do mais recente para o mais antigo, com paginação e filtros. parameters: - name: page in: query description: Página, a partir de `1`. schema: type: integer minimum: 1 default: 1 example: 1 - name: quantityPerPage in: query description: Itens por página. schema: type: integer minimum: 1 default: 10 example: 20 - name: orderBy in: query description: | Campo e direção separados por ponto: `createdAt.DESC`, `amount.total.ASC`. Padrão: `createdAt.DESC`. schema: type: string example: createdAt.DESC - name: status in: query description: Filtra pelo status do pagamento (`transaction.status`). schema: $ref: "#/components/schemas/CryptoInvoiceStatus" - name: type in: query description: Filtra pelo tipo do registro. Pagamentos recebidos são `PAYMENT`. schema: type: string example: PAYMENT - name: start_date in: query description: | Data inicial (`AAAA-MM-DD`), considerada a partir de 00:00 no horário de Brasília. Só filtra quando `end_date` também é enviado. schema: type: string format: date example: 2026-10-01 - name: end_date in: query description: | Data final (`AAAA-MM-DD`), incluída até 23:59:59 no horário de Brasília. Só filtra quando `start_date` também é enviado. schema: type: string format: date example: 2026-10-31 - name: amount in: query description: Valor exato em centavos da moeda fiduciária (`50000` = 500,00). schema: type: integer minimum: 0 example: 50000 - name: currency in: query description: Filtra pela moeda fiduciária ou pela moeda cripto do pagamento. schema: type: string example: USDTBSC responses: "200": description: Página de pagamentos. content: application/json: schema: $ref: "#/components/schemas/CryptoInvoiceList" example: items: - id: 68d2fa97b30181b2d2f13600 type: PAYMENT amount: total: 500 final: 88.5 currency: BRL pay_currency: USDTBSC fiat_currency: BRL dollar: base: 91.24 effective: 88.5 transaction: id: d615bb9b-e935-47c4-ac19-ad046e4b5f1a gatewayId: "6043353044" status: WAITING_PAYMENT extra: image: iVBORw0KGgoAAAANSUhEUgAA... text: 0x1CEfB8730786f34af8B10dC4e5B8028F79a63abd?amount=91.24 externalReference: pedido-0005 fees: value: 15 client: name: Maria da Silva email: cliente@example.com options: redirectUrl: null expireAt: 2026-10-23T14:00:00.000Z createdAt: 2026-10-22T14:00:00.000Z updatedAt: 2026-10-22T14:00:00.000Z actualPage: 1 pagesQuantity: 1 total: 1 "401": $ref: "#/components/responses/Unauthorized" "500": $ref: "#/components/responses/InternalError" ``` ## Regras - Lista os pagamentos criados por [Criar pagamento em cripto](../crypto-payments.mdx). Para cobranças de `/charge` em cripto, use as consultas de cobrança. - O filtro de data só vale com `start_date` e `end_date` juntos, e considera dias inteiros no horário de Brasília. - `amount` no filtro é em centavos (`50000` = 500,00); no corpo da resposta, os valores são números em unidades da moeda. - A resposta pode levar até 45 segundos para refletir um pagamento novo ou uma mudança de status. --- # Reembolsar invoice (/api-reference/endpoint/refund) Devolve ao pagador o valor total ou parcial de uma invoice paga do recurso legado /invoices. ```yaml POST /refunds/invoice/{invoiceId}: tags: - Invoices (legado) operationId: refundInvoice summary: Reembolsar invoice description: | Devolve ao pagador todo o valor de uma invoice paga, ou parte dele. Use só para vendas criadas pelo recurso legado `/invoices`; para cobranças de `/charge`, use `POST /charge/{chargeId}/refund`. parameters: - name: invoiceId in: path required: true description: Id numérico da invoice. schema: type: integer example: 72276 requestBody: required: false content: application/json: schema: $ref: "#/components/schemas/CreateInvoiceRefundRequest" example: value: 50 reason: Produto com defeito responses: "201": description: Reembolso processado. content: application/json: schema: $ref: "#/components/schemas/InvoiceRefund" example: id: 7d3f1e2a-9b8c-4d6e-a5f4-3c2b1a0e9d8c gateway: null transaction_id: 70e451d6aa994cfb96229e5b74933540 amount: 50 description: null status: PROCESSED external_refund_id: "" reason: Produto com defeito invoice: id: 72276 amount: 120 amount_final: 115.2 status: Reembolso solicitado transaction_pix_id: 70e451d6aa994cfb96229e5b74933540 external_reference: pedido-0099 user: id: 456 user: id: 456 username: Loja Exemplo email: financeiro@example.com createdAt: 2026-10-22T14:30:15.123Z updatedAt: 2026-10-22T14:30:15.456Z "400": description: | A invoice não está paga, tem mais de 7 dias, o valor passa do valor da invoice, o saldo não cobre o reembolso, ou houve outro pedido de reembolso para a mesma invoice nos últimos 60 segundos. content: application/json: schema: $ref: "#/components/schemas/Error" examples: notPaid: summary: Invoice não paga value: statusCode: 400 code: BAD_REQUEST message: Only PAID invoices can be refunded traceId: 8b0d2f4a-6c8e-4a1b-9d3f-5a7c9e1b3d5f tooSoon: summary: Pedido repetido value: statusCode: 400 code: BAD_REQUEST message: Espere 60 segundos antes de executar novamente. traceId: 0a2c4e6b-8d0f-4b2d-a4f6-8b0d2f4a6c8e "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" ``` Este endpoint vale só para invoices, criadas pelo recurso legado. Para cobranças de `/charge`, use [Reembolsar cobrança](./charge/refund.mdx). ## Regras - `value` é número em reais (`50.00`), diferente do reembolso de cobrança, que usa string. - A invoice precisa estar paga e ter sido criada há no máximo 7 dias. Fora disso, a resposta é `400`. - Sem `value`, o reembolso é do valor total da invoice. Um `value` maior que o da invoice responde `400`. - O valor sai do seu saldo. Se o saldo não cobrir, a resposta é `400`. - Um segundo pedido para a mesma invoice em menos de 60 segundos é recusado com `400`. Espere a resposta do primeiro antes de repetir. - `status: "PROCESSED"` na resposta significa reembolso feito; a invoice passa a `Reembolso solicitado`. --- # Reenviar webhook de invoice (/api-reference/endpoint/resend-webhook) Gera de novo o evento invoice.paid de uma invoice paga e o entrega às suas inscrições de webhook. ```yaml POST /invoices/resend-webhook/{id}: tags: - Invoices (legado) operationId: resendInvoiceWebhook summary: Reenviar webhook de invoice description: | Gera de novo o evento `invoice.paid` de uma invoice paga e o entrega às inscrições de webhook da conta que assinam esse evento. Use quando o seu sistema perdeu a notificação original. parameters: - name: id in: path required: true description: Id numérico da invoice. schema: type: integer example: 72276 responses: "201": description: Evento gerado. content: application/json: schema: $ref: "#/components/schemas/ResendWebhookResult" example: message: Webhooks reenviados com sucesso invoiceId: 72276 webhooksSent: emitted: true outboxCount: 1 "400": description: O id não é numérico ou a invoice não está paga. content: application/json: schema: $ref: "#/components/schemas/Error" example: statusCode: 400 code: BAD_REQUEST message: "Invoice 72276 não está com status PAGAMENTO_REALIZADO. Status atual: Aguardando pagamento" traceId: 4e6a8c0b-2d4f-4a6c-8e0b-2d4f6a8c0e2a "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" ``` ## Regras - Só invoices pagas: outra situação responde `400` com o status atual na mensagem. - O evento reenviado é sempre `invoice.paid`, entregue às inscrições de webhook da conta que assinam esse evento. A URL de webhook global configurada no painel não recebe o reenvio. - Cada reenvio é uma entrega nova, com `x-Webhook-Event-Id` novo. Se você deduplica pelo id do evento, deduplique também pelo `id` da invoice no corpo. - `webhooksSent.outboxCount` é o número de entregas criadas. `0` significa que nenhuma inscrição assina `invoice.paid`: crie ou atualize uma inscrição antes de reenviar. Veja [Webhooks](../../guias/webhooks.mdx). --- # Bloquear cliente (/api-reference/endpoint/subscription/customer/block) Muda o status do cliente para BLOCKED, impedindo que ele seja usado em novas assinaturas. ```yaml POST /customer/{id}/block: tags: - Clientes operationId: blockCustomer summary: Bloquear cliente description: | Muda o status do cliente para `BLOCKED`. Um cliente bloqueado não pode ser usado em `customerId` para criar assinatura. responses: "201": description: Cliente bloqueado. content: application/json: schema: $ref: "#/components/schemas/Customer" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" ``` ## Exemplo ```bash curl -X POST "https://api.gates2b.com/customer/01JB7Z1A2B3C4D5E6F7G8H9J0K/block" \ -H "Authorization: Bearer $API_KEY" ``` A resposta traz o cliente com `status: BLOCKED`. ## Regras - Com o cliente bloqueado, [Criar assinatura](../subscription/create.mdx) com o `customerId` dele responde `400`. - O bloqueio não cancela nem pausa as assinaturas que o cliente já tem. Para parar de cobrar, use [Cancelar assinatura](../subscription/status.mdx). - O cliente bloqueado continua contando como duplicata em [Cadastrar cliente](./create.mdx). - Para reverter, use [Desbloquear cliente](./unblock.mdx). --- # Cadastrar cliente (/api-reference/endpoint/subscription/customer/create) Cadastra um cliente sem abrir assinatura, para usar depois em customerId. Recusa duplicatas com 409. ```yaml POST /customer: tags: - Clientes operationId: createCustomer summary: Cadastrar cliente description: | Cadastra um cliente sem abrir assinatura, para usar depois em `customerId`. Recusa com `409` um cliente com o mesmo e-mail ou telefone de outro já cadastrado. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CustomerInput" examples: complete: summary: Cadastro completo (modo A) value: name: João da Silva taxID: "12345678909" email: cliente@example.com phone: "5511999999999" address: zipcode: "01310100" street: Avenida Paulista number: "1000" neighborhood: Bela Vista city: São Paulo state: SP country: BR minimal: summary: Só nome e e-mail (modo B) value: name: Maria Souza email: cliente@example.com responses: "201": description: Cliente cadastrado. content: application/json: schema: $ref: "#/components/schemas/CustomerCreateResponse" examples: complete: summary: Modo A value: id: 01JB7Z1A2B3C4D5E6F7G8H9J0K name: João da Silva taxID: 123******09 email: cl*****@example.com phone: 55*******99 addressZipcode: "01310100" addressStreet: Avenida Paulista addressNumber: "1000" addressNeighborhood: Bela Vista addressCity: São Paulo addressState: SP addressComplement: null addressCountry: BR status: ACTIVE customerIdentityId: null invitedAt: null activatedAt: 2026-05-28T12:58:00.000Z createdAt: 2026-05-28T12:58:00.000Z updatedAt: 2026-05-28T12:58:00.000Z mode: A invite: null minimal: summary: Modo B value: id: 01JB7ZA1B2C3D4E5F6G7H8J9K0 name: Maria Souza taxID: null email: cl*****@example.com phone: null addressZipcode: null addressStreet: null addressNumber: null addressNeighborhood: null addressCity: null addressState: null addressComplement: null addressCountry: null status: ACTIVE customerIdentityId: null invitedAt: 2026-05-28T12:58:00.000Z activatedAt: null createdAt: 2026-05-28T12:58:00.000Z updatedAt: 2026-05-28T12:58:00.000Z mode: B invite: url: https://portal.example.com/activate?token=q8Zx3vN1 expiresInSeconds: 259200 "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "409": description: Já existe um cliente da conta com o mesmo e-mail ou telefone (inclusive bloqueado). content: application/json: schema: $ref: "#/components/schemas/Error" example: statusCode: 409 code: CUSTOMER_ALREADY_EXISTS message: Você já tem um cliente com este e-mail. Use `customerId` para reaproveitá-lo. traceId: 3b9c6f2a-71d4-4e0b-b8a5-0c2e9f41d7a6 ``` ## Como funciona Cadastre o cliente antes quando ele vai ter mais de uma assinatura, ou quando você quer validar os dados antes de abrir o contrato. Depois, crie as assinaturas com `customerId`. Se faltar algum dado que o Pix Automático exige, o cliente recebe um convite para completar o cadastro: *Figura: Cadastro incompleto (modo B): o cliente completa os dados pelo convite e as assinaturas Pix pendentes seguem para a autorização.* - Cadastro incompleto: Resposta com mode B e invite.url. - Repasse o convite: Validade em invite.expiresInSeconds (padrão de 72 h). - Cliente completa os dados: Documento, telefone e endereço. - Autorização liberada: Assinaturas Pix em PENDING_CUSTOMER vão para AWAITING_PAYER_AUTHORIZATION. ## Regras - Obrigatórios: `name` e pelo menos um entre `email` e `phone`. Sem os dois, a resposta é `400`. - Não exige a verificação da conta (KYC/KYB): cadastrar cliente não gera cobrança. - O mesmo cadastro pode nascer dentro de [Criar assinatura](../subscription/create.mdx), no campo `customer`, com a mesma validação. A diferença: lá um cliente novo é sempre criado; aqui a duplicata é recusada. ### Modo A e modo B O payload decide o modo; não há campo para escolher. - **Modo A**: `name`, `taxID`, `email`, `phone` e endereço completo (menos `complement`). `invite` volta `null`. - **Modo B**: falta algum desses dados. A resposta traz `invite.url`, um link para o cliente completar o cadastro, válido por `invite.expiresInSeconds`. Repasse o link ao cliente, principalmente se ele não tem e-mail. O modo descreve o cadastro, não o que a assinatura vai exigir. Um cliente em modo B com nome e e-mail já serve para um plano de cartão. Só o plano Pix precisa do cadastro completo. ### Duplicata - Um cliente da conta com o mesmo e-mail ou telefone responde `409` com `code: CUSTOMER_ALREADY_EXISTS`. Cliente bloqueado também conta. - E-mail é comparado sem diferenciar maiúsculas; telefone, só pelos dígitos. - A resposta não traz o id do cliente existente. Encontre-o em [Listar clientes](./list.mdx) com o filtro `email` ou `phone` e use-o em `customerId`. Se ele estiver bloqueado, [desbloqueie](./unblock.mdx) em vez de cadastrar de novo. --- # Consultar cliente (/api-reference/endpoint/subscription/customer/get) Devolve um cliente da conta pelo id, com documento, e-mail e telefone mascarados. ```yaml GET /customer/{id}: tags: - Clientes operationId: getCustomer summary: Consultar cliente description: Devolve um cliente da conta pelo id, com e-mail, telefone e documento mascarados. responses: "200": description: O cliente. content: application/json: schema: $ref: "#/components/schemas/Customer" examples: customer: $ref: "#/components/examples/Customer" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" ``` `taxID`, `email` e `phone` vêm mascarados; o endereço vem completo, em campos separados (`addressZipcode`, `addressStreet`…). Responde `404` se o cliente não existe ou é de outra conta. --- # Listar clientes (/api-reference/endpoint/subscription/customer/list) Lista os clientes da conta, do mais recente para o mais antigo, com filtro por status, e-mail e telefone. ```yaml GET /customer: tags: - Clientes operationId: listCustomers summary: Listar clientes description: | Lista os clientes da conta, do mais recente para o mais antigo, com filtros opcionais por status, e-mail e telefone. E-mail, telefone e documento vêm mascarados. parameters: - name: status in: query description: Filtra pelo status do cliente. schema: $ref: "#/components/schemas/CustomerStatus" - name: email in: query description: Filtra pelo e-mail exato, sem diferenciar maiúsculas de minúsculas. schema: type: string format: email example: cliente@example.com - name: phone in: query description: Filtra pelo telefone exato. Envie só dígitos, com DDI e DDD, como ele é gravado. schema: type: string example: "5511999999999" - $ref: "#/components/parameters/Limit" - $ref: "#/components/parameters/Offset" responses: "200": description: Página de clientes. content: application/json: schema: type: object required: - data - total properties: data: type: array items: $ref: "#/components/schemas/Customer" total: type: integer description: Quantidade de itens **nesta página**, não o total da conta. example: 1 examples: page: $ref: "#/components/examples/CustomerPage" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" ``` ## Exemplo Encontrar o cliente que já tem um e-mail, por exemplo depois de um `409` em [Cadastrar cliente](./create.mdx): ```bash curl "https://api.gates2b.com/customer?email=cliente@example.com" \ -H "Authorization: Bearer $API_KEY" ``` Use o `id` do item em `data` como `customerId` em [Criar assinatura](../subscription/create.mdx). ## Regras - `email` busca o endereço exato, sem diferenciar maiúsculas de minúsculas. - `phone` busca o número exato como é gravado: só dígitos, com DDI e DDD (`5511999999999`). Pontuação no filtro não encontra nada. - A página tem 50 itens por padrão e no máximo 100. Avance com `offset`. - `total` é a quantidade de itens **desta página**, não o total da conta. - `taxID`, `email` e `phone` vêm mascarados. --- # Desbloquear cliente (/api-reference/endpoint/subscription/customer/unblock) Volta o status do cliente para ACTIVE, liberando-o para novas assinaturas. ```yaml POST /customer/{id}/unblock: tags: - Clientes operationId: unblockCustomer summary: Desbloquear cliente description: Volta o status do cliente para `ACTIVE`, liberando-o para novas assinaturas. responses: "201": description: Cliente desbloqueado. content: application/json: schema: $ref: "#/components/schemas/Customer" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" ``` Depois do desbloqueio, o cliente pode ser usado de novo em `customerId` em [Criar assinatura](../subscription/create.mdx). --- # Atualizar cliente (/api-reference/endpoint/subscription/customer/update) Altera os dados enviados de um cliente. null apaga o campo; os ausentes ficam como estão. ```yaml PATCH /customer/{id}: tags: - Clientes operationId: updateCustomer summary: Atualizar cliente description: | Altera os campos enviados e mantém os demais. `null` apaga o campo. As assinaturas já criadas guardam a cópia dos dados feita na criação (`customerMeta`) e não mudam. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CustomerUpdateRequest" example: phone: "5511988887777" address: number: "1200" complement: null responses: "200": description: Cliente atualizado. content: application/json: schema: $ref: "#/components/schemas/Customer" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "409": description: Outro cliente da conta já usa o e-mail ou o telefone enviado. content: application/json: schema: $ref: "#/components/schemas/Error" example: statusCode: 409 code: CONFLICT message: Você já tem outro cliente com esse telefone. traceId: 3b9c6f2a-71d4-4e0b-b8a5-0c2e9f41d7a6 ``` ## Regras - Envie os dados sem máscara. A resposta volta mascarada. - `null` apaga o campo. `name` não pode ficar vazio. - No `address`, cada campo enviado é alterado e os ausentes ficam como estão. A resposta traz o endereço em campos separados (`addressZipcode`…). - E-mail ou telefone já usados por outro cliente da conta respondem `409`. - As assinaturas existentes não mudam: elas guardam a cópia dos dados feita na criação, em `customerMeta`. --- # Criar plano (/api-reference/endpoint/subscription/plan/create) Cria o modelo de uma cobrança recorrente, com valor em centavos, periodicidade e meio de pagamento. ```yaml POST /plan: tags: - Planos operationId: createPlan summary: Criar plano description: | Cria um plano: o valor, a periodicidade e o meio de pagamento de uma cobrança recorrente. Cada assinatura guarda uma cópia dos termos do plano no momento em que é criada. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PlanCreateRequest" examples: pix: summary: Pix Automático value: name: Plano Mensal Premium amountCents: 9990 frequency: MONTHLY type: PIX_RECURRING paymentMethods: - PIX pixRecurringOptions: journey: ONLY_RECURRENCY retryPolicy: THREE_RETRIES_7_DAYS card: summary: Cartão de crédito value: name: Plano Mensal Premium amountCents: 9990 frequency: MONTHLY type: RECURRENT paymentMethods: - CREDIT_CARD responses: "201": description: Plano criado. content: application/json: schema: $ref: "#/components/schemas/Plan" examples: pix: $ref: "#/components/examples/PixPlan" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" ``` ## Como funciona O plano é o modelo; a assinatura é o contrato de um cliente com esse modelo. Crie o plano uma vez e use o `id` dele em quantas assinaturas quiser. *Figura: Ordem de criação: plano primeiro, cliente opcionalmente antes, assinatura por último.* - Criar plano: Valor, periodicidade e meio de pagamento. Uma vez por oferta. - Cadastrar cliente: Opcional: dá para mandar o cliente dentro da assinatura. - Criar assinatura: planId + cliente + dayGenerateCharge. - Pagador autoriza: Pix no app do banco ou cartão no checkout. ### Exemplo ```bash curl -X POST "https://api.gates2b.com/plan" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Plano Mensal Premium", "amountCents": 9990, "frequency": "MONTHLY", "type": "PIX_RECURRING", "paymentMethods": ["PIX"], "pixRecurringOptions": { "journey": "ONLY_RECURRENCY" } }' ``` O plano acima cobra R$ 99,90 por mês no Pix Automático, com a primeira cobrança no `dayGenerateCharge` de cada assinatura. A resposta traz o `id` que vai em `planId`, e `retryPolicy` já preenchido com `THREE_RETRIES_7_DAYS`. ## Regras - Só três campos são obrigatórios: `name`, `amountCents` e `paymentMethods`. `type` assume `PIX_RECURRING` e `frequency` assume `MONTHLY`. - `amountCents` é um inteiro em **centavos**: `9990` cobra R$ 99,90 por ciclo. O mínimo é `100`. - Use um meio de pagamento por plano: `["PIX"]` com `type: PIX_RECURRING`, ou `["CREDIT_CARD"]` com `type: RECURRENT`. A lista com os dois é aceita aqui, mas a criação da assinatura responde `501`. - Em plano Pix, `pixRecurringOptions` incompleto recebe os padrões `journey: PAYMENT_ON_APPROVAL` e `retryPolicy: THREE_RETRIES_7_DAYS`. Com o padrão `PAYMENT_ON_APPROVAL`, a primeira cobrança acontece quando o pagador autoriza, e toda assinatura deste plano precisa de `dayGenerateCharge` igual ao dia de hoje. Para deixar a data livre, envie `journey: ONLY_RECURRENCY`. - `passthroughFees: true` faz o assinante pagar a tarifa: `amountCents` vira o valor líquido que você recebe. Só vale para Pix e não pode ser alterado depois. - Plano de cartão não aceita `installmentCount`: a criação da assinatura responde `400`. A recorrência no cartão é sempre contínua até o cancelamento. - Alterar o plano depois não muda as assinaturas existentes. Cada uma guarda os termos do momento em que foi criada (`planSnapshot`). --- # Consultar plano (/api-reference/endpoint/subscription/plan/get) Devolve um plano da conta pelo id, com as opções de Pix Automático já preenchidas. ```yaml GET /plan/{id}: tags: - Planos operationId: getPlan summary: Consultar plano description: Devolve um plano da conta pelo id, arquivado ou não. responses: "200": description: O plano. content: application/json: schema: $ref: "#/components/schemas/Plan" examples: pix: $ref: "#/components/examples/PixPlan" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" ``` Responde `404` se o plano não existe ou é de outra conta. Planos arquivados também são devolvidos, com `isArchived: true`. --- # Listar planos (/api-reference/endpoint/subscription/plan/list) Lista os planos da conta, do mais recente para o mais antigo, com a contagem de assinaturas de cada um. ```yaml GET /plan: tags: - Planos operationId: listPlans summary: Listar planos description: | Lista os planos da conta, do mais recente para o mais antigo. Planos arquivados ficam de fora, a menos que você envie `includeArchived=true`. parameters: - name: includeArchived in: query description: "`true` inclui os planos arquivados. Qualquer outro valor é tratado como `false`." schema: type: boolean default: false - $ref: "#/components/parameters/Limit" - $ref: "#/components/parameters/Offset" responses: "200": description: Página de planos. content: application/json: schema: type: object required: - data - total properties: data: type: array items: $ref: "#/components/schemas/PlanListItem" total: type: integer description: Quantidade de itens **nesta página**, não o total da conta. example: 1 example: data: - id: 01JB7Y2M3N4P5Q6R7S8T9V0W1X name: Plano Mensal Premium comment: null amountCents: 9990 currency: BRL dayDue: null type: PIX_RECURRING frequency: MONTHLY installmentCount: null paymentMethods: - PIX pixRecurringOptions: journey: ONLY_RECURRENCY retryPolicy: THREE_RETRIES_7_DAYS passthroughFees: false isArchived: false createdAt: 2026-05-28T13:00:00.000Z updatedAt: 2026-05-28T13:00:00.000Z activeSubscriptionsCount: 12 outdatedSubscriptionsCount: 0 total: 1 "401": $ref: "#/components/responses/Unauthorized" ``` ## Exemplo ```bash curl "https://api.gates2b.com/plan?includeArchived=true&limit=100&offset=0" \ -H "Authorization: Bearer $API_KEY" ``` ## Regras - Planos arquivados só aparecem com `includeArchived=true`. - A página tem 50 itens por padrão e no máximo 100. Avance com `offset`. - `total` é a quantidade de itens **desta página**, não o total da conta. Para saber se há mais páginas, peça a próxima até receber menos itens que o `limit`. - `activeSubscriptionsCount` conta as assinaturas vigentes do plano; `outdatedSubscriptionsCount`, as ativas que cobram um valor diferente do `amountCents` atual. --- # Atualizar plano (/api-reference/endpoint/subscription/plan/update) Altera os campos enviados de um plano. As assinaturas já criadas mantêm os termos originais. ```yaml PATCH /plan/{id}: tags: - Planos operationId: updatePlan summary: Atualizar plano description: | Altera os campos enviados e mantém os demais. A mudança vale para as assinaturas criadas daqui em diante; as existentes continuam com os termos copiados em `planSnapshot`. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PlanUpdateRequest" example: amountCents: 10990 responses: "200": description: Plano atualizado. content: application/json: schema: $ref: "#/components/schemas/Plan" example: id: 01JB7Y2M3N4P5Q6R7S8T9V0W1X name: Plano Mensal Premium comment: null amountCents: 10990 currency: BRL dayDue: null type: PIX_RECURRING frequency: MONTHLY installmentCount: null paymentMethods: - PIX pixRecurringOptions: journey: ONLY_RECURRENCY retryPolicy: THREE_RETRIES_7_DAYS passthroughFees: false isArchived: false createdAt: 2026-05-28T13:00:00.000Z updatedAt: 2026-06-02T09:30:00.000Z "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" ``` ## Como funciona Cada assinatura guarda uma cópia dos termos do plano no momento em que foi criada, em `planSnapshot`. Atualizar o plano muda só o modelo: as assinaturas existentes continuam cobrando o valor copiado. *Figura: Depois de mudar o valor do plano de R$ 99,90 para R$ 109,90, só a assinatura nova cobra o valor novo.* - Plano - Assinatura de março - Assinatura de abril - Assinatura nova Para saber quantas assinaturas ativas estão com valor diferente do plano, veja `outdatedSubscriptionsCount` em [Listar planos](./list.mdx). ```bash curl -X PATCH "https://api.gates2b.com/plan/01JB7Y2M3N4P5Q6R7S8T9V0W1X" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "amountCents": 10990 }' ``` ## Regras - Envie só o que vai mudar. Os campos ausentes ficam como estão. - A mudança vale para as assinaturas criadas depois. As existentes continuam cobrando o que está no `planSnapshot` delas. - `pixRecurringOptions` é mesclado: enviar só `journey` mantém o `retryPolicy` e o `minimumValue` atuais. `null` volta às opções padrão. - `passthroughFees` não muda depois da criação. Enviar o valor atual é aceito; um valor diferente responde `400`. Para mudar o repasse, crie outro plano. - Plano arquivado não pode ser editado: responde `400`. --- # Criar assinatura (/api-reference/endpoint/subscription/subscription/create) Liga um plano a um cliente e devolve o Pix copia e cola ou o link de checkout para o pagador autorizar. ```yaml POST /subscription: tags: - Assinaturas operationId: createSubscription summary: Criar assinatura description: | Liga um plano a um cliente e devolve o que o pagador precisa para autorizar a recorrência: o código Pix copia e cola (Pix Automático) ou o link do checkout (cartão). Nada é cobrado na criação. parameters: - name: x-idempotency-key in: header required: false description: | Chave de idempotência. Gere um UUID novo por assinatura. Repetir uma chave já usada pela conta devolve a assinatura criada com ela, com `invite: null`, sem criar outra. schema: type: string maxLength: 128 example: 7f3c1e9a-2b45-4d8e-9a10-c6d2f8b4e501 requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/SubscriptionCreateRequest" examples: pix: summary: Pix Automático, cliente novo value: planId: 01JB7Y2M3N4P5Q6R7S8T9V0W1X dayGenerateCharge: 25 externalReference: pedido-123456 customer: name: João da Silva taxID: "12345678909" email: cliente@example.com phone: "5511999999999" address: zipcode: "01310100" street: Avenida Paulista number: "1000" neighborhood: Bela Vista city: São Paulo state: SP country: BR complement: Conjunto 51 card: summary: Cartão, com URLs de retorno value: planId: 01JB7Y9C8D7E6F5G4H3J2K1M0N dayGenerateCharge: 25 customer: name: Maria Souza email: cliente@example.com gatewayOptions: redirectUrl: https://sualoja.example.com/assinatura/obrigado cancelUrl: https://sualoja.example.com/assinatura/cancelada existingCustomer: summary: Cliente já cadastrado value: planId: 01JB7Y2M3N4P5Q6R7S8T9V0W1X customerId: 01JB7Z1A2B3C4D5E6F7G8H9J0K dayGenerateCharge: 10 responses: "201": description: | Assinatura criada, ou devolvida de novo por causa da `x-idempotency-key`. content: application/json: schema: $ref: "#/components/schemas/SubscriptionCreateResponse" examples: pix: $ref: "#/components/examples/PixSubscriptionCreated" card: summary: Cartão value: id: 01JB7Z9P8Q7R6S5T4V3W2X1Y0Z planId: 01JB7Y9C8D7E6F5G4H3J2K1M0N customerId: 01JB7Z5F6G7H8J9K0M1N2P3Q4R status: AWAITING_PAYER_AUTHORIZATION mode: A dayGenerateCharge: 25 externalReference: null gatewayOptions: redirectUrl: https://sualoja.example.com/assinatura/obrigado cancelUrl: https://sualoja.example.com/assinatura/cancelada planSnapshot: planId: 01JB7Y9C8D7E6F5G4H3J2K1M0N name: Plano Mensal Premium amountCents: 9990 currency: BRL dayDue: null type: RECURRENT frequency: MONTHLY installmentCount: null comment: null pixRecurringOptions: null paymentMethods: - CREDIT_CARD passthroughFees: false snapshottedAt: 2026-05-28T13:05:00.000Z customerMeta: name: Maria Souza taxID: null email: cl*****@example.com phone: null address: zipcode: null street: null number: null neighborhood: null city: null state: null complement: null country: null activation: status: open pixRecurring: null checkout: url: https://checkout.example.com/session/a1B2c3D4 expiresAt: 1780059900 nextBillingAt: null postCancelCycles: null needsPayerAuthorization: true invite: null cancelledAt: null createdAt: 2026-05-28T13:05:00.000Z updatedAt: 2026-05-28T13:05:00.000Z pixModeB: summary: Pix com cadastro incompleto (modo B) value: id: 01JB7ZB2C3D4E5F6G7H8J9K0M1 planId: 01JB7Y2M3N4P5Q6R7S8T9V0W1X customerId: 01JB7ZA1B2C3D4E5F6G7H8J9K0 status: PENDING_CUSTOMER mode: B dayGenerateCharge: 25 externalReference: null gatewayOptions: null planSnapshot: planId: 01JB7Y2M3N4P5Q6R7S8T9V0W1X name: Plano Mensal Premium amountCents: 9990 currency: BRL dayDue: null type: PIX_RECURRING frequency: MONTHLY installmentCount: null comment: null pixRecurringOptions: journey: ONLY_RECURRENCY retryPolicy: THREE_RETRIES_7_DAYS paymentMethods: - PIX passthroughFees: false snapshottedAt: 2026-05-28T13:05:00.000Z customerMeta: name: João da Silva taxID: null email: cl*****@example.com phone: null address: zipcode: null street: null number: null neighborhood: null city: null state: null complement: null country: null activation: null needsPayerAuthorization: false invite: url: https://portal.example.com/activate?token=q8Zx3vN1 expiresInSeconds: 259200 cancelledAt: null createdAt: 2026-05-28T13:05:00.000Z updatedAt: 2026-05-28T13:05:00.000Z "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/KycPending" "404": $ref: "#/components/responses/NotFound" "501": $ref: "#/components/responses/NotImplemented" ``` ## Como funciona A criação não cobra nada: ela devolve o que o pagador precisa para autorizar a recorrência. No Pix Automático, o pagador lê o código no app do banco e aprova o débito; a partir daí, cada ciclo pago vira uma cobrança e dispara o webhook `charge.paid`, com o `externalReference` da assinatura. *Figura: Assinatura por Pix Automático: você cria, o pagador autoriza no banco e cada ciclo pago chega como charge.paid.* - Seu servidor → API Gates2b: POST /subscription - API Gates2b → Seu servidor: activation.pixRecurring.emv - Seu servidor → Pagador: envia o código Pix - Pagador → Banco do pagador: autoriza o débito - Banco do pagador → API Gates2b: autorização confirmada - API Gates2b → API Gates2b: status ACTIVE - Banco do pagador → API Gates2b: débito de cada ciclo - API Gates2b → Seu servidor: webhook charge.paid No cartão, o código Pix dá lugar a um link de checkout (`activation.checkout.url`) e o ciclo segue a data em que o pagador cadastrou o cartão. Veja o fluxo em [Assinatura por cartão](../../../../guias/assinatura-por-cartao.mdx). *Figura: Status de uma assinatura: PENDING_CUSTOMER só existe no Pix com cadastro incompleto, e CANCELLED é definitivo.* - PENDING_CUSTOMER: Pix com cadastro incompleto (modo B) — (cliente completa pelo convite) - AWAITING_PAYER_AUTHORIZATION: Nada cobrado ainda — (pagador autoriza) - ACTIVE: Cada ciclo pago vira cobrança - undefined → undefined: CANCELLED: (você cancela) - undefined → undefined: CANCELLED: (você cancela) - undefined → undefined: CANCELLED: Por você ou pelo pagador. Definitivo: reativar responde 409 — (cancelamento) Com cadastro completo (modo A), a assinatura já nasce em `AWAITING_PAYER_AUTHORIZATION`. Assinatura de cartão nunca passa por `PENDING_CUSTOMER`. ### Exemplo ```bash curl -X POST "https://api.gates2b.com/subscription" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -H "x-idempotency-key: $(uuidgen)" \ -d '{ "planId": "01JB7Y2M3N4P5Q6R7S8T9V0W1X", "dayGenerateCharge": 10, "externalReference": "pedido-1042", "customer": { "name": "João da Silva", "taxID": "12345678909", "email": "cliente@example.com", "phone": "5511999999999", "address": { "zipcode": "01310100", "street": "Avenida Paulista", "number": "1000", "neighborhood": "Bela Vista", "city": "São Paulo", "state": "SP", "country": "BR" } } }' ``` Mostre ao pagador o código `activation.pixRecurring.emv` da resposta, como copia e cola ou QR Code. Guarde o `id` da assinatura e o `customerId`: com eles você consulta o status e reaproveita o cliente em outra assinatura. ## Regras - Envie **exatamente um** de cada par: `planId` ou `plan` (plano criado na mesma chamada), e `customerId` ou `customer` (cliente novo). Os dois do mesmo par, ou nenhum, responde `400`. - `customer` sempre cria um cliente novo, mesmo que o e-mail ou o telefone já existam. Para reaproveitar um cliente, envie `customerId`. - A conta precisa ter a verificação (KYC/KYB) concluída. Sem ela, a resposta é `403` com `code: KYC_PENDING`. - O plano não pode estar arquivado e o cliente não pode estar bloqueado: os dois casos respondem `400`. ### Dados do cliente por meio de pagamento | Plano | Exigido de `customer` | Se faltar | | --- | --- | --- | | Cartão (`["CREDIT_CARD"]`) | `name` e `email` | `400`, com os campos que faltam na `message` | | Pix (`["PIX"]`) | `name`, `taxID`, `email`, `phone` e `address` completo (menos `complement`) | Modo B: a assinatura fica em `PENDING_CUSTOMER` e a resposta traz `invite.url` para o cliente completar o cadastro | Em qualquer caso, `email` ou `phone` precisa vir: sem os dois, a resposta é `400`. Confira `customerMeta.taxID` na resposta: se voltou `null`, o documento enviado não tinha dígitos e não foi gravado. ### `dayGenerateCharge` - Pix mensal: de `1` a `27`. Os dias 28 a 31 são recusados porque não existem em todo mês. - Pix semanal (`WEEKLY`): de `1` a `7`. - Plano com `journey: PAYMENT_ON_APPROVAL`: tem de ser o dia de hoje, porque a primeira cobrança acontece na autorização. - Cartão: o valor é gravado mas não define a data. O ciclo segue o dia em que o pagador concluiu o checkout; leia a próxima cobrança em `activation.nextBillingAt`. ### Idempotência [#idempotência] Gere um UUID novo em `x-idempotency-key` para cada assinatura. A chave vale para toda a conta, independentemente do plano e do cliente: repetir uma chave já usada responde `201` com a assinatura **antiga**, e nenhuma nova é criada. Não copie um valor fixo de exemplo. ### Cartão [#cartão] - `gatewayOptions.redirectUrl` e `gatewayOptions.cancelUrl` definem para onde o pagador volta do checkout. Precisam ser URLs absolutas com `http` ou `https`; um caminho relativo responde `400`. Plano Pix ignora o objeto. - `cancelUrl` não herda `redirectUrl`. Sem ele vale o endereço padrão da conta, para quem desistiu não cair na sua página de sucesso. - Plano com `installmentCount` responde `400`. Plano com os dois meios de pagamento, ou com `passthroughFees: true` no cartão, responde `501`. --- # Consultar assinatura (/api-reference/endpoint/subscription/subscription/get) Devolve uma assinatura com o estado da autorização e o plano atual, para comparar com os termos contratados. ```yaml GET /subscription/{id}: tags: - Assinaturas operationId: getSubscription summary: Consultar assinatura description: | Devolve uma assinatura com o estado da autorização (`activation`) e o plano atual (`plan`), para você comparar com os termos contratados em `planSnapshot`. responses: "200": description: A assinatura. content: application/json: schema: $ref: "#/components/schemas/SubscriptionDetail" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" ``` ## Regras - `planSnapshot` traz os termos contratados; `plan`, o plano como está hoje. Se diferirem, o plano foi alterado depois da criação, e a assinatura continua cobrando o que está em `planSnapshot`. - `needsPayerAuthorization` é `true` enquanto o pagador não autorizou. Reenvie a ele o `activation.pixRecurring.emv` ou o `activation.checkout.url`. - No cartão, a data da próxima cobrança está em `activation.nextBillingAt`, não em `dayGenerateCharge`. --- # Listar assinaturas (/api-reference/endpoint/subscription/subscription/list) Lista as assinaturas da conta, da mais recente para a mais antiga, com filtro por status e meio de pagamento. ```yaml GET /subscription: tags: - Assinaturas operationId: listSubscriptions summary: Listar assinaturas description: | Lista as assinaturas da conta, da mais recente para a mais antiga, com filtros opcionais por status e por meio de pagamento contratado. parameters: - name: status in: query description: Filtra pelo status da assinatura. schema: $ref: "#/components/schemas/SubscriptionStatus" - name: paymentMethod in: query description: | Filtra pelo meio de pagamento contratado (o do `planSnapshot`, não o do plano atual). Valor fora da lista responde `400`. schema: $ref: "#/components/schemas/PaymentMethod" - $ref: "#/components/parameters/Limit" - $ref: "#/components/parameters/Offset" responses: "200": description: Página de assinaturas. content: application/json: schema: type: object required: - data - total properties: data: type: array items: $ref: "#/components/schemas/Subscription" total: type: integer description: Quantidade de itens **nesta página**, não o total da conta. example: 1 examples: page: $ref: "#/components/examples/SubscriptionPage" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" ``` ## Exemplo Assinaturas de cartão que ainda esperam o pagador cadastrar o cartão: ```bash curl "https://api.gates2b.com/subscription?status=AWAITING_PAYER_AUTHORIZATION&paymentMethod=CREDIT_CARD" \ -H "Authorization: Bearer $API_KEY" ``` ## Regras - `paymentMethod` filtra pelo meio contratado, gravado em `planSnapshot`. Um valor fora de `PIX` e `CREDIT_CARD` responde `400`. - A página tem 50 itens por padrão e no máximo 100. Avance com `offset`. - `total` é a quantidade de itens **desta página**, não o total da conta. - A lista não traz o plano atual (`plan`). Para comparar com `planSnapshot`, use [Consultar assinatura](./get.mdx). --- # Reconciliar assinatura (/api-reference/endpoint/subscription/subscription/reconcile) Confere uma assinatura de cartão contra a operadora, cria as cobranças que faltam e reaplica o cancelamento. ```yaml POST /subscription/{id}/reconcile: tags: - Assinaturas operationId: reconcileSubscription summary: Reconciliar assinatura description: | Confere uma assinatura de cartão contra a operadora e corrige o que ficou fora de sincronia: cria as cobranças de ciclos pagos que não chegaram, ativa ou encerra o registro local e reenvia um cancelamento que não foi aplicado. Pode ser repetida sem duplicar cobranças. responses: "201": description: | Relatório da reconciliação. Responde `201` mesmo quando algo falhou: leia `report.errors`. content: application/json: schema: $ref: "#/components/schemas/ReconcileResponse" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/KycPending" "404": $ref: "#/components/responses/NotFound" "429": $ref: "#/components/responses/TooManyRequests" ``` Use quando o status local e a cobrança no cartão não batem: um ciclo pago que não virou cobrança, uma assinatura parada em `AWAITING_PAYER_AUTHORIZATION` que já cobra, ou um cancelamento que não chegou à operadora. ## Regras - Só para assinatura de cartão. Assinatura Pix responde `400`. - A conta precisa ter a verificação (KYC/KYB) concluída. Sem ela, `403`. - Limite de 10 chamadas por minuto. Acima disso, `429`. - Pode ser repetida: um ciclo que já tem cobrança não é cobrado de novo. ## Fluxo 1. Corrige o vínculo com o contrato na operadora, se estiver quebrado (`providerSubscriptionIdHealed: true`). Sem esse vínculo, o cancelamento não chega à operadora. 2. Lê o status do contrato (`gatewayStatus`) e a próxima cobrança (`nextBillingAt`). 3. Lista os ciclos pagos. Se a assinatura **não** está cancelada, cria as cobranças que faltam e credita o saldo; é aqui que `AWAITING_PAYER_AUTHORIZATION` vira `ACTIVE`. Se está cancelada, reenvia o cancelamento e conta os ciclos cobrados depois dele em `postCancelInvoices`. 4. Se o contrato já foi encerrado na operadora, cancela a assinatura local com a data de hoje e registra um aviso em `warnings`. Sem nenhum ciclo pago com valor, a assinatura não é ativada: período de teste ou ciclo de valor zero mantém `AWAITING_PAYER_AUTHORIZATION`. ## Como ler o relatório [#como-ler-o-relatório] A resposta é `201` mesmo quando algo falhou. `report.errors` vazio é o único sinal de sucesso completo. Um contador em zero ao lado de um erro quer dizer "não sei", não "não havia nada". - `gatewayStatus: null` significa que a leitura falhou, não que o contrato não existe. - `warnings` não é falha: explica como ler o resultado (data inferida, listagem truncada, encerramento vindo da operadora). - `chargesWithoutBalanceCredit` maior que zero: chame de novo. O motivo está em `errors`. - Ciclos cobrados depois do cancelamento não viram cobrança nem saldo. Eles aparecem em `postCancelInvoices` e em `activation.postCancelCycles`. O reembolso desses ciclos é manual e não é feito por esta API. Para cada caso de dessincronia, veja [Assinatura por cartão](../../../../guias/assinatura-por-cartao.mdx#colocando-a-assinatura-de-volta-em-sincronia). --- # Cancelar assinatura (/api-reference/endpoint/subscription/subscription/status) Cancela uma assinatura em qualquer status. O cancelamento é definitivo. ```yaml PATCH /subscription/{id}/status: tags: - Assinaturas operationId: cancelSubscription summary: Cancelar assinatura description: | Cancela a assinatura. `CANCELLED` é o único status aceito e o cancelamento é definitivo: para voltar a cobrar o cliente, crie uma assinatura nova. requestBody: required: true content: application/json: schema: type: object required: - status properties: status: type: string enum: - CANCELLED description: Novo status. Só `CANCELLED` é aceito. example: CANCELLED example: status: CANCELLED responses: "200": description: Assinatura cancelada. content: application/json: schema: $ref: "#/components/schemas/Subscription" "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "409": description: A assinatura já estava cancelada. content: application/json: schema: $ref: "#/components/schemas/Error" example: statusCode: 409 code: CONFLICT message: Assinatura já cancelada e não pode ser reativada. traceId: 3b9c6f2a-71d4-4e0b-b8a5-0c2e9f41d7a6 ``` ## Regras - `CANCELLED` é o único valor aceito em `status`. Qualquer outro responde `400`. - Uma assinatura já cancelada responde `409`. Para voltar a cobrar o cliente, crie uma assinatura nova. - A resposta traz `status: CANCELLED` e a data em `cancelledAt`. O `200` confirma o cancelamento no nosso registro. Se o aviso à operadora do cartão falhar, o status muda mesmo assim. Em assinatura de cartão, chame [Reconciliar assinatura](./reconcile.mdx) em seguida e confira `cancelledAtGateway` ou `gatewayStatus` no relatório. --- # Eventos de webhook (/api-reference/endpoint/webhook-events) Corpo e headers de cada evento que a sua callbackUrl recebe, um por nome de evento. Como receber, verificar a assinatura e deduplicar as entregas está no guia de [Webhooks](../../guias/webhooks.mdx). --- # Ativar inscrição (/api-reference/endpoint/webhook-subscription/activate) Volta a entregar eventos a uma inscrição pausada, a partir dos eventos gerados depois da chamada. ```yaml POST /webhook-subscriptions/{id}/activate: tags: - Webhooks operationId: activateWebhookSubscription summary: Ativar inscrição description: | Muda o status da inscrição para `active`. A entrega recomeça a partir dos eventos gerados depois desta chamada. responses: "200": description: Inscrição ativa. content: application/json: schema: $ref: "#/components/schemas/WebhookSubscription" example: id: 01KTQRHR29PZ588RB1YQZWS4A6 ownerId: 314 subscribedEvents: - charge.paid - charge.refunded - payout.paid - payout.failed callbackUrl: https://loja.example.com/webhooks/pagamentos status: active failureCount: 0 lastFailureAt: null createdAt: 2026-06-15T14:00:00.000Z updatedAt: 2026-06-18T09:00:00.000Z "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" ``` ## Regras - A entrega recomeça com os eventos gerados depois desta chamada. O que aconteceu durante a pausa não é reenviado; consulte pela API. - Se a inscrição foi pausada porque a URL foi recusada, corrija a `callbackUrl` com [Atualizar inscrição](./update.mdx) antes de ativar. Senão, a primeira entrega pausa a inscrição de novo. - Ativar não muda o `secret`. --- # Criar inscrição (/api-reference/endpoint/webhook-subscription/create) Cadastra a URL que recebe os eventos da sua conta, escolhe os eventos e devolve o segredo da assinatura. ```yaml POST /webhook-subscriptions: tags: - Webhooks operationId: createWebhookSubscription summary: Criar inscrição description: | Cria uma inscrição de webhook para a sua conta e gera o `secret` usado para assinar as entregas. A inscrição nasce `active`. O `secret` vem em texto puro só nesta resposta. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateWebhookSubscriptionRequest" examples: charges: summary: Cobranças e saques value: callbackUrl: https://loja.example.com/webhooks/pagamentos subscribedEvents: - charge.paid - charge.refunded - payout.paid - payout.failed crypto: summary: Pagamentos em cripto value: callbackUrl: https://loja.example.com/webhooks/cripto subscribedEvents: - crypto_payment.finished - crypto_payment.partially_paid - crypto_payment.expired responses: "201": description: Inscrição criada. Contém o `secret`, exibido só desta vez. content: application/json: schema: $ref: "#/components/schemas/WebhookSubscriptionWithSecret" example: id: 01KTQRHR29PZ588RB1YQZWS4A6 ownerId: 314 subscribedEvents: - charge.paid - charge.refunded - payout.paid - payout.failed callbackUrl: https://loja.example.com/webhooks/pagamentos status: active failureCount: 0 lastFailureAt: null createdAt: 2026-06-15T14:00:00.000Z updatedAt: 2026-06-15T14:00:00.000Z secret: 4QypFUhtII81w7FdxdkK7ob9wVVRH0dyOgumZkU2yqg "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "409": description: Já existe uma inscrição `active` com a mesma `callbackUrl` na sua conta. content: application/json: schema: $ref: "#/components/schemas/Error" example: statusCode: 409 code: CONFLICT message: Já existe uma assinatura ativa para esta URL nesta conta. traceId: 3b7c1f0e-8a2d-4c4e-9f1a-6d2b5e8c9a10 ``` O `secret` aparece só nesta resposta. Guarde-o em um cofre de segredos antes de qualquer outra coisa: ele valida o header `x-Webhook-Signature` de cada entrega. Se perder, use [Rotacionar segredo](./rotate-secret.mdx). ## Regras - A inscrição pertence à conta da chave de API. Um `ownerId` enviado no corpo é ignorado. - Só o dono ou um administrador da conta cria inscrições. Outros perfis recebem `403`. - Cada conta pode ter uma única inscrição `active` por `callbackUrl`. Repetir a URL responde `409`; para mudar os eventos, use [Atualizar inscrição](./update.mdx). - Para mandar eventos diferentes para URLs diferentes, crie uma inscrição por URL. Um evento assinado por duas inscrições é entregue às duas. - A URL é validada no cadastro e de novo a cada entrega. Se, na entrega, ela apontar para um endereço proibido (IP privado, por exemplo), a inscrição passa para `paused`. - Os nomes em `subscribedEvents` são exatos. Um nome com erro de grafia é aceito e nunca recebe nada. Antes de criar a inscrição, prepare o endpoint para validar a assinatura. Veja [Webhooks](../../../guias/webhooks.mdx). --- # Consultar inscrição (/api-reference/endpoint/webhook-subscription/get) Retorna uma inscrição de webhook pelo id, com o status e os contadores de falha de entrega. ```yaml GET /webhook-subscriptions/{id}: tags: - Webhooks operationId: getWebhookSubscription summary: Consultar inscrição description: Retorna uma inscrição de webhook da sua conta pelo `id`. O `secret` nunca aparece. responses: "200": description: Inscrição encontrada. content: application/json: schema: $ref: "#/components/schemas/WebhookSubscriptionDetail" example: id: 01KTQRHR29PZ588RB1YQZWS4A6 ownerId: 314 subscribedEvents: - charge.paid - charge.refunded - payout.paid - payout.failed callbackUrl: https://loja.example.com/webhooks/pagamentos status: active failureCount: 2 lastFailureAt: 2026-06-16T09:12:44.000Z createdAt: 2026-06-15T14:00:00.000Z updatedAt: 2026-06-16T09:12:44.000Z errorEventsCount: 1 "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/ForbiddenNotOwner" "404": $ref: "#/components/responses/NotFound" ``` ## Regras - Responde `404` se o `id` não existe e `403` se a inscrição é de outra conta. - O `secret` nunca volta nesta consulta. Se perder o seu, use [Rotacionar segredo](./rotate-secret.mdx). - `status` `paused` sem você ter pausado indica que a URL foi recusada na hora da entrega. Corrija a URL com [Atualizar inscrição](./update.mdx) e depois [ative](./activate.mdx) a inscrição. --- # Listar inscrições (/api-reference/endpoint/webhook-subscription/list) Lista as inscrições de webhook da sua conta em páginas, das mais recentes para as mais antigas. ```yaml GET /webhook-subscriptions: tags: - Webhooks operationId: listWebhookSubscriptions summary: Listar inscrições description: | Lista as inscrições de webhook da sua conta, das mais recentes para as mais antigas, em páginas. O `secret` nunca aparece. parameters: - name: page in: query description: Página a retornar, a partir de 1. schema: type: integer minimum: 1 default: 1 example: 1 - name: limit in: query description: Itens por página. schema: type: integer minimum: 1 maximum: 100 default: 20 example: 20 responses: "200": description: Página de inscrições. content: application/json: schema: $ref: "#/components/schemas/WebhookSubscriptionPage" example: items: - id: 01KTQRHR29PZ588RB1YQZWS4A6 ownerId: 314 subscribedEvents: - charge.paid - charge.refunded - payout.paid - payout.failed callbackUrl: https://loja.example.com/webhooks/pagamentos status: active failureCount: 0 lastFailureAt: null createdAt: 2026-06-15T14:00:00.000Z updatedAt: 2026-06-15T14:00:00.000Z errorEventsCount: 0 actualPage: 1 pagesQuantity: 1 total: 1 "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" ``` ## Regras - A lista traz só as inscrições da conta da chave de API, em qualquer status. - `limit` vai até `100`. Para percorrer tudo, avance `page` até `pagesQuantity`. - `errorEventsCount` conta eventos que ainda não chegaram ao destino. `failureCount` conta tentativas que falharam desde a última entrega com sucesso: um único evento pode somar várias. --- # Pausar inscrição (/api-reference/endpoint/webhook-subscription/pause) Interrompe a entrega de eventos para a inscrição sem apagá-la; reative quando quiser. ```yaml POST /webhook-subscriptions/{id}/pause: tags: - Webhooks operationId: pauseWebhookSubscription summary: Pausar inscrição description: | Muda o status da inscrição para `paused`. Nenhum evento é entregue enquanto ela estiver pausada, nem depois: eventos gerados nesse intervalo não ficam guardados para reenvio. responses: "200": description: Inscrição pausada. content: application/json: schema: $ref: "#/components/schemas/WebhookSubscription" example: id: 01KTQRHR29PZ588RB1YQZWS4A6 ownerId: 314 subscribedEvents: - charge.paid - charge.refunded - payout.paid - payout.failed callbackUrl: https://loja.example.com/webhooks/pagamentos status: paused failureCount: 0 lastFailureAt: null createdAt: 2026-06-15T14:00:00.000Z updatedAt: 2026-06-18T08:00:00.000Z "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" ``` Eventos não ficam guardados durante a pausa. Uma nova tentativa que vencer durante a pausa é descartada, e os eventos gerados enquanto a inscrição está `paused` nunca são entregues, nem depois de [ativar](./activate.mdx). Consulte pela API o que mudou nesse intervalo. ## Regras - Use para manutenção do seu endpoint. Para desligar a URL de vez, use [Revogar inscrição](./revoke.mdx). - A Gates2b também pausa a inscrição quando a URL é recusada na hora da entrega (endereço privado ou porta não permitida). - Os status possíveis e o que muda em cada um estão em [Status da inscrição](../../../guias/webhooks.mdx#status-da-inscrição). --- # Revogar inscrição (/api-reference/endpoint/webhook-subscription/revoke) Desliga a inscrição e para na hora todas as entregas, inclusive as tentativas pendentes. ```yaml POST /webhook-subscriptions/{id}/revoke: tags: - Webhooks operationId: revokeWebhookSubscription summary: Revogar inscrição description: | Muda o status da inscrição para `revoked` e para a entrega na hora, inclusive das tentativas pendentes. Use quando a URL deixar de existir ou o `secret` tiver vazado. responses: "200": description: Inscrição revogada. content: application/json: schema: $ref: "#/components/schemas/WebhookSubscription" example: id: 01KTQRHR29PZ588RB1YQZWS4A6 ownerId: 314 subscribedEvents: - charge.paid - charge.refunded - payout.paid - payout.failed callbackUrl: https://loja.example.com/webhooks/pagamentos status: revoked failureCount: 0 lastFailureAt: null createdAt: 2026-06-15T14:00:00.000Z updatedAt: 2026-06-18T10:00:00.000Z "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" ``` ## Regras - Use quando a URL deixar de existir ou o `secret` tiver vazado. Para uma interrupção temporária, use [Pausar inscrição](./pause.mdx). - Tentativas pendentes são descartadas e eventos novos não são gerados para a inscrição. - A inscrição continua aparecendo em [Listar inscrições](./list.mdx), com `status` `revoked`. - Depois de revogar, cadastre a nova URL com [Criar inscrição](./create.mdx). Ela recebe um `secret` novo. --- # Rotacionar segredo (/api-reference/endpoint/webhook-subscription/rotate-secret) Gera um novo segredo para a inscrição e invalida o anterior na mesma hora. ```yaml POST /webhook-subscriptions/{id}/rotate-secret: tags: - Webhooks operationId: rotateWebhookSubscriptionSecret summary: Rotacionar segredo description: | Gera um novo `secret` para a inscrição e invalida o anterior na hora. O novo `secret` vem em texto puro só nesta resposta. responses: "200": description: Segredo rotacionado. Contém o novo `secret`, exibido só desta vez. content: application/json: schema: $ref: "#/components/schemas/WebhookSubscriptionWithSecret" example: id: 01KTQRHR29PZ588RB1YQZWS4A6 ownerId: 314 subscribedEvents: - charge.paid - charge.refunded - payout.paid - payout.failed callbackUrl: https://loja.example.com/webhooks/pagamentos status: active failureCount: 0 lastFailureAt: null createdAt: 2026-06-15T14:00:00.000Z updatedAt: 2026-06-18T08:00:00.000Z secret: Zt9mQ2v7Lr0xWk4bNc8pHs1yFd6gJu3eTa5oViXqR2M "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" ``` O segredo anterior deixa de valer assim que a resposta chega. Entregas assinadas a partir daí, inclusive novas tentativas de eventos antigos, usam o segredo novo. Guarde o `secret` da resposta: ele não aparece de novo. ## Fluxo A troca é instantânea do lado da Gates2b: a partir da resposta desta rota, toda entrega sai assinada com o segredo novo. Para não rejeitar nada nesse meio-tempo, faça o seu endpoint aceitar os dois segredos por alguns minutos. *Figura: Rotação sem rejeitar entregas: aceite os dois segredos, rotacione, confirme o novo e só então remova o antigo.* - Aceite dois segredos: valide com o atual OU com um segundo, lido de outra variável - Rotacione: POST /rotate-secret; grave o secret da resposta na segunda variável - Remova o antigo: quando as entregas validarem só com o novo Na validação com dois segredos, calcule o HMAC com cada um e aceite se qualquer um bater com o `v1`. O resto da verificação (janela de 5 minutos, corpo cru, comparação em tempo constante) não muda; veja [Verificar a assinatura](../../../guias/webhooks.mdx#verificar-a-assinatura). Rotacione sempre que o segredo puder ter vazado ou quando alguém com acesso a ele sair do time. Se o segredo vazou, rotacione direto, sem o primeiro passo: uma entrega que o seu endpoint rejeitar nesse intervalo volta como nova tentativa, já assinada com o segredo novo. --- # Atualizar inscrição (/api-reference/endpoint/webhook-subscription/update) Troca os eventos, a URL ou o status de uma inscrição, mantendo o mesmo segredo. ```yaml PATCH /webhook-subscriptions/{id}: tags: - Webhooks operationId: updateWebhookSubscription summary: Atualizar inscrição description: | Altera os eventos, a URL ou o status de uma inscrição. Só os campos enviados mudam; os omitidos ficam como estão. O `secret` não muda. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateWebhookSubscriptionRequest" examples: events: summary: Trocar os eventos value: subscribedEvents: - charge.paid - payout.paid - payout.failed url: summary: Trocar a URL value: callbackUrl: https://loja.example.com/webhooks/v2/pagamentos responses: "200": description: Inscrição atualizada. content: application/json: schema: $ref: "#/components/schemas/WebhookSubscription" example: id: 01KTQRHR29PZ588RB1YQZWS4A6 ownerId: 314 subscribedEvents: - charge.paid - payout.paid - payout.failed callbackUrl: https://loja.example.com/webhooks/pagamentos status: active failureCount: 0 lastFailureAt: null createdAt: 2026-06-15T14:00:00.000Z updatedAt: 2026-06-17T10:30:00.000Z "400": $ref: "#/components/responses/BadRequest" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" "404": $ref: "#/components/responses/NotFound" ``` ## Regras - Só os campos enviados mudam. Um corpo vazio responde `200` sem alterar nada. - `subscribedEvents` substitui a lista inteira, não acrescenta. Envie todos os eventos que quer manter. - Uma nova `callbackUrl` passa pela mesma validação da criação. - `status` aqui tem o mesmo efeito das rotas [Pausar](./pause.mdx), [Ativar](./activate.mdx) e [Revogar](./revoke.mdx). - O `secret` não muda. Para trocá-lo, use [Rotacionar segredo](./rotate-secret.mdx). --- # Criar saque (/api-reference/endpoint/withdrawal/create) Envia um PIX do saldo da conta para uma carteira cadastrada ou para uma chave PIX, com idempotência obrigatória. ```yaml POST /v2/withdraw: tags: - Saques operationId: createWithdrawal summary: Criar saque description: | Debita o saldo da conta e envia um PIX para uma carteira cadastrada (`walletId`) ou para uma chave informada no pedido (`pixKeyType` + `pixKey`). Envie exatamente um dos dois destinos. O header `X-Idempotency-Key` é obrigatório. Reenviar o mesmo pedido com a mesma chave devolve o saque já criado, com o header `Idempotent-Replayed: true`, sem sacar de novo. A mesma chave com outro valor, destino ou `urgent` responde `409`. Depois de um saque aceito, a conta fica 30 minutos sem poder criar outro (`403`). O desfecho chega pelos eventos `payout.*`. parameters: - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateWithdrawalRequest" examples: wallet: summary: Para uma carteira cadastrada value: amount: 150.75 urgent: false walletId: 812 pixKey: summary: Para uma chave PIX value: amount: 150.75 urgent: false pixKeyType: CPF pixKey: "12345678909" description: Repasse pedido 123 responses: "201": description: | Saque aceito, ou o saque já criado com esta `X-Idempotency-Key` (com o header `Idempotent-Replayed: true`). headers: Idempotent-Replayed: description: "`true` quando a resposta é o saque já criado com a mesma chave." schema: type: string enum: - "true" content: application/json: schema: $ref: "#/components/schemas/Withdrawal" example: id: 4242 id_transaction: 8f0e6c1a-3b2d-4e5f-9a8b-7c6d5e4f3a2b idempotencyKey: saque-123 status: Saque em andamento statusCode: WITHDRAWAL_IN_PROGRESS amount: 150.75 fee: 2.5 amount_final: -153.25 isUrgent: false reason: null transactionType: PIX createdAt: 2026-10-22T14:00:00.000Z updatedAt: 2026-10-22T14:00:00.000Z "400": description: | Corpo inválido ou header ausente. `IDEMPOTENCY_KEY_REQUIRED`: falta o `X-Idempotency-Key` ou ele está fora do formato. `WITHDRAW_PIX_KEY_INVALID`: a chave não bate com o tipo. `WITHDRAW_DESTINATION_CONFLICT`: `walletId` e chave PIX juntos. `VALIDATION`: campo fora da regra (valor abaixo de `5.00`, por exemplo). content: application/json: schema: $ref: "#/components/schemas/Error" example: statusCode: 400 code: IDEMPOTENCY_KEY_REQUIRED message: "Envie o header X-Idempotency-Key: de 1 a 64 caracteres (letras, números, ponto, hífen, sublinhado ou dois-pontos)." traceId: 3b7c1f0e-8a2d-4c4e-9f1a-6d2b5e8c9a10 "401": $ref: "#/components/responses/Unauthorized" "403": description: | `WITHDRAW_API_KEY_DISABLED`: o saque por API não está liberado para a conta. `WITHDRAW_API_IP_NOT_ALLOWED`: a chamada saiu de um IP fora da lista. `KYC_PENDING`: a conta ainda não foi verificada. Sem `code` específico: saque recente (espere os minutos de `data.timeLeftMinutes`) ou outro saque ainda em criação. content: application/json: schema: $ref: "#/components/schemas/Error" example: statusCode: 403 code: WITHDRAW_API_KEY_DISABLED message: O saque via API key não está liberado para esta conta. traceId: 3b7c1f0e-8a2d-4c4e-9f1a-6d2b5e8c9a10 "409": description: | `IDEMPOTENCY_KEY_CONFLICT`: a chave já foi usada num saque com outro valor, destino ou `urgent` (o `withdrawId` dele vem no corpo). `IDEMPOTENCY_KEY_IN_USE`: outro pedido com a mesma chave está sendo criado agora; consulte pelo `idempotencyKey`. content: application/json: schema: $ref: "#/components/schemas/Error" example: statusCode: 409 code: IDEMPOTENCY_KEY_CONFLICT message: Este X-Idempotency-Key já foi usado em outro saque com valor, carteira ou tipo diferentes. withdrawId: 4242 traceId: 3b7c1f0e-8a2d-4c4e-9f1a-6d2b5e8c9a10 ``` O saque por API vem desligado. Peça a liberação da sua conta ao suporte e cadastre no painel os IPs que vão chamar a rota (veja [Liberação de IP](../../../guias/liberacao-de-ip.mdx)). Sem liberação, a resposta é `403` com `WITHDRAW_API_KEY_DISABLED`; de um IP fora da lista, `403` com `WITHDRAW_API_IP_NOT_ALLOWED`. ## Regras - `amount` é número em reais (`150.75`), mínimo `5`. A tarifa é debitada do saldo além do valor. - Envie `walletId` **ou** `pixKeyType` + `pixKey`. Os dois juntos respondem `400` com `WITHDRAW_DESTINATION_CONFLICT`. - Gere uma `X-Idempotency-Key` por saque e guarde-a antes de chamar. Em timeout ou erro de rede, repita o mesmo pedido com a mesma chave: se o saque já existe, a resposta é `201` com o header `Idempotent-Replayed: true`, sem novo débito. - Depois de um saque aceito, a conta espera 30 minutos para criar outro. Antes disso, a resposta é `403` com os minutos restantes em `data.timeLeftMinutes`. - `201` quer dizer saque aceito, não dinheiro enviado. O desfecho chega pelos eventos `payout.paid` e `payout.failed` (veja [Webhooks](../../../guias/webhooks.mdx)), ou consulte por [Consultar saque](./get.mdx). --- # Consultar saque pela chave de idempotência (/api-reference/endpoint/withdrawal/find-by-idempotency-key) Retorna o saque criado com uma X-Idempotency-Key, para saber depois de um timeout se ele foi criado. ```yaml GET /v2/withdraw: tags: - Saques operationId: findWithdrawalByIdempotencyKey summary: Consultar saque pela chave de idempotência description: | Retorna o saque criado com a `X-Idempotency-Key` informada. Use depois de um timeout para saber se o saque foi criado antes de tentar de novo. parameters: - name: idempotencyKey in: query required: true description: A mesma `X-Idempotency-Key` enviada na criação. schema: type: string example: saque-123 responses: "200": description: Saque encontrado. content: application/json: schema: $ref: "#/components/schemas/Withdrawal" "400": description: "`idempotencyKey` ausente." content: application/json: schema: $ref: "#/components/schemas/Error" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" ``` ## Regras - `404` quer dizer que nenhum saque foi criado com a chave. Aí é seguro repetir o [Criar saque](./create.mdx) com a mesma chave. - Se a criação respondeu `409` com `IDEMPOTENCY_KEY_IN_USE`, espere alguns segundos e consulte aqui antes de repetir. --- # Consultar saque (/api-reference/endpoint/withdrawal/get) Retorna um saque da conta pelo id devolvido na criação, com o status atual. ```yaml GET /v2/withdraw/{id}: tags: - Saques operationId: getWithdrawal summary: Consultar saque description: Retorna um saque da conta pelo `id` devolvido na criação. parameters: - name: id in: path required: true description: "`id` numérico do saque." schema: type: integer minimum: 1 example: 4242 responses: "200": description: Saque encontrado. content: application/json: schema: $ref: "#/components/schemas/Withdrawal" "401": $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" ``` ## Regras - Decida pelo `statusCode`. O `status` é texto para exibição e pode mudar. - `WITHDRAWAL_COMPLETED` é o único status em que o dinheiro saiu. `WITHDRAWAL_IN_PROGRESS` e `WITHDRAWAL_IN_PROCESSING` ainda podem terminar em `WITHDRAWAL_FAILED`. --- # Central de ajuda (/ajuda) Respostas sobre saldo, taxas, MED, cadastro, acessos e atendimento da sua conta. Aqui estão as respostas para as dúvidas que mais chegam ao nosso atendimento. Se a sua não estiver aqui, fale com o [suporte](https://t.me/Gates2b). ## Dinheiro - [Quando o dinheiro fica disponível](/ajuda/liberacao-de-saldo): Prazo de liberação por meio de pagamento, saldo disponível e a receber, saques. - [Como as taxas são aplicadas](/ajuda/taxas): Tarifa por venda, repasse ao cliente, reembolso e saque. - [MED (devolução de PIX)](/ajuda/med): O que é, por que um valor fica bloqueado e o que fazer. ## Conta - [Dados e documentos do cadastro](/ajuda/cadastro): Os dados da empresa e do representante que pedimos, e por quê. - [Membros e acessos](/ajuda/membros): Dê acesso à sua equipe, cada pessoa com o próprio login. - [Mais de uma empresa](/ajuda/empresas): Opere várias empresas com o mesmo login. ## Atendimento - [Suporte](/ajuda/suporte): Como falar com a gente e o que enviar para resolvermos mais rápido. - [Perguntas frequentes](/ajuda/perguntas-frequentes): Reenvio de webhook, chave de API, cobrança que não confirmou e mais. --- # Dados e documentos do cadastro (/ajuda/cadastro) O que pedimos para abrir e liberar a sua conta, o que cada status da análise quer dizer e como atualizar seus dados. Para receber pagamentos, a sua empresa passa por uma verificação. Pedimos os dados da empresa, de quem responde por ela e um envio de documentos. Essa verificação é exigida pela regulação de meios de pagamento e de prevenção à lavagem de dinheiro: precisamos saber quem recebe e para onde o dinheiro vai. **Só empresas abrem conta** O cadastro é feito para pessoa jurídica: a conta fica no nome da empresa (CNPJ, ou o registro equivalente se a empresa for de fora do Brasil). Não há cadastro novo de pessoa física. ## As etapas Depois de criar o login e confirmar o e-mail, o [painel](https://painel.gates2b.com) abre o cadastro em tela cheia. Uma barra no topo mostra a etapa em que você está: *Figura: As cinco etapas do cadastro na Gates2b, na ordem em que o painel as mostra.* - Verificação: Dados da empresa, endereço, representante legal e envio de documentos - Métodos: Como seus clientes vão pagar, de onde eles são e como você vai sacar - Segurança: Ativar a autenticação em dois fatores (2FA) - Conta de saque: Conta bancária ou chave PIX da própria empresa Na etapa **Métodos**, a tela pergunta **O que você quer fazer?** e lista os meios de pagamento que você pode oferecer: PIX, cartão, boleto e cripto. Escolha só o que vai usar agora. Dá para mudar depois, e pedimos só os dados que faltam para o que você escolheu. O painel só abre por completo depois da conta de saque. Até lá, qualquer página leva de volta ao cadastro. O suporte continua acessível em todas as etapas. ## Antes de começar [#antes-de-começar] Separe estas informações. Com elas em mãos, o formulário leva poucos minutos: - CNPJ e data de fundação da empresa - E-mail e telefone de contato da empresa - Endereço completo da sede, com CEP - Nome completo, CPF, e-mail, telefone e data de nascimento do representante legal - Os documentos que a janela de verificação pedir (veja [Documentos](#documentos)) - Um celular com aplicativo autenticador, para a etapa **Segurança** - Os dados da conta bancária ou a chave PIX **da empresa**, para a conta de saque ## Dados da empresa Para empresa brasileira, o formulário tem três partes. **Dados da empresa** - País - CNPJ (ao digitar, consultamos o cadastro público e preenchemos o que der) - Razão social - Data de fundação - E-mail da empresa - Telefone da empresa **Endereço da empresa**: o endereço completo da sede (CEP, rua, número, complemento, bairro, cidade e estado). **Representante legal**: a pessoa que responde legalmente pela empresa. - Nome completo - CPF - E-mail - Telefone - Data de nascimento Empresa de fora do Brasil informa só país, razão social e número de registro, e segue direto para o envio de documentos. ## Documentos Ao enviar o formulário, abre a janela **Verificação de identidade**. É nela que você envia os documentos e conclui a verificação, seguindo as instruções que aparecem na tela. Para que a análise ande sem ida e volta: - Use documentos válidos, legíveis e sem cortes. - Os dados precisam bater com o que você digitou no formulário (nome, CNPJ, CPF). - Faça a verificação até o fim de uma vez. Se você sair no meio, ao voltar ao painel o cadastro retoma da verificação. ## Conta de saque A conta que recebe os seus saques tem de ser **da própria empresa**: mesmo titular e mesmo CNPJ da conta verificada. Vale tanto para conta bancária quanto para chave PIX. Saque para conta de outro titular é recusado. Para cadastrar ou trocar a conta de saque, a autenticação em dois fatores (ou uma passkey) precisa estar ativa. É por isso que a etapa **Segurança** vem antes. ## Status da análise [#status-da-análise] *Figura: Por onde passa a verificação da empresa, do envio dos dados até a aprovação ou a reprovação.* - Dados da empresa: Formulário preenchido — (você envia) - Envio de documentos: Janela Verificação de identidade — (você conclui o envio) - Verificação em análise: Avisamos por e-mail ao terminar — (aprovação) - Conta verificada: Segue para a etapa Métodos - undefined → undefined: Verificação não aprovada: Fale com o suporte — (reprovação) A aprovação da empresa não libera tudo de uma vez. Cada método de pagamento tem a própria liberação, e o painel mostra o estado de cada um ao lado do nome. A tabela abaixo junta os avisos que você pode ver no caminho. | O que aparece no painel | O que quer dizer | O que fazer | | --- | --- | --- | | **Verificação em análise** | Recebemos seus dados e documentos e estamos analisando. | Aguarde. Avisamos por e-mail quando terminar. | | **Conta verificada** | A verificação da empresa foi aprovada. | Siga para a escolha dos métodos. | | **Verificação não aprovada** | Não foi possível aprovar a verificação. | Veja [Se a verificação não for aprovada](#se-a-verificação-não-for-aprovada). | | **Em liberação** (ao lado de um método) | O método ainda depende da análise da conta. Os outros métodos já funcionam. | Aguarde. O painel indica de 2 a 3 dias úteis, e o método é liberado sozinho. | | **Liberado** (ao lado de um método) | O método está pronto para cobrar. | Nada. | | **Faltam dados para você poder receber** | Falta alguma informação do cadastro para liberar o recebimento. | Clique no aviso. Ele leva à tela **Complete seus dados** ou ao suporte. | Antes da aprovação, recursos que dependem da verificação mostram **Verificação necessária**, com o botão **Verificar minha conta**. ## Se a verificação não for aprovada [#se-a-verificação-não-for-aprovada] Na tela **Verificação não aprovada**, clique em **Tentar novamente**. O botão abre o atendimento. Informe ao [suporte](https://t.me/Gates2b) o CNPJ da conta. Ele diz o que precisa ser corrigido ou reenviado. Corrija os dados ou envie os documentos que o suporte pedir. ## Quando pedimos mais dados Às vezes, depois da aprovação, um método precisa de uma informação que ainda não temos (um endereço, o telefone do representante). O painel mostra um aviso no topo. Clique nele: - Se o dado pode ser preenchido no painel, abre a tela **Complete seus dados**, que pergunta **só o que falta**. Preencha e clique em **Enviar dados**. - Se não pode (nome, CNPJ, razão social, por exemplo), o aviso leva ao suporte. Enquanto o dado não chega, as cobranças do método afetado não são processadas. Os outros métodos seguem funcionando. ## Atualizar seus dados depois | O que mudar | Onde | | --- | --- | | E-mail, telefone e endereço do seu cadastro | **Configurações** → aba **Perfil** → **Dados pessoais** → **Editar** | | Conta de saque | **Configurações** → aba **Contas de saque** (pede 2FA ou passkey) | | Métodos de pagamento e saque | **Configurações** → aba **Perfil** → card **Métodos e Cobranças** → **Alterar** | | Razão social, CNPJ, representante legal | Fale com o [suporte](https://t.me/Gates2b) | Só o dono da conta escolhe os métodos. Veja [Membros e acessos](/ajuda/membros). ## Perguntas comuns **Posso abrir conta como pessoa física?** Não. O cadastro é só para empresas. A conta fica no nome da empresa, e o saque vai para uma conta da própria empresa. **Já fui aprovado, mas um método continua Em liberação. Por quê?** A aprovação da empresa e a liberação de cada método são etapas diferentes. O método **Em liberação** depende da análise da conta, que o painel indica levar de 2 a 3 dias úteis. Enquanto isso, você já cobra com os métodos **Liberados**. **Posso sacar para a minha conta pessoal (CPF)?** Não. A conta de saque precisa ser da empresa, com o mesmo CNPJ da conta verificada. Saque para outro titular é recusado. **Mudei de endereço ou de telefone. Preciso refazer a verificação?** Não. Atualize em **Configurações** → **Perfil** → **Dados pessoais**. Mudança de razão social, CNPJ ou representante legal é feita pelo suporte. **Fechei a janela de verificação no meio. Perdi tudo?** Não. Ao voltar ao painel, o cadastro retoma da etapa de verificação. Se a janela não abrir, fale com o suporte. --- # Mais de uma empresa (/ajuda/empresas) Opere várias empresas com o mesmo login, cada uma com saldo, equipe e integração próprios. Com um login só, você pode operar mais de uma empresa. No [painel](https://painel.gates2b.com), cada empresa é uma **conta** separada: tem verificação, saldo, cobranças, equipe e integração próprios. Você troca de conta pelo menu, sem sair e entrar de novo. Uma conta aparece para você em dois casos: - **Você criou a conta.** Você é o dono dela. - **Alguém convidou você.** Você é administrador ou operador nela. Veja [Membros e acessos](/ajuda/membros). *Figura: Um login da Gates2b ligado a várias contas: o que fica no login vale em todas, o resto é separado por empresa.* - Seu login - Empresa A (você é dono) - Empresa B (você é dono) - Empresa C (você é convidado) Na prática, a troca de conta funciona como entrar em outra empresa: tudo o que você vê e faz no painel passa a ser daquela conta, até você trocar de novo. ## Abrir a conta de outra empresa No topo do menu lateral, clique no seu nome para abrir o menu da conta. Na seção **Contas**, clique em **Nova conta**. Em **Nome da conta**, informe a razão social, o nome fantasia ou um apelido que identifique a empresa. Clique em **Criar conta**. O painel entra na conta nova e abre **Membros**, para você convidar quem vai operar essa empresa. Convidar agora é opcional. Faça a verificação da empresa dentro da conta nova. Ela segue as mesmas etapas do primeiro cadastro. Veja [Dados e documentos do cadastro](/ajuda/cadastro). A conta nasce sem verificação. Até a empresa ser aprovada, cobranças e saques dessa conta ficam bloqueados. A verificação de uma conta não vale para outra: cada empresa é verificada com o próprio CNPJ. Você pode criar até **10 contas**. Contas em que você é só membro não contam para esse limite. Para abrir mais, fale com o [suporte](https://t.me/Gates2b). ## Trocar de conta No topo do menu lateral, clique no seu nome. Na seção **Contas**, clique na conta que você quer operar. A conta ativa tem um sinal de confirmação ao lado. O painel recarrega já na conta escolhida. No celular, a lista **Contas** fica no menu de navegação inferior. **Confira a conta antes de agir** Cobranças, saques, chaves de API e convites são feitos sempre na conta ativa. O nome dela aparece no topo do menu lateral. Confira antes de sacar ou gerar uma chave. ## O que é separado e o que é compartilhado [#o-que-é-separado-e-o-que-é-compartilhado] | Item | Por conta | Observação | | --- | :---: | --- | | Verificação da empresa | Sim | Cada conta faz a sua. | | Saldo, extrato e saques | Sim | O dinheiro de uma conta não aparece nem é sacado pela outra. | | Conta de saque | Sim | Precisa ser da própria empresa da conta. | | Cobranças, links, checkouts e assinaturas | Sim | — | | Métodos de pagamento escolhidos | Sim | — | | Taxas | Sim | Definidas para cada conta. | | Chaves de API | Sim | A chave de uma conta só opera aquela conta. | | IPs liberados | Sim | Cadastre os IPs em cada conta. Veja [Liberação de IP](/guias/liberacao-de-ip). | | Webhooks | Sim | Cada conta tem as próprias inscrições. | | Membros e funções | Sim | A mesma pessoa pode ser operadora numa conta e administradora em outra. | | Login (e-mail e senha) | Compartilhado | Um login para todas as contas. | | 2FA e passkeys | Compartilhado | Ficam no seu login e valem em todas as contas. | Para integrar duas empresas pela API, gere uma chave em cada conta e use a chave da conta certa em cada chamada. ## Perguntas comuns **Posso transferir saldo de uma conta para a outra?** Não pelo painel. Cada conta tem saldo próprio, e o saque vai para a conta bancária da própria empresa. **Preciso de outro e-mail para a segunda empresa?** Não. Crie a conta nova com o seu login em **Nova conta**. Você continua entrando com o mesmo e-mail e senha. **Fiz uma cobrança na conta errada. E agora?** A cobrança fica na conta em que foi criada e não muda de conta. Crie a cobrança de novo na conta certa. Se a errada já foi paga, fale com o suporte. **Não vejo a opção Nova conta no menu.** Ela some quando você chega ao limite de 10 contas criadas. Fale com o suporte para abrir mais. **Fui convidado para a conta de outra empresa. Isso muda a minha conta?** Não. A conta da outra empresa aparece na lista **Contas** ao lado da sua, e cada uma continua com saldo e dados próprios. --- # Quando o dinheiro fica disponível (/ajuda/liberacao-de-saldo) Prazo de liberação de cada venda, a diferença entre saldo disponível e aguardando, e quanto tempo um saque leva. Uma venda paga não vira saldo para saque na mesma hora. Ela fica um tempo **aguardando liberação** e depois entra no **saldo disponível**. Só o saldo disponível pode ser sacado. O prazo padrão é de **1 dia** depois do pagamento. O prazo da sua conta pode ser outro: veja em **Limites** › **Limites e tarifas**, no item **Cobrança/venda**, campo **Período de liberação**. O caminho completo de uma venda PIX até a sua conta bancária, com os prazos padrão: *Figura: Exemplo com os prazos padrão: uma venda PIX paga na segunda às 15h e sacada assim que liberada chega à sua conta na quarta às 10h.* - Paga o PIX: Seg 15h — R$ 100,00 confirmados na hora - Pede o saque: Ter 15h05 — Saque normal; o valor vai para Em trânsito O prazo da venda e o prazo do saque se somam. Quem precisa do dinheiro antes pode pedir o [saque emergencial](#saques), que sai em até 30 minutos com outra tarifa. ## Os saldos da tela inicial Na tela **Início** do [painel](https://painel.gates2b.com) o seu dinheiro aparece separado em cards: | Card | O que é | Pode sacar? | | --- | --- | --- | | **Saldo disponível** | Vendas já liberadas, menos saques e reembolsos. | Sim | | **Aguardando** | Vendas pagas que ainda estão no prazo de liberação. | Ainda não | | **Em trânsito** | Saques pedidos que ainda não chegaram na sua conta bancária (valor + tarifa do saque). | Não, já saiu do disponível | | **Retido MED** | Parte das vendas PIX guardada como reserva de segurança. Só aparece se a sua conta tiver reserva. Veja [MED](/ajuda/med#reserva-de-seguranca). | Não, até o fim da retenção | | **Saldo total** | Disponível + Aguardando + Em trânsito. | — | *Figura: Exemplo: de um saldo total de R$ 1.500,00, só os R$ 900,00 do saldo disponível podem ser sacados agora.* - Saldo disponível (pode sacar): 900 - Aguardando (vendas no prazo): 450 - Em trânsito (saques a caminho): 150 O **Retido MED** não entra no **Saldo total**: ele aparece num card à parte e só volta para você no fim da retenção. O valor que entra em **Aguardando** já vem **sem a tarifa** e sem a reserva MED. Para ver a conta de uma venda, abra a venda em **Transações**: o detalhe mostra **Cliente pagou**, **Taxa**, **Retido MED** e **Você recebeu**. A conta passo a passo está em [Como as taxas são aplicadas](/ajuda/taxas). ## Prazo de liberação por meio de pagamento [#prazo-de-liberação-por-meio-de-pagamento] O prazo começa a contar no momento em que o pagamento é **confirmado**, não quando a cobrança é criada. Ele é contado em **dias corridos, de 24 horas**, incluindo fins de semana e feriados. Uma venda paga no sábado às 10h, com o prazo padrão, fica disponível no domingo às 10h. | Meio de pagamento | Quando a venda conta como paga | Quando fica disponível (padrão) | | --- | --- | --- | | PIX | Na hora em que o cliente paga. | 1 dia depois do pagamento | | Boleto | Quando o banco confirma a compensação, o que costuma levar de 1 a 3 dias úteis depois de o cliente pagar. | 1 dia depois da confirmação | | Cartão de crédito | Quando a transação é aprovada. | 1 dia depois da aprovação, quando a venda entra no seu saldo (veja abaixo) | No boleto, o tempo até o dinheiro ficar disponível é a compensação do banco **mais** o prazo de liberação. Um boleto pago na segunda e compensado na terça às 9h fica disponível na quarta às 9h. ### Cartão com saldo separado [#cartão-com-saldo-separado] Em algumas contas as vendas no cartão não entram no saldo da Gates2b: elas ficam numa tela própria, **Cartão** (Vendas no cartão), com saldo, prazo e saque separados. Se essa opção aparece no seu menu, as vendas no cartão seguem o prazo mostrado nela, não o da tabela acima, e não aparecem nos cards da tela **Início**. ### Cripto Pagamentos em cripto não passam pelo saldo em reais. O valor recebido fica no seu saldo cripto, na tela **Cripto**, e segue as regras dessa tela para conversão e saque. ## Saques Você saca o **saldo disponível** em **Saques**. A tarifa do saque é somada ao valor pedido e as duas saem do saldo disponível juntas: para sacar R$ 100,00 com tarifa de R$ 2,99, você precisa de R$ 102,99 disponíveis. Na sua conta bancária chega exatamente o valor que você pediu. | Tipo | Quando o dinheiro sai (padrão) | Tarifa padrão | | --- | --- | --- | | Normal | 2 dias depois do pedido, a partir das 10h | R$ 2,99 | | Emergencial | Em até 30 minutos | 0,99% do valor | O prazo, a tarifa e a quantidade de saques grátis por mês da sua conta estão em **Limites** › **Limites e tarifas**, em **Saque normal**, **Saque emergencial**, **Saques grátis** e **Saques emergenciais grátis**. Os detalhes de cada tarifa estão em [Como as taxas são aplicadas](/ajuda/taxas#saques). *Figura: Exemplo com os prazos padrão: o mesmo saque pedido na segunda às 15h sai na quarta às 10h como normal, ou até as 15h30 como emergencial.* - Pede o saque: Seg 15h — Valor + tarifa saem do disponível - Emergencial sai: Seg até 15h30 — Tarifa padrão de 0,99% do valor - Normal sai: Qua 10h — Tarifa padrão de R$ 2,99 Quanto à hora: o saque normal sai no dia do prazo a partir das 10h. Por isso, pedir às 8h ou às 18h dá no mesmo: os dois saem às 10h do dia do prazo. ### O que acontece com um saque *Figura: Um saque sai do saldo disponível, fica em trânsito até o prazo e é pago; se o banco recusar, o valor volta para o seu saldo.* - Pedido: Valor + tarifa reservados do disponível — (dentro dos limites e com saldo) - Em trânsito: Aguarda o prazo do tipo de saque — (prazo vencido) - Pago: Dinheiro na sua conta bancária - undefined → undefined: Recusado: Nada sai do saldo — (sem saldo, limite ou carência) - undefined → undefined: Devolvido: O valor volta ao disponível — (banco recusou) ### Valores e limites | Regra | Valor | | --- | --- | | Valor mínimo por saque | R$ 5,00 | | Valor máximo por saque no painel | R$ 15.000,00 | | Limites diário, semanal e mensal | Definidos por conta. Veja em **Limites** › **Limites e tarifas**. | Os limites diário, semanal e mensal recomeçam sozinhos no início de cada período. A tela **Limites** mostra quanto já foi usado e quanto resta. Para sacar mais, use **Solicitar aumento de limite** na mesma tela. ### Por que o meu saque ainda não saiu [#por-que-o-meu-saque-ainda-não-saiu] Um saque pode esperar por estes motivos. Confira na ordem: 1. **Ainda está no prazo.** Saque normal sai no prazo da sua conta (padrão: 2 dias, às 10h). Enquanto isso ele fica em **Em trânsito**. 2. **A conta de saque é nova ou foi alterada.** Por segurança, uma conta de saque nova ou editada só recebe saques **3 dias** depois. O aviso mostra a data e a hora da liberação. A carência protege você: se alguém invadir a sua conta e trocar o destino, o dinheiro não sai na hora. 3. **Há um reembolso em processamento.** Enquanto um reembolso não termina, novos saques são recusados com a mensagem "Você possui estornos pendentes". Espere alguns minutos e tente de novo. 4. **O limite do período acabou.** Se o saque passar do limite diário, semanal ou mensal, ele é recusado. O quanto resta aparece em **Limites**. 5. **O saldo disponível não cobre o saque mais a tarifa.** Diminua o valor ou espere a liberação das vendas em **Aguardando**. Se o banco de destino recusar a transferência, o valor do saque **volta para o seu saldo disponível** e você pode pedir de novo. **A chave PIX do saque precisa ser sua** Saques vão para uma conta no mesmo CPF ou CNPJ do cadastro. Chave de outra pessoa ou empresa é recusada antes de o dinheiro sair do seu saldo. ## Perguntas comuns **A venda foi paga, por que não consigo sacar?** Porque ela ainda está em **Aguardando**. O dinheiro passa para **Saldo disponível** depois do prazo de liberação da sua conta (padrão: 1 dia depois do pagamento). Veja o seu prazo em **Limites** › **Limites e tarifas**. **O prazo conta fim de semana?** Conta. A liberação das vendas é em dias corridos de 24 horas: uma venda paga no sábado às 10h fica disponível no domingo às 10h. **Por que o Saldo total é maior do que o que eu posso sacar?** Porque o **Saldo total** soma também o que está em **Aguardando** e em **Em trânsito**. Só o **Saldo disponível** pode ser sacado. **Meu Aguardando diminuiu sem eu fazer nada. Por quê?** Duas causas comuns: vendas que terminaram o prazo e passaram para **Saldo disponível**, ou um [MED](/ajuda/med) que descontou o valor contestado das vendas ainda em **Aguardando**. Um MED aparece em **Transações** como **Desconto MED**. **Vale a pena pedir saque emergencial?** Só quando você precisa do dinheiro hoje. Ele sai em até 30 minutos, mas a tarifa padrão é percentual (0,99% do valor), contra R$ 2,99 fixos do saque normal. Num saque de R$ 1.000,00, a tarifa emergencial padrão é R$ 9,90. Abaixo de cerca de R$ 300,00, o emergencial padrão sai mais barato que o normal. **O que é o saque automático?** Ao criar uma cobrança você pode pedir que o valor seja sacado sozinho depois de liberado. O saque é feito cerca de 30 minutos após a liberação, cobra a tarifa de saque e é ignorado se o saldo disponível não cobrir o valor mais a tarifa. --- # MED (devolução de PIX) (/ajuda/med) O que é o MED, por que um valor do seu saldo fica retido, como responder e como reduzir as contestações. O **MED (Mecanismo Especial de Devolução)** é uma regra do Banco Central para devolver o dinheiro de um PIX em caso de **golpe, fraude** ou **falha operacional**. Quem abre o MED é o **banco de quem pagou**, a pedido do cliente. Você não precisa ter feito nada de errado para receber um: basta o pagador contestar a transação no banco dele. O MED existe só para **PIX**. Vendas por boleto e cartão não passam por ele. ## Como funciona *Figura: Um MED do começo ao fim: o cliente contesta no banco dele, a Gates2b retém o valor no seu saldo e o resultado decide se o dinheiro volta ao cliente ou a você.* - Cliente → Banco do cliente: contesta o PIX - Banco do cliente → Gates2b: abre o MED - Gates2b → Gates2b: retém o valor - Gates2b → Você: aviso de Retenção - Você → Gates2b: envia comprovação - Banco do cliente → Banco do cliente: analisa a contestação - Banco do cliente → Gates2b: resultado - Gates2b → Você: valor devolvido ou liberado **O pagador contesta.** O cliente diz ao banco dele que o PIX foi golpe ou erro. Pela regra do Banco Central, ele pode fazer isso em até 80 dias depois do pagamento. Por isso um MED pode chegar semanas depois de uma venda que você já considerava encerrada. **O valor é retido.** O banco do pagador avisa a Gates2b, e o valor contestado é retido do seu saldo de forma cautelar, até o fim da análise. Retido não quer dizer perdido: é um bloqueio enquanto o caso é analisado. Você recebe um aviso no painel. **A contestação é analisada.** Os dados da transação e o que você enviar como comprovação são considerados. Quanto antes você mandar a prova da venda, melhor. **Sai o resultado.** Ou o valor é devolvido ao pagador, ou o caso é encerrado e o valor volta a ser seu. ## O que você vê no painel [#o-que-você-vê-no-painel] | Onde | O que aparece | | --- | --- | | Ao entrar no [painel](https://painel.gates2b.com) | Um **Aviso** de **Retenção**: "Uma de suas transações foi contestada pelo mecanismo MED e fizemos uma retenção de valor no seu saldo", com a data e o botão **Entrar em contato**. | | **Transações** | Uma linha de **Desconto MED** com o valor retido e o motivo. | | **Início** | O card **Retido MED**, se a sua conta tiver reserva de segurança (veja abaixo). | ### De onde sai o valor retido O valor de um MED é descontado nesta ordem: 1. da sua **reserva de segurança** (**Retido MED**), se houver; 2. das vendas em **Aguardando** liberação, da mais antiga para a mais nova. *Figura: Exemplo: um MED de R$ 150,00 numa conta com R$ 100,00 de reserva usa a reserva inteira e tira os R$ 50,00 que faltam da venda mais antiga em Aguardando.* - R$ 150,00 contestados: MED — Valor a reter no seu saldo - Reserva (Retido MED): 1º — Usa os R$ 100,00 da reserva - Vendas em Aguardando: 2º — Tira R$ 50,00, da venda mais antiga para a mais nova Por isso um MED pode fazer o seu **Aguardando** diminuir sem que você tenha sacado nada. O seu **Saldo disponível** não é usado enquanto a reserva e o **Aguardando** cobrem o valor. ## Possíveis resultados [#possíveis-resultados] | Resultado | O que acontece com o seu saldo | | --- | --- | | **Devolução ao pagador** | O valor retido é devolvido ao cliente. Ele não volta para você. A tarifa da venda original não é estornada. | | **Encerrado sem devolução** | A contestação não procede. O valor retido é liberado e volta para o seu saldo. | *Figura: Depois de retido, o valor de um MED tem dois destinos: volta para você se o caso é encerrado, ou vai para o cliente se a devolução é aprovada.* - Retido: Valor bloqueado no seu saldo — (contestação não procede) - Encerrado: Valor volta para você - undefined → undefined: Devolvido: Valor vai para o cliente — (contestação procede) A devolução pode ser parcial: só uma parte do valor contestado é devolvida, e o restante é liberado para você. ## Como responder a um MED Hoje não há envio de defesa pelo painel. Use o botão **Entrar em contato** do aviso, ou fale com o [suporte](https://t.me/Gates2b), e envie: - o **id da cobrança** ou o identificador do pedido no seu sistema; - nome e documento (CPF/CNPJ) do cliente que pagou; - a **prova de entrega**: código de rastreio, nota fiscal, registro de acesso ao produto digital, conversa com o cliente; - qualquer contato do cliente confirmando a compra. **Não devolva o dinheiro por fora** Se você fizer um PIX de volta ao cliente por conta própria enquanto o MED está aberto, o valor pode acabar devolvido duas vezes: uma por você e outra pelo MED. Para devolver, use o reembolso da cobrança ou aguarde o resultado. ## Reserva de segurança [#reserva-de-segurança] Algumas contas têm uma **reserva de segurança** sobre as vendas PIX: uma porcentagem de cada venda fica guardada por um número de dias e depois é liberada automaticamente para você. Ela existe para que um MED seja coberto sem mexer no seu saldo disponível. **Exemplo:** numa conta com reserva de 5% por 30 dias, uma venda PIX de R$ 100,00 com tarifa de R$ 2,99 entra assim: *Figura: Exemplo de conta com reserva de 5% por 30 dias e prazos padrão: a venda fica disponível em 1 dia e a reserva, 30 dias depois do pagamento.* - Paga R$ 100,00: Dia 0 — Taxa padrão de R$ 2,99 - R$ 92,01 disponíveis: Dia 1 — Prazo normal de liberação - R$ 5,00 disponíveis: Dia 30 — Fim da retenção, se nenhum MED usou o valor A reserva é do seu dinheiro: ela não é tarifa. Se nenhum MED usar o valor, ele é liberado inteiro no fim do prazo. O total retido aparece no card **Retido MED** da tela **Início** e, em cada venda, na linha **Retido MED** do detalhe. ## Como reduzir os MEDs - **Identifique quem paga.** Cobranças com nome, CPF/CNPJ e e-mail do cliente facilitam provar a venda. - **Guarde a prova de entrega** de cada pedido: rastreio, nota fiscal, registro de acesso. - **Use uma descrição clara** na cobrança, que o cliente reconheça no extrato do banco. - **Responda rápido** quando o cliente reclamar. Quem é atendido raramente contesta no banco. - **Desconfie de pedidos fora do padrão:** valor alto de cliente novo, várias compras seguidas, pressa para receber. - **Prefira reembolsar** a deixar uma reclamação sem resposta: um reembolso encerra o assunto; um MED retém o valor até a análise terminar. ## Perguntas comuns **Por que meu saldo diminuiu sem eu sacar?** Provavelmente um MED foi aberto contra uma venda PIX e o valor foi retido. Veja em **Transações** se há uma linha de **Desconto MED**. O valor sai da reserva de segurança e, depois, das vendas em **Aguardando**. **Quem decidiu devolver o dinheiro ao cliente?** O MED é aberto pelo banco de quem pagou, seguindo a regra do Banco Central. A Gates2b aplica a retenção no seu saldo e acompanha o caso até o resultado. **O que é o card Retido MED?** É a sua reserva de segurança: uma parte das vendas PIX guardada por um período e liberada para você no fim dele. Não é tarifa e não é um MED aberto. **Boleto e cartão têm MED?** Não. O MED é exclusivo do PIX. --- # Membros e acessos (/ajuda/membros) Dê acesso à sua equipe com um login para cada pessoa, escolha a função de cada uma e tire o acesso de quem sai. Cada pessoa que opera a sua conta deve ter o próprio login. No [painel](https://painel.gates2b.com), você convida a pessoa por e-mail, escolhe a função dela e pode mudar ou tirar o acesso quando quiser. A gestão fica em **Membros**, no grupo **Conta** do menu lateral. **Não compartilhe o seu login** Login compartilhado não tem como ser rastreado nem tirado de uma pessoa só. Convide cada pessoa como membro, com a menor função que resolve o trabalho dela. ## Funções [#funções] | Função | Para quem | | --- | --- | | **Dono** | Quem criou a conta. Há um por conta, e ele não pode ser alterado, desativado nem removido. | | **Administrador** | Quem administra a conta com o dono: equipe, saques. | | **Operador** | Quem trabalha no dia a dia: cobra e acompanha as vendas, sem tirar dinheiro da conta. | ### O que cada função pode fazer [#o-que-cada-função-pode-fazer] | Ação | Dono | Administrador | Operador | | --- | :---: | :---: | :---: | | Criar cobranças, links e checkouts; ver transações e extrato | Sim | Sim | Sim | | Sacar | Sim | Sim | Não | | Convidar membros | Sim | Sim | Não | | Editar função, desativar, excluir ou redefinir a senha de um membro | Todos os membros | Só operadores | Não | | Gerar e revogar chaves de API | Sim | Não | Não | | Criar e alterar webhooks | Sim | Não | Não | | Escolher os métodos de pagamento da conta | Sim | Não | Não | A função vale só para a conta em que a pessoa foi convidada. Quem opera mais de uma empresa tem uma função em cada uma. Veja [Mais de uma empresa](/ajuda/empresas). ### Qual função escolher [#qual-função-escolher] - **Financeiro que faz saques e acompanha o extrato:** Administrador. - **Sócio ou gestor que também cuida da equipe:** Administrador. - **Atendimento ou vendas, que gera cobranças e links e confere pagamentos:** Operador. - **Contador ou auditor que só precisa olhar as transações:** Operador. - **Desenvolvedor que vai integrar a API:** a chave de API é gerada pelo dono. Convide o desenvolvedor como Operador e entregue a chave por um canal seguro. ## Convidar uma pessoa Dono e administradores convidam. O caminho completo, do convite ao primeiro acesso: *Figura: Como um convite vira acesso: você convida, a pessoa aceita pelo e-mail e entra no painel da Gates2b.* - Novo membro: E-mail, nome e função - Confirmar convite: Cria a senha, ou só aceita se já tem login - Login: Mesmo e-mail e senha de sempre - Acesso à conta: Com a função que você escolheu No menu lateral, abra **Membros** e clique em **Novo membro**. Preencha **Email**, **Nome** e **Sobrenome** e escolha a **Função** (**Administrador** ou **Operador**). Clique em **Enviar convite**. A pessoa recebe um e-mail com o assunto "Convite para acessar a conta" seguido do nome da sua conta. O convite vale por **7 dias**. Enquanto não é aceito, ele fica na aba **Convites Pendentes**, de onde você pode **Reenviar convite** ou **Cancelar convite**. ## Aceitar um convite Quem recebe o convite clica no link do e-mail e cai na tela **Confirmar Convite**. - **Quem ainda não tem login** cria o acesso: nome de usuário, senha e confirmação da senha (telefone é opcional). A senha tem de 8 a 50 caracteres, com letra maiúscula, minúscula, número e caractere especial. Depois clica em **Confirmar Convite**. - **Quem já tem login** (em outra conta, por exemplo) só clica em **Aceitar convite** e continua entrando com o mesmo e-mail e senha. Em seguida, a pessoa faz login. Se ela tiver acesso a mais de uma conta, troca entre elas pelo menu do nome, no topo do menu lateral. Se o link mostrar "Convite inválido, expirado ou já aceito", peça um novo convite a quem convidou. ## Mudar a função ou tirar o acesso [#mudar-a-função-ou-tirar-o-acesso] Em **Membros**, abra o menu de ações na linha da pessoa: | Ação | O que acontece | | --- | --- | | **Editar membro** | Troca a função entre **Administrador** e **Operador**. | | **Desativar membro** | A pessoa perde o acesso a esta conta. Dá para reverter com **Ativar membro**. | | **Excluir membro** | Remove a pessoa da conta. Para voltar, ela precisa de um convite novo. | | **Redefinir senha** | Envia à pessoa um e-mail para ela criar uma senha nova. | O dono gerencia todos os membros. O administrador gerencia só operadores. Ninguém altera o dono. Quando alguém sai da empresa, desative ou exclua o acesso no mesmo dia. Desativar ou excluir tira o acesso só desta conta: o login da pessoa continua existindo se ela for membro de outras contas. ## Autenticação em dois fatores (2FA) [#autenticação-em-dois-fatores-2fa] A 2FA pede, além da senha, um código de 6 dígitos gerado por um aplicativo autenticador no celular. Mesmo que a senha vaze, ninguém entra sem o código. - O dono ativa a 2FA durante o cadastro: é a etapa **Segurança**. - Sacar, cadastrar ou trocar a conta de saque e confirmar algumas ações de integração exigem 2FA (ou uma passkey) ativa. Sem ela, o painel mostra **Autenticação em dois fatores necessária**. Peça a cada membro que ative a 2FA no primeiro acesso: No menu lateral, abra **Configurações** e a aba **Segurança**. No card **Autenticação de dois fatores**, clique em **Ativar verificação** e instale um aplicativo autenticador no celular, se ainda não tiver. Leia o QR Code com o aplicativo e digite o código de 6 dígitos que ele mostra. Guarde os códigos de backup em lugar seguro. Eles servem para entrar se você perder o celular. Na mesma aba você também pode cadastrar uma **passkey**, que confirma o acesso com a biometria do seu aparelho. ## Boas práticas de segurança [#boas-práticas-de-segurança] - **Um login por pessoa.** Nunca entregue a sua senha a um funcionário ou prestador de serviço. Convide como membro. - **A menor função possível.** Quem só cobra e acompanha vendas é **Operador**. - **2FA ativa para todos.** E nunca informe o código 2FA a ninguém, nem a quem diz falar em nosso nome. - **Revise a lista de membros** de tempos em tempos e tire o acesso de quem não precisa mais. - **Chave de API não é login.** Ela dá acesso à conta inteira pela API; guarde-a só no servidor e nunca a envie por e-mail ou chat. ## Perguntas comuns **Posso ter mais de um dono?** Não. O dono é quem criou a conta. Para dividir a administração, convide a outra pessoa como **Administrador**. **O operador consegue sacar?** Não. Saque é do dono e dos administradores. Se um operador tentar, o painel avisa que o perfil dele não permite saque. **O convite não chegou. O que faço?** Peça à pessoa que confira a caixa de spam e o e-mail digitado. Em **Membros** → **Convites Pendentes**, use **Reenviar convite**. Se o convite expirou (passados 7 dias), envie um novo. **A pessoa já tem login em outra conta. Ela precisa de outro e-mail?** Não. Convide o mesmo e-mail. Ela aceita com **Aceitar convite** e passa a ver as duas contas no mesmo login. **Um funcionário saiu da empresa. Como tiro o acesso dele?** Em **Membros**, abra as ações na linha dele e use **Desativar membro** (reversível) ou **Excluir membro**. Ele deixa de acessar esta conta. --- # Perguntas frequentes (/ajuda/perguntas-frequentes) Respostas rápidas para as dúvidas mais comuns de integração, saldo e conta. ## Webhooks **Como reenvio um webhook?** As entregas que falham são repetidas automaticamente, até 15 vezes ao longo de cerca de 32 horas ([política de novas tentativas](/guias/webhooks#novas-tentativas)). Depois disso: - **Invoice paga:** peça o reenvio com [Reenviar webhook](/api-reference/endpoint/resend-webhook). Chega uma entrega nova de `invoice.paid`, com outro `x-Webhook-Event-Id`, às inscrições que assinam esse evento. - **Cobrança (`/charge`):** não há reenvio. Consulte o estado atual com [Consultar cobrança](/api-reference/endpoint/charge/get) ou [Buscar cobrança pela referência](/api-reference/endpoint/charge/find-by-reference). **O webhook não chega. O que conferir?** 1. A inscrição está `active`? Consulte com [Listar inscrições](/api-reference/endpoint/webhook-subscription/list). Uma inscrição pausada não recebe nada, e eventos gerados enquanto ela estava pausada não são entregues depois. 2. O `failureCount` da inscrição está subindo? Então as entregas chegam, mas a sua URL não responde `2xx` em até 10 segundos. 3. A URL é pública, `https`, sem redirecionamento, numa porta permitida (80, 443, 8080 ou 8443)? Redirecionamento conta como falha, e endereço não permitido pausa a inscrição. 4. O nome do evento em `subscribedEvents` está exatamente como no [catálogo](/guias/webhooks#eventos)? Um nome com erro de grafia é aceito, mas nunca recebe nada. **Perdi o segredo (secret) do webhook** O segredo só aparece na criação. Gere um novo com [Rotacionar segredo](/api-reference/endpoint/webhook-subscription/rotate-secret) e atualize o seu servidor. O anterior deixa de valer na hora. **Recebi o mesmo evento duas vezes** É esperado: a entrega é *pelo menos uma vez*. Guarde o `x-Webhook-Event-Id` de cada entrega processada e ignore repetições. Veja [Idempotência](/guias/webhooks#idempotencia). ## Integração [#integração] **Toda chamada volta 401** A chave de API está ausente, fora do formato ou inválida. Envie `Authorization: Bearer ` e teste com [Validar chave de API](/api-reference/endpoint/api-key-validate). Veja [Autenticação](/guias/autenticacao). **Toda chamada volta 403 com API_KEY_IP_NOT_ALLOWED** O IP de saída do seu servidor não está cadastrado na conta. Cadastre em **Integração** no [painel](https://painel.gates2b.com). Veja [Liberação de IP](/guias/liberacao-de-ip). **Perdi a chave de API ou ela vazou** A chave não é exibida de novo. Gere uma nova no painel, troque nos seus servidores e avise o [suporte](https://t.me/Gates2b) se a anterior precisar ser invalidada. **O cliente pagou, mas o meu sistema não sabe** Confirme pela API, que é a fonte da verdade: [Buscar cobrança pela referência](/api-reference/endpoint/charge/find-by-reference) com o seu número de pedido. Se ela estiver `PAID`, o problema está no recebimento do webhook; veja "O webhook não chega" acima. **Repeti a criação da cobrança e recebi 409** A `attemptIdempotencyKey` já foi usada: a primeira tentativa foi criada. Não crie outra; busque a cobrança pelo `externalReference`. ## Cobranças, reembolsos e assinaturas [#cobranças-reembolsos-e-assinaturas] **Até quando posso reembolsar?** Até 7 dias depois da criação da cobrança, desde que ela esteja paga. Alguns meios de pagamento só aceitam reembolso total. Veja [Reembolsar cobrança](/api-reference/endpoint/charge/refund). **Como cancelo uma assinatura?** Com [Cancelar assinatura](/api-reference/endpoint/subscription/subscription/status). O cancelamento não pode ser desfeito; para voltar a cobrar, crie uma assinatura nova. **Qual é o valor mínimo de uma cobrança?** R$ 3,00 no padrão; a sua conta pode ter outro mínimo. Veja [Regras de negócio](/guias/regras-de-negocio). ## Saldo e conta **Quando o dinheiro de uma venda fica disponível?** Depende do meio de pagamento. Veja [Quando o dinheiro fica disponível](/ajuda/liberacao-de-saldo). **Parte do meu saldo está bloqueada** O card **Retido MED** é uma reserva de segurança sobre as vendas PIX: uma parte de cada venda fica guardada por um prazo e é liberada inteira se nenhum pedido de devolução (MED) usar o valor. Veja [MED](/ajuda/med). **Como dou acesso ao meu contador ou à minha equipe?** Convide cada pessoa como membro, com o próprio login. Para quem só precisa ver relatórios, use o papel **Operador**. Veja [Membros e acessos](/ajuda/membros). **Tenho outra empresa. Preciso de outro login?** Não. O mesmo login opera mais de uma empresa, cada uma com saldo, chaves e webhooks próprios. Veja [Mais de uma empresa](/ajuda/empresas). **Preciso mudar a razão social ou o CNPJ** Esses dados não são editáveis no painel. Fale com o [suporte](https://t.me/Gates2b); veja [Suporte](/ajuda/suporte) para o que enviar. --- # Suporte (/ajuda/suporte) Como falar com o atendimento e o que enviar para o seu caso ser resolvido no primeiro contato. Antes de abrir um chamado, veja se a resposta está nas [perguntas frequentes](/ajuda/perguntas-frequentes). Se não estiver, fale com o [suporte](https://t.me/Gates2b). ## O que enviar Um chamado com estas informações é resolvido sem ida e volta: | Informação | Onde encontrar | | --- | --- | | E-mail ou documento (CPF/CNPJ) da conta | Seu cadastro no [painel](https://painel.gates2b.com) | | Id da cobrança, da assinatura ou do saque | Resposta da API ou detalhe da transação no painel | | Seu identificador do pedido (`externalReference`) | O valor que você enviou ao criar a cobrança | | `traceId` do erro | Corpo de qualquer resposta de erro da API ([formato](/guias/codigos-http)) | | Data e hora aproximadas | Com o fuso horário | | O que você esperava e o que aconteceu | Uma ou duas frases; print de tela ajuda | Para problema de integração, inclua a requisição enviada (método, URL e corpo) e a resposta recebida, **sem a chave de API**. ## Segurança no atendimento [#segurança-no-atendimento] **Nunca pedimos senha, código 2FA ou chave de API** Ninguém do atendimento pede a sua senha, o código de autenticação em dois fatores ou a chave de API, por nenhum canal. Se alguém pedir em nosso nome, não envie e avise o suporte pelo canal oficial. - Fale com o suporte só pelos canais listados nesta página e no painel. - Se a chave de API foi exposta num chamado ou num print, gere uma nova no painel e troque nos seus servidores. ## Quem pode abrir chamado Qualquer pessoa com acesso à conta. Pedidos que mudam dados da conta (titular, conta bancária de saque, membros) só são atendidos para o titular ou administradores; veja [Membros e acessos](/ajuda/membros). --- # Como as taxas são aplicadas (/ajuda/taxas) Quanto custa cada venda e cada saque, quando a tarifa é cobrada, como repassá-la ao cliente e o que acontece num reembolso. A Gates2b cobra uma tarifa por **venda paga** e uma tarifa por **saque**. A tarifa da venda é descontada do valor que o cliente pagou; o que sobra é o que entra no seu saldo. As tarifas são definidas **por conta**. Os valores desta página são o padrão da plataforma; se você negociou outros, valem os do seu contrato. Para ver os seus: - **PIX e saques:** **Limites** › **Limites e tarifas**, quadro **Suas tarifas - Método PIX**. - **Cartão:** **Limites** › aba **Taxas de cartão**. - **Uma venda específica:** abra a venda em **Transações**. O detalhe mostra **Cliente pagou**, **Taxa**, **Retido MED** e **Você recebeu**. ## Tarifa por venda | Meio de pagamento | Como a tarifa é calculada | Padrão | | --- | --- | --- | | PIX | Valor fixo por venda, e percentual se a sua conta tiver. | R$ 2,99 por venda paga | | Boleto | Tabela própria do boleto: percentual e/ou valor fixo. | Definido por conta | | Cartão de crédito | Percentual (e valor fixo, se houver) que varia pela bandeira, pelo número de parcelas e pela faixa de faturamento da sua conta. | Veja a aba **Taxas de cartão** | Algumas contas têm um percentual adicional no PIX para vendas acima de um valor definido no contrato. Se for o seu caso, ele aparece no detalhe da venda junto da **Taxa**. Em **cripto**, a Gates2b não cobra tarifa sobre a venda. O provedor da rede desconta a tarifa dele do valor recebido, e o que chega no seu saldo cripto já vem líquido. **Exemplo (PIX, tarifa padrão):** o cliente paga R$ 100,00. A tarifa é R$ 2,99 e você recebe R$ 97,01. *Figura: Tarifa padrão: de uma venda PIX de R$ 100,00, R$ 2,99 ficam com a Gates2b e R$ 97,01 entram no seu saldo.* - Você recebeu: 97.01 - Taxa: 2.99 Se a sua conta tem **reserva de segurança MED**, uma parte da venda PIX fica guardada por um período e volta para você no fim dele. Ela não é tarifa: é o seu dinheiro, só que liberado mais tarde. No detalhe da venda ela aparece como **Retido MED**. *Figura: Exemplo de conta com reserva de 5%: a mesma venda de R$ 100,00 entra como R$ 92,01 agora e R$ 5,00 depois, no fim da retenção.* - Você recebeu (no prazo normal): 92.01 - Retido MED (volta no fim da retenção): 5 - Taxa: 2.99 A reserva é calculada sobre o valor que o cliente pagou, não sobre o líquido. O percentual e o prazo da reserva são definidos por conta. Veja [MED](/ajuda/med#reserva-de-seguranca). **Exemplo (PIX com tarifa fixa + percentual):** numa conta com R$ 0,99 + 1%, uma venda de R$ 200,00 tem tarifa de R$ 0,99 + R$ 2,00 = R$ 2,99, e você recebe R$ 197,01. ### Quando a tarifa é cobrada [#quando-a-tarifa-é-cobrada] A tarifa só é descontada quando o pagamento é **confirmado**. Criar uma cobrança, gerar um QR Code ou um boleto não custa nada. Cobrança que vence ou é cancelada sem pagamento não gera tarifa. Se a cobrança aceita mais de um meio de pagamento, vale a tarifa do meio que o cliente **usou** para pagar. ### Valor mínimo da cobrança [#valor-mínimo-da-cobrança] A cobrança precisa ser maior que a tarifa, para sobrar pelo menos R$ 0,01 para você. Com a tarifa padrão, o mínimo é **R$ 3,00**. Se o valor estiver abaixo do mínimo da sua conta, a cobrança é recusada e a mensagem informa o mínimo aceito. ## Repassar a tarifa para o cliente Você pode fazer o cliente pagar a tarifa, em vez de descontá-la do seu recebimento. Na API isso é o campo `passthroughFees: true` na [criação da cobrança](/api-reference/endpoint/charge/create). O valor que você informa passa a ser **o que você quer receber**, e a Gates2b calcula quanto cobrar do cliente para que, descontada a tarifa, sobre exatamente esse valor. | | Sem repasse | Com repasse | | --- | --- | --- | | Valor informado na cobrança | R$ 100,00 | R$ 100,00 | | Cliente paga | R$ 100,00 | R$ 102,99 | | Tarifa (padrão PIX) | R$ 2,99 | R$ 2,99 | | Você recebe | R$ 97,01 | R$ 100,00 | *Figura: Com repasse e tarifa padrão: para você receber R$ 100,00, o cliente paga R$ 102,99 e a tarifa sai da parte que ele pagou a mais.* - Você recebe (valor informado): 100 - Taxa repassada ao cliente: 2.99 O cliente vê o valor final já com a tarifa no QR Code, no boleto ou no checkout: não há cobrança extra depois. No detalhe da venda em **Transações**, **Cliente pagou** mostra o valor com o repasse. Quando a tarifa tem parte percentual, o valor cobrado do cliente é um pouco maior que "valor + percentual", porque o percentual também incide sobre a parte repassada. Numa conta com 1% sem valor fixo, receber R$ 100,00 exige cobrar cerca de R$ 101,01, e não R$ 101,00. - **Cartão:** o valor final para o cliente só é definido na hora do pagamento, quando a bandeira e o número de parcelas são conhecidos. - **Reserva MED:** o repasse cobre só a tarifa. Se a sua conta tem reserva MED, ela continua saindo do seu valor e volta para você no fim da retenção. Veja [MED](/ajuda/med#reserva-de-seguranca). ## Reembolso Num reembolso, o valor devolvido ao cliente sai do seu saldo e **a tarifa da venda não é devolvida**. **Exemplo:** você vendeu R$ 100,00 por PIX e recebeu R$ 97,01. Ao reembolsar o valor total, R$ 100,00 saem do seu saldo. No fim, a venda custou R$ 2,99 para você. - O reembolso pode ser feito em até **7 dias** depois da criação da cobrança, total ou parcial. - O valor sai do saldo disponível somado ao que está em **Aguardando**. Se os dois juntos não cobrem o reembolso, ele é recusado. - Alguns meios de pagamento só aceitam reembolso do valor total. As regras completas estão em [Reembolsar cobrança](/api-reference/endpoint/charge/refund). ## Saques A tarifa do saque é **somada** ao valor pedido e sai do saldo disponível junto com ele. Você recebe na conta bancária exatamente o valor que pediu. | Tipo | Tarifa padrão | Prazo padrão | | --- | --- | --- | | Normal | R$ 2,99 fixo | 2 dias, às 10h | | Emergencial | 0,99% do valor | Até 30 minutos | **Exemplo:** um saque normal de R$ 500,00 tira R$ 502,99 do saldo disponível. O mesmo saque como emergencial tira R$ 504,95. *Figura: Tarifa padrão de saque normal: para receber R$ 500,00 na sua conta bancária, saem R$ 502,99 do saldo disponível.* - Chega na sua conta bancária: 500 - Tarifa do saque normal: 2.99 Por isso, para sacar **todo** o saldo disponível, peça um valor menor que ele: o valor mais a tarifa precisam caber no saldo. Com R$ 1.000,00 disponíveis e a tarifa padrão do saque normal, o máximo é R$ 997,01. A tela **Saques** avisa quando o valor digitado mais a tarifa passa do saldo. Sua conta pode ter **saques grátis** por mês (normais e emergenciais, contados separadamente). Enquanto houver saque grátis no mês, a tarifa não é cobrada. A quantidade está em **Limites** › **Limites e tarifas**. Prazos e motivos de espera estão em [Quando o dinheiro fica disponível](/ajuda/liberacao-de-saldo#saques). **Tarifa negociada vale por conta** Se você tem mais de uma empresa, cada conta tem as próprias tarifas. Uma negociação feita para uma conta não muda a tarifa das outras. ## Perguntas comuns **Por que recebi menos do que o cliente pagou?** Porque a tarifa da venda é descontada do valor pago e, se a sua conta tiver reserva MED, uma parte fica retida por um período. Abra a venda em **Transações** para ver cada parcela: **Taxa**, **Retido MED** e **Você recebeu**. **Pago tarifa por cobrança que não foi paga?** Não. A tarifa só é cobrada quando o pagamento é confirmado. **Se eu reembolsar, recebo a tarifa de volta?** Não. O reembolso devolve ao cliente o valor que ele pagou, e esse valor sai do seu saldo; a tarifa da venda original não é estornada. **Como consigo uma tarifa menor?** Tarifas são negociadas por conta, conforme o volume. Fale com o [suporte](https://t.me/Gates2b) ou com o seu gerente comercial. **Onde vejo quanto paguei de tarifa no mês?** Em **Transações**, exporte o extrato do período. A planilha traz a coluna **Tarifa Aplicada** em cada venda.