> ## Documentation Index
> Fetch the complete documentation index at: https://scaleup-c34c4386.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Checkout com Cartão de Crédito

> Guia completo para integrar pagamentos com cartão de crédito — tokenização segura, parcelamento em até 12x, pré-autorização e captura

Este guia cobre o fluxo completo de pagamento com cartão de crédito na Chargefy: desde a criação da sessão de checkout até o tratamento de respostas, incluindo parcelamento, pré-autorização e boas práticas de segurança.

## Visão geral do fluxo

O pagamento com cartão de crédito na Chargefy segue este fluxo:

```
Cliente preenche dados → Tokenização segura → Confirmação → Aprovado/Recusado
```

**1. Criar sessão de checkout**

Seu backend cria uma sessão via API com o produto e valor.

**2. Coletar dados do cartão**

O frontend coleta os dados do cartão de forma segura (tokenização client-side).

**3. Confirmar pagamento**

Envie os dados tokenizados junto com o número de parcelas para confirmar o pagamento.

**4. Tratar resposta**

Verifique se o pagamento foi aprovado, recusado ou se houve erro, e aja de acordo.

## Pré-requisitos

* Uma conta Chargefy com [Supabase JWT](https://scaleup-c34c4386.mintlify.site/integrate/authentication.md)
* Pelo menos um [produto criado](https://scaleup-c34c4386.mintlify.site/features/products.md) no dashboard
* Node.js 18+ e o SDK `@chargefy/sdk` instalado
* Familiaridade com o [ambiente sandbox](https://scaleup-c34c4386.mintlify.site/integrate/sandbox.md)

```bash npm theme={null}
npm install @chargefy/sdk
```

```bash pnpm theme={null}
pnpm add @chargefy/sdk
```

Configure a variável de ambiente:

```bash .env theme={null}
CHARGEFY_ACCESS_TOKEN=<supabase_jwt>
```

## Passo 1: Criar sessão de checkout

Crie uma sessão de checkout no seu backend informando o produto e opções de pagamento.

```typescript TypeScript theme={null}
import { Chargefy } from '@chargefy/sdk'

const chargefy = new Chargefy({
  accessToken: process.env.CHARGEFY_ACCESS_TOKEN!,
  // server: 'sandbox' // Para ambiente de testes
})

async function criarCheckoutCartao() {
  const checkout = await chargefy.checkouts.create({
    product_price_id: 'price_xxx',
    payment_method: 'credit_card',
    success_url: 'https://meusite.com.br/pagamento/sucesso',
    customer_email: 'cliente@email.com',
  })

  return {
    id: checkout.id,
    client_secret: checkout.client_secret,
    url: checkout.url,
    amount: checkout.amount, // Valor em centavos (ex: 9990 = R$ 99,90)
  }
}
```

```bash cURL theme={null}
curl -X POST https://api.chargefy.io/api/v1/checkouts/ \
  -H "Authorization: Bearer $CHARGEFY_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "product_price_id": "price_xxx",
    "payment_method": "credit_card",
    "success_url": "https://meusite.com.br/pagamento/sucesso",
    "customer_email": "cliente@email.com"
  }'
```

A resposta inclui o `client_secret`, que sera usado para confirmar o pagamento no frontend.

## Passo 2: Coletar dados do cartão com segurança

Os dados do cartão devem ser coletados diretamente no frontend e enviados para confirmacao. A Chargefy realiza a tokenizacao dos dados sensiveis de forma segura.

> [!WARNING]
>
> **Conformidade PCI-DSS**: Nunca armazene, registre em logs ou trafegue dados completos de cartao pelo seu servidor em texto plano. A tokenizacao da Chargefy garante que os dados sensiveis sao processados em ambiente seguro e certificado PCI-DSS Level 1.

Os campos necessarios para o cartao sao:

| Campo | Tipo | Descricao | Exemplo |
| - | - | - | - |
| `card_number` | `string` | Numero do cartao (sem espacos) | `"4111111111111111"` |
| `holder_name` | `string` | Nome impresso no cartao | `"JOAO SILVA"` |
| `expiry_month` | `string` | Mes de validade (2 digitos) | `"12"` |
| `expiry_year` | `string` | Ano de validade (4 digitos) | `"2028"` |
| `cvv` | `string` | Codigo de seguranca (3-4 digitos) | `"123"` |

## Passo 3: Confirmar pagamento com dados do cartao

Com a sessao criada e os dados do cartao coletados, confirme o pagamento:

```typescript TypeScript theme={null}
async function confirmarPagamentoCartao(
  clientSecret: string,
  dadosCartao: {
    card_number: string
    holder_name: string
    expiry_month: string
    expiry_year: string
    cvv: string
  },
  parcelas: number = 1
) {
  const resultado = await chargefy.checkouts.confirm(clientSecret, {
    customer_name: 'Joao Silva',
    customer_email: 'joao@email.com',
    customer_tax_id: '123.456.789-00',
    payment_method: 'credit_card',
    card: {
      card_number: dadosCartao.card_number,
      holder_name: dadosCartao.holder_name,
      expiry_month: dadosCartao.expiry_month,
      expiry_year: dadosCartao.expiry_year,
      cvv: dadosCartao.cvv,
    },
    installments: parcelas, // 1 a 12
  })

  return resultado
}
```

```bash cURL theme={null}
curl -X POST https://api.chargefy.io/api/v1/checkouts/cs_xxx/confirm \
  -H "Authorization: Bearer $CHARGEFY_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_name": "Joao Silva",
    "customer_email": "joao@email.com",
    "customer_tax_id": "123.456.789-00",
    "payment_method": "credit_card",
    "card": {
      "card_number": "4111111111111111",
      "holder_name": "JOAO SILVA",
      "expiry_month": "12",
      "expiry_year": "2028",
      "cvv": "123"
    },
    "installments": 3
  }'
```

> [!NOTE]
>
> Os dados do cartao sao tokenizados automaticamente durante a confirmacao. A Chargefy nunca armazena os dados sensiveis do cartao — apenas o token gerado e utilizado para processar a transacao.

## Passo 4: Parcelamento (1-12x)

A Chargefy suporta parcelamento de **1 a 12 vezes** no cartao de credito. O comportamento varia conforme a configuracao do produto:

| Parcelas | Tipo | Descricao |
| - | - | - |
| `1` | A vista | Valor integral sem acrescimo |
| `2-6` | Sem juros (configuravel) | Valor dividido igualmente |
| `7-12` | Com juros (configuravel) | Juros repassados ao cliente |

### Exemplo: Calcular parcelas para exibicao

```typescript theme={null}
async function calcularParcelas(checkoutId: string) {
  const checkout = await chargefy.checkouts.get(checkoutId)
  const valorTotal = checkout.amount // em centavos

  const opcoesParcelas = []

  for (let i = 1; i <= 12; i++) {
    const temJuros = i > 6 // Exemplo: juros a partir de 7x
    const taxaJuros = temJuros ? 0.0199 : 0 // 1.99% ao mes
    const valorComJuros = temJuros
      ? valorTotal * Math.pow(1 + taxaJuros, i)
      : valorTotal
    const valorParcela = Math.ceil(valorComJuros / i)

    opcoesParcelas.push({
      parcelas: i,
      valor_parcela: valorParcela, // centavos
      valor_total: temJuros ? Math.ceil(valorComJuros) : valorTotal,
      tem_juros: temJuros,
      label: temJuros
        ? `${i}x de R$ ${(valorParcela / 100).toFixed(2)} (com juros)`
        : `${i}x de R$ ${(valorParcela / 100).toFixed(2)} sem juros`,
    })
  }

  return opcoesParcelas
}

// Exemplo de saida para produto de R$ 199,90:
// [
//   { parcelas: 1, label: "1x de R$ 199,90 sem juros" },
//   { parcelas: 2, label: "2x de R$ 99,95 sem juros" },
//   { parcelas: 3, label: "3x de R$ 66,64 sem juros" },
//   ...
//   { parcelas: 12, label: "12x de R$ 20,23 (com juros)" },
// ]
```

> [!TIP]
>
> As regras de parcelamento (quantidade maxima de parcelas, juros por faixa) sao configuradas por produto no dashboard da Chargefy. A API retorna as opcoes disponiveis automaticamente.

## Passo 5: Tratar a resposta

Apos confirmar o pagamento, verifique o status da resposta para tomar a acao adequada:

```typescript theme={null}
async function processarPagamento(clientSecret: string, dadosCartao: any) {
  try {
    const resultado = await chargefy.checkouts.confirm(clientSecret, {
      customer_name: 'Joao Silva',
      customer_email: 'joao@email.com',
      customer_tax_id: '123.456.789-00',
      payment_method: 'credit_card',
      card: dadosCartao,
      installments: 1,
    })

    switch (resultado.status) {
      case 'succeeded':
        // Pagamento aprovado imediatamente
        console.log('Pagamento aprovado! Transacao:', resultado.transaction_id)
        // Liberar acesso, enviar email de confirmacao, etc.
        return { sucesso: true, transacao: resultado.transaction_id }

      case 'confirmed':
        // Pagamento em processamento (pre-autorizacao)
        console.log('Pagamento em analise:', resultado.transaction_id)
        return { sucesso: true, pendente: true, transacao: resultado.transaction_id }

      case 'failed':
        // Pagamento recusado pela operadora
        console.log('Pagamento recusado:', resultado.error?.message)
        return {
          sucesso: false,
          erro: resultado.error?.message || 'Pagamento recusado pela operadora',
          codigo: resultado.error?.code,
        }

      default:
        return { sucesso: false, erro: 'Status desconhecido' }
    }
  } catch (error: any) {
    // Erro de comunicacao ou validacao
    console.error('Erro ao processar pagamento:', error.message)
    return { sucesso: false, erro: 'Erro interno ao processar pagamento' }
  }
}
```

### Codigos de recusa comuns

| Codigo | Descricao | Acao recomendada |
| - | - | - |
| `insufficient_funds` | Saldo/limite insuficiente | Solicitar outro cartao ou valor menor |
| `card_declined` | Cartao recusado pela operadora | Verificar dados ou usar outro cartao |
| `expired_card` | Cartao vencido | Solicitar cartao valido |
| `invalid_cvv` | CVV incorreto | Solicitar novo CVV |
| `processing_error` | Erro no processamento | Tentar novamente em alguns segundos |
| `fraud_suspected` | Suspeita de fraude | Contatar operadora do cartao |

## Pre-autorizacao e captura

Para cenarios onde voce precisa **reservar o valor** no cartao e **capturar depois** (ex: marketplaces, entregas, reservas), use o fluxo de pre-autorizacao:

### 1. Criar checkout com pre-autorizacao

```typescript TypeScript theme={null}
const checkout = await chargefy.checkouts.create({
  product_price_id: 'price_xxx',
  payment_method: 'credit_card',
  capture: false, // Pre-autorizacao: reserva sem capturar
  success_url: 'https://meusite.com.br/reserva/confirmada',
})
```

```bash cURL theme={null}
curl -X POST https://api.chargefy.io/api/v1/checkouts/ \
  -H "Authorization: Bearer $CHARGEFY_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "product_price_id": "price_xxx",
    "payment_method": "credit_card",
    "capture": false,
    "success_url": "https://meusite.com.br/reserva/confirmada"
  }'
```

### 2. Confirmar pagamento (reserva o valor)

```typescript theme={null}
const resultado = await chargefy.checkouts.confirm(clientSecret, {
  customer_name: 'Joao Silva',
  customer_email: 'joao@email.com',
  customer_tax_id: '123.456.789-00',
  payment_method: 'credit_card',
  card: {
    card_number: '4111111111111111',
    holder_name: 'JOAO SILVA',
    expiry_month: '12',
    expiry_year: '2028',
    cvv: '123',
  },
  installments: 1,
})

// Status sera 'confirmed' (valor reservado, aguardando captura)
console.log('Valor reservado:', resultado.status)
console.log('Transaction ID:', resultado.transaction_id)
```

### 3. Capturar o valor (quando pronto para cobrar)

```typescript TypeScript theme={null}
// Captura total
const captura = await chargefy.transactions.capture(resultado.transaction_id)
console.log('Valor capturado:', captura.status) // 'succeeded'

// Captura parcial (ex: valor menor que o reservado)
const capturaParcial = await chargefy.transactions.capture(
  resultado.transaction_id,
  {
    amount: 5000, // Capturar apenas R$ 50,00 de R$ 99,90 reservados
  }
)
```

```bash cURL theme={null}
# Captura total
curl -X POST https://api.chargefy.io/api/v1/transactions/txn_xxx/capture \
  -H "Authorization: Bearer $CHARGEFY_ACCESS_TOKEN"

# Captura parcial
curl -X POST https://api.chargefy.io/api/v1/transactions/txn_xxx/capture \
  -H "Authorization: Bearer $CHARGEFY_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"amount": 5000}'
```

### 4. Cancelar pre-autorizacao (liberar o valor)

```typescript theme={null}
// Se nao quiser mais cobrar, libere o valor reservado
const cancelamento = await chargefy.transactions.void(resultado.transaction_id)
console.log('Pre-autorizacao cancelada:', cancelamento.status)
```

> [!WARNING]
>
> A pre-autorizacao expira em **7 dias**. Se nao for capturada ou cancelada nesse prazo, o valor e liberado automaticamente para o titular do cartao.

## Componente React para formulario de cartao

Exemplo de componente React para coletar dados do cartao com validacao:

```tsx components/CardForm.tsx theme={null}
import { useState, FormEvent } from 'react'

interface CardFormData {
  card_number: string
  holder_name: string
  expiry_month: string
  expiry_year: string
  cvv: string
  installments: number
}

interface CardFormProps {
  amount: number // valor em centavos
  maxInstallments?: number
  onSubmit: (data: CardFormData) => Promise<void>
}

export function CardForm({ amount, maxInstallments = 12, onSubmit }: CardFormProps) {
  const [loading, setLoading] = useState(false)
  const [erro, setErro] = useState<string | null>(null)
  const [form, setForm] = useState<CardFormData>({
    card_number: '',
    holder_name: '',
    expiry_month: '',
    expiry_year: '',
    cvv: '',
    installments: 1,
  })

  function formatarNumeroCartao(valor: string): string {
    const numeros = valor.replace(/\D/g, '').slice(0, 16)
    return numeros.replace(/(\d{4})(?=\d)/g, '$1 ')
  }

  function detectarBandeira(numero: string): string {
    const num = numero.replace(/\D/g, '')
    if (/^4/.test(num)) return 'Visa'
    if (/^5[1-5]/.test(num)) return 'Mastercard'
    if (/^3[47]/.test(num)) return 'Amex'
    if (/^(636368|438935|504175|451416|509|606282|301)/.test(num)) return 'Elo'
    return ''
  }

  function gerarOpcoesParcelas() {
    const opcoes = []
    for (let i = 1; i <= maxInstallments; i++) {
      const temJuros = i > 6
      const taxa = temJuros ? 0.0199 : 0
      const total = temJuros ? amount * Math.pow(1 + taxa, i) : amount
      const parcela = Math.ceil(total / i)

      opcoes.push({
        valor: i,
        label: temJuros
          ? `${i}x de R$ ${(parcela / 100).toFixed(2)} (com juros)`
          : `${i}x de R$ ${(parcela / 100).toFixed(2)} sem juros`,
      })
    }
    return opcoes
  }

  async function handleSubmit(e: FormEvent) {
    e.preventDefault()
    setErro(null)

    // Validacoes basicas
    const numero = form.card_number.replace(/\D/g, '')
    if (numero.length < 13 || numero.length > 19) {
      setErro('Numero do cartao invalido')
      return
    }
    if (!form.holder_name.trim()) {
      setErro('Nome do titular obrigatorio')
      return
    }
    if (!form.expiry_month || !form.expiry_year) {
      setErro('Data de validade obrigatoria')
      return
    }
    if (form.cvv.length < 3) {
      setErro('CVV invalido')
      return
    }

    setLoading(true)
    try {
      await onSubmit({
        ...form,
        card_number: numero, // Enviar sem espacos
      })
    } catch (err: any) {
      setErro(err.message || 'Erro ao processar pagamento')
    } finally {
      setLoading(false)
    }
  }

  const bandeira = detectarBandeira(form.card_number)

  return (
    <form onSubmit={handleSubmit} className="space-y-4 max-w-md">
      {/* Numero do cartao */}
      <div>
        <label className="block text-sm font-medium mb-1">
          Numero do cartao {bandeira && <span className="text-gray-500">({bandeira})</span>}
        </label>
        <input
          type="text"
          inputMode="numeric"
          placeholder="0000 0000 0000 0000"
          value={formatarNumeroCartao(form.card_number)}
          onChange={(e) =>
            setForm({ ...form, card_number: e.target.value })
          }
          className="w-full border rounded-lg px-3 py-2"
          autoComplete="cc-number"
          required
        />
      </div>

      {/* Nome do titular */}
      <div>
        <label className="block text-sm font-medium mb-1">
          Nome impresso no cartao
        </label>
        <input
          type="text"
          placeholder="JOAO SILVA"
          value={form.holder_name}
          onChange={(e) =>
            setForm({ ...form, holder_name: e.target.value.toUpperCase() })
          }
          className="w-full border rounded-lg px-3 py-2"
          autoComplete="cc-name"
          required
        />
      </div>

      {/* Validade e CVV */}
      <div className="flex gap-4">
        <div className="flex-1">
          <label className="block text-sm font-medium mb-1">Validade</label>
          <div className="flex gap-2">
            <select
              value={form.expiry_month}
              onChange={(e) =>
                setForm({ ...form, expiry_month: e.target.value })
              }
              className="flex-1 border rounded-lg px-3 py-2"
              autoComplete="cc-exp-month"
              required
            >
              <option value="">Mes</option>
              {Array.from({ length: 12 }, (_, i) => (
                <option key={i + 1} value={String(i + 1).padStart(2, '0')}>
                  {String(i + 1).padStart(2, '0')}
                </option>
              ))}
            </select>
            <select
              value={form.expiry_year}
              onChange={(e) =>
                setForm({ ...form, expiry_year: e.target.value })
              }
              className="flex-1 border rounded-lg px-3 py-2"
              autoComplete="cc-exp-year"
              required
            >
              <option value="">Ano</option>
              {Array.from({ length: 10 }, (_, i) => {
                const ano = new Date().getFullYear() + i
                return (
                  <option key={ano} value={String(ano)}>
                    {ano}
                  </option>
                )
              })}
            </select>
          </div>
        </div>

        <div className="w-24">
          <label className="block text-sm font-medium mb-1">CVV</label>
          <input
            type="text"
            inputMode="numeric"
            placeholder="123"
            maxLength={4}
            value={form.cvv}
            onChange={(e) =>
              setForm({ ...form, cvv: e.target.value.replace(/\D/g, '') })
            }
            className="w-full border rounded-lg px-3 py-2"
            autoComplete="cc-csc"
            required
          />
        </div>
      </div>

      {/* Parcelas */}
      <div>
        <label className="block text-sm font-medium mb-1">Parcelas</label>
        <select
          value={form.installments}
          onChange={(e) =>
            setForm({ ...form, installments: Number(e.target.value) })
          }
          className="w-full border rounded-lg px-3 py-2"
        >
          {gerarOpcoesParcelas().map((opcao) => (
            <option key={opcao.valor} value={opcao.valor}>
              {opcao.label}
            </option>
          ))}
        </select>
      </div>

      {/* Erro */}
      {erro && (
        <div className="bg-red-50 text-red-700 px-4 py-2 rounded-lg text-sm">
          {erro}
        </div>
      )}

      {/* Botao */}
      <button
        type="submit"
        disabled={loading}
        className="w-full bg-blue-600 text-white py-3 rounded-lg font-medium
                   hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
      >
        {loading
          ? 'Processando...'
          : `Pagar R$ ${(amount / 100).toFixed(2)}`}
      </button>

      <p className="text-xs text-gray-500 text-center">
        Pagamento processado com seguranca pela Chargefy. Seus dados estao protegidos.
      </p>
    </form>
  )
}
```

## Exemplo completo: Express + React

### Backend (Express)

```typescript src/routes/card-checkout.ts theme={null}
import { Router } from 'express'
import { Chargefy } from '@chargefy/sdk'

const chargefy = new Chargefy({
  accessToken: process.env.CHARGEFY_ACCESS_TOKEN!,
})

export const cardCheckoutRouter = Router()

// 1. Criar sessao de checkout
cardCheckoutRouter.post('/create', async (req, res) => {
  try {
    const { productPriceId, customerEmail } = req.body

    const checkout = await chargefy.checkouts.create({
      product_price_id: productPriceId,
      payment_method: 'credit_card',
      success_url: `${process.env.FRONTEND_URL}/pagamento/sucesso`,
    })

    res.json({
      checkoutId: checkout.id,
      clientSecret: checkout.client_secret,
      amount: checkout.amount,
      currency: checkout.currency,
    })
  } catch (error: any) {
    console.error('Erro ao criar checkout:', error.message)
    res.status(400).json({ error: 'Falha ao criar sessao de checkout' })
  }
})

// 2. Confirmar pagamento com cartao
cardCheckoutRouter.post('/confirm', async (req, res) => {
  try {
    const {
      clientSecret,
      customerName,
      customerEmail,
      customerTaxId,
      card,
      installments,
    } = req.body

    const resultado = await chargefy.checkouts.confirm(clientSecret, {
      customer_name: customerName,
      customer_email: customerEmail,
      customer_tax_id: customerTaxId,
      payment_method: 'credit_card',
      card: {
        card_number: card.card_number,
        holder_name: card.holder_name,
        expiry_month: card.expiry_month,
        expiry_year: card.expiry_year,
        cvv: card.cvv,
      },
      installments: installments || 1,
    })

    if (resultado.status === 'succeeded') {
      res.json({
        success: true,
        transactionId: resultado.transaction_id,
        message: 'Pagamento aprovado com sucesso!',
      })
    } else if (resultado.status === 'failed') {
      res.status(402).json({
        success: false,
        error: resultado.error?.message || 'Pagamento recusado',
        code: resultado.error?.code,
      })
    } else {
      res.json({
        success: true,
        pending: true,
        transactionId: resultado.transaction_id,
        message: 'Pagamento em processamento',
      })
    }
  } catch (error: any) {
    console.error('Erro ao confirmar pagamento:', error.message)
    res.status(500).json({
      success: false,
      error: 'Erro interno ao processar pagamento',
    })
  }
})
```

### Frontend (React)

```tsx pages/Checkout.tsx theme={null}
import { useState, useEffect } from 'react'
import { CardForm } from '../components/CardForm'

export function CheckoutPage() {
  const [checkout, setCheckout] = useState<{
    clientSecret: string
    amount: number
  } | null>(null)
  const [resultado, setResultado] = useState<{
    success: boolean
    message: string
  } | null>(null)

  useEffect(() => {
    // Criar sessao de checkout ao montar a pagina
    fetch('/api/card-checkout/create', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        productPriceId: 'price_xxx',
        customerEmail: 'cliente@email.com',
      }),
    })
      .then((res) => res.json())
      .then(setCheckout)
  }, [])

  async function handlePayment(cardData: any) {
    const response = await fetch('/api/card-checkout/confirm', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        clientSecret: checkout!.clientSecret,
        customerName: cardData.holder_name,
        customerEmail: 'cliente@email.com',
        customerTaxId: '123.456.789-00',
        card: cardData,
        installments: cardData.installments,
      }),
    })

    const data = await response.json()

    if (data.success) {
      setResultado({
        success: true,
        message: data.message,
      })
    } else {
      throw new Error(data.error || 'Pagamento recusado')
    }
  }

  if (resultado?.success) {
    return (
      <div className="text-center py-12">
        <h2 className="text-2xl font-bold text-green-600">
          Pagamento aprovado!
        </h2>
        <p className="mt-2 text-gray-600">{resultado.message}</p>
      </div>
    )
  }

  if (!checkout) {
    return <div className="text-center py-12">Carregando checkout...</div>
  }

  return (
    <div className="max-w-lg mx-auto py-12 px-4">
      <h1 className="text-2xl font-bold mb-6">Finalizar pagamento</h1>
      <CardForm
        amount={checkout.amount}
        maxInstallments={12}
        onSubmit={handlePayment}
      />
    </div>
  )
}
```

## Testes no sandbox

Use o [ambiente sandbox](https://scaleup-c34c4386.mintlify.site/integrate/sandbox.md) para testar pagamentos sem cobrar de verdade. Utilize os cartoes de teste abaixo:

### Cartoes de teste

| Numero | Resultado | Uso |
| - | - | - |
| `4111 1111 1111 1111` | Aprovado | Simular pagamento bem-sucedido |
| `4000 0000 0000 0002` | Recusado | Simular cartao recusado |

> [!NOTE]
>
> Para cartoes de teste, use qualquer data de validade futura (ex: `12/2028`) e qualquer CVV de 3 digitos (ex: `123`). O nome do titular pode ser qualquer valor.

### Testar via cURL

```bash theme={null}
# Teste com cartao aprovado
curl -X POST https://api.chargefy.io/api/v1/checkouts/cs_sandbox_xxx/confirm \
  -H "Authorization: Bearer $CHARGEFY_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_name": "Teste Aprovado",
    "customer_email": "teste@email.com",
    "customer_tax_id": "000.000.000-00",
    "payment_method": "credit_card",
    "card": {
      "card_number": "4111111111111111",
      "holder_name": "TESTE APROVADO",
      "expiry_month": "12",
      "expiry_year": "2028",
      "cvv": "123"
    },
    "installments": 1
  }'

# Teste com cartao recusado
curl -X POST https://api.chargefy.io/api/v1/checkouts/cs_sandbox_xxx/confirm \
  -H "Authorization: Bearer $CHARGEFY_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_name": "Teste Recusado",
    "customer_email": "teste@email.com",
    "customer_tax_id": "000.000.000-00",
    "payment_method": "credit_card",
    "card": {
      "card_number": "4000000000000002",
      "holder_name": "TESTE RECUSADO",
      "expiry_month": "12",
      "expiry_year": "2028",
      "cvv": "123"
    },
    "installments": 1
  }'
```

## Boas praticas de seguranca

**1. Nunca registre dados de cartao em logs**

Nunca use `console.log()`, `logger.info()` ou qualquer mecanismo de log para registrar numero do cartao, CVV ou data de validade. Registre apenas os 4 ultimos digitos para referencia.

**2. Use HTTPS em producao**

Todo trafego contendo dados de pagamento deve ocorrer exclusivamente sobre HTTPS/TLS. Nunca transmita dados de cartao em conexoes nao criptografadas.

**3. Prefira tokenizacao client-side**

Sempre que possivel, use o [Checkout Embed](https://scaleup-c34c4386.mintlify.site/features/checkout/embed.md) ou a tokenizacao Chargefy.js no frontend para que os dados do cartao nunca passem pelo seu servidor.

**4. Valide no servidor**

Mesmo com validacoes no frontend, sempre valide os dados novamente no backend antes de enviar para a API da Chargefy.

**5. Implemente idempotencia**

Use chaves de idempotencia para evitar cobranças duplicadas em caso de retry ou timeout de rede.

**6. Monitore transacoes**

Configure [webhooks](https://scaleup-c34c4386.mintlify.site/integrate/webhooks/endpoints.md) para receber notificacoes em tempo real sobre aprovacoes, recusas e estornos.

> [!WARNING]
>
> **PCI-DSS**: Se voce processa, armazena ou transmite dados de cartao pelo seu servidor, sua aplicacao precisa estar em conformidade com o padrao PCI-DSS. A maneira mais simples de evitar esse requisito e usar o Checkout Embed da Chargefy ou a tokenizacao client-side via Chargefy.js, onde os dados sensiveis nunca passam pela sua infraestrutura.

## Proximos passos

> [card] [Checkout PIX](https://scaleup-c34c4386.mintlify.site/guides/pix-checkout.md)
>
> Integre pagamentos via PIX com QR Code.

> [card] [Webhooks](https://scaleup-c34c4386.mintlify.site/integrate/webhooks/endpoints.md)
>
> Receba notificacoes de pagamento em tempo real.

> [card] [Checkout Embed](https://scaleup-c34c4386.mintlify.site/features/checkout/embed.md)
>
> Incorpore o checkout diretamente no seu site.

> [card] [Reembolsos](https://scaleup-c34c4386.mintlify.site/features/refunds.md)
>
> Processe estornos totais e parciais.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.