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

# Checkout white-label

> Receba pagamentos por cartão em uma página própria, com a sua marca, usando Chargefy.js para tokenizar o cartão no navegador.

O **Checkout white-label** é o caminho para cobrar cartão dentro da sua própria experiência: sua URL, sua interface, sua marca e seus estados de pagamento. A Chargefy fica por trás, cuidando da tokenização, do cofre do cartão, da cobrança e dos webhooks.

A regra de segurança é simples: o número do cartão e o CVC são tokenizados **no navegador do comprador** com [Chargefy.js](/features/chargefy-js). O seu backend nunca recebe dados sensíveis do cartão; ele recebe apenas um `token_id` de uso único e chama a API da Chargefy com a sua chave secreta.

<Info>
  Use Checkout white-label quando você quer controlar a tela de pagamento inteira. Se preferir uma página pronta da Chargefy, use [Checkout Sessions](/features/checkout-sessions).
</Info>

## Quando usar

| Use Checkout white-label quando...                                              | Use checkout hospedado quando...                                  |
| ------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| O pagamento precisa acontecer dentro do seu app, domínio ou fluxo já existente. | Você quer colocar uma página pronta no ar rapidamente.            |
| Sua equipe quer controlar layout, copy, validação visual, loading e retry.      | Você não quer construir nem manter os campos de pagamento.        |
| Você quer salvar o cartão e cobrar imediatamente ou depois.                     | Você quer delegar toda a experiência de checkout para a Chargefy. |
| Você já tem backend para criar customers, intents e tratar webhooks.            | Você prefere criar uma sessão e redirecionar o comprador.         |

## O que fica com quem

| Parte                                                          | Responsável                         |
| -------------------------------------------------------------- | ----------------------------------- |
| Layout, campos, validação visual e mensagens para o comprador  | Sua aplicação                       |
| Tokenização segura do cartão no navegador                      | Chargefy.js                         |
| Customer, setup intent e payment intent                        | Seu backend chamando a API Chargefy |
| Cofre do cartão, cobrança, recusa e webhooks                   | Chargefy                            |
| Confirmação final do pedido, liberação de acesso e conciliação | Seu backend, a partir dos webhooks  |

## Como as peças se encaixam

| Objeto                    | Papel                                                         |
| ------------------------- | ------------------------------------------------------------- |
| `token_id` (`tok_*`)      | Cartão recém-digitado, tokenizado no browser. É de uso único. |
| `setup_intent` (`seti_*`) | Troca o `token_id` por um cartão salvo. Não cobra.            |
| `payment_method` (`pm_*`) | Cartão salvo e reutilizável.                                  |
| `payment_intent` (`pi_*`) | Cobrança. Referencia o customer e o `payment_method`.         |

<Warning>
  Um payment intent é cobrado com um `payment_method` (`pm_*`), nunca com um `token_id` direto. O caminho seguro é sempre `token_id` → `setup_intent` → `pm_*` → `payment_intent`.
</Warning>

```mermaid theme={}
sequenceDiagram
  participant Browser as Sua página
  participant Backend as Seu backend
  participant API as Chargefy API

  Browser->>Browser: Tokeniza o cartão com Chargefy.js
  Browser->>Backend: Envia token_id
  Backend->>API: Cria setup intent confirmado
  API-->>Backend: Retorna payment_method pm_*
  Backend->>API: Cria payment intent confirmado
  API-->>Backend: Retorna payment_intent
  API-->>Backend: Envia webhook payment.intent.succeeded
```

## Pagamento imediato

### 1. Crie ou reutilize um customer

O cartão pertence a um customer. Para cartão no Brasil, crie o customer com `document` (CPF/CNPJ).

```bash theme={}
curl -X POST "https://api.chargefy.io/v1/customers" \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "document": "11144477735",
    "email": "nome@email.com",
    "name": "Cliente"
  }'
```

<Tip>
  Reutilize o mesmo customer quando o comprador já existir no seu sistema. Assim você mantém cartões salvos, histórico e cobranças futuras no mesmo perfil.
</Tip>

### 2. Tokenize o cartão no navegador

