Documentação

Documentação, do token ao repasse.

Tudo o que um desenvolvedor precisa para assinar um pedido, abrir o checkout e dividir o valor entre os recebedores. Sem SDK, sem integrar API: um token já carrega a informação.

Detalhe de uma carta lacrada com cera vermelha, pintada por Holbein em 1532.
Fig. I — A carta é o contrato. Holbein, O mercador Georg Gisze, 1532 (detalhe).

Começando

Comece em 3 passos

O CheckoutPP roda na sua infraestrutura e entende um único idioma: um token assinado. Sua loja, seu ERP ou um parceiro assina o pedido e redireciona o cliente. Pronto: nenhuma chamada de API do seu lado.

Se o seu sistema sabe assinar um JWT, ele já sabe integrar.

Passo 1

Suba o CheckoutPP e crie a sua store

Localmente, docker compose up sobe o PostgreSQL e o app em localhost:8091 (as migrações e o seed de demonstração rodam na inicialização). Em produção é um binário Go com PostgreSQL, e há deploy em um clique no Railway. Cada store tem um ORDER_SECRET, o segredo que assina os pedidos:

terminal
# Aplica o schema e cria a store (gera ORDER_SECRET e SELLER_SECRET)
./bin/server migrate up
./bin/server store create MINHA_STORE

# Cria o acesso ao painel admin
./bin/server add-admin [email protected] <senha> MINHA_STORE

Passo 2

Assine o pedido no seu backend

O pedido viaja como um JWT HS256 assinado com o ORDER_SECRET. O segredo nunca deve chegar ao navegador. Qualquer linguagem com uma biblioteca JWT serve; veja outras em Como funciona.

checkout.js · Node
import { SignJWT } from 'jose';

// ORDER_SECRET da store: fica no seu backend, nunca no navegador
const secret = new TextEncoder().encode(process.env.ORDER_SECRET);

const token = await new SignJWT({
  store_id: 'MINHA_STORE',
  external_id: 'PED_1042',        // o ID do pedido no seu sistema
  idempotency_key: 'PED_1042_v1', // única por pedido
  seller_id: 'seller_123',        // opcional: habilita o split
  customer: { email: '[email protected]', name: 'Ana Lima' },
  order: {
    amount: 15000,                // em centavos
    items: [{ desc: 'Plano anual', qty: 1, price: 15000 }],
  },
})
  .setProtectedHeader({ alg: 'HS256' })
  .setIssuedAt()
  .setExpirationTime('30m')
  .sign(secret);

// O cliente abre o checkout com um redirecionamento:
const url = `https://checkout.suaempresa.com/pay?session_token=${token}`;

Passo 3

Redirecione o cliente

Envie o cliente para /pay?session_token=<jwt>. A página troca o token por um pedido (GET /checkout?session_key=…) e abre o checkout hospedado em /checkout/<order_id>.

troca do token
# O checkout hospedado faz esta troca por você em /pay
curl "https://checkout.suaempresa.com/checkout?session_key=<jwt>"
resposta · 200
{
  "status": "success",
  "order_id": "0198a3c2-7c2a-7e1f-b9a4-3f2c9d1e4a10",
  "redirect_url": "/checkout/0198a3c2-7c2a-7e1f-b9a4-3f2c9d1e4a10"
}

Integração

O token

O pedido inteiro viaja dentro de um JWT assinado com o ORDER_SECRET da store. O servidor localiza o segredo pela store informada no token, confere a assinatura (e a expiração, se houver) e só então cria o pedido, de forma idempotente.

Sem SDK e sem chamadas de API: o token é o contrato.

