Caso de uso · Checkout e integração

Conduza um ciclo de venda completo em seu sistema

Publique os planos de um produto, converta o comprador, receba a confirmação da ativação, provisione o acesso e acompanhe a recorrência sem reconstruir o motor financeiro do RecoPay.

Plano e recursos necessários

Este fluxo usa checkout público, incluído no Growth e no Scale na oferta atual. Ative Integrações Externas para consultar a situação financeira no pós-venda. A emissão de NFS-e depende do recurso fiscal e da configuração da empresa.

Confira os requisitos por tipo de integração e compare os planos disponíveis.

O problema resolvido

Uma venda não termina no botão “assinar”

Em um SaaS, o ciclo começa na oferta e continua por muito tempo depois da ativação. O cliente escolhe um plano, informa seus dados, aceita termos e paga quando houver valor inicial. Seu sistema ainda precisa saber quando liberar, avisar, restringir ou restaurar o acesso.

O RecoPay concentra catálogo, contrato, cobrança, gateway, conciliação, régua de comunicação e NFS-e. O sistema terceiro concentra aquisição, onboarding e entrega do produto. A integração conecta esses dois domínios sem duplicar a verdade financeira.

Regra central

O navegador inicia a venda, mas não confirma pagamento nem autoriza acesso. A ativação nasce de um evento do backend e o estado financeiro deve ser revalidado pela API protegida.

Divisão de responsabilidades

Entenda quem decide cada parte do ciclo

Seu sistema

  • Apresenta a oferta e o onboarding.
  • Recebe e processa o webhook.
  • Provisiona a conta, workspace ou licença.
  • Define carência e política de acesso.
  • Mantém o vínculo local com a assinatura.

RecoPay

  • Publica produtos, planos e componentes.
  • Cria cliente, assinatura e cobranças.
  • Processa e concilia pagamentos.
  • Dispara automações e mensagens.
  • Expõe fatos financeiros pela API.
CanalOrigemUso correto
Checkout públicoNavegadorCatálogo, cadastro, aceite, contratação e redirecionamento retornado pela API.
Webhook primeiro_pagamento_confirmadoRecoPay → backend terceiroIniciar o provisionamento depois do primeiro pagamento confirmado.
Webhook assinatura_ativada_sem_cobrancaRecoPay → backend terceiroIniciar o provisionamento quando o valor inicial for zero e não existir primeira cobrança.
URL de boas-vindasNavegador do compradorConduzir a experiência após a ativação; nunca provar pagamento nem ativação.
API de integraçõesBackend terceiro → RecoPayConsultar fatos financeiros usando uma chave com escopo mínimo.
Antes de escrever código

Prepare produto, domínio e credenciais

  1. Cadastre o produto, os planos, componentes, gateways e termos no RecoPay.
  2. Em Planos, gere o identificador público do checkout e copie o código do produto.
  3. No produto, informe a origem HTTPS exata do checkout. Ela não pode conter caminho, wildcard, credenciais ou HTTP.
  4. Defina a URL de boas-vindas e o webhook de plano ativo conforme a arquitetura do seu produto.
  5. Em Webhooks, gere o segredo do produto e armazene-o somente no backend receptor.
  6. Para consultas financeiras, ative Integrações Externas e crie uma chave com o escopo financeiro:ler.
Campo do produtoExemploEfeito no ciclo
URL do sitehttps://produto-a.exampleIdentifica a presença pública do produto. Hoje é informativa no contrato do Checkout.
URL do app / painelhttps://app.produto-a.exampleIdentifica onde o cliente usa o produto. Não substitui a URL de boas-vindas.
URL do checkout deste produtohttps://checkout.produto-a.exampleAutoriza a origem e vincula aquele domínio ao produto, exibindo apenas seus planos.
URL de boas-vindashttps://app.produto-a.example/onboardingRecebe o navegador após a ativação, com ou sem primeira cobrança.
Webhook de plano ativohttps://api.produto-a.example/webhooks/recopay/plano-ativoRecebe um POST servidor a servidor para iniciar o provisionamento.
Uma empresa, vários produtos

O checkoutPublicoId pertence à empresa. Cada produto possui seu próprio código e pode ter sua própria origem. Assim, checkout.produto-a.example e checkout.produto-b.example usam o mesmo identificador da empresa, mas filtram produtos diferentes. O domínio .example é usado somente como placeholder nesta documentação.

Roadmap literal

