GraphQL da vitrine
Consulta catálogo, categorias, sellers, páginas, carrinho e dados do cliente logado com uma única requisição GraphQL.
O endpoint /graphql é a API da vitrine em GraphQL: ele devolve exatamente os campos que você pedir, em uma só requisição. É útil para sites e apps que montam telas de catálogo, carrinho e conta do cliente. Para administrar a loja (criar produto, mudar pedido) use a API REST administrativa, o GraphQL não tem essas operações.
Todos os valores em dinheiro são inteiros em centavos (30000 = R$ 300,00). Os ids são UUID em string. Datas saem como texto.
Autenticação
O endpoint aceita três formas, todas opcionais:
| Forma | Como enviar | Para quê |
|---|---|---|
| Nenhuma | sem cabeçalho | catálogo, categorias, sellers e páginas públicas |
| Token de cliente | Authorization: Bearer <jwt> | customer, e carrinho do usuário logado |
| Sessão de visitante | X-Session-ID: <texto livre estável> | carrinho de quem não fez login |
| Chave de API da vitrine | Authorization: Bearer sfk_... | integrações de servidor, com limite de requisições por chave |
Uma chave sfk_ inválida ou revogada devolve 401 invalid or revoked API key. Passando do limite da chave, 429 rate limit exceeded com Retry-After: 60.
As operações de carrinho exigem token ou X-Session-ID. Sem nenhum dos dois: authentication or X-Session-ID header required for cart operations. A consulta customer sem login devolve null e o erro authentication required.
Limites
| Limite | Valor | Erro |
|---|---|---|
| Profundidade da consulta | 10 níveis | 400, query depth N exceeds maximum allowed depth of 10 |
| Complexidade (total de campos pedidos) | 200 | 400, query complexity N exceeds maximum allowed complexity of 200 |
first em listas | máximo 100 (acima disso vale 100) | sem erro |
/graphqlAutenticadaExecutar uma consulta ou mutação GraphQL
Corpo da requisição
querystringobrigatóriovariablesobjectoperationNamestringCabeçalhos
X-Tenant-IDstringAuthorizationstringBearer <jwt> do cliente ou Bearer sfk_.... Opcional.X-Session-IDstring/graphqlAutenticadaExecutar uma consulta via query string
Mesmas regras do POST, com os parâmetros na URL. Prefira o POST: a URL tem tamanho limitado e aparece em logs. Mutações não devem ser enviadas por GET.
Parâmetros de consulta
querystringobrigatóriovariablesstringoperationNamestringExemplo de requisição
curl -X POST "$BASE_URL/graphql" \
-H "Content-Type: application/json" \
-d '{"query":"query($n:Int){ products(first:$n){ totalCount pageInfo{hasNextPage endCursor} edges{cursor node{id name slug price inStock}} } }","variables":{"n":2}}'Resposta
{
"data": {
"products": {
"totalCount": 4976,
"pageInfo": { "hasNextPage": true, "endCursor": "Y3Vyc29yOjE=" },
"edges": [
{
"cursor": "Y3Vyc29yOjA=",
"node": {
"id": "22fbd12a-1b6e-41ea-a84f-4d9cf06c8766",
"name": "Camisa do Flamengo Masculina I 26 Adidas",
"slug": "camisa-flamengo-masculina-i-26-adidas",
"price": 30000,
"inStock": true
}
}
]
}
}
}Campos da resposta
dataobjectnull quando a operação inteira falha.errorsarraymessage e, quando aplicável, locations e path.Erros
| Status | Quando | Corpo de exemplo |
|---|---|---|
| 200 | Erro de execução (campo inexistente ou não autenticado) | {"data":null,"errors":[{"message":"Cannot query field \"nope\" on type \"Query\"."}]} |
| 400 | Corpo que não é JSON | {"errors":[{"message":"invalid JSON body"}]} |
| 400 | Consulta vazia | {"errors":[{"message":"query is required"}]} |
| 400 | Profundidade ou complexidade acima do limite | {"errors":[{"message":"query depth 11 exceeds maximum allowed depth of 10"}]} |
| 401 | Chave sfk_ inválida | {"errors":[{"message":"invalid or revoked API key"}]} |
| 403 | Introspecção em produção sem ser administrador | {"errors":[{"message":"introspection is disabled in production"}]} |
| 405 | Método diferente de GET e POST | {"errors":[{"message":"only GET and POST are supported"}]} |
| 429 | Limite da chave sfk_ excedido | {"errors":[{"message":"rate limit exceeded"}]} |
Consultas (Query)
| Consulta | Argumentos | Devolve |
|---|---|---|
products | first (padrão 20, máx. 100), after, filter, sort; antigos: page, perPage, categoryId, search | ProductConnection |
product | id ou slug | Product ou null |
categories | parentId | lista de Category |
category | id ou slug | Category ou null |
vendors | first, after, search | VendorConnection |
vendor | id ou slug | Vendor ou null |
cart | nenhum | Cart (exige token ou X-Session-ID para ter itens) |
customer | nenhum | Customer (exige token de cliente) |
pages | type | lista de Page |
page | slug (obrigatório) | Page ou null |
filter (ProductFilter) aceita categoryId, vendorId, search, minPrice e maxPrice (centavos) e inStock. sort (ProductSort) aceita PRICE_ASC, PRICE_DESC, NEWEST, NAME_ASC, NAME_DESC, BEST_SELLING e TOP_RATED.
Paginação
As listas products e vendors usam cursor estilo Relay: leia pageInfo.endCursor e envie em after para a próxima página, enquanto hasNextPage for verdadeiro. Trate o cursor como texto opaco. Quando você manda first, ele vale mais que o perPage.
Mutações (Mutation)
| Mutação | Argumentos | Efeito |
|---|---|---|
addToCart | productId (obrigatório), quantity (obrigatório), options (JSON) | Adiciona o produto e devolve o Cart |
updateCartItem | productId, quantity | Muda a quantidade de um item |
removeFromCart | productId | Remove o item |
clearCart | nenhum | Esvazia o carrinho |
createCheckout | cartId (obrigatório), guestEmail, guestName, guestPhone | Cria a sessão de checkout a partir do carrinho. guestEmail é necessário em compra de visitante |
Exemplo de mutação, com a resposta real do ambiente de teste:
mutation {
addToCart(productId: "22fbd12a-1b6e-41ea-a84f-4d9cf06c8766", quantity: 2) {
id itemCount subtotal total currency
items { productId name unitPrice quantity total }
}
}{
"data": {
"addToCart": {
"id": "e040ceb9-9bbf-44b9-8820-f51a7b6984ba",
"itemCount": 2,
"subtotal": 60000,
"total": 60000,
"currency": "BRL",
"items": [
{ "productId": "22fbd12a-1b6e-41ea-a84f-4d9cf06c8766", "name": "Camisa do Flamengo Masculina I 26 Adidas", "unitPrice": 30000, "quantity": 2, "total": 60000 }
]
}
}
}Tipos
| Tipo | Campos principais |
|---|---|
Product | id, name, slug, description, shortDescription, sku, price, listPrice (centavos), images, category, vendor, inStock, stockQuantity, options, averageRating, reviewCount, freeShipping, weight, createdAt |
ProductImage | id, url, altText, position, isPrimary |
ProductOption / OptionValue | id, name, type, required, position, values; valor: value, priceModifier (centavos), position |
Category | id, parentId, name, slug, description, imageUrl, position, productCount, children |
Vendor | id, companyName, slug, logoUrl, description, city, state |
Cart / CartItem | carrinho: id, items, itemCount, subtotal, shippingTotal, taxTotal, discountTotal, total, currency; item: productId, name, imageUrl, unitPrice, quantity, total |
Page | id, title, slug, body, pageType, seoTitle, seoDescription, createdAt, updatedAt |
Customer | id, email, firstName, lastName, phone, cpf, createdAt, addresses, orders(first, after), wishlist(first) |
CustomerAddress | id, label, isDefault, firstName, lastName, addressLine1, addressLine2, city, state, postalCode, country, district, phone |
Order / OrderItem | pedido: id, orderNumber, status, subtotal, shippingTotal, taxTotal, discountTotal, total, currency, paymentMethod, paymentStatus, shippingMethod, trackingNumber, customerNotes, items, createdAt; item: id, productId, productName, productSku, productImage, unitPrice, quantity, discount, tax, total |
WishlistItem | id, productId, productName, productSlug, productImage, currentPrice, priceAtAdd, inStock, priority, addedAt |
CheckoutSession | id, cartId, step, subtotal, shippingCost, discount, tax, total, createdAt |
PageInfo | hasNextPage, hasPreviousPage, startCursor, endCursor |
ProductConnection também expõe os campos items, total, page, perPage e totalPages, para quem pagina por número de página.
/graphql/playgroundPúblicaAbrir o playground do GraphQL
Devolve uma página HTML com um editor de consultas apontando para /graphql. Ela não expõe dados: para consultar algo que exige login, cole seu cabeçalho Authorization no painel de cabeçalhos do playground. O editor carrega seus scripts de uma CDN pública.