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

# Criando checkout sessions

> Todas as formas de criar uma checkout session: itens do catálogo ou ad-hoc, pagamento único ou assinatura com trial, vínculo a cliente, campos obrigatórios, aparência, descontos e métodos de pagamento.

Uma **checkout session** é uma tentativa única de compra: uma sessão descartável
que coleta o comprador, apresenta os métodos de pagamento e confirma a cobrança.
Este guia percorre cada decisão que você toma no `POST /v1/checkout-sessions` e o
que a Chargefy resolve do lado dela. O schema completo está em
[Criar checkout session](/api-reference/checkout-sessions/create).

## O que você sempre envia: `line_items`

`line_items` é o único campo obrigatório. Cada item assume **exatamente uma** de
três formas.

### (a) Preço do catálogo

O caminho mais curto: um preço que você já cadastrou. Produto, valor e
recorrência saem do próprio preço.

```bash theme={}
curl -X POST https://api.chargefy.io/v1/checkout-sessions \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "line_items": [{ "price_id": "price_789", "quantity": 1 }]
  }'
```

### (b) Produto do catálogo + valor ad-hoc

Reusa o produto cadastrado (nome/descrição), mas com um valor único desta sessão.
**Não** cria um preço novo no catálogo.

```bash theme={}
curl -X POST https://api.chargefy.io/v1/checkout-sessions \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "line_items": [{
      "price_data": {
        "currency": "brl",
        "product_id": "prod_123",
        "unit_amount": 14990
      },
      "quantity": 1
    }]
  }'
```

### (c) Tudo ad-hoc (headless)

Sem catálogo: produto e valor existem só nesta sessão.

```bash theme={}
curl -X POST https://api.chargefy.io/v1/checkout-sessions \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "line_items": [{
      "price_data": {
        "currency": "brl",
        "product_data": { "name": "Consultoria avulsa" },
        "unit_amount": 50000
      },
      "quantity": 1
    }]
  }'
```

<Warning>
  Regras do array, validadas no create (cada uma retorna `400`):

  * Todos os itens compartilham a mesma `currency`.
  * Ou **todos** os itens são recorrentes, ou **nenhum** é — sem misturar.
  * Cada item tem exatamente um entre `price_id` e `price_data`.
  * Com `price_data`, exatamente um entre `product_id` e `product_data`.
</Warning>

## Pagamento único ou assinatura

Você **não** envia `mode` — ele é derivado dos `line_items`. Se algum item é
recorrente (preço com recorrência, ou `price_data.recurring`), a sessão vira
`mode: "subscription"`; senão, `mode: "payment"`.

### Assinatura com período de teste

Para assinaturas, `subscription_data` controla o trial. Use **um** de
`trial_period_days` ou `trial_end`:

```bash theme={}
curl -X POST https://api.chargefy.io/v1/checkout-sessions \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "line_items": [{
      "price_data": {
        "currency": "brl",
        "product_data": { "name": "Plano Pro" },
        "recurring": { "interval": "month" },
        "unit_amount": 4990
      }
    }],
    "subscription_data": {
      "trial_period_days": 7,
      "trial_settings": {
        "end_behavior": { "missing_payment_method": "pause" }
      }
    }
  }'
```

<Note>
  Quando há trial, o comprador informa o cartão mas **nenhuma cobrança acontece no
  checkout**: a sessão fecha com `payment_status: "no_payment_required"` e a
  assinatura nasce em período de teste. A primeira cobrança real ocorre ao fim do
  trial. Não criar assinatura sem um preço recorrente — não existe assinatura sem
  `price_id`/`price_data` recorrente.

  `subscription_data.trial_settings.end_behavior.missing_payment_method` controla
  o fim do trial quando não há payment method salvo: `create_invoice` abre uma
  invoice, `pause` deixa a assinatura em `paused` sem gerar invoice, e `cancel`
  cancela a assinatura.
</Note>

## Vincular a um cliente

Como a sessão se relaciona ao `customer` depende do que você envia:

| O que você envia                                        | Comportamento                                                                                                   |
| ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `customer` (id de cliente existente)                    | A sessão fica **travada** nesse cliente. O e-mail vem preenchido e somente leitura; o `id` do cliente não muda. |
| `customer_email` / `customer_document` (sem `customer`) | **Pré-preenchem** os campos. Nenhum cliente é criado no create.                                                 |
| Nada                                                    | Checkout de convidado: campos editáveis.                                                                        |

