Clientes por token de app
Acesso de aplicativos de terceiros aos clientes, com token vat_ e escopos read_customers e write_customers, sem usuário administrador.
Um app de terceiros (um conector de CRM, uma ferramenta de e-mail marketing, um sistema de fidelidade) não deve usar o login de uma pessoa. A plataforma oferece o token de app: o app é cadastrado no portal de desenvolvedores da loja, recebe um token que começa com vat_live_ ou vat_test_ e só pode o que os escopos aprovados permitem.
As rotas de clientes sob /api/admin/... aceitam esse token. Elas leem e alteram os mesmos cadastros das demais rotas desta seção, mas com um formato próprio: ids em UUID, nomes de campo como first_name e email, datas em RFC 3339 e paginação por page e per_page. Esta página descreve o cabeçalho, os escopos, as rotas, os parâmetros e a resposta de cada uma. O mesmo mecanismo vale para pedidos (Pedidos por token de app).
Rotas disponíveis com token de app
| Rota | Escopo | O que faz |
|---|---|---|
GET /api/admin/users | read_customers | Lista usuários, com filtros e paginação. |
GET /api/admin/users/{id} | read_customers | Consulta um usuário. |
PUT /api/admin/users/{id} | write_customers | Altera dados de um usuário. |
GET /api/admin/users/{id}/addresses | read_customers | Lista os endereços de um usuário. |
GET /api/admin/users/{id}/orders | read_orders | Lista os pedidos de um cliente. |
/api/admin/usersAutenticadaListar usuários
Escopo read_customers. Os filtros se combinam (E lógico).
Parâmetros de consulta
pageintegerpadrão: 1per_pageintegerpadrão: 20sort_bystringpadrão: created_atcreated_atemailfirst_namelast_namelast_login_atupdated_atlogin_countcreated_at. O desempate é pelo id.sort_dirstringpadrão: descascdescuser_typestringcustomervendoradminroot_adminuser_typesstringadmin,vendor). Tem precedência sobre user_type.vendor_iduuidexclude_trade_rep_managersbooleanpadrão: truevendor, esconde os gerentes de venda que não são donos de seller. Mande false para incluí-los.exclude_subaccountsbooleanpadrão: truecustomer, esconde subcontas B2B. Mande false para ver todos os logins.statusstringADPactive, disabled, pending, inactive, deleted).searchstringemailstringphonestringcpfstringcnpjstringperson_typestringFPFJPJcitystringstatestringcountrystringlanguagestringpt-BRenesemail_verifiedbooleantrue ou false. Valor inválido é ignorado.marketing_opt_inbooleanwhatsapp_opt_inbooleanregistered_afterstringAAAA-MM-DD ou RFC 3339).registered_beforestringAAAA-MM-DD o dia inteiro entra.last_login_afterstringlast_login_beforestringAAAA-MM-DD).has_ordersbooleantrue: tem ao menos um pedido; false: nunca comprou.min_total_spendintegermax_total_spendinteger/api/admin/users/{id}AutenticadaConsultar um usuário
Escopo read_customers. Devolve o cadastro completo do usuário.
Parâmetros de caminho
iduuidobrigatório/api/admin/users/{id}AutenticadaAtualizar um usuário
Escopo write_customers. Só os campos enviados mudam e a resposta é o usuário atualizado. Como o app não é um usuário, a proteção contra o administrador alterar a si mesmo não se aplica: cuide dos campos user_type, status e is_root, que um app com write_customers consegue mudar.
Parâmetros de caminho
iduuidobrigatórioCorpo da requisição
first_namestringlast_namestringemailstringemail already in use.phonestringuser_typestringcustomervendoradminroot_admininvalid user_type.statusstringADPinvalid status.cpfstring"" apaga.cnpjstring"" apaga.state_regstringperson_typestringFPFJPJlegal_namestringfirst_name.trade_namestringresponsible_namestringresponsible_cpfstringlanguagestringpt-BRenesinvalid language.currencystringBRL).timezonestringAmerica/Sao_Paulo).whatsapp_phonestringwhatsapp_opt_inbooleanmarketing_opt_inbooleantrue grava a data de agora, false apaga.notify_on_ordersbooleanis_rootboolean/api/admin/users/{id}/addressesAutenticadaListar os endereços de um usuário
Escopo read_customers. Usuário sem endereços devolve lista vazia ([]).
Parâmetros de caminho
iduuidobrigatório/api/admin/users/{id}/ordersAutenticadaListar os pedidos de um usuário
Os pedidos de um cliente, no mesmo formato da lista de pedidos (Listar pedidos), já filtrados por esse cliente. Aceita os demais filtros e a paginação da lista de pedidos. Escopo read_orders.
Parâmetros de caminho
iduuidobrigatórioExemplo de requisição
curl "$BASE_URL/api/admin/users?user_type=customer&sort_by=updated_at&sort_dir=asc&per_page=50" \
-H "Authorization: Bearer $APP_TOKEN"Resposta da lista
{
"users": [
{
"id": "3dc023ca-3746-4b6e-8afd-686a4a9af99f",
"email": "contato@paodoce.example.com",
"user_type": "customer",
"status": "A",
"first_name": "Padaria Pão Doce Ltda",
"last_name": "",
"phone": "+551133334444",
"cnpj": "11222333000181",
"legal_name": "Padaria Pão Doce Ltda",
"trade_name": "Pão Doce",
"language": "pt-BR",
"currency": "BRL",
"timezone": "America/Sao_Paulo",
"email_verified": false,
"login_count": 0,
"is_root": false,
"account_type": "individual",
"person_type": "J",
"person_type_declared": true,
"display_name": "Pão Doce",
"created_at": "2026-10-11T20:55:51.332285Z",
"updated_at": "2026-10-11T20:56:18.510829Z",
"user_id": "3dc023ca-3746-4b6e-8afd-686a4a9af99f",
"firstname": "Padaria Pão Doce Ltda",
"lastname": "",
"tax_id": "11222333000181",
"timestamp": 1791752151,
"updated_timestamp": 1791752178
}
],
"total": 8173,
"page": 1,
"per_page": 50,
"total_pages": 164
}Campos da resposta
usersarraysms_opt_in, push_opt_in, whatsapp_opt_in e notify_on_orders podem vir false mesmo quando a conta tem outro valor: leia o usuário para o valor real.totalintegerpageintegerper_pageintegertotal_pagesintegerResposta da consulta de um usuário
{
"id": "3dc023ca-3746-4b6e-8afd-686a4a9af99f",
"email": "contato@paodoce.example.com",
"user_type": "customer",
"status": "A",
"first_name": "Padaria Pão Doce Ltda",
"last_name": "",
"phone": "+551133334444",
"cnpj": "11222333000181",
"legal_name": "Padaria Pão Doce Ltda",
"trade_name": "Pão Doce",
"language": "pt-BR",
"currency": "BRL",
"timezone": "America/Sao_Paulo",
"email_verified": false,
"login_count": 0,
"is_root": false,
"whatsapp_opt_in": false,
"sms_opt_in": false,
"push_opt_in": true,
"notify_on_orders": true,
"account_type": "individual",
"person_type": "J",
"person_type_declared": true,
"display_name": "Pão Doce",
"responsible_name": "João Pereira",
"created_at": "2026-10-11T20:55:51.332285Z",
"updated_at": "2026-10-11T20:56:18.510829Z",
"user_id": "3dc023ca-3746-4b6e-8afd-686a4a9af99f",
"firstname": "Padaria Pão Doce Ltda",
"lastname": "",
"tax_id": "11222333000181",
"timestamp": 1791752151,
"updated_timestamp": 1791752178
}Campos da resposta
iduuiduser_id repete o mesmo valor.emailstringuser_typestringcustomervendoradminroot_adminstatusstringADPA ativo, D desativado, P pendente.first_namestringlegal_name).last_namestringphonestring+55...) quando gravado pela plataforma. Vazio se não informado.avatar_urlstringcpfstringcnpjstringlegal_namestringtrade_namestringstate_regstringperson_typestringFJF física, J jurídica. Sempre preenchido.person_type_declaredbooleantrue se alguém declarou o tipo; false se ele foi deduzido do documento.display_namestringresponsible_namestringcompany_namestringlanguagestringpt-BRenescurrencystringBRL).timezonestringAmerica/Sao_Paulo).email_verifiedbooleanemail_verified_at traz a data (RFC 3339), quando existe.last_login_atstringlogin_count conta os logins.vendor_namestringis_rootbooleanwhatsapp_phonestringwhatsapp_opt_inbooleanmarketing_consent_atstringterms_accepted_atstringprivacy_accepted_atstringsms_opt_inbooleanpush_opt_inbooleannotify_on_ordersbooleanaccount_typestringindividualcorporate_parentsubaccountindividual é uma conta comum; corporate_parent é a conta-mãe de uma empresa B2B; subaccount é um comprador (funcionário) da empresa.created_atstringupdated_at é a última alteração.firstnamestringuser_id, firstname, lastname, tax_id (CPF ou CNPJ), timestamp (cadastro em Unix), updated_timestamp e last_login (Unix, só se já entrou).Resposta da alteração
{
"id": "3dc023ca-3746-4b6e-8afd-686a4a9af99f",
"email": "contato@paodoce.example.com",
"user_type": "customer",
"status": "A",
"first_name": "Padaria Pão Doce Ltda",
"phone": "+5511977776666",
"legal_name": "Padaria Pão Doce Ltda",
"trade_name": "Pão Doce Centro",
"person_type": "J",
"display_name": "Pão Doce Centro",
"updated_at": "2026-10-11T20:56:18.510829Z"
}A resposta é o usuário completo, com os campos da consulta acima.
Resposta dos endereços
{
"addresses": [
{
"id": "d9e1749d-ae6a-4f9a-8943-22d93d90cde0",
"user_id": "3dc023ca-3746-4b6e-8afd-686a4a9af99f",
"label": "Matriz",
"is_default": true,
"first_name": "Padaria Pão Doce Ltda",
"last_name": "",
"address_line1": "Avenida Paulista, 1000",
"complement": "Sala 14",
"district": "Bela Vista",
"city": "São Paulo",
"state": "SP",
"postal_code": "01310-100",
"country": "BR",
"phone": "1133334444",
"created_at": "2026-10-11T20:56:23.338259Z",
"updated_at": "2026-10-11T20:57:46.981711Z"
}
],
"total": 1
}Campos do endereço
iduuidaddress_id repete o valor.user_iduuidlabelstringis_defaultbooleanfirst_namestringlast_namestringaddress_line1stringAvenida Paulista, 1000).address_line2stringcomplementstringSala 14, Bloco B). Campo próprio, não se mistura com address_line2.districtstringdistrict_id é o id no catálogo de bairros, quando o bairro existe lá.citystringcity_id é o id no catálogo de cidades, quando a cidade existe lá (usado para casar áreas de entrega).statestringSP).postal_codestring01310-100 ou 01310100).countrystringpadrão: BRphonestringtypestringD).s_*, b_*strings_firstname, s_lastname, s_address, s_city, s_state, s_zipcode, s_country, s_phone) e cobrança (b_*, os mesmos nomes). Sempre iguais aos campos acima.created_atstringupdated_at é a última alteração.Erros
| Status | Quando | Corpo |
|---|---|---|
| 400 | Corpo da alteração que não é JSON, ou campo recusado (por exemplo status ou user_type inválido) | {"error":"invalid request body","detail":"..."} ou {"error":"invalid status: zzz (must be active, disabled, or pending)"} |
| 401 | Sem token, ou um JWT de usuário no lugar do token de app | {"error":"app_token_required"} |
| 401 | Token de app inválido, revogado ou expirado | {"error":"invalid or expired app access token"} |
| 403 | O app não tem o escopo exigido pela rota | {"error":"missing_scope","required":"read_customers"} |
| 404 | Usuário inexistente | {"error":"user not found"} |
| 500 | Id que não é UUID | {"error":"failed to get user","detail":"..."} |