Na sua tela de pagamento, carregue o [Chargefy.js](/features/chargefy-js) e envie os dados do cartão para tokenização.

```html theme={}
<script src="https://api.chargefy.io/v1/chargefy.js"></script>
```

```js theme={}
const chargefy = Chargefy({ environment: "live" });

const token = await chargefy.createPaymentToken({
  cvc: cvc,
  exp_month: expMonth,
  exp_year: expYear,
  name: holderName,
  number: cardNumber,
});

await fetch("/api/pay", {
  body: JSON.stringify({ token_id: token.id }),
  method: "POST",
});
```

O seu backend recebe `token.id` (`tok_*`). Ele não recebe número do cartão, CVC nem dados sensíveis.

### 3. Salve o cartão

No backend, confirme um setup intent com o `token_id`. A resposta traz o `payment_method` (`pm_*`) que será usado para cobrar.

```bash theme={}
curl -X POST "https://api.chargefy.io/v1/setup-intents" \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "confirm": true,
    "customer": "cus_123",
    "token_id": "tok_123"
  }'
```

```json theme={}
{
  "id": "seti_123",
  "object": "setup_intent",
  "customer": "cus_123",
  "payment_method": "pm_123",
  "status": "succeeded",
  "usage": "off_session"
}
```

### 4. Cobre com o cartão salvo

Crie o payment intent com `customer`, `payment_method` e `confirm: true`.

```bash theme={}
curl -X POST "https://api.chargefy.io/v1/payment-intents" \
  -H "Authorization: Bearer {{API_KEY}}" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 49900,
    "confirm": true,
    "currency": "brl",
    "customer": "cus_123",
    "payment_method": "pm_123"
  }'
```

Para cartão, a confirmação é síncrona: a resposta já volta com o resultado atual em `status`.

```json theme={}
{
  "id": "pi_123",
  "object": "payment_intent",
  "amount": 49900,
  "currency": "brl",
  "customer": "cus_123",
  "latest_charge": "ch_123",
  "payment_method": "pm_123",
  "status": "succeeded"
}
```

<Tip>
  Mesmo em uma compra avulsa, o cartão salvo fica disponível no customer. Isso permite retry com consentimento, recompra e assinaturas sem pedir os dados de novo.
</Tip>

## Parcelamento

Parcelas são definidas em `payment_method_options.credit_card.installments` no create ou update do payment intent. Não envie parcelamento no confirm.

```json theme={}
{
  "amount": 120000,
  "confirm": true,
  "currency": "brl",
  "customer": "cus_123",
  "payment_method": "pm_123",
  "payment_method_options": {
    "credit_card": {
      "installments": {
        "count": 3,
        "has_interest": true
      }
    }
  }
}
```

| Campo          | Descrição                                                                              |
| -------------- | -------------------------------------------------------------------------------------- |
| `count`        | Número de parcelas, de `1` a `12`. O limite pode cair conforme o valor da venda.       |
| `has_interest` | `true` = comprador paga os juros do parcelamento. `false` = sua loja absorve os juros. |

O objeto retornado detalha o cálculo do parcelamento:

```json theme={}
{
  "amount_subtotal": 120000,
  "amount_total": 123600,
  "count": 3,
  "has_interest": true,
  "interest_amount": 3600
}
```

<Warning>
  Enviar `installments` no corpo do confirm retorna `400`. Defina as parcelas no create ou update do payment intent.
</Warning>

## UX recomendada

| Momento         | O que mostrar                                                                             |
| --------------- | ----------------------------------------------------------------------------------------- |
| Antes de enviar | Valor total, parcelas, bandeira aceita, CPF/CNPJ do customer quando fizer sentido.        |
| Tokenizando     | Loading curto no botão. Não envie o formulário duas vezes.                                |
| Salvando cartão | Mensagem de processamento discreta. O comprador não precisa ver detalhes de setup intent. |
| Cobrando        | Estado de "processando pagamento" até a resposta do payment intent.                       |
| Aprovado        | Confirme o pedido visualmente, mas libere acesso/entrega a partir do webhook.             |
| Recusado        | Mostre uma mensagem humana e ofereça tentativa com outro cartão.                          |