payload do JWT
{
  "store_id": "MINHA_STORE",
  "external_id": "PED_1042",
  "idempotency_key": "PED_1042_v1",
  "seller_id": "seller_123",
  "customer": { "email": "[email protected]", "name": "Ana Lima" },
  "order": {
    "amount": 15000,
    "items": [
      { "desc": "Plano anual", "qty": 1, "price": 15000 }
    ]
  },
  "iat": 1760000000,
  "exp": 1760001800
}
  • store_id · iss stringobrigatório

    Identifica a store. O servidor usa store_id e, se ausente, iss. A assinatura é conferida com o ORDER_SECRET dessa store.

  • idempotency_key stringobrigatório

    Única por pedido dentro da store. A mesma chave devolve o pedido já criado, sem duplicar os itens. Se for omitida, todos os pedidos sem chave colidem e o servidor devolve sempre o primeiro.

  • order.amount inteiroobrigatório

    Total do pedido, em centavos. Precisa ser maior que zero para o pagamento ser aceito.

  • order.items[] arrayrecomendado

    Itens do pedido: desc, qty e price (em centavos). Aparecem no resumo do checkout.

  • external_id stringrecomendado

    ID do pedido no seu sistema. Fica guardado no pedido.

  • seller_id stringopcional

    O external_id do recebedor cadastrado no onboarding; habilita o split. Numa store com modo marketplace ligado é obrigatório (400 sem ele); nas demais é ignorado.

  • split_rule stringopcional

    Nome de uma regra de split cadastrada em Admin → Regras de split. Vale antes da regra do vendedor e do padrão da store, nas formas de pagamento que ela define. Só em store marketplace; se o nome não existir na store, a troca do token falha com 400.

  • customer objetoopcional

    JSON livre, guardado no pedido. O painel exibe name e email.

  • iat · exp númerorecomendado

    Emissão e expiração (segundos Unix). Se exp existir, é verificada. Recomendado: 30 minutos.

A assinatura usa a família HS (use HS256). O token trafega na URL do redirecionamento; por isso, mantenha a validade curta.

Mesma chave, mesmo pedido: reenviar um token é seguro.

Quando o token é recusado

A troca GET /checkout?session_key=… responde em texto puro. A página /pay mostra a mensagem quando algo falha.

Se o token falhar, a página /pay diz por quê.

  • 400session_key is required

    O parâmetro session_key não foi enviado.

  • 400Invalid token format

    O valor não é um JWT.

  • 400Store ID (iss) is required

    O token não traz store_id nem iss.

  • 401Store keys not found

    Não existe store com esse identificador.

  • 401Invalid token signature or expired

    Assinatura inválida (outro segredo) ou token expirado.

  • 400seller_id is required for marketplace stores

    A store está em modo marketplace e o token não traz seller_id.

  • 404Seller not found

    O seller_id não corresponde a nenhum recebedor dessa store.

  • 500Internal error processing order

    Falha ao gravar o pedido; tente de novo.

Arquitetura

Fluxo de pagamento

Da intenção de compra até a confirmação: o pedido nasce pending e muda de status conforme os webhooks do Pagar.me chegam. O checkout hospedado acompanha o pedido por GET /api/v1/orders/{id}.

O checkout consulta o pedido até o status mudar.

Para quem paga, o checkout hospedado tem duas etapas e nenhuma forma de pagamento vem escolhida. Na I · Forma de pagamento aparecem só as formas que a store ligou em Integrações. Escolhendo cartão, os campos do cartão surgem abaixo e o Prosseguir, sempre visível, só é liberado quando todos estiverem válidos; Pix e boleto liberam na hora. Na II · Seus dados ele informa contato, nome e CPF/CNPJ e endereço de cobrança, e paga. O endereço pergunta primeiro só o CEP: ao informá-lo, o restante abre já preenchido; se o CEP não for encontrado (ou a consulta falhar), o formulário completo abre vazio para ser digitado. O botão Alterar (ou o voltar do navegador) retorna à etapa I sem apagar nada; se a store tem uma única forma, ela já vem escolhida.

  1. i

    Seu backend → Cliente

    redireciona → /pay?session_token

  2. ii

    Cliente → CheckoutPP

    GET /checkout?session_key=JWT

  3. iii

    CheckoutPPvalida assinatura · cria pedido (pending)

  4. iv

    CheckoutPP → Cliente

    { order_id, redirect_url }

  5. v

    Cliente → CheckoutPP

    POST /api/v1/checkout

  6. vi

    CheckoutPP → Pagar.me

    cria order + split (Activity)

  7. vii

    Pagar.me → CheckoutPP

    webhook order.paid

  8. viii

    CheckoutPPstatus do pedido = paid

  9. ix

    Cliente → CheckoutPP

    GET /api/v1/orders/{id}