Fluxo completo da visita ao pós-venda

Carregue a oferta

O Checkout consulta os planos do produto e o detalhe do plano diretamente na API.

Identifique o comprador

Cliente novo informa o cadastro. Cliente existente autentica sua identidade antes de contratar novamente.

Crie a contratação

Uma requisição idempotente cria o cliente e a assinatura. Com valor inicial positivo, cria também a primeira cobrança; com valor zero, ativa a assinatura sem gerar cobrança.

Conclua o pagamento, quando necessário

Consulte pagamentoNecessario. Quando for true, o navegador segue a checkoutUrl oficial para pagar; quando for false, a mesma propriedade leva à experiência de boas-vindas.

Ative e notifique

O RecoPay enfileira primeiro_pagamento_confirmado após o pagamento ou assinatura_ativada_sem_cobranca na ativação imediata de valor inicial zero.

Provisione e receba o cliente

Seu backend cria o acesso de forma idempotente; o navegador pode seguir para o onboarding.

Acompanhe a recorrência

O RecoPay gera e cobra os próximos ciclos. Seu backend consulta fatos financeiros para aplicar sua política de acesso.

Como ler os exemplos desta página

Enviado ao RecoPay identifica a requisição criada pelo Checkout ou pelo seu backend. Recebido do RecoPay identifica a resposta da API. No webhook, recebido pelo seu backend é o POST enviado pelo RecoPay, e devolvido ao RecoPay é somente a resposta HTTP do seu endpoint.

Etapa 1

Publique o Checkout para um produto

Na cópia hospedada em seu domínio, fixe o identificador público da empresa e o código do produto durante o build. Nenhum desses dois valores é uma chave secreta.

ENV · build do Checkout
VITE_RECO_API_URL=https://api.recopay.com.br
VITE_RECOPAY_APP_URL=https://recopay.app
VITE_CLIENTES_URL=https://clientes.recopay.com.br
VITE_CHECKOUT_PUBLICO_ID=SEU_CHECKOUT_PUBLICO_ID
VITE_PRODUTO_CODIGO=produto-a

O catálogo deve sempre vir da API. Isso mantém preço, componentes, formas de pagamento, periodicidade e termos sincronizados com o painel.

GET/checkout/{checkoutPublicoId}/produtos/{produtoCodigo}/planos
cURL · catálogo do produto
curl --request GET \
  --url https://api.recopay.com.br/checkout/SEU_CHECKOUT_PUBLICO_ID/produtos/produto-a/planos \
  --header "Accept: application/json"

curl --request GET \
  --url https://api.recopay.com.br/checkout/SEU_CHECKOUT_PUBLICO_ID/planos/42 \
  --header "Accept: application/json"
Não use o frontend como fonte de preço

O comprador pode alterar o JavaScript ou o payload. Envie IDs e quantidades válidos; o servidor recalcula e revalida todo o contrato.

Etapa 2

Trate cliente novo e cliente existente

Antes da revisão final, verifique documento e e-mail. A resposta orienta a experiência sem permitir que um cadastro existente seja apropriado por outra pessoa.

POST/checkout/{checkoutPublicoId}/clientes/verificacao
Enviado ao RecoPay · verificar cliente
curl --request POST \
  --url https://api.recopay.com.br/checkout/SEU_CHECKOUT_PUBLICO_ID/clientes/verificacao \
  --header "Content-Type: application/json" \
  --header "Accept: application/json" \
  --data '{
    "documento": "12345678000190",
    "email": "[email protected]"
  }'
Recebido do RecoPay · HTTP 200
{
  "mensagem": "Cliente ja cadastrado para esta empresa. Faca login para continuar a contratacao.",
  "dados": {
    "clienteExistente": true,
    "documentoEmUso": true,
    "emailEmUso": true,
    "requerLogin": true
  }
}

Quando requerLogin for verdadeiro, autentique o cliente e envie o token retornado apenas na contratação. Cliente novo não usa Bearer.

POST/clientes/auth/login
Enviado ao RecoPay · autenticar cliente existente
curl --request POST \
  --url https://api.recopay.com.br/clientes/auth/login \
  --header "Content-Type: application/json" \
  --header "Accept: application/json" \
  --data '{
    "checkoutPublicoId": "SEU_CHECKOUT_PUBLICO_ID",
    "email": "[email protected]",
    "senha": "SENHA_DO_CLIENTE"
  }'
