Skip to main content
Este guia mostra como criar cobranças diretamente pela API, sem depender de uma Checkout Session. Ao final, seu sistema será capaz de:
  • criar uma cobrança vinculada ao objeto do seu sistema;
  • exibir o QR Code e o copia-e-cola de um PIX;
  • concluir a operação de negócio somente quando o pagamento for confirmado;
  • tratar corretamente tentativas que falham ou são canceladas;
  • lidar com retries, eventos duplicados e eventos fora de ordem;
  • receber eventos de organizações conectadas quando a integração for de plataforma.
A integração server-to-server usa a API REST. Você não precisa de um SDK da Chargefy: os exemplos abaixo usam HTTP diretamente. Mantenha a API key apenas no seu backend.

O desenho da integração

O payment_intent representa uma cobrança: uma compra, uma invoice ou um ciclo que precisa ser pago. Cada tentativa concreta dentro dela é registrada como uma charge. O objeto de negócio continua pertencendo ao seu sistema; guarde nele o ID do Payment Intent que representa aquela cobrança. Separe os estados do seu objeto de negócio dos estados do pagamento:
Não use redirect, callback do frontend, ausência de next_action ou checkout.session.completed como prova de pagamento. Para concluir a operação, processe payment.intent.succeeded.

Antes de começar

Você precisa de:
  1. uma API key do ambiente correto;
  2. um registro no seu banco para relacionar a cobrança ao seu objeto de negócio;
  3. uma URL HTTPS para receber webhooks assinados;
  4. uma restrição de unicidade para os IDs evt_* já processados.
No seu banco, guarde pelo menos:
Grave a relação principal no seu banco, em payment_intent_id. Assim, cada webhook pode ser correlacionado pelo ID do Payment Intent sem depender de campos livres enviados pelo cliente.

1. Crie e confirme o PIX

Para obter o QR Code em uma única chamada, envie confirm: true e permita somente pix. Use uma chave de idempotência estável para criar a cobrança. Se sua chamada sofrer timeout, repita a mesma requisição com a mesma chave em vez de criar outro intent.
A resposta é o objeto completo. Em PIX, o estado comum após a confirmação é pending, e next_action contém os dados que o frontend deve apresentar.
Depois da resposta:
  1. grave pi_yEiGAw9jN95nBBL8 em payment_intent_id;
  2. mantenha a operação local em awaiting_payment;
  3. grave next_action.pix_display_qr_code.expires_at em pix_code_expires_at;
  4. envie ao frontend apenas os campos necessários de next_action;
  5. aguarde o webhook para concluir a operação ou encerrar a tentativa.

Se você opera uma plataforma

Use a API key da plataforma e envie o header Organization com a organização conectada que receberá o pagamento:
O Payment Intent pertence à organização indicada no header. Use a mesma organização ao consultá-lo, cancelá-lo ou regenerar o PIX.

2. Exiba o PIX

Leia next_action.type. Para PIX, o valor é pix_display_qr_code. O frontend pode mostrar uma contagem regressiva, mas não deve alterar o estado financeiro. Quando a contagem terminar, consulte o Payment Intent no backend ou aguarde payment.intent.canceled.
expires_at pertence ao código PIX dentro de next_action; o payment_intent não tem um expires_at top-level. O prazo comercial para concluir o pagamento (payment_expires_at) também é seu e pode ser diferente da validade do código de pagamento.

Eventos da confirmação e da expiração

Quando a confirmação muda o intent de requires_confirmation para pending, a Chargefy emite payment.intent.updated. Use o objeto completo do evento para sincronizar status, latest_charge, next_action e pix_code_expires_at. Se o PIX vencer sem pagamento, a expiração encerra a tentativa — não o intent: O intent aceita um novo código via /regenerate_pix. Não espere recuperar expires_at no payload da expiração: persista-o a partir da resposta de confirmação ou do payment.intent.updated que trouxe o código. A sequência acima é lógica; as requisições de webhook ainda podem chegar fora de ordem ou ser reentregues.

3. Cobre um cartão salvo

Para cartão, informe um payment_method salvo do customer. Com confirm: true, a cobrança costuma ser resolvida na mesma chamada.
Se ainda não existe um método salvo, use um Setup Intent e a tokenização segura do cartão antes de criar a cobrança.

4. Cadastre os webhooks necessários

Os tipos devem ser cadastrados individualmente. Não existe wildcard para payment.intent.*. Para manter uma visão completa do ciclo da cobrança, inscreva:
O secret whsec_... aparece somente na resposta de criação. Guarde-o em um gerenciador de secrets.

Organização ou plataforma

events_from: "platform" não inclui os eventos próprios da organização da plataforma. Se você precisa dos dois fluxos, crie dois endpoints. Eles podem usar a mesma URL, mas terão secrets independentes.

5. Verifique a assinatura

A implementação oficial segue Standard Webhooks. Cada entrega inclui:
  • webhook-id;
  • webhook-timestamp;
  • webhook-signature;
  • um secret no formato whsec_....
