Fluxo recomendado — checkout próprio

Sequência mínima para um parceiro ou cliente entregar checkout custom sem fork do core.

  1. Passo 1

    Catálogo e preço

    GET /products e GET /prices/resolve com Bearer server-side.

    API Explorer
  2. Passo 2

    Sessão checkout

    POST /checkout/sessions → salvar session_token (httpOnly).

    Ver passo a passo
  3. Passo 3

    Place-order

    PATCH estado → POST place-order com Idempotency-Key → redirect checkout_url.

    Ver erros HTTP

Princípios

Checkout headless = regras no core, UX substituível. SSOT humano: docs/headless-checkout.md

RegraDetalhe
API-firstValidação, pedido e pagamento autoritativos no Go — não no React
UX substituívelapp/(compra)/* é referência; destino apps/checkout no repo cliente
Sem PAN/CVVGateway tokenizado — redirect ou hosted checkout (PCI SAQ A)
Dois atores authComprador (X-Checkout-Session-Token) ≠ integrador (Bearer mc_live_…)

Dois caminhos

Preferir checkout sessions (A). Caminho B para bots, ERP ou MCP conversacional.

Caminho A — sessionsCaminho B — granular
Quando usarWeb, app, BFF customERP, automação, MCP direto
EstadoServer-side JSON (TTL 30 min)Monta OrderCreate no integrador
EndpointsPOST/GET/PATCH /checkout/sessions + place-orderPOST /orders → submit → payments/initiate
SDKcreateCheckoutSession, patchCheckoutSession, placeCheckoutOrdercreateOrder, submitOrder, initiatePayment

Autenticação

SuperfícieHeaderQuem
Checkout sessionsX-Checkout-Session-Token (cks_tok_…)Comprador — rotas públicas
Catálogo / preçosAuthorization: Bearer mc_live_…Backend integrador (server-side)
MCPX-API-Key (kind: mcp)Agente / bot
Conta pós-compraBearer mc_sess_…POST /auth/customer/*

Rate limits checkout (comprador) são distintos do tier integrador — ver checkout-anti-fraud.md.

1. Criar sessão

POST /v1/checkout/sessions
POST /v1/checkout/sessions
Content-Type: application/json

{
  "member_id": "550e8400-e29b-41d4-a716-446655440000",
  "warehouse_id": "660e8400-e29b-41d4-a716-446655440001",
  "channel": "web",
  "state": { "cart": [], "identity_verified": false }
}

→ 201: id, session_token (uma vez), expires_at

2. Atualizar estado (PATCH merge)

PATCH /v1/checkout/sessions/{id}
PATCH /v1/checkout/sessions/{session_id}
X-Checkout-Session-Token: cks_tok_…

{
  "state": {
    "cart": [
      { "sku": "SKU-001", "qty": 2, "selected": true, "unit_price": 19990 }
    ],
    "customer_name": "Maria Silva",
    "customer_email": "[email protected]",
    "identity_verified": true,
    "payment_method_id": "pix",
    "delivery_mode": "shipping"
  }
}

3. Place-order

POST /v1/checkout/sessions/{id}/place-order
POST /v1/checkout/sessions/{session_id}/place-order
X-Checkout-Session-Token: cks_tok_…
Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7

→ 201: { order, session_id, payment_status?, checkout_url? }
→ Redireccionar comprador para checkout_url quando existir

Validação server-side (place-order)

Implementação: internal/checkout/validate.go · state_to_order.go

Campo / regraObrigatórioNotas
identity_verifiedSim (true)Identidade confirmada antes de fechar
cart[].selected + qty > 0SimPelo menos um item selecionado
placed_order_idVazioSessão single-use após pedido
member_id no stateSe presente = sessãoAnti cross-tenant
warehouse_idSimNa sessão ou no state

Estado da sessão (referência)

CampoUso
cartItens com sku, qty, selected, unit_price
customer_*Nome, email, whatsapp
identity_verifiedGate obrigatório para place-order
payment_method_idpix | boleto | card | wallet
delivery_mode, address_id, shipping_speedEntrega
schedule_slot_id, scheduled_forServiços agendados
coupon_code + coupon_appliedDesconto
channelweb | whatsapp → origin do pedido

Tipo TS: lib/compra/types.ts (CompraSessionState). OpenAPI: additionalProperties — evolui com o core pin LTS.

Códigos HTTP — place-order

StatusSignificadoAção UX
201Pedido criadoConfirmar + redirect se checkout_url
401Token inválido / expiradoReiniciar checkout
402Pagamento recusadoMensagem genérica — nunca detalhe de cartão
403checkout.validate bloqueouMostrar message do core
409Incompleto ou sessão já usadaRevisar passos
429VelocityRespeitar Retry-After

SDK TypeScript

@mira/commerce-client-sdk
import {
  createCommerceClient,
  createCheckoutSession,
  patchCheckoutSession,
  placeCheckoutOrder,
} from "@mira/commerce-client-sdk"

const client = createCommerceClient({
  baseUrl: process.env.COMMERCE_API_URL,
  getAccessToken: () => process.env.MC_API_TOKEN, // só server-side
})

const { data: session } = await createCheckoutSession({
  client,
  body: { member_id, warehouse_id, channel: "web" },
})

await placeCheckoutOrder({
  client,
  path: { session_id: session.id },
  headers: {
    "X-Checkout-Session-Token": sessionToken,
    "Idempotency-Key": crypto.randomUUID(),
  },
})

Regenerar: npm run sdk:generate · Catálogo completo: /dev/experience/sdk · Ver sdk-wiring.md

Padrão BFF (browser)

Rota Next.js (protótipo)Core API
POST /api/checkout/sessionPOST /checkout/sessions
PATCH /api/checkout/sessionPATCH /checkout/sessions/{id}
POST /api/compra/place-orderPOST /checkout/sessions/{id}/place-order
  • lib/compra/checkout-api.ts

    Cliente BFF no browser

  • app/api/checkout/session/route.ts

    Proxy sessão + cookie httpOnly

  • app/(compra)/*

    Implementação referência UX

Repo cliente (Fase 4)

{cliente}-commerce/
├── apps/checkout/       ← UX custom (este guia)
├── apps/storefront/
├── manifest.yaml        ← pin core LTS
└── extensions/          ← plugins Go (Mirá)

Anti-patterns

EvitarPreferir
Regra de desconto só no frontGET /prices/resolve + PATCH sessão + hook
Bearer mc_live_ no browserBFF server-side
Formulário PAN/CVV na appcheckout_url do gateway
Fork mira-commerce-coreapps/checkout + pin LTS
Retry place-order sem Idempotency-KeyUUID estável por tentativa UX

Checklist integrador

  1. Ler OpenAPI tags checkout, catalog, pricing
  2. Escolher caminho A (sessions) ou B (orders direto)
  3. BFF se front browser; Bearer só server-side
  4. Idempotency-Key em place-order e initiate payment
  5. Mensagens genéricas em 402 (ADR 0013)
  6. Testar com mc_test_… antes de produção
API Explorer (integradores)MCP (checkout conversacional)Checkout referência (/compra) /compra