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

# Expirar uma sessão de checkout

> Encerra uma sessão aberta antes do prazo e cancela o payment intent dela com expired.

Encerra imediatamente uma sessão de checkout aberta, sem esperar o `expires_at`.
O comprador que abrir o link depois disso vê um checkout expirado.

Este também é o caminho para encerrar a tentativa de pagamento por trás da
sessão. A sessão é a dona do ciclo de vida do `payment_intent` dela: expirar a
sessão cancela o intent com `cancellation_reason: "expired"`, do mesmo jeito que
acontece quando o prazo termina sozinho.

<Check>
  Enquanto a sessão está aberta o intent fica aberto de propósito — é isso que
  permite ao comprador voltar ao link, trocar de meio de pagamento ou pedir um
  novo código PIX dentro do prazo da sessão. Só quando a sessão termina é que a
  tentativa termina.
</Check>

## Parâmetros de caminho

<ParamField path="id" type="string" required>
  ID da checkout session (`cs_*`).
</ParamField>

Não há corpo. A API key da própria organização atua diretamente; a API key de
plataforma exige o header `Organization: <id>` apontando para uma organização
conectada ativa.

<RequestExample>
  ```bash cURL theme={"theme":"css-variables"}
  curl -X POST "https://api.chargefy.io/v1/checkout-sessions/cs_ESZSB92S1L4ZwFqH/expire" \
    -H "Authorization: Bearer {{API_KEY}}"
  ```
</RequestExample>

## Quais sessões podem ser expiradas

Os valores abaixo são de `checkout_session.status`, que tem três valores
possíveis. Só o primeiro aceita a chamada.

| `checkout_session.status` | Resultado da chamada                             |
| ------------------------- | ------------------------------------------------ |
| `open`                    | `200 OK`; a sessão passa para `expired`.         |
| `complete`                | `409`; a sessão já foi submetida pelo comprador. |
| `expired`                 | `409`; a sessão já está expirada.                |

## Efeito no payment intent

A partir daqui, `status` é o do **payment intent** — outro objeto, outra lista
de valores. Não confunda com a tabela acima.

O intent da sessão é cancelado em quatro dos oito valores possíveis. Nos outros
quatro nada acontece, e cada exclusão é intencional:

| `payment_intent.status`   | O que acontece ao expirar a sessão                                          | Por quê                                                                                                                                         |
| ------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `requires_payment_method` | Vira `canceled`, `cancellation_reason: "expired"`, `canceled_at` preenchido | O comprador nunca escolheu como pagar                                                                                                           |
| `requires_confirmation`   | idem                                                                        | Escolheu, mas não confirmou                                                                                                                     |
| `pending`                 | idem                                                                        | PIX ou boleto emitido e não pago                                                                                                                |
| `processing`              | idem                                                                        | Em processamento sem desfecho                                                                                                                   |
| `succeeded`               | Nada                                                                        | O comprador pagou. Um pagamento concluído nunca é reescrito                                                                                     |
| `canceled`                | Nada                                                                        | Já encerrado; chamar de novo não muda nada                                                                                                      |
| `failed`                  | Nada                                                                        | A recusa já explica o desfecho, e `expired` apagaria essa informação                                                                            |
| `requires_capture`        | Nada                                                                        | Há valor autorizado e reservado no cartão do comprador. Libere com [POST /v1/payment-intents/:id/cancel](/api-reference/payment-intents/cancel) |

Se havia um PIX ou boleto emitido e ainda pendente sob esse intent, a cobrança
também é encerrada como `failed` — o comprovante já não podia ser pago.

## Resposta

`200 OK` com o objeto `checkout.session` completo — mesmo shape de
[GET /v1/checkout-sessions/:id](/api-reference/checkout-sessions/get) — agora com
`status: "expired"`.

