Visão geral
O Checkout Session é o modelo recomendado quando o pagamento é iniciado no frontend (browser, app mobile). Em vez de expor sua X-API-Key no cliente, o fluxo funciona em duas etapas:
- Backend cria uma sessão com
X-Client-ID + X-API-Key — recebe um token de curta duração
- Frontend usa esse token para submeter o pagamento — sem contato com a API key
Backend Frontend
│ │
│ POST /checkout/sessions │
│ X-Client-ID + X-API-Key ────► │ (token, expires_at, saved_cards)
│ │
│ ◄──── │ POST /checkout/payments/card
│ │ X-Checkout-Token: cs_live_...
Campos críticos como amount, currency e merchant_order_id são travados na sessão pelo backend — o frontend não pode alterá-los, o que elimina a possibilidade de manipulação de preço pelo cliente.
Criar sessão
POST /api/v1/checkout/sessions — requer X-Client-ID + X-API-Key. Chamada exclusivamente pelo backend da empresa.
POST /api/v1/checkout/sessions
Content-Type: application/json
X-Client-ID: client_...
X-API-Key: sk_...
{
"amount": 15000,
"currency": "BRL",
"merchant_order_id": "ORD-2026-12345",
"payment_method": "card",
"gateway_first_try": "pagarme",
"expires_in": 1800,
"success_url": "https://meusite.com/pedido/sucesso",
"cancel_url": "https://meusite.com/pedido/cancelado",
"metadata": {
"order_ref": "ORD-2026-12345",
"user_id": "usr_789"
},
"customer": {
"token": "cus_7556..."
}
}
| Campo | Tipo | Obrigatório | Descrição |
|---|
amount | inteiro (centavos) | sim | Valor da cobrança — imutável após criação |
currency | BRL|USD | sim | Moeda |
merchant_order_id | string (max 255) | sim | Referência do pedido no seu sistema — imutável após criação |
payment_method | card|pix | não | Restringe o método aceito. Omitir permite cartão e PIX |
gateway_first_try | string | não | Gateway prioritário para essa sessão. Sobrepõe qualquer valor enviado pelo frontend |
expires_in | inteiro (60–86400) | não | Duração da sessão em segundos. Padrão: 1800 (30 min). Máx: 86400 (24h) |
success_url | URL (max 2048) | não | Redirecionamento em caso de pagamento aprovado |
cancel_url | URL (max 2048) | não | Redirecionamento em caso de falha ou cancelamento |
metadata | objeto | não | Dados livres repassados ao frontend na resposta da sessão |
customer.token | string | não | Token do cliente — carrega os cartões salvos dele na resposta |
customer.email | string | não | Alternativa ao token: busca o cliente pelo e-mail |
customer.document | string | não | Alternativa ao token: busca o cliente pelo CPF/CNPJ |
success_url e cancel_url passam por validação SSRF: IPs privados e intervalos reservados (10.x, 192.168.x, 127.x) são rejeitados com 422.
Resposta 201:
{
"token": "cs_live_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6",
"amount": 15000,
"currency": "BRL",
"merchant_order_id": "ORD-2026-12345",
"payment_method": "card",
"gateway_first_try": "pagarme",
"metadata": {
"order_ref": "ORD-2026-12345",
"user_id": "usr_789"
},
"success_url": "https://meusite.com/pedido/sucesso",
"cancel_url": "https://meusite.com/pedido/cancelado",
"expires_at": "2026-06-25T12:30:00+00:00",
"saved_cards": [
{
"holder_name": "JOAO SILVA",
"token": "card_86123...",
"brand": "visa",
"first_6_digits": "411111",
"last_4_digits": "1111",
"expire_month": "12",
"expire_year": "2028",
"status": "active",
"created_at": "2026-01-10T08:00:00+00:00",
"updated_at": "2026-01-10T08:00:00+00:00"
}
]
}
O array saved_cards é preenchido quando o campo customer é informado e o cliente possui cartões salvos. Use-o para exibir uma lista de cartões ao usuário sem que o frontend precise consultar outra rota.
Submeter pagamento
O token recebido na criação da sessão é enviado no header X-Checkout-Token. Ele é de uso único — ao iniciar uma tentativa de pagamento, a sessão é marcada como usada e não pode ser reutilizada, mesmo que a cobrança falhe.
Cartão
POST /api/v1/checkout/payments/card — requer X-Checkout-Token.
POST /api/v1/checkout/payments/card
Content-Type: application/json
X-Checkout-Token: cs_live_a1b2c3...
Idempotency-Key: ORD-2026-12345 (opcional, mas recomendado)
Com cartão novo:
{
"payment_method": "card",
"customer": {
"name": "João Silva",
"email": "joao@example.com",
"document": "12345678909"
},
"card": {
"number": "4111111111111111",
"cvv": "123",
"expiration_month": "12",
"expiration_year": "2028",
"installments": 1,
"holder": "Fulano da Silva",
"holder_birthdate": "1990-05-25",
"holder_document": "12345678909",
"holder_phone": "11987542563",
"save_card": true
},
"billing_address": {
"street": "Rua dos Advogados",
"number": "321",
"neighborhood": "Jardim",
"zip_code": "35900000",
"city": "Belo Horizonte",
"state": "MG",
"country": "Brasil"
}
}
Com cartão salvo (token de saved_cards):
{
"payment_method": "card",
"customer": {
"token": "cus_7556..."
},
"card": {
"token": "card_86123...",
"installments": 1
}
}
Ao usar um cartão salvo, billing_address e os dados do titular não são necessários — eles já estão no vault.
PIX
POST /api/v1/checkout/payments/pix — requer X-Checkout-Token.
POST /api/v1/checkout/payments/pix
Content-Type: application/json
X-Checkout-Token: cs_live_a1b2c3...
{
"customer": {
"name": "Maria Santos",
"email": "maria@example.com",
"document": "98765432100"
}
}
O payment_method não é necessário no PIX via checkout — a rota já define o método. O amount, currency e merchant_order_id são injetados automaticamente da sessão.
Campos travados pela sessão
O middleware de checkout injeta automaticamente os valores abaixo no corpo da requisição, sobrescrevendo qualquer valor que o frontend tente enviar:
| Campo | Origem |
|---|
amount | Sessão (imutável) |
currency | Sessão (imutável) |
merchant_order_id | Sessão (imutável) |
gateway_first_try | Sessão (se definido; caso contrário, o frontend pode sugerir) |
Resposta do pagamento
Idêntica ao pagamento direto — mesmos campos, mesmas regras de status HTTP:
| HTTP | Significado |
|---|
201 Created | Aprovado dentro do time_to_wait_sync |
202 Accepted | Processando — aguarde via webhook ou polling |
500 | Falhou em todas as tentativas |
Ciclo de vida da sessão
| Estado | Condição |
|---|
| Válida | used_at nulo e expires_at no futuro |
| Expirada | expires_at no passado → 401 |
| Usada | used_at preenchido (pagamento iniciado) → 409 Conflict |
A sessão é marcada como usada antes de o pagamento ser processado. Se a cobrança falhar (gateway recusa, timeout), a sessão continua consumida e não pode ser reutilizada. Crie uma nova sessão para uma nova tentativa.
Referência rápida de rotas
| Método | Rota | Auth | Quem chama |
|---|
POST | /api/v1/checkout/sessions | X-Client-ID + X-API-Key | Backend |
POST | /api/v1/checkout/payments/card | X-Checkout-Token | Frontend |
POST | /api/v1/checkout/payments/pix | X-Checkout-Token | Frontend |