Recebido do RecoPay · HTTP 200
{
  "sucesso": true,
  "mensagem": "Login realizado com sucesso.",
  "dados": {
    "token": "rct_TOKEN_DO_CLIENTE",
    "expiraEm": "2026-08-31T19:00:00Z",
    "trocaSenhaObrigatoria": false
  }
}
Etapa 3

Crie a assinatura e a primeira cobrança

POST/checkout/{checkoutPublicoId}/contratacoes

Gere uma Idempotency-Key para a tentativa lógica de compra. Se houver timeout, repita o mesmo payload com a mesma chave. Uma nova intenção de compra recebe outra chave.

Enviado ao RecoPay · criar contratação
curl --request POST \
  --url https://api.recopay.com.br/checkout/SEU_CHECKOUT_PUBLICO_ID/contratacoes \
  --header "Content-Type: application/json" \
  --header "Accept: application/json" \
  --header "Idempotency-Key: venda-produto-a-20260831-000184" \
  --data '{
    "planoId": 42,
    "cliente": {
      "tipoPessoa": "J",
      "nome": "Empresa Exemplo LTDA",
      "nomeFantasia": "Empresa Exemplo",
      "documento": "12345678000190",
      "email": "[email protected]",
      "telefone": "11999999999",
      "endereco": {
        "cep": "01001000",
        "logradouro": "Praca da Se",
        "numero": "100",
        "bairro": "Se",
        "municipio": "Sao Paulo",
        "uf": "SP",
        "codigoMunicipioIbge": "3550308"
      }
    },
    "componentes": [
      { "planoPrecoId": 73, "quantidade": 1 }
    ],
    "formaPagamento": "pix",
    "nfseModoEmissao": "automatico_pagamento",
    "descricao": "Contratacao pelo checkout do Produto A",
    "dataInicio": "2026-08-31",
    "diaVencimento": 10,
    "termosUsoAceitos": true
  }'
Authorization é condicional

No exemplo acima, o cliente é novo. Para cliente existente, acrescente Authorization: Bearer TOKEN_DO_CLIENTE e mantenha documento e e-mail compatíveis com a identidade autenticada.

Recebido do RecoPay · HTTP 200
{
  "mensagem": "Contratacao criada com sucesso.",
  "dados": {
    "checkoutUrl": "https://recopay.app/cobrancas/visualizar/...",
    "contratacaoReferencia": "550e8400-e29b-41d4-a716-446655440000",
    "assinaturaReferencia": "b9df2f8020574c2d812863f59a86a264",
    "pagamentoNecessario": true,
    "statusAssinatura": "pendente"
  }
}

Quando a composição inicial resulta em valor zero, a resposta mantém os mesmos campos, mas retorna pagamentoNecessario: false, statusAssinatura: "ativa" e checkoutUrl apontando para a URL de boas-vindas com somente ?ref={contratacaoReferencia}. Essa compatibilidade permite que checkouts já publicados continuem usando a URL retornada sem alteração.

Etapa 4

Redirecione e aguarde a confirmação real

Use exclusivamente dados.checkoutUrl e consulte dados.pagamentoNecessario para distinguir o fluxo. Não componha uma URL com IDs internos e não use o redirecionamento como prova de pagamento ou ativação.

JavaScript · redirecionamento
window.location.assign(resultado.dados.checkoutUrl);
MeioComportamento esperadoQuando liberar
Valor inicial zeroA assinatura nasce ativa e nenhuma cobrança de R$ 0 é criada.Após o webhook assinatura_ativada_sem_cobranca.
PixPode confirmar em poucos segundos.Somente após o webhook de primeiro pagamento.
CartãoPode aprovar, processar ou recusar.Somente quando o pagamento for confirmado.
BoletoNormalmente permanece pendente até a compensação.Depois da confirmação assíncrona, nunca na emissão.

Quando o valor inicial é positivo, o primeiro pagamento confirmado ativa a assinatura, processa as operações aplicáveis e dispara o webhook do produto. Quando o valor inicial é zero, a assinatura é ativada e o webhook correspondente é enfileirado na mesma transação, sem criar cobrança nem simular pagamento.

Etapa 5

Receba a ativação da assinatura

Em Planos → Webhooks, gere um segredo exclusivo para o produto e copie-o para o cofre de segredos do sistema receptor. O endereço configurado recebe um POST assinado; a chave rpk_ da API não participa desta assinatura.