Tavola II Ciclo de vida de uma ordem

Status do pedido

O webhook POST /api/v1/webhooks/pagarme atualiza o status local de acordo com o evento recebido.

Evento do Pagar.meStatus local
order.paid · charge.paidpaid
order.payment_failedfailed
order.canceledcanceled
charge.refundedrefunded

Todo pedido começa em pending. Quando o Temporal está ativo, a resposta do checkout traz status: "processing" até o workflow concluir.

Marketplace

Recebedores

Recebedor (ou seller) é quem recebe uma parte da venda. Ele entra por um convite assinado, preenche os dados uma única vez e o CheckoutPP o registra no gateway, o Pagar.me hoje.

O external_id é a ponte entre o seu ID de vendedor e o recebedor no gateway.

  1. i

    O admin gera o convite. No painel, em Convites, “Gerar convite” cria um JWT de 7 dias assinado com SELLER_JWT_SECRET.

  2. ii

    Você envia o link. /onboarding?token=<convite>. Acrescente &storeId=<store>&externalId=<id-no-seu-sistema> para vincular o recebedor ao seu sistema.

  3. iii

    O recebedor se cadastra em quatro passos: identificação, endereço, dados bancários e repasses.

  4. iv

    O servidor registra. POST /api/v1/recipients (com o convite em Authorization: Bearer) cria o recebedor no Pagar.me (na conta da store) e o salva com o status devolvido pelo gateway e o external_id. O e-mail é único por store: um e-mail que já é vendedor da store devolve 409, porque o cadastro nunca sobrescreve um vendedor existente.

Do cadastro ao split

No token, seller_id é o externalId do recebedor (e só vale em uma store com modo marketplace). A plataforma fica com uma comissão de cada venda, em percentual ou valor fixo, e o vendedor recebe o resto. A regra é por forma de pagamento (cartão, Pix, boleto) e vem de, nesta ordem: a regra própria do vendedor para aquela forma, o padrão da store para ela e, sem nenhum dos dois, 10%.

Os valores são calculados em centavos no servidor (a comissão arredonda para cima na metade) e as duas partes sempre somam o total. A parte da plataforma vai para o recebedor da plataforma (campo em Integrações → Pagar.me, ou o padrão da conta): sem ele, o pagamento é recusado em vez de dar tudo ao vendedor.

Sem seller_id, a venda é direta e o valor não é dividido.

Exemplo · taxa de 10%

R$ 150,00
Seller · 90%
R$ 135,00
Plataforma · 10%
R$ 15,00

Pagamentos

Gateways

O CheckoutPP foi desenhado para falar com mais de um gateway: o contrato mínimo está em domain/provider.go. Hoje o Pagar.me v5 é o único integrado (cartão, Pix e boleto, recebedores e split).

Planejado: o token continua o mesmo, só o adaptador muda.

domain/provider.go
// domain/provider.go — o contrato mínimo de um gateway
type Provider interface {
	ProcessPayment(ctx context.Context, req PaymentRequest) (*PaymentResponse, error)
	RegisterSeller(ctx context.Context, params SellerParams) (*SellerResponse, error)
}

Um adaptador precisa, no mínimo, de duas coisas: ProcessPayment (cria a cobrança com as regras de split e devolve o ProviderOrderID e o status) e RegisterSeller (cadastra o recebedor e devolve o ProviderSellerID e o status). Na prática, ele também traduz os webhooks do gateway para os status locais.

