> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chargefy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Após receber com um Checkout

> Conecte uma Checkout Session ao seu pedido, mostre o estado correto no retorno e conclua a entrega a partir de webhooks.

Quando seu backend cria uma Checkout Session, ele já conhece o pedido, o
comprador e a regra de entrega. Depois que o comprador conclui a página, seu
trabalho é reunir três caminhos que podem terminar em momentos diferentes:

* o navegador volta para a `success_url`;
* a Chargefy entrega o webhook da sessão;
* seu backend ativa o produto, registra o pedido ou libera o serviço.

O objetivo deste guia é fazer esses caminhos convergirem para **um único pedido
e uma única decisão de entrega**, mesmo com atraso, repetição ou pagamento
assíncrono.

<Info>
  Este artigo é para uma Checkout Session criada pelo seu backend para um pedido
  específico. Se você compartilha uma URL reutilizável, veja [Após receber com
  um Link de pagamento](/payments/payment-link-post-payment): cada acesso ao
  link cria uma sessão diferente.
</Info>

## O fluxo depois do checkout

| Momento                   | Fonte                                     | O que seu sistema faz                                             |
| ------------------------- | ----------------------------------------- | ----------------------------------------------------------------- |
| Sessão criada             | Resposta do `POST /v1/checkout-sessions`  | Liga o `cs_*` ao pedido que já existe no seu banco.               |
| Comprador conclui         | `checkout.session.completed`              | Registra que o formulário terminou e lê `payment_status`.         |
| Pagamento assíncrono muda | Evento `checkout.session.async.payment.*` | Confirma ou encerra a espera de Pix e boleto.                     |
| Navegador retorna         | `success_url`                             | Consulta o estado do pedido no seu backend; não decide pagamento. |
| Entrega termina           | Seu worker                                | Marca o pedido como entregue, ativo ou disponível uma única vez.  |

No checkout hospedado, a primeira tentativa de
`checkout.session.completed` é imediata. A Chargefy aguarda um `2xx` por até 10
segundos antes de liberar o redirect; se não receber confirmação, redireciona o
comprador e mantém o evento na fila para novas tentativas.

Por isso, responda `2xx` depois de **persistir** o evento, não depois de concluir
todo o trabalho de entrega.

## 1. Ligue a sessão ao pedido

Crie o pedido ou a tentativa local antes de chamar a API. Depois que a Checkout
Session for criada, salve o `session.id` nessa mesma operação de negócio.

| Dado local           | Para que serve                                                   |
| -------------------- | ---------------------------------------------------------------- |
| ID do pedido         | Referência estável do seu sistema.                               |
| `checkout_session`   | Permite reconciliar a resposta, o webhook e a página de retorno. |
| Usuário ou comprador | Impede que uma pessoa consulte o pedido de outra.                |
| Estado da entrega    | Separa pagamento pendente, processamento e conclusão.            |
| Último erro e datas  | Permitem retry, suporte e auditoria.                             |

Você também pode enviar uma referência própria em `metadata`. Esse objeto é
opcional, controlado pelo seu sistema e ecoado nos eventos da sessão. Mesmo
usando `metadata`, mantenha a relação entre pedido e `cs_*` no seu banco: ela é
mais direta para consultas e suporte.

<Warning>
  Não procure o pedido por e-mail, valor ou nome do comprador. Esses dados podem
  se repetir. Use a relação explícita com a Checkout Session.
</Warning>

## 2. Configure a página de retorno

Há duas formas seguras de identificar qual pedido voltou:

| Opção                   | Como funciona                                                                         | Quando usar                                                    |
| ----------------------- | ------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
| `{CHECKOUT_SESSION_ID}` | A Chargefy substitui o placeholder pelo ID da sessão no redirect.                     | Caminho mais simples quando seu backend pode receber o `cs_*`. |
| `state` opaco           | Seu backend gera um valor temporário, salva o vínculo com o pedido e o inclui na URL. | Quando você não quer expor IDs de recursos na URL.             |

Com o placeholder:

```text theme={"theme":"css-variables"}
https://meusite.com/pedido/retorno?session_id={CHECKOUT_SESSION_ID}
```