O mesmo endpoint recebe dois fatos de ativação: primeiro_pagamento_confirmado, quando uma cobrança inicial foi paga, e assinatura_ativada_sem_cobranca, quando o valor inicial é zero. Ambos podem iniciar o provisionamento; o segundo não possui objeto cobranca.

Requisição HTTP enviada pelo RecoPay

O padrão de transporte é um POST HTTPS com JSON em UTF-8. Em cada retentativa, o eventoId e o corpo permanecem iguais; o timestamp e a assinatura são recalculados.

Recebido pelo seu backend · requisição HTTP
POST /webhooks/recopay/plano-ativo HTTP/1.1
Host: api.produto-a.example
Content-Type: application/json; charset=utf-8
User-Agent: RecoPay-Webhooks/1.0
X-Recopay-Event-Id: 93a8f7a1-37e4-4ce5-9c1c-41b918b17765
X-Recopay-Timestamp: 1788197538
X-Recopay-Signature: v1=HMAC_SHA256_EM_HEXADECIMAL_MINUSCULO

{ ...corpo JSON documentado abaixo... }
CabeçalhoObrigatórioConteúdo
Content-TypeSimapplication/json; charset=utf-8.
User-AgentSimRecoPay-Webhooks/1.0. É informativo e não substitui a validação HMAC.
X-Recopay-Event-IdSimUUID estável do evento. Também aparece em eventoId.
X-Recopay-TimestampSimInstante da tentativa em segundos Unix.
X-Recopay-SignatureSimv1= + HMAC-SHA256 em hexadecimal minúsculo de timestamp + "." + corpo original.

Corpo JSON recebido pelo seu backend

O corpo abaixo é o documento completo do evento com pagamento. Preserve seus bytes originais até concluir a validação da assinatura.

Recebido pelo seu backend · JSON completo
{
  "eventoId": "93a8f7a1-37e4-4ce5-9c1c-41b918b17765",
  "evento": "primeiro_pagamento_confirmado",
  "ocorridoEm": "2026-08-31T17:32:18.114Z",
  "contratacaoReferencia": "550e8400-e29b-41d4-a716-446655440000",
  "assinaturaReferencia": "b9df2f8020574c2d812863f59a86a264",
  "cliente": {
    "nome": "Empresa Exemplo LTDA",
    "documento": "12345678000190",
    "email": "[email protected]"
  },
  "checkout": {
    "publicoId": "79be63f8765b11f18848bc2411061702"
  },
  "produto": {
    "codigo": "produto-a"
  },
  "plano": {
    "id": 42
  },
  "cobranca": {
    "id": 2310,
    "valor": 149.90,
    "moeda": "BRL",
    "vencimento": "2026-08-31",
    "formaPagamento": "pix",
    "gateway": "mercadopago"
  }
}
CaminhoTipo JSONObrigatórioDescrição
eventoIdstring (UUID)SimIdentificador estável para idempotência, igual ao cabeçalho X-Recopay-Event-Id.
eventostringSimprimeiro_pagamento_confirmado ou assinatura_ativada_sem_cobranca.
ocorridoEmstring (date-time)SimInstante UTC do fato, no padrão ISO 8601.
contratacaoReferenciastring (UUID)SimReferência opaca compartilhada com contratação, callback e ferramentas administrativas.
assinaturaReferenciastringSimReferência pública estável usada nas consultas financeiras.
clienteobjectSimDados do titular da contratação.
cliente.nomestringSimNome ou razão social.
cliente.documentostringSimCPF ou CNPJ normalizado, sem máscara.
cliente.emailstringSimE-mail principal do cliente.
checkoutobjectSimContexto do Checkout público.
checkout.publicoIdstring ou nullSimIdentificador público da empresa que originou a contratação.
produtoobjectSimProduto que será provisionado.
produto.codigostringSimCódigo público estável do produto.
planoobjectSimPlano contratado.
plano.idintegerSimID do plano no RecoPay.
cobrancaobjectNo evento de pagamentoPrimeira cobrança cujo pagamento ativou a assinatura. Não existe no evento sem cobrança.
cobranca.idintegerNo evento de pagamentoID da cobrança no RecoPay.
cobranca.valornumber (decimal)No evento de pagamentoValor na unidade monetária indicada; não é inteiro em centavos.
cobranca.moedastringNo evento de pagamentoCódigo da moeda, como BRL.
cobranca.vencimentostring (date)No evento de pagamentoData de vencimento no formato AAAA-MM-DD.
cobranca.formaPagamentostring ou nullNo evento de pagamentoForma de pagamento efetiva, como pix, quando conhecida.
cobranca.gatewaystring ou nullNo evento de pagamentoGateway que confirmou o pagamento, quando conhecido.