GatewayEstadoNota
iPagar.me disponível Cartão, Pix e boleto · API v5 · recebedores e split
iiWoovi planejado —
iiiPague.dev planejado —
ivAbacatePay planejado —
vCriptoPag planejado —
viHodle planejado —

Marca

Alfaiataria

O checkout hospedado pode vestir a sua marca. Em Admin → Alfaiataria você escolhe o nome e o logo, a cor da marca, o destaque, o corte dos cantos e a tipografia, e vê o resultado ao vivo, no papel claro e no escuro, antes de salvar.

CampoValoresEfeito no checkout
nameaté 40 caracteresNome da loja no alto do recibo, no lugar do identificador.
logo_urlhttps, até 300 caracteresImagem do selo do recibo. Vazio: a inicial do nome.
brand#rrggbbBotão de pagar e estados selecionados.
accent#rrggbbNumerais romanos e marcas pequenas.
cornersretos · suaves · redondosRaio dos campos, cartões e botões.
fontclassica · moderna · eleganteTipografia dos títulos e do valor total.

Pela API

O painel usa estes dois endereços, protegidos pela sessão do admin. O PUT aceita os campos acima; o que for omitido volta ao padrão, e um valor inválido devolve 400 com a mensagem de cada campo.

terminal
# Lê o tema atual (cookie de sessão do admin)
curl -b cookies.txt https://checkout.suaempresa.com/api/v1/admin/theme

# Salva: campos omitidos voltam ao padrão
curl -b cookies.txt -X PUT https://checkout.suaempresa.com/api/v1/admin/theme \
  -H "Content-Type: application/json" \
  -d '{"name":"Ateliê Lume","brand":"#0f5c63","accent":"#b8892a","font":"elegante","corners":"redondos"}'
GET /api/v1/admin/theme
{
  "theme": {
    "name": "Ateliê Lume",
    "logo_url": "https://suaempresa.com/logo.png",
    "brand": "#0f5c63",
    "accent": "#b8892a",
    "font": "elegante",
    "corners": "redondos"
  },
  "defaults": { "brand": "#1b1713", "accent": "#b8341a", "font": "classica", "corners": "suaves", "name": "", "logo_url": "" },
  "store_id": "MINHA_STORE"
}
400 Bad Request
{ "errors": { "logo_url": "O logo precisa ser servido por https." } }

No checkout, o tema chega junto do pedido: GET /api/v1/orders/{id} devolve o campo theme. Se a store não personalizou nada, ou se a leitura falhar, o campo some e a página mantém o visual padrão. Um tema nunca impede um pagamento.

A mudança vale a partir do próximo checkout aberto: não há deploy nem reinício. Pedidos que já estão abertos na tela de quem paga mantêm o visual com que foram carregados.

Marca

Stores e integrações

Uma store é uma separação: tem os seus próprios pedidos, vendedores, convites, visual (Alfaiataria) e integrações. Só o identificador é obrigatório (o store_id que vai nos tokens); o nome é opcional. Uma mesma conta de admin gerencia várias stores: o seletor no topo do painel troca a store em que tudo trabalha, e Nova store cria outra.