Com `state`, gere um valor aleatório no backend, guarde apenas o hash quando
possível e defina uma expiração. Não coloque e-mail, CPF, ID de usuário ou outra
informação pessoal nesse valor.

<Warning>
  O ID da sessão identifica um recurso, mas não autentica o comprador nem prova
  pagamento. Nunca coloque `client_secret` ou API key na `success_url`.
</Warning>

Quando a página abrir, envie o identificador ao seu backend e peça o estado do
pedido. A interface não deve consultar a Chargefy diretamente nem liberar
acesso com base apenas no parâmetro da URL.

## 3. Escolha o evento que autoriza a entrega

`status` responde se o checkout foi concluído. `payment_status` responde se o
pagamento foi confirmado. Para Pix e boleto, esses estados mudam em momentos
diferentes.

| Situação                                 | Sinal confiável                                                          | Próxima ação                                                  |
| ---------------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------- |
| Cartão aprovado                          | `checkout.session.completed` com `payment_status: "paid"`                | Enfileire a entrega.                                          |
| Total zero ou trial sem cobrança inicial | `checkout.session.completed` com `payment_status: "no_payment_required"` | Valide a subscription e aplique a regra de acesso do produto. |
| Pix ou boleto gerado                     | `checkout.session.completed` com `payment_status: "unpaid"`              | Mostre pagamento pendente; ainda não entregue.                |
| Pix ou boleto compensado                 | `checkout.session.async.payment.succeeded`                               | Enfileire a entrega.                                          |
| Pagamento assíncrono falhou ou venceu    | `checkout.session.async.payment.failed`                                  | Encerre a espera sem cobrar novamente.                        |
| Sessão aberta expirou                    | `checkout.session.expired`                                               | Ofereça criar uma nova Checkout Session para o mesmo pedido.  |

<Info>
  `status: "complete"` não significa necessariamente `payment_status: "paid"`.
  Em Pix e boleto, o comprador pode concluir o formulário antes de o dinheiro
  ser compensado.
</Info>

Assine seu endpoint nos eventos necessários, valide a assinatura sobre o corpo
bruto, persista `event.id` com unicidade e execute o trabalho demorado fora da
resposta. Os detalhes ficam em [Entrega de
webhooks](/integrate/webhooks/delivery).

## 4. Traduza o pagamento para estados do seu produto

O frontend entende melhor estados de produto do que estados financeiros. Seu
backend pode expor uma resposta simples como:

| Estado local      | O que significa                                                      | O que a página mostra                                   |
| ----------------- | -------------------------------------------------------------------- | ------------------------------------------------------- |
| `processing`      | O webhook foi recebido ou o resultado ainda está sendo reconciliado. | “Estamos confirmando seu pedido.”                       |
| `pending_payment` | Pix ou boleto ainda aguarda compensação.                             | Instruções de pagamento e atualização de estado.        |
| `ready`           | O pagamento e a entrega exigidos foram concluídos.                   | Acesso ao produto, pedido ou próximo passo.             |
| `failed`          | O pagamento ou a entrega falhou de forma recuperável.                | Motivo seguro e ação de retry ou suporte.               |
| `expired`         | A sessão não pode mais ser usada.                                    | Botão para iniciar outra tentativa para o mesmo pedido. |

Mantenha pagamento e entrega separados. Um pedido pode estar pago enquanto seu
worker ainda provisiona acesso; também pode estar entregue sem cobrança inicial
quando um trial válido começa.

## 5. Faça a página consultar o seu backend

A página de retorno deve consultar um endpoint autenticado do seu sistema. Esse
endpoint resolve o pedido pelo `session_id` ou `state` e devolve apenas o estado
necessário para a interface.

Um polling curto pode usar intervalos progressivos, por exemplo 1, 2, 3 e 5
segundos. Depois disso, mostre que o processamento continua e ofereça uma forma
de atualizar a página. Não transforme ausência de resposta em falha e não envie
o comprador automaticamente para criar outra cobrança.

Uma mensagem útil é mais clara do que um spinner sem contexto:

> **Estamos confirmando seu pedido**
>
> Seu checkout foi concluído. Isso normalmente leva alguns segundos. Você pode
> manter esta página aberta.