<ResponseExample>
  ```json 200 theme={"theme":"css-variables"}
  {
    "id": "cs_ESZSB92S1L4ZwFqH",
    "object": "checkout.session",
    "allow_discount_codes": false,
    "amount_discount": 0,
    "amount_subtotal": 19990,
    "amount_tax": 0,
    "amount_total": 19990,
    "cancel_url": "https://meusite.com/cancelado",
    "client_reference_id": null,
    "client_secret": "78434edd0947319d02b16452c4c516d5176403c19fc660cd56ec79f59e63e412",
    "created_at": "2026-05-19T18:31:00Z",
    "currency": "brl",
    "customer": "cus_A2aHh2bPdmihXEgm",
    "customer_document": "12345678901",
    "customer_document_type": "cpf",
    "customer_email": "nome@email.com",
    "customer_name": "Cliente Exemplo",
    "discount": null,
    "expires_at": "2026-05-20T18:31:00Z",
    "has_surcharge": false,
    "invoice_creation": false,
    "line_items": [
      {
        "id": "li_mEkXYS6Qx46gUgP8",
        "adjustable_quantity": {
          "enabled": false,
          "maximum": null,
          "minimum": null
        },
        "amount_discount": 0,
        "amount_subtotal": 19990,
        "amount_tax": 0,
        "amount_total": 19990,
        "currency": "brl",
        "description": "Plano Pro mensal",
        "metadata": {},
        "position": 0,
        "price": "price_khN9pm1LeXMtE9ip",
        "price_data": null,
        "product": "prod_aHjZFX1ZqeyGeGxA",
        "quantity": 1,
        "recurring_interval": null,
        "recurring_interval_count": null,
        "unit_amount": 19990
      }
    ],
    "livemode": true,
    "marketing_attribution": null,
    "metadata": {},
    "mode": "payment",
    "payment_data": null,
    "payment_method_collection": "always",
    "payment_status": "unpaid",
    "status": "expired",
    "submit_type": "auto",
    "subscription": null,
    "success_url": "https://meusite.com/sucesso",
    "url": "https://pay.chargefy.io/session/9f4c2a1b8e3d7f06a5c4b2e1d8f3a6b09c5e2a1f4b7d8c3e6a9f1d2c4b5e8a0f"
  }
  ```

  ```json 401 theme={"theme":"css-variables"}
  {
    "error": {
      "code": "authentication_failed",
      "message": "Invalid API key provided.",
      "type": "authentication_error"
    }
  }
  ```

  ```json 404 theme={"theme":"css-variables"}
  {
    "error": {
      "code": "resource_missing",
      "message": "Checkout session not found",
      "type": "invalid_request_error"
    }
  }
  ```

  ```json 409 theme={"theme":"css-variables"}
  {
    "error": {
      "code": "resource_state_conflict",
      "message": "Checkout session cannot be expired in status complete.",
      "type": "invalid_request_error"
    }
  }
  ```
</ResponseExample>

## Erros

| HTTP  | `code`                    | Quando ocorre                                                                  |
| ----- | ------------------------- | ------------------------------------------------------------------------------ |
| `401` | `authentication_failed`   | API key ausente, mal formada ou inválida.                                      |
| `403` | `permission_denied`       | API key de plataforma sem `Organization`, ou `Organization` sem vínculo ativo. |
| `404` | `resource_missing`        | A sessão não existe nesta organização.                                         |
| `409` | `resource_state_conflict` | A sessão não está em `open`.                                                   |

## Webhooks gerados

| Evento                                                                         | Quando                                                                     |
| ------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
| [`checkout.session.expired`](/api-reference/webhooks/checkout.session.expired) | Sempre. Carrega a sessão completa em `data.object`.                        |
| [`payment.intent.canceled`](/api-reference/webhooks/payment.intent.canceled)   | Quando havia um intent em andamento, com `cancellation_reason: "expired"`. |

Os dois eventos descrevem a mesma decisão. Trate-os de forma idempotente para
não encerrar o pedido duas vezes no seu sistema.

<CardGroup cols={2}>
  <Card title="Objeto da sessão" icon="cube" href="/api-reference/checkout-sessions/object">
    Campos, estados e relação com o pagamento.
  </Card>

  <Card title="Cancelar um pagamento" icon="ban" href="/api-reference/payment-intents/cancel">
    Quando o cancelamento vai pelo lado do intent.
  </Card>
</CardGroup>