Ativação sem cobrança inicial

Quando o valor inicial é zero, o RecoPay envia o mesmo contexto de contratação, substitui cobranca por ativacao e não cria uma cobrança de R$ 0.

Recebido pelo seu backend · valor inicial zero
{
  "eventoId": "93a8f7a1-37e4-4ce5-9c1c-41b918b17765",
  "evento": "assinatura_ativada_sem_cobranca",
  "ocorridoEm": "2026-09-19T16:30:00Z",
  "contratacaoReferencia": "550e8400-e29b-41d4-a716-446655440000",
  "assinaturaReferencia": "b9df2f8020574c2d812863f59a86a264",
  "cliente": {
    "nome": "Empresa Exemplo LTDA",
    "documento": "12345678000190",
    "email": "[email protected]"
  },
  "checkout": {
    "publicoId": "79be63f8765b11f18848bc2411061702"
  },
  "produto": {
    "codigo": "produto-a"
  },
  "plano": {
    "id": 42
  },
  "ativacao": {
    "status": "ativa",
    "motivo": "valor_inicial_zero",
    "valorInicial": 0.00,
    "moeda": "BRL"
  }
}
CaminhoTipo JSONObrigatórioDescrição
ativacaoobjectNo evento sem cobrançaContexto da ativação imediata.
ativacao.statusstringNo evento sem cobrançaRetorna ativa.
ativacao.motivostringNo evento sem cobrançaRetorna valor_inicial_zero.
ativacao.valorInicialnumber (decimal)No evento sem cobrançaRetorna 0.00.
ativacao.moedastringNo evento sem cobrançaCódigo da moeda, como BRL.
Valores monetários

cobranca.valor é decimal na moeda indicada, e não inteiro em centavos. Neste exemplo, 149.90 significa R$ 149,90.

Teste local · simular envio do RecoPay
curl --request POST \
  --url https://api.produto-a.example/webhooks/recopay/plano-ativo \
  --header "Content-Type: application/json" \
  --header "X-Recopay-Event-Id: 93a8f7a1-37e4-4ce5-9c1c-41b918b17765" \
  --header "X-Recopay-Timestamp: 1788197538" \
  --header "X-Recopay-Signature: v1=HMAC_HEXADECIMAL" \
  --data @plano-ativo.json
Entrega persistente

O RecoPay considera entregue somente um HTTP 2xx. Falhas de rede, 408, 425, 429 e 5xx recebem novas tentativas com intervalo progressivo. Erros permanentes ficam visíveis em Planos e na Central de Problemas para reprocessamento manual.

Etapa 6

Processe rápido, de forma idempotente e auditável

O receptor não deve criar toda a conta dentro da requisição. Valide primeiro a assinatura sobre os bytes originais, persista o evento, coloque o trabalho em fila e devolva qualquer status 2xx.

  1. Exija HTTPS e aceite apenas POST com JSON.
  2. Leia o corpo sem transformá-lo e recuse timestamps com diferença superior a cinco minutos.
  3. Calcule o HMAC com o segredo do produto e compare em tempo constante.
  4. Confirme que o header X-Recopay-Event-Id coincide com eventoId.
  5. Aceite somente primeiro_pagamento_confirmado e assinatura_ativada_sem_cobranca; valide também produto.codigo, plano.id e as referências públicas.
  6. Crie restrição única por eventoId.
  7. Na mesma transação, grave o evento e crie um job de provisionamento.
  8. Responda 204 No Content e processe o job fora da requisição.
  9. Crie ou atualize o tenant, associe o plano e registre o vínculo pelas referências do RecoPay.
  10. Se o mesmo evento chegar novamente, retorne sucesso sem duplicar licença, workspace ou usuário.
Node.js · validação antes do JSON
import crypto from 'node:crypto';
import express from 'express';