```bash theme={}
# Travado a um cliente que já existe no seu sistema
curl -X POST https://api.chargefy.io/v1/checkout-sessions \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": "cus_123",
    "line_items": [{ "price_id": "price_789", "quantity": 1 }]
  }'
```

O cliente é resolvido **uma única vez no confirm**, com os dados finais. Sem
`customer`, a Chargefy **cria um cliente novo** — o e-mail **não** é usado para
reaproveitar um cliente existente, porque e-mail não é chave de identidade
(vários clientes podem ter o mesmo e-mail na organização). Se você quer reusar um
cliente, faça o lookup na sua base e passe o `customer`. Veja
[Gestão de clientes](/features/customer-management).

<Note>
  O **documento** (CPF/CNPJ) é a chave soberana da identidade de pagamento:
  instrumentos salvos (cartões) são organizados por ele. Documentos diferentes
  geram identidades de pagamento diferentes — o que evita atrelar um cartão à
  pessoa errada.
</Note>

## Campos obrigatórios do comprador

Por padrão a sessão herda a política da organização, mas você pode sobrescrever
por sessão:

| Campo                     | Efeito                                                             |
| ------------------------- | ------------------------------------------------------------------ |
| `require_document`        | Exige CPF/CNPJ em qualquer método.                                 |
| `require_phone`           | Exige telefone (enviado no confirm como `customer_details.phone`). |
| `require_billing_address` | Exige endereço de cobrança.                                        |

Esses flags só **adicionam** exigências sobre o piso de cada método — boleto, por
exemplo, sempre exige documento e endereço, independentemente da política.

## Aparência

Três eixos independentes, todos opcionais:

| Campo               | Controla                                                                             |
| ------------------- | ------------------------------------------------------------------------------------ |
| `template`          | Estrutura/layout da página: `minimal` ou `booking`.                                  |
| `branding_settings` | Cor, fonte, tema (claro/escuro) e estilo de borda. `null` herda 100% da organização. |
| `submit_type`       | Verbo do botão: `auto`, `pay`, `subscribe`, `book`, `donate`.                        |

```bash theme={}
curl -X POST https://api.chargefy.io/v1/checkout-sessions \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "branding_settings": { "brand_color": "#5149EF", "theme": "light" },
    "line_items": [{ "price_id": "price_789", "quantity": 1 }],
    "submit_type": "pay"
  }'
```

## Descontos

Há duas formas, que coexistem:

* **Desconto automático** — passe `discount_id` no create; ele já entra aplicado.
* **Cupom do comprador** — deixe `allow_discount_codes` ativo (padrão) e o
  comprador digita o código na própria página.

```bash theme={}
curl -X POST https://api.chargefy.io/v1/checkout-sessions \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "discount_id": "di_123",
    "line_items": [{ "price_id": "price_789", "quantity": 1 }]
  }'
```

## Métodos de pagamento

Por padrão a sessão oferece todos os métodos habilitados na organização. Os
métodos disponíveis chegam no campo `payment_method_types` da resposta, e a
página só mostra as abas correspondentes.

## Entregar ao comprador

A resposta traz dois caminhos — escolha um:

* **`url`** — a página hospedada, pronta. Redirecione o comprador.
* **`client_secret`** — credencial de runtime do browser (não é segredo de
  servidor) para um frontend próprio chamar as rotas públicas de consulta e
  confirmação sem expor a sua API key.

A confirmação acontece no browser via
`POST /v1/checkout-sessions/public/:client_secret/confirm`. O seu servidor não
precisa criar nem confirmar nenhuma movimentação interna — veja
[Confirmar checkout session](/api-reference/checkout-sessions/confirm).

## Ciclo de webhooks

| Evento                                     | Quando                                                                                                     |
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
| `checkout.session.created`                 | A sessão foi criada.                                                                                       |
| `checkout.session.completed`               | O comprador concluiu o checkout. Em cartão, normalmente já pago; em PIX/boleto, ainda aguarda compensação. |
| `checkout.session.async.payment.succeeded` | PIX/boleto compensou — **evento confiável para liberar produto** em pagamento assíncrono.                  |
| `checkout.session.async.payment.failed`    | O pagamento assíncrono falhou ou expirou.                                                                  |
| `checkout.session.expired`                 | A sessão passou das 24h sem confirmação.                                                                   |

O `metadata` que você enviou é ecoado em todos esses eventos, então você
reconcilia o resultado contra o seu pedido guardando apenas o seu próprio
identificador.