EndpointO que faz
GET · POST /admin/storesLista as stores da conta; cria uma (store_id e label opcionais).
PATCH /admin/stores/{id}Renomeia (só o label).
POST /admin/stores/switchTroca a store da sessão. O servidor confere no banco que a conta gerencia a store.
GET · POST /admin/signing-key[/rotate]Lê ou renova o ORDER_SECRET da store (a chave que assina o token).
GET /admin/integrationsGateways (com o estado de cada um nesta store), formas de pagamento e o que o checkout oferece agora.
PUT · DELETE /admin/integrations/gateways/{gateway}Cadastra, atualiza (enabled e fields) ou remove as credenciais da store.
PUT /admin/integrations/methodsLiga ou desliga cada forma de pagamento, escolhe o gateway que a atende e, no Pagar.me de uma store marketplace, o split padrão dela ({"type":"percentage","percent":7.5} ou {"type":"flat","flat_cents":250}).
PUT /admin/integrations/marketplaceLiga ou desliga o modo marketplace da store ({"enabled":true}).
GET · PUT /admin/sellers/{id}/splitLê e grava as regras de split próprias de um vendedor, por forma de pagamento (null remove a regra e o vendedor volta a seguir a store).
GET /admin/splitTodas as regras da store numa resposta: padrão por forma de pagamento, regras com nome, vendedores com regra própria e o padrão do sistema.
PUT · DELETE /admin/split/presets/{key}Cria, substitui ou remove uma regra com nome ({"label":"Premium","methods":{"card":{"type":"percentage","percent":6}}}). A chave tem minúsculas, números, hífen e _; a regra precisa definir ao menos uma forma de pagamento.
terminal
# Cria uma store (o identificador sai do nome, se omitido) e passa a trabalhar nela
curl -b cookies.txt -X POST https://checkout.suaempresa.com/api/v1/admin/stores \
  -H "Content-Type: application/json" -d '{"label":"Ateliê Lume"}'
curl -b cookies.txt -X POST https://checkout.suaempresa.com/api/v1/admin/stores/switch \
  -H "Content-Type: application/json" -d '{"store_id":"ATELIE_LUME"}'

# Cadastra o Pagar.me da store e liga só cartão e boleto
curl -b cookies.txt -X PUT https://checkout.suaempresa.com/api/v1/admin/integrations/gateways/pagarme \
  -H "Content-Type: application/json" \
  -d '{"enabled":true,"fields":{"secret_key":"sk_…","public_key":"pk_…"}}'
curl -b cookies.txt -X PUT https://checkout.suaempresa.com/api/v1/admin/integrations/methods \
  -H "Content-Type: application/json" \
  -d '{"methods":{"card":{"enabled":true,"gateway":"pagarme"},"pix":{"enabled":false,"gateway":"pagarme"},"boleto":{"enabled":true,"gateway":"pagarme"}}}'

Modo marketplace

O modo marketplace é uma opção da integração com o Pagar.me v5, a única que faz split até o momento: o interruptor fica no cartão do Pagar.me, em Integrações. Ligado, a store vende por vendedores e só o Pagar.me pode ser usado (a API recusa rotear uma forma para outro gateway). Desligado, a store vende direto: não há vendedores nem split, um seller_id no token é ignorado e o painel esconde Vendedores e Convites.

  • Só liga com o Pagar.me ativo e com chaves (da store ou da instalação), e sem nenhuma forma de pagamento em outro gateway.
  • Enquanto estiver ligado, o Pagar.me não pode ser desativado na store, nem ter as chaves da store removidas se a instalação não tiver chaves para assumir: primeiro se desliga o modo.
  • Uma store nova começa desligada. As stores que já tinham vendedores foram ligadas pela migração.
  • Ligado, todo token precisa de seller_id de um vendedor da própria store (400 sem ele, 404 se não existir).
  • As regras de split têm quatro níveis, e vale o primeiro que existir para a forma de pagamento: a regra com nome que o token indica em split_rule, a regra própria do vendedor (na página dele), o padrão da store (em cada forma de pagamento) e, por fim, os 10% do sistema. Tudo fica reunido em Regras de split. Uma regra com nome pode definir só algumas formas de pagamento; as demais seguem para o nível seguinte. O nome é guardado no pedido; apagar a regra depois faz os pedidos em aberto caírem no nível seguinte, e tokens novos com esse nome são recusados.
  • O corpo do POST /checkout nunca decide o split: percentuais e valores enviados pelo navegador são descartados quando o pedido existe.

Como o checkout escolhe