Se o navegador for fechado, o backend continua processando o webhook. A entrega
nunca deve depender de a página permanecer aberta.

## 6. Reconcilie atrasos sem duplicar efeitos

Webhook e página de retorno podem encontrar o mesmo pedido ao mesmo tempo. Os
dois caminhos devem chamar a mesma operação idempotente.

Quando o estado local parecer atrasado, seu backend pode:

1. consultar `GET /v1/checkout-sessions/{id}`;
2. comparar `status` e `payment_status` com o pedido salvo;
3. consultar a subscription quando `session.subscription` estiver preenchido;
4. chamar a mesma função de entrega usada pelo worker;
5. devolver o estado local atualizado para a página.

Defina um intervalo mínimo entre reconciliações para não consultar a API em
cada rodada do polling.

| Falha                          | Recuperação correta                                                         |
| ------------------------------ | --------------------------------------------------------------------------- |
| Webhook atrasado               | Mantenha `processing`; retry ou reconciliação conclui depois.               |
| Evento duplicado               | A chave única de `event.id` evita outro trabalho.                           |
| Webhook e polling concorrentes | A chave idempotente do pedido impede duas entregas.                         |
| Worker indisponível            | O evento persistido permanece disponível para retry.                        |
| Evento fora de ordem           | Não rebaixe estado terminal; consulte o recurso atual quando houver dúvida. |
| Falha na ativação              | Preserve a compra e repita apenas a ativação, nunca a cobrança.             |

## 7. Trate assinaturas depois da primeira sessão

Uma Checkout Session recorrente coordena apenas a entrada na assinatura. Depois
da conclusão:

* use `session.subscription` para relacionar a compra à assinatura criada;
* libere trial quando a subscription estiver `trialing` e essa for a regra do
  produto;
* acompanhe renovações por `invoice.paid`;
* trate falhas e recuperação pelo lifecycle da assinatura, não criando outra
  Checkout Session a cada ciclo.

Veja [Assinaturas](/payments/subscriptions) para o ciclo recorrente completo.

## Chargefy for Platforms

<Warning>
  Esta seção só se aplica a contas com o produto **Chargefy for Platforms**
  habilitado. Nesse produto, uma plataforma opera pagamentos para suas
  organizações filhas.
</Warning>

Além do ID da sessão, use o `organization` do topo do evento para validar qual
organização filha é dona do pedido. Nunca localize uma compra apenas pelo `cs_*`
sem confirmar esse vínculo no seu sistema.

## Checklist de produção

* [ ] O pedido existe antes da criação da Checkout Session.
* [ ] O `cs_*` retornado fica salvo no pedido.
* [ ] A `success_url` usa `{CHECKOUT_SESSION_ID}` ou um `state` opaco.
* [ ] Nenhuma API key ou `client_secret` aparece na URL ou no frontend.
* [ ] A página consulta o estado do seu backend, não decide pagamento.
* [ ] `paid`, `unpaid` e `no_payment_required` têm regras diferentes.
* [ ] Pix e boleto aguardam o evento assíncrono de sucesso.
* [ ] O webhook é validado, persistido e deduplicado antes do `2xx`.
* [ ] Webhook, polling e retry chamam a mesma entrega idempotente.
* [ ] Uma falha de ativação não cria outra cobrança.
* [ ] Renovações de assinatura usam eventos de invoice.

## Próximos passos

<CardGroup cols={2}>
  <Card title="Criar uma Sessão de checkout" icon="cart-shopping" href="/payments/create-hosted-checkout-page">
    Configure itens, comprador, recorrência e URLs de retorno.
  </Card>

  <Card title="Entregar pedidos" icon="box-open" href="/payments/fulfill-orders">
    Implemente persistência, idempotência, retry e compensação.
  </Card>

  <Card title="Entrega de webhooks" icon="webhook" href="/integrate/webhooks/delivery">
    Valide assinatura, trate reentregas e monitore seu endpoint.
  </Card>

  <Card title="Consultar Checkout Session" icon="magnifying-glass" href="/api-reference/checkout-sessions/get">
    Leia o estado atual da tentativa pelo backend.
  </Card>
</CardGroup>