const app = express();
app.post('/webhooks/recopay/plano-ativo',
  express.raw({ type: 'application/json' }),
  async (req, res) => {
    const eventId = req.get('X-Recopay-Event-Id') || '';
    const timestamp = req.get('X-Recopay-Timestamp') || '';
    const received = req.get('X-Recopay-Signature') || '';
    const now = Math.floor(Date.now() / 1000);

    if (!/^\d+$/.test(timestamp) || Math.abs(now - Number(timestamp)) > 300) {
      return res.sendStatus(401);
    }

    const rawBody = req.body;
    const expected = 'v1=' + crypto
      .createHmac('sha256', process.env.RECOPAY_WEBHOOK_SECRET)
      .update(timestamp + '.')
      .update(rawBody)
      .digest('hex');
    const a = Buffer.from(expected, 'ascii');
    const b = Buffer.from(received, 'ascii');
    if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
      return res.sendStatus(401);
    }

    const evento = JSON.parse(rawBody.toString('utf8'));
    const eventosAceitos = new Set([
      'primeiro_pagamento_confirmado',
      'assinatura_ativada_sem_cobranca'
    ]);
    if (evento.eventoId !== eventId || !eventosAceitos.has(evento.evento)) {
      return res.sendStatus(400);
    }

    await persistirEventoEEnfileirarProvisionamento(evento); // UNIQUE(eventoId)
    return res.sendStatus(204);
  });

Resposta devolvida ao RecoPay

O contrato de confirmação usa o status HTTP, não um JSON de resposta. A forma recomendada é responder 204 No Content sem corpo depois de persistir o evento e o job na mesma transação.

Devolvido ao RecoPay · sucesso recomendado
HTTP/1.1 204 No Content

Também é válido devolver outro 2xx. Se o seu framework exigir um corpo, o JSON abaixo é apenas uma confirmação local: o RecoPay não o interpreta nem o persiste como contrato.

Devolvido ao RecoPay · alternativa opcional
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "recebido": true,
  "eventoId": "93a8f7a1-37e4-4ce5-9c1c-41b918b17765"
}
Resposta do receptorTratamento pelo RecoPay
Qualquer 2xxEntrega concluída. O corpo, se existir, é ignorado.
Falha de rede, 408, 425, 429 ou 5xxFalha transitória; retorna à fila com intervalo progressivo.
Demais respostas 4xxFalha permanente; não há repetição automática até correção e reprocessamento manual.
Dado local recomendadoFinalidade
recopay_evento_idIdempotência da recepção e correlação com o reprocessamento.
recopay_contratacao_referenciaCorrelacionar checkout, boas-vindas, logs e onboarding.
recopay_produto_codigoSelecionar o provisionador correto em empresas com vários produtos.
recopay_plano_idMapear direitos e limites do produto contratado.
recopay_cobranca_idAuxiliar a auditoria financeira quando o evento possuir cobrança; deve aceitar nulo na ativação sem cobrança.
recopay_assinatura_referenciaConsultar a situação financeira pela API.
Não use JSON remontado

Espaços, ordem de propriedades e escapes alteram o HMAC. A assinatura deve ser verificada sobre o corpo bruto recebido, antes de JSON.parse.

Etapa 7

Use o retorno do navegador apenas para experiência

Depois da ativação, com ou sem primeira cobrança, o navegador pode seguir para a URL de boas-vindas. A query string transporta somente uma referência opaca:

URL · retorno após ativação
https://app.produto-a.example/onboarding?ref=550e8400-e29b-41d4-a716-446655440000

Use ref para procurar a contratação já registrada pelo webhook e montar a experiência. Ela não contém e-mail, documento, plano, cobrança nem ID interno. Ainda assim, não confie no navegador para liberar acesso: a URL pode ser alterada, repetida ou nem sequer aberta.

Uma referência em todo o ciclo

contratacaoReferencia aparece na resposta da contratação, no webhook, no redirecionamento, nos logs do RecoPay e na tela administrativa de entregas. Grave a mesma referência nos logs do seu sistema.

Etapa 8

Deixe a recorrência no RecoPay e consulte fatos financeiros

As próximas cobranças, conciliação, régua de cobrança e NFS-e permanecem no RecoPay. Seu sistema define a política comercial de acesso: por exemplo, avisar no primeiro dia, aplicar sete dias de carência e bloquear somente depois disso.

A consulta protegida exige uma chave de Integrações Externas com o escopo financeiro:ler e a referência pública da assinatura.

GET/integracoes/assinaturas/{assinaturaReferencia}/situacao-financeira
Enviado ao RecoPay · situação financeira
curl --request GET \
  --url https://api.recopay.com.br/integracoes/assinaturas/REFERENCIA_PUBLICA/situacao-financeira \
  --header "Authorization: Bearer SUA_CHAVE_RPK" \
  --header "Accept: application/json"
