Tokens e escopos
Os tipos de credencial da API, o que há dentro do JWT, expiração, revogação e escopos de tokens de app e chaves de API.
A API aceita cinco tipos de credencial. Quase todo integrador usa só um ou dois, mas conhecer todos evita escolher o errado.
Tipos de credencial
| Credencial | Formato | Onde vai | Para quem | Escopos |
|---|---|---|---|---|
| Token de acesso de usuário | JWT | Authorization: Bearer <jwt> | Administrador, seller, cliente | Não tem escopos; vale o tipo de usuário e os privilégios do grupo |
| Token de renovação | Texto opaco (64 caracteres) | Corpo de POST /api/v1/auth/refresh | O mesmo usuário | Não se aplica |
| Token de app | vat_live_... ou vat_test_... | Authorization: Bearer vat_... | Aplicativos de terceiros nas rotas de administração | read_orders, write_products... |
| Chave de API da vitrine | sfk_... | X-API-Key: sfk_... ou Authorization: Bearer sfk_... | Integrações de leitura e carrinho na vitrine e no GraphQL | storefront:read, storefront:write... |
Login e o par de tokens
O login devolve três campos:
{
"access_token": "eyJhbGciOi...",
"refresh_token": "7b1f0c2e...",
"expires_at": "2026-10-12T14:30:00Z"
}Campos da resposta
access_tokenstringAuthorization.refresh_tokenstringexpires_atstringaccess_token expira, RFC 3339 em UTC.account_statusstringpending_approvalaccept_pending_session. A sessão é restrita (veja abaixo).Se o usuário tem verificação em duas etapas (2FA) ativa, o login não devolve o par final: ele pede o código, que você envia em POST /api/v1/auth/verify-2fa. Veja Autenticação.
Duração
O token de acesso é de vida curta. O padrão da plataforma é 15 minutos e o do refresh é 7 dias, mas cada ambiente pode configurar valores diferentes (alguns ambientes usam valores bem maiores). Por isso, nunca fixe uma duração no seu código: leia expires_at e renove um pouco antes. Uma estratégia simples é renovar ao receber o primeiro 401 invalid or expired token e repetir a chamada uma vez.
Renovação
POST /api/v1/auth/refresh com o refresh_token devolve um novo par. O refresh usado é descartado (rotação): se você tentar usá-lo de novo, recebe erro. Por isso, em integrações com várias threads, serialize a renovação e guarde sempre o par mais recente.
curl -X POST "$BASE_URL/api/v1/auth/refresh" \
-H "Content-Type: application/json" \
-d '{"refresh_token":"'"$REFRESH_TOKEN"'"}'O que há dentro do JWT
O token de acesso é um JWT assinado pela plataforma. Você não precisa (nem deve) validar a assinatura: trate-o como um texto opaco e deixe o servidor decidir. Ler o conteúdo é útil para depurar e para saber de que loja e usuário o token é.
| Claim | Tipo | Significado |
|---|---|---|
user_id, sub | UUID | Id do usuário. |
email | string | E-mail do usuário. |
user_type | string | admin, vendor ou customer. Decide quais prefixos o token abre. |
tenant_id | UUID | A loja que emitiu o token. O token só vale nela. |
token_version | inteiro | Número da "geração" do token do usuário. Se mudar no servidor, os tokens antigos morrem (veja Revogação). |
exp, iat | inteiro | Expiração e emissão, em Unix timestamp (segundos). |
jti | UUID | Id único do token. |
account_type | string | Em contas B2B: individual, corporate_parent ou subaccount. |
parent_account_id | UUID | Em subcontas, a conta corporativa pai. |
current_organization_id | UUID | Organização B2B ativa do cliente, quando há. |
impersonator_id, impersonator_email | string | Só em sessões em que um administrador atua como outro usuário. |
Os campos acima podem ser omitidos quando não se aplicam. Não dependa da presença de nenhum além de user_id, user_type, tenant_id e exp.
Revogação
Um token de acesso deixa de valer antes do exp nestes casos:
| Ação | Efeito |
|---|---|
POST /api/v1/auth/logout | Encerra este aparelho: o refresh é apagado e o access_token usado passa a ser recusado (em até cerca de 10 segundos em todas as instâncias). Tokens de outros aparelhos continuam válidos. |
POST /api/v1/auth/logout-all | Apaga todos os refresh do usuário e incrementa token_version: todos os tokens de acesso dele, em qualquer aparelho, morrem na próxima chamada. |
| Troca ou redefinição de senha | Também incrementa token_version. |
| Bloqueio ou reaprovação da conta pela loja | Também incrementa token_version. |
Um token revogado responde 401 com uma mensagem que começa com token revoked. A resposta correta é voltar ao login: o refresh de uma sessão revogada também é recusado.
Sessão restrita de conta pendente
Lojas B2B podem exigir aprovação de contas novas. Se o cliente informa accept_pending_session: true no login ou no cadastro, em vez de ser recusado ele recebe uma sessão restrita (account_status: "pending_approval") que só abre as rotas de perfil e envio de documentos. As demais respondem 403 account_pending_approval. Quando a loja aprova a conta, o token restrito morre e o próximo refresh devolve um token completo.
Escopos
Usuários: tipo e privilégios
O JWT de usuário não tem lista de escopos. O acesso é decidido pelo user_type (qual prefixo) e, no administrador e no seller, pelos privilégios do grupo de usuários. Veja Atores e APIs.
Alguns tokens têm uma restrição extra de rota. Um token restrito usado numa rota que não o aceita responde 403 {"error":"this token is not valid for this route","code":"token_scope"}.
Tokens de app (vat_...)
O app é cadastrado no portal de desenvolvedores da loja, que gera o token. Cada app recebe um conjunto de escopos aprovado pela loja. Os escopos disponíveis são:
| Escopo | Permite |
|---|---|
read_products, write_products | Ler / alterar produtos. |
read_orders, write_orders | Ler / alterar pedidos. |
read_customers, write_customers | Ler / alterar clientes. |
read_content, write_content | Ler / alterar conteúdo (páginas, banners). |
read_inventory, write_inventory | Ler / alterar estoque. |
read_shipping, write_shipping | Ler / alterar frete e remessas. |
read_analytics | Ler relatórios. |
read_store_info | Ler dados da loja. |
Por padrão um app novo recebe read_products e read_orders. Sem o escopo da rota, a resposta é 403. Um token de app só funciona nas rotas que o aceitam (por exemplo /api/admin/orders, veja Pedidos por token de app); um JWT de usuário nessas rotas responde 401 app_token_required.
Chaves de API da vitrine (sfk_...)
O administrador gera a chave no painel; o valor completo aparece uma única vez. Escopos válidos:
| Escopo | Permite |
|---|---|
storefront:read | Ler produtos, categorias e páginas. É o padrão. |
storefront:write | Alterar carrinho e fazer checkout. |
customer:read, customer:write | Ler / alterar dados do cliente autenticado. |
markethub:read, markethub:write | Estado e ações do hub de marketplaces. |
erphub:read, erphub:write | Estado e ações do hub de ERP. |
Cada chave tem seu próprio limite de requisições por minuto (padrão: 100) e responde 429 rate_limit_exceeded ao estourar. Uma chave inválida ou revogada responde 401 invalid_api_key.
Erros comuns
- Guardar só o
access_token. Sem o refresh você precisa pedir a senha de novo a cada expiração. - Renovar em paralelo. Duas threads usando o mesmo refresh: uma delas falha, porque o refresh é de uso único.
- Esperar que
logoutencerre todos os aparelhos. Para isso élogout-all. - Decodificar o JWT para tomar decisões de segurança. O servidor revalida tudo; o conteúdo é só informativo.
- Usar um token de app numa rota de usuário. Rotas
/api/v1/admin/...esperam JWT de usuário; o token de app vale nas rotas que o aceitam.