Cada store cadastra os gateways que usa, com credenciais próprias (criptografadas com AES-GCM; a chave secreta nunca volta ao navegador, só uma máscara). Em Formas de pagamento ela liga ou desliga cartão, Pix e boleto e escolhe o gateway de cada um. O pedido público (GET /api/v1/orders/{id}) devolve payment_methods e a chave pública da store; a página mostra só essas formas, e o servidor recusa (400) qualquer outra, porque a página não é uma barreira de segurança.

  • Sem credenciais próprias, a store usa as da instalação (variáveis de ambiente ou a tabela de configurações da API), como sempre foi. Se não houver nenhuma, o checkout avisa que a loja não aceita pagamentos.
  • Desativar o gateway numa store tira as formas dele do checkout, mesmo que a instalação tenha chaves.
  • A store de um pagamento vem sempre do pedido no banco, nunca do corpo da requisição: um pagamento nunca é assinado com a chave de outra store.

Hoje só o Pagar.me tem adaptador (cartão, Pix e boleto). Woovi, Pague.dev, AbacatePay, CriptoPag e Hodle aparecem como planejados e não podem ser escolhidos; Cripto também é uma forma planejada.

A escolha por forma de pagamento já está pronta para o dia em que houver mais de um gateway.

Arquitetura

Componentes

A aplicação separa a entrada (handlers), as regras de negócio (serviços) e a infraestrutura (cliente do Pagar.me, banco, Temporal). Os handlers só validam e coordenam; os serviços concentram as regras.

ICliente

Seu backend

Assina o JWT do pedido com o ORDER_SECRET da store.

Navegador do cliente

Abre o checkout hospedado: cartão, Pix ou boleto.

IIEntrada

Handlers · API

Valida JWT, cookies de sessão e payloads. Rotas de checkout, pedidos, sellers, convites e webhook.

JWTCookieAuthWebhook

IIINúcleo

Checkout Service

Cálculo do split e criação do pedido.

Recipient Service

Cadastro de sellers e vínculo com o Pagar.me.

Settings Service

Chaves e segredos criptografados (AES).

IVAdaptadores

Pagar.me v5

Orders, split rules e recipients.

PostgreSQL · sqlc

Pedidos, sellers, convites e configurações.

Temporal worker

CheckoutWorkflow e Activities com retry (opcional).

Outros gateways

Woovi, Pague.dev, AbacatePay, CriptoPag, Hodle — planejado.

Tavola I Componentes do sistema

Configuração

Variáveis de ambiente

O servidor lê estas variáveis na inicialização. Use o .env.example do repositório como ponto de partida.

  • DATABASE_URL

    String de conexão do PostgreSQL.

    postgres://user:pass@host:5432/db

  • TEMPORAL_ADDR

    Endereço do servidor Temporal usado pelo worker e pelo cliente de workflows.

    localhost:7233

  • TEMPORAL_NAMESPACE

    Namespace do Temporal.

    default

  • TEMPORAL_API_KEY

    Chave de API do Temporal (Temporal Cloud). Opcional em ambiente local.

  • USE_TEMPORAL_FOR_ACTIONS

    true: o checkout inicia o CheckoutWorkflow e responde 202 (processing). false: processa de forma síncrona.

    false

  • ENABLE_SPLIT_MARKETPLACE

    Padrão do modo marketplace para pedidos sem store e para stores sem registro próprio. Cada store liga ou desliga o seu em Admin → Integrações.

    true

  • JWT_SECRET

    Segredo dos tokens JWT de clientes.

    um-segredo-forte

  • SELLER_JWT_SECRET

    Segredo dos tokens de convite e das sessões de seller/admin.

    outro-segredo-forte

  • PAGARME_SECRET_KEY

    Chave secreta da API do Pagar.me v5.

    sk_test_…

  • PAGARME_PUBLIC_KEY

    Chave pública usada na tokenização do cartão no navegador. Lida primeiro da tabela de configurações e, se ausente, desta variável.

    pk_test_…

  • PAGARME_WEBHOOK_SECRET

    Segredo do webhook configurado no Pagar.me (reservado para validação de assinatura).

  • PAGARME_BASE_URL

    URL base da API do Pagar.me.

    https://api.pagar.me/core/v5

  • SETTINGS_ENCRYPTION_KEY

    Chave AES-GCM que criptografa os valores sensíveis das configurações e as credenciais dos gateways das stores. 16, 24 ou 32 caracteres são usados como estão; qualquer outro tamanho passa por SHA-256.

    32 caracteres

  • PORT

    Porta HTTP do servidor.

    8080