Recebido do RecoPay · HTTP 200
{
  "assinaturaReferencia": "REFERENCIA_PUBLICA",
  "assinaturaStatus": "ativa",
  "cliente": {
    "id": 318,
    "nome": "Empresa Exemplo LTDA",
    "documento": "12345678000190",
    "email": "[email protected]"
  },
  "situacaoFinanceira": "inadimplente",
  "possuiCobrancasEmAtraso": true,
  "quantidadeCobrancasEmAtraso": 1,
  "valorTotalEmAtraso": 149.90,
  "maiorAtrasoDias": 8,
  "consultadoEm": "2026-09-18T10:20:00-03:00",
  "cobrancasEmAtraso": [
    {
      "id": 2441,
      "vencimento": "2026-09-10",
      "diasEmAtraso": 8,
      "valor": 149.90,
      "linkPagamento": "https://recopay.app/cobrancas/visualizar/..."
    }
  ]
}
A API retorna fatos, não a decisão

situacaoFinanceira e maiorAtrasoDias informam o estado. Dias de carência, redução de recursos, bloqueio e desbloqueio pertencem ao seu produto.

Vínculo direto

O webhook entrega assinaturaReferencia, a mesma referência exigida por esta rota. Persista-a junto ao tenant provisionado; não use o ID numérico da cobrança como substituto.

Resiliência e segurança

Planeje falhas antes de abrir o tráfego

SituaçãoTratamento correto
Timeout ao criar a contrataçãoRepetir o mesmo payload com a mesma Idempotency-Key.
HTTP 400Corrigir dados, componentes, termos ou forma de pagamento; não repetir automaticamente.
HTTP 401/403Renovar a autenticação do cliente ou revisar chave e escopo no backend.
HTTP 409Autenticar cliente existente ou revisar conflito de idempotência.
HTTP 429/5xxAplicar backoff exponencial com jitter e limite de tentativas.
Webhook duplicadoRetornar sucesso para o eventoId já processado, sem provisionar novamente.
Webhook falhouO RecoPay repete falhas transitórias; revise as falhas permanentes em Planos e reprocese depois da correção.
Callback não ocorreuNão fazer nada financeiro. O webhook e a reconciliação sustentam o estado.
API financeira indisponívelUsar cache curto e não bloquear exclusivamente por timeout ou erro 5xx.
  • Nunca exponha a chave rpk_ no Checkout, no app mobile ou no navegador.
  • Sanitize termosUsoHtml antes de renderizar conteúdo persistido.
  • Não registre senha, token, chave Bearer nem payload completo com dados pessoais.
  • Restrinja o webhook ao produto e empresa esperados; rejeite eventos de outros contextos.
  • Separe os estados assinatura ativa, pagamento confirmado e provisionamento concluído.
  • Crie alertas para eventos persistidos que não concluíram o provisionamento.
Homologação

Teste o ciclo como uma máquina de estados

CenárioResultado esperado
Cliente novo + Pix aprovadoUma assinatura, uma cobrança, um webhook e um provisionamento.
Plano apenas por uso, sem opcional inicialAssinatura ativa, nenhuma cobrança de R$ 0, um webhook assinatura_ativada_sem_cobranca e um provisionamento.
Cliente existente sem loginContratação recusada sem alterar o cadastro.
Retry com a mesma chave e payloadMesmo resultado, sem segunda assinatura, cobrança ou entrega de webhook.
Mesma chave com payload diferenteConflito explícito; nenhuma mutação silenciosa.
Cartão recusadoSem webhook de plano ativo e sem acesso definitivo.
Boleto emitido e ainda pendenteSem ativação até a compensação.
Webhook entregue duas vezesSegundo processamento tratado como sucesso idempotente.
Receptor responde 500Falha observável e item de reconciliação criado no sistema terceiro.
Comprador fecha a página após ativaçãoProvisionamento continua independente do callback do navegador.
Cobrança recorrente atrasada e depois pagaCarência aplicada e acesso restaurado após nova consulta financeira.
Antes de publicar