## Recusa e retry

Se o cartão for recusado, o payment intent fica `failed` e o motivo vem em `last_payment_error`. Para tentar de novo:

1. Tokenize um novo cartão no navegador.
2. Confirme um novo setup intent para gerar outro `pm_*`.
3. Crie um novo payment intent com esse `pm_*`.

Não reutilize um `token_id` nem reconfirme um payment intent terminado.

```json theme={}
{
  "id": "pi_456",
  "object": "payment_intent",
  "amount": 49900,
  "currency": "brl",
  "customer": "cus_123",
  "last_payment_error": {
    "category": "issuer_declined",
    "code": "payment_failed",
    "message": "Payment method was declined"
  },
  "payment_method": "pm_456",
  "status": "failed"
}
```

## 3DS e autenticação

Hoje a cobrança de cartão é síncrona: ao confirmar, o `status` já volta `succeeded`, `requires_capture` (quando `capture_method: manual`) ou `failed`. Não há etapa de redirecionamento ou desafio 3DS no fluxo de cartão.

<Note>
  `next_action` existe para métodos assíncronos, como PIX e boleto. Cartão não usa `next_action` no Checkout white-label.
</Note>

## Webhooks são a fonte da verdade

A resposta síncrona ajuda a atualizar a tela, mas o estado final da sua operação deve vir dos webhooks. Verifique a assinatura antes de processar eventos — veja [Entrega de webhooks](/integrate/webhooks/delivery).

| Evento                     | Quando usar                                           |
| -------------------------- | ----------------------------------------------------- |
| `payment.intent.succeeded` | Confirmar pagamento aprovado e liberar pedido/acesso. |
| `payment.intent.failed`    | Registrar falha e permitir retry.                     |
| `payment.intent.canceled`  | Marcar tentativa cancelada.                           |
| `setup.intent.succeeded`   | Confirmar que o cartão foi salvo no customer.         |
| `payment.method.attached`  | Atualizar a lista de cartões salvos do customer.      |

<Tip>
  Uma cobrança de cartão também emite `charge.succeeded` ou `charge.failed`. Para o estado do pagamento, escute `payment.intent.*`; `charge.*` é o detalhe da tentativa de cobrança.
</Tip>

## Erros esperados

Todos seguem o [formato de erro](/api-reference/errors) `{ error: { code, message, param, type } }`.

| Situação                                       | Resposta                                                          |
| ---------------------------------------------- | ----------------------------------------------------------------- |
| Token inválido, expirado ou recusado ao salvar | `402` `card_error` no confirm do setup intent.                    |
| Cartão recusado na cobrança                    | Payment intent `status: failed` com `last_payment_error`.         |
| Parcelas inválidas                             | `400` em `payment_method_options.credit_card.installments.count`. |
| `customer` ausente                             | `400` com `param: customer`.                                      |
| `payment_method` ausente no confirm de cartão  | `400` com `param: payment_method`.                                |
| Customer sem documento                         | `422` — defina `document` (CPF/CNPJ) antes de salvar o cartão.    |
| `payment_method` não pertence ao customer      | `400` com `param: payment_method`.                                |

## Sandbox

Em `test`, o número do cartão escolhe o cenário (aprovado, recusado, saldo insuficiente etc.). Use a chave `ch_test_` no backend e `environment: "test"` no Chargefy.js.

Veja os cartões de teste em [Chargefy.js](/features/chargefy-js#cartoes-de-teste) e os cenários completos em [Sandbox](/integrate/sandbox).

## Próximos passos

<CardGroup cols={2}>
  <Card title="Chargefy.js" icon="code" href="/features/chargefy-js">
    Referência do script de tokenização no navegador.
  </Card>

  <Card title="Tokenização de cartão" icon="credit-card" href="/features/card-tokenization">
    Salve cartão para assinaturas, recompra e cobrança futura.
  </Card>

  <Card title="Payment Intents" icon="bolt" href="/api-reference/payment-intents">
    Contrato completo de create, confirm, capture e cancel.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/integrate/webhooks/delivery">
    Entrega, assinatura e processamento idempotente.
  </Card>
</CardGroup>