Verifique o corpo bruto antes de parsear o JSON. O exemplo abaixo usa uma biblioteca compatível com Standard Webhooks; ela não é um SDK da Chargefy.
Não valide um HMAC apenas sobre o JSON já parseado. A assinatura cobre $ {webhook - id}.${webhook - timestamp}.${corpo_bruto} e usa os bytes decodificados do secret whsec_....
Veja implementações completas e o algoritmo manual em Entrega e assinatura de webhooks. Depois de persistir o evento, processe a inbox em background. Assim você responde em menos de 20 segundos e não perde o payload se sua regra de negócio estiver temporariamente indisponível.

6. Processe os eventos sem duplicar efeitos

Cada data.object contém o objeto payment_intent público completo no estado registrado pelo evento. data.previous_attributes, quando presente, contém somente os valores anteriores dos campos alterados. Um handler seguro segue esta ordem:

Duplicação e ordem

  • A entrega é at least once: o mesmo event.id pode chegar novamente.
  • Eventos diferentes podem chegar fora de ordem.
  • Não compare apenas a ordem em que as requisições chegaram.
  • Não deixe um evento antigo rebaixar uma operação que já está completed.
  • data.object é o snapshot completo do momento do evento, não uma garantia de que continua atual quando a entrega chega.
  • Antes de aplicar falha ou cancelamento, consulte o Payment Intent pelo ID e preserve succeeded.

7. Consulte o pagamento ao reabrir a tela

O webhook mantém o backend sincronizado. O GET é útil quando o comprador reabre a tela de pagamento, atualiza a página ou volta depois de um período offline.
Use a resposta para reconstruir a tela: Polling contínuo não é necessário. Se você optar por polling apenas para atualizar a tela do comprador, trate-o como conveniência de UX; o efeito de negócio continua sendo processado no backend.

8. Cancele a tentativa quando necessário

Você pode cancelar um intent que ainda não está em succeeded ou canceled:
Valores aceitos: A Chargefy também escreve motivos por conta própria — automatic, expired, failed_invoice e void_invoice. Você recebe esses valores na resposta e nos webhooks, mas não pode enviá-los: a requisição responde 400.
Se a tentativa nasceu de uma sessão de checkout, o cancelamento não vai por aqui. A sessão é a dona do ciclo de vida do intent, então use POST /v1/checkout-sessions/{id}/expire — o intent é cancelado junto, com expired. O cancelamento direto responde 409, exceto em requires_capture.
Você não precisa cruzar dados para saber o que aconteceu: expired já diz que um prazo acabou. E abandoned nunca chega da Chargefy — se você recebeu esse motivo, foi porque você mesmo o enviou.
O endpoint retorna o Payment Intent completo já cancelado e também gera payment.intent.canceled. Faça a atualização local de maneira idempotente para que a resposta e o webhook não produzam o mesmo efeito duas vezes.

9. Permita outra tentativa com segurança

Use uma destas estratégias: Cada novo fluxo terminal deve ter um identificador próprio no seu sistema. Um padrão simples é payment-order-8f4c2a, payment-order-8f4c2a-retry-2 e assim por diante. Dentro do mesmo intent, latest_charge e os eventos charge.* identificam as tentativas concretas, como um PIX regenerado.

10. Entenda Payment Intent, Charge e Transaction

Os três objetos respondem perguntas diferentes: Para avançar ou encerrar a operação no seu sistema, use o Payment Intent. Para investigar uma recusa, consulte latest_charge. Para conciliação financeira e liquidação, consulte Transactions.

Checklist de testes

Antes de produção, valide pelo menos:
  • PIX criado e confirmado com next_action completo;
  • pagamento PIX concluído de forma assíncrona;
  • PIX não pago e tentativa encerrada corretamente;
  • cancelamento manual solicitado pelo comprador;
  • cartão aprovado;
  • cartão recusado com last_payment_error;
  • reentrega do mesmo event.id sem duplicar efeitos;
  • eventos de intents antigos sem alterar a cobrança atual ou uma operação concluída;
  • webhook indisponível temporariamente e recuperado pelos retries;
  • assinatura inválida rejeitada antes do processamento;
  • fluxo events_from: "platform" identificando a origem por organization;
  • ambiente de teste separado do ambiente live.

Referência rápida

Objeto Payment Intent

Campos, enums, status, next_action, valores e timestamps.

Criar Payment Intent

Parâmetros e respostas de criação.

Consultar Payment Intent

Estado atual e expansões de payment_method e latest_charge.

Confirmar Payment Intent

Confirmação de cartão e PIX.

Cancelar Payment Intent

Estados canceláveis e motivos de cancelamento.

Eventos de Payment Intent

Catálogo e páginas individuais de cada payload.

Entrega e assinatura

Standard Webhooks, retry, timeout, duplicação e ordem.

Lifecycle financeiro

Relação entre Payment Intent, Charge, Transaction e Invoice.