> ## 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.

# Entregar pedidos com segurança

> Use webhooks, idempotência e estado financeiro confirmado para liberar produtos ou serviços uma única vez.

Fulfillment é a ação que acontece depois do pagamento: liberar acesso, reservar estoque, emitir ingresso, iniciar serviço ou marcar um pedido como pago. Essa decisão deve acontecer no seu backend a partir de um webhook assinado — nunca apenas porque o comprador chegou à `success_url`.

## Escolha o sinal correto

| Fluxo                                | Sinal para avaliar                         | Condição antes de entregar                                                     |
| ------------------------------------ | ------------------------------------------ | ------------------------------------------------------------------------------ |
| Checkout hospedado com cartão        | `checkout.session.completed`               | `data.object.payment_status` é `paid`.                                         |
| Checkout hospedado com Pix ou boleto | `checkout.session.async.payment.succeeded` | A sessão passou de pendente para paga.                                         |
| Cobrança direta                      | `payment.intent.succeeded`                 | O payment intent está `succeeded`.                                             |
| Invoice ou ciclo de assinatura       | `invoice.paid`                             | A invoice está `paid`; vincule a entrega ao período ou invoice correspondente. |

<Warning>
  `checkout.session.status: "complete"` significa que o comprador concluiu o
  formulário. Não significa, sozinho, que Pix ou boleto foi pago. Confira sempre
  `payment_status` ou aguarde o evento assíncrono de sucesso.
</Warning>

Trials e compras de valor zero podem chegar a `no_payment_required`. Trate esse caso como uma regra explícita de acesso, separada da confirmação de dinheiro recebido.

No checkout hospedado, a Chargefy tenta entregar `checkout.session.completed` imediatamente e aguarda um `2xx` por até 10 segundos antes de seguir para a `success_url`. Responda somente depois de persistir o evento de forma durável, mas não execute trabalho demorado dentro dessa resposta. Se o endpoint falhar ou estourar o prazo, a fila continua as tentativas sem bloquear o comprador.

Para ligar esse processamento à experiência do comprador, siga o guia [Após
receber com um Checkout](/payments/checkout-post-payment). Ele mostra como usar
uma tela de ativação, polling no seu backend e reconciliação sem transformar um
atraso em uma nova tentativa de compra.

## Fluxo recomendado

| Etapa | Condição                                 | Ação                               |
| ----- | ---------------------------------------- | ---------------------------------- |
| 1     | Webhook recebido                         | Verifique a assinatura.            |
| 2     | Assinatura válida                        | Persista `evt_id` com unicidade.   |
| 3     | Evento persistido                        | Responda `2xx`.                    |
| 4     | Processamento assíncrono                 | O worker carrega o pedido.         |
| 5     | O estado financeiro não permite entregar | Registre o resultado e encerre.    |
| 6     | O estado financeiro permite entregar     | Marque o fulfillment atomicamente. |
| 7     | Fulfillment marcado pela primeira vez    | Execute o efeito externo.          |

<Steps>
  <Step title="Correlacione com seu pedido">
    Salve um identificador estável, como `order_id`, em `metadata` ao criar a
    checkout session, o payment intent ou a invoice daquele pedido. Em payment
    links reutilizáveis, use metadata apenas para campanha ou canal e
    correlacione a compra pela checkout session materializada em cada acesso. No
    webhook, use esses dados para localizar o pedido sem depender de busca por
    e-mail ou valor.
  </Step>

  <Step title="Verifique e deduplique">
    Valide a assinatura sobre o corpo bruto. Depois, tente inserir o `id` do
    evento em uma tabela com restrição de unicidade. Se ele já existe, responda
    `2xx` e não repita o processamento.
  </Step>

  <Step title="Confirme o estado financeiro">
    Confira o status no `data.object`. Se eventos chegaram fora de ordem ou o
    objeto local está desatualizado, consulte o recurso atual pela API antes de
    tomar uma decisão irreversível.
  </Step>

  <Step title="Trave a operação de negócio">
    Atualize o pedido com uma condição atômica, por exemplo de
    `awaiting_payment` para `fulfilling`. Se outro worker já mudou o estado,
    encerre sem executar a entrega novamente.
  </Step>

  <Step title="Registre o resultado">
    Guarde o recurso financeiro usado, o momento da entrega e a chave do efeito
    externo. Isso permite suporte, retry controlado e conciliação posterior.
  </Step>
</Steps>

## Duas camadas de idempotência

Deduplique em dois níveis:

1. **Evento:** o mesmo `evt_...` pode ser reentregue. Uma chave única impede que o mesmo payload rode duas vezes.
2. **Ação de negócio:** eventos diferentes podem representar o mesmo resultado, e endpoints distintos recebem IDs próprios. Uma restrição por pedido, invoice ou período impede duas ativações, dois ingressos ou duas remessas.

Esse segundo nível é essencial para plataformas e para fluxos que escutam tanto eventos de checkout quanto de payment intent.

## Não dependa da ordem

Eventos diferentes não têm garantia de ordem global. Um worker pode ver `payment.intent.succeeded` antes de outro evento criado segundos antes. Modele handlers como aplicação de estado:

* estados finais não voltam para estados anteriores;
* uma duplicata é sucesso sem novo efeito;
* um evento antigo não desfaz uma decisão mais recente;
* quando a ordem importa, consulte o objeto atual pela API.

## Falha durante a entrega

Separar “pagamento confirmado” de “produto entregue” permite retry sem cobrar de novo. Se seu provedor de e-mail, estoque ou acesso falhar:

* mantenha o pedido em um estado intermediário, como `fulfilling` ou `fulfillment_failed`;
* repita apenas o efeito de fulfillment, usando uma chave idempotente própria;
* não crie outro payment intent;
* alerte a operação depois do limite de tentativas.

## Reembolsos e disputas

Fulfillment não termina no evento de sucesso. Defina uma política separada para:

* `refund.*` ou `charge.refunded`: cancelar acesso, registrar devolução ou iniciar logística reversa quando aplicável;
* `charge.dispute.*`: restringir benefício, preservar evidências e acionar o fluxo de contestação;
* reembolso parcial: ajustar apenas a parte do pedido ligada ao valor devolvido.

Não apague o histórico de entrega. Registre a compensação como uma nova transição auditável.

## Plataformas

Em endpoints com `events_from: platform`, leia o campo top-level `organization` antes de resolver o pedido. Ele identifica a organização conectada que originou o evento. Valide que o pedido pertence à mesma organização antes de liberar qualquer coisa.

<CardGroup cols={2}>
  <Card title="Após receber com um Checkout" icon="arrow-right-to-bracket" href="/payments/checkout-post-payment">
    Conecte webhook, worker e página de ativação sem depender do redirect.
  </Card>

  <Card title="Entrega de webhooks" icon="webhook" href="/integrate/webhooks/delivery">
    Implemente assinatura, reentrega e deduplicação.
  </Card>

  <Card title="Ciclo de pagamento" icon="arrows-rotate" href="/integrate/payment-lifecycle">
    Entenda qual objeto é fonte da verdade em cada etapa.
  </Card>

  <Card title="Reembolsar pagamento" icon="arrow-rotate-left" href="/payments/refund-payment">
    Devolva valores e acompanhe o resultado financeiro.
  </Card>

  <Card title="Responder a disputas" icon="gavel" href="/payments/respond-to-disputes">
    Organize evidências, prazos e estados da contestação.
  </Card>
</CardGroup>