.env
DATABASE_URL=postgres://postgres:postgres@localhost:5432/checkout_db?sslmode=disable
USE_TEMPORAL_FOR_ACTIONS=false
ENABLE_SPLIT_MARKETPLACE=true
JWT_SECRET=your-customer-jwt-secret
SELLER_JWT_SECRET=your-seller-jwt-secret
PAGARME_SECRET_KEY=sk_test_...
PAGARME_PUBLIC_KEY=pk_test_...
PAGARME_BASE_URL=https://api.pagar.me/core/v5
PORT=8080

Configuração

Segurança

O pedido é assinado com HS256 usando o ORDER_SECRET da store. O servidor localiza o segredo pela store informada no token, verifica a assinatura e a expiração e só então cria o pedido. Os claims estão descritos em O token.

Boas práticas

  • Assine sempre no backend. O playground assina no navegador apenas para demonstração.
  • Mantenha o token curto (≈ 30 minutos): ele trafega na URL do redirecionamento.
  • Use idempotency_key estável por pedido para tolerar reenvios e cliques duplicados.
  • Chaves do Pagar.me e demais segredos guardados nas configurações e nas integrações das stores são criptografados com AES-GCM (SETTINGS_ENCRYPTION_KEY).
  • O painel admin usa sessão por cookie HTTP-only, ligada a uma store; trocar de store reemite a sessão depois de conferir no banco que a conta a gerencia. Convites de seller são JWTs com validade de 7 dias e não valem como sessão de admin.
  • Vendedores, pedidos, saldos, repasses e estornos são sempre da store da sessão: o de outra store responde 404, mesmo que o identificador seja conhecido.
  • As configurações da instalação (/api/v1/settings) só aceitam sessão de admin, e a listagem nunca devolve valores, só os nomes e se estão criptografadas.

O segredo da store é a única coisa que não pode vazar.

Operação

CLI

A administração acontece pelo mesmo binário do servidor. Em desenvolvimento, go run main.go <comando> é equivalente, e as tarefas mise run db:migrate, db:seed-demo e db:add-admin são atalhos.

Comandos essenciais

terminal
./bin/server                          # inicia a API (padrão)
./bin/server migrate up               # aplica as migrações
./bin/server migrate down             # reverte TODAS as migrações (destrutivo)
./bin/server seed-demo                # cria store, seller e admin de demonstração
./bin/server add-admin <email> <senha> <store_id>
./bin/server keygen [--save]          # gera 32 bytes aleatórios (hex) para criptografia

Gestão de stores

Cada store possui um ORDER_SECRET, que assina os pedidos (o JWT do checkout). A CLI também gera um SELLER_SECRET e o guarda junto, mas os convites de onboarding são assinados com a variável SELLER_JWT_SECRET.

terminal
# Provisiona as chaves da store (aleatórias se omitidas)
./bin/server store create <store_id> [--order-secret s1] [--seller-secret s2]

# Gera um JWT de teste para o checkout
./bin/server store jwt <store_id> <amount_cents> "<item_name>"
saída de store create
Store 'MINHA_STORE' created successfully!
--------------------------------------------------
ORDER_SECRET:  9f2c…d41a
SELLER_SECRET: 51be…07c3
--------------------------------------------------
Keep these secrets safe. They are stored in the database.

Os segredos ficam no banco. O ORDER_SECRET pode ser consultado e renovado em Admin → Integrações; stores criadas pelo painel já nascem com ele. A CLI também registra a store e o vínculo do admin.