Checklist de produção

  • Produto e planos ativos
  • Gateways validados
  • Termos revisados
  • Origem HTTPS exata
  • ID público configurado
  • Código do produto fixado
  • Catálogo vindo da API
  • Cliente existente autenticado
  • Idempotency-Key persistida
  • Redirecionamento pela URL retornada
  • Webhook em HTTPS
  • Segredo separado da chave da API
  • HMAC sobre o corpo bruto
  • Janela antirreplay de cinco minutos
  • Comparação em tempo constante
  • Fila de provisionamento
  • Restrição única por eventoId
  • Dois eventos de ativação aceitos
  • Auditoria sem segredos
  • Callback tratado como UX
  • Reprocessamento homologado
  • Chave rpk_ somente no backend
  • Escopo financeiro:ler
  • Política de carência definida
  • Reconciliação operacional
Implementação assistida

Contrato resumido para agentes de IA

Prompt de integração
OBJETIVO
Integrar um ciclo de venda de SaaS com Checkout, API e webhook do RecoPay.

CONFIGURACAO DO CHECKOUT
- VITE_CHECKOUT_PUBLICO_ID identifica a empresa e nao e segredo.
- VITE_PRODUTO_CODIGO fixa o produto exibido neste dominio.
- A origem deve ser HTTPS exata e estar vinculada ao produto no RecoPay.

FLUXO DE AQUISICAO
1. GET /checkout/{checkoutPublicoId}/produtos/{produtoCodigo}/planos
2. GET /checkout/{checkoutPublicoId}/planos/{planoId}
3. POST /checkout/{checkoutPublicoId}/clientes/verificacao
4. Se existente, POST /clientes/auth/login e usar o token do cliente.
5. POST /checkout/{checkoutPublicoId}/contratacoes com Idempotency-Key.
6. Ler dados.pagamentoNecessario e dados.statusAssinatura.
7. Redirecionar exclusivamente para dados.checkoutUrl, que permanece obrigatoria nos dois fluxos.
8. Nao ativar acesso pelo navegador ou pela emissao de Pix/boleto.

ATIVACAO
- Gerar um segredo de webhook por produto e guarda-lo somente no backend.
- Receber primeiro_pagamento_confirmado quando uma cobranca inicial for paga.
- Receber assinatura_ativada_sem_cobranca quando o valor inicial for zero.
- Tratar os dois eventos como fatos de ativacao capazes de iniciar o provisionamento.
- No evento sem cobranca, validar ativacao.status = ativa e ativacao.motivo = valor_inicial_zero; nao exigir cobranca.
- Antes do JSON, validar timestamp de ate 5 minutos e HMAC-SHA256 de timestamp + "." + corpo bruto.
- Comparar X-Recopay-Signature em tempo constante.
- Confirmar X-Recopay-Event-Id = eventoId e persistir com restricao unica.
- Enfileirar provisionamento e responder 2xx rapidamente.
- Persistir contratacaoReferencia e assinaturaReferencia.
- Tratar /boas-vindas?ref=contratacaoReferencia somente como experiencia.

POS-VENDA
- O RecoPay gera recorrencia, cobra, concilia, notifica e processa NFS-e.
- Consultar no backend:
  GET /integracoes/assinaturas/{assinaturaReferencia}/situacao-financeira
- Usar chave Bearer rpk_ com escopo financeiro:ler.
- A API retorna fatos; carencia e bloqueio pertencem ao sistema consumidor.
- Nao bloquear exclusivamente por timeout ou erro 5xx.

ENTREGA
- O RecoPay entrega somente quando recebe HTTP 2xx.
- A resposta recomendada e 204 No Content; qualquer corpo de resposta e ignorado.
- Rede, 408, 425, 429 e 5xx recebem retentativa progressiva.
- Demais respostas 4xx sao falhas permanentes ate reprocessamento manual.
- Falhas permanentes ficam disponiveis para analise e reprocessamento em Planos.
- Reprocessamentos repetem o mesmo eventoId e corpo; o receptor deve ser idempotente.

GUARDRAILS
- Nao acessar o banco RecoPay.
- Nao inventar preco, plano, componente ou forma de pagamento.
- Nao expor rpk_, senha ou token de cliente em logs.
- Reutilizar Idempotency-Key apenas no retry do mesmo payload.
- Provisionamento deve ser idempotente, auditavel e reversivel.

Continue sua integração

Próximo passo

Valide primeiro o contrato, depois construa a experiência

Execute em homologação os caminhos com pagamento e com valor inicial zero. Quando o backend estiver idempotente, aceitar os dois eventos de ativação e estiver observável, conecte o onboarding e a política de acesso.