24 KiB
Atomenta Mobile App API Documentation
🔐 Authentication & Headers
The mobile app accesses distinct sets of APIs:
- App APIs (
/api/app/*): For general app features like Home Screen and Orders listing. - Customer APIs (
/api/customer/*): For User Registration, Login, and Profile Management. - Store External APIs (
/api/store/*): For store-specific operations like Catalog and Checkout.
Common Headers
All requests should ideally include:
Accept: application/json
Content-Type: application/json
Authentication Strategies
1. Customer Auth (for App & Customer APIs)
Used for everything related to the logged-in user (Profile, Orders, etc).
- Header:
Authorization: Bearer <Users_JWT_Token> - Note: Obtained via
/api/customer/login.
3. Hybrid Store Auth (for Store External APIs)
Used when interacting with a specific store (Catalog, Checkout).
- Header 1:
Atomenta-Token: 550e8400-e29b-41d4-a716-446655440008(Store Module ID) - Header 2:
Authorization: Bearer <Users_JWT_Token>(Required for Checkout/Orders)
👤 Customer Management
1. Register Customer
POST /api/customer
Headers:
Atomenta-Token: 550e8400-e29b-41d4-a716-44665544000a(Customer Module ID)
Body:
{
"name": "Daniel Loverde",
"email": "daniel@example.com",
"phoneNumber": "+5511999999999",
"birthDate": "1990-01-01T00:00:00Z" // Opcional
}
Response:
{
"error": false,
"code": "CUSTOMER_CREATED",
"result": {
"id": "cust_uuid...",
"name": "Daniel Loverde",
"email": "daniel@example.com"
}
}
2. Login (Get Token)
POST /api/customer/login
Body (email + phoneNumber are mandatory):
{
"email": "daniel@example.com",
"phoneNumber": "+5511999999999"
}
Fluxo:
- Passo 1: enviar
email+phoneNumberpara receber código por email. - Passo 2: enviar
email+phoneNumbere o OTP no headerAuthorization: Bearer <OTP>.
Response:
{
"error": false,
"code": "LOGIN_SUCCESS",
"result": {
"token": "eyJhbGciOi...", // <--- Use as Bearer Token for other requests
"customer": {
"id": "cust_uuid...",
"name": "Daniel Loverde",
"email": "daniel@example.com"
}
}
}
3. Get Profile
GET /api/customer/profile
Headers:
Authorization: Bearer <JWT_Token>Atomenta-Token: 550e8400-e29b-41d4-a716-44665544000a
Response:
{
"error": false,
"code": "CUSTOMER_PROFILE_RETRIEVED",
"result": {
"id": "cust_uuid...",
"name": "Daniel Loverde",
"email": "daniel@example.com",
"phoneNumber": "+5511999999999",
"favorites": ["store_abc...", "store_xyz..."],
"address_book": [],
"verified": true,
"biometricsEnabled": false,
"createdAt": "2026-01-21T22:37:56.472Z",
"updatedAt": "2026-02-13T19:00:00.000Z"
}
}
Campos internos não retornados para o app: keyHash, strongHash, source, isShadow, profile_metrics, behavioral_stats, otpHash, otpHashParams, otpExpiresAt.
4. Update Profile
POST /api/customer/:id
Headers:
Authorization: Bearer <JWT_Token>Atomenta-Token: 550e8400-e29b-41d4-a716-44665544000a
Body:
{
"name": "Daniel A. Loverde", // Fields to update
"phoneNumber": "+5511988888888",
"biometricsEnabled": true,
"address_book": [
{
"label": "Casa",
"type": "residential",
"address": "Avenida das Andorinhas",
"number": "477",
"neighborhood": "Jardim Andorinhas",
"city": "Campinas",
"state": "SP",
"zipCode": "13101-400",
"country": "Brasil",
"complement": "Apto 78",
"lat_long": [-22.9064, -47.0616]
}
]
}
Regra de coordenadas (address_book.lat_long):
- Se existir
zipCodeválido e houver cache do CEP no Atomenta (/api/public/cep/:cep) para o mesmo usuário, a API valida o ponto enviado. - Se não houver cache local, o Atomenta consulta a AwesomeAPI e atualiza o cache antes de validar.
- Se
lat_longestiver ausente/inválido, a API preenche com as coordenadas do CEP cacheado. - Se a distância entre
lat_longenviado e o ponto do CEP for maior que1.5 km, a API substituilat_longpelo ponto do CEP cacheado. - Objetivo: evitar discrepâncias grandes entre endereço e coordenada salva no perfil.
5. List Favorite Stores
GET /api/customer/favorites
Headers:
Authorization: Bearer <JWT_Token>Atomenta-Token: 550e8400-e29b-41d4-a716-44665544000a
Notes:
- Retorna as lojas favoritas do customer autenticado.
- Apenas lojas públicas/visíveis são retornadas.
- A ordem segue a ordem salva em
favorites.
Response:
{
"error": false,
"code": "CUSTOMER_FAVORITES_RETRIEVED",
"result": [
{
"id": "store_1775510226293_yn5ys",
"name": "CPS Drinks",
"logo": null,
"cover": null,
"category": "Doces & Bolos",
"rating": 4.8,
"totalReviews": 12,
"isOpen": true,
"statusLabel": "Aberto",
"nextOpenLabel": null
}
]
}
6. Add Store to Favorites
POST /api/customer/favorites/:storeId
Headers:
Authorization: Bearer <JWT_Token>Atomenta-Token: 550e8400-e29b-41d4-a716-44665544000a
Notes:
- Salva a loja nos favoritos do customer autenticado.
- Se a loja já estiver favoritada, a operação continua idempotente.
- A loja precisa existir e estar publicamente visível.
Response:
{
"error": false,
"code": "CUSTOMER_FAVORITE_SAVED",
"result": {
"favorites": ["store_1775510226293_yn5ys"],
"store": {
"id": "store_1775510226293_yn5ys",
"name": "CPS Drinks",
"logo": null,
"cover": null,
"category": "Doces & Bolos",
"rating": 4.8,
"totalReviews": 12,
"isOpen": true,
"statusLabel": "Aberto",
"nextOpenLabel": null
}
}
}
7. Remove Store from Favorites
DELETE /api/customer/favorites/:storeId
Headers:
Authorization: Bearer <JWT_Token>Atomenta-Token: 550e8400-e29b-41d4-a716-44665544000a
Notes:
- Remove a loja dos favoritos do customer autenticado.
- A operação é idempotente: se a loja não estiver favoritada, o array volta sem ela.
Response:
{
"error": false,
"code": "CUSTOMER_FAVORITE_REMOVED",
"result": {
"favorites": []
}
}
🏠 App Home Screen
List Categories
GET /api/public/categories
Headers:
Accept: application/json
Response:
{
"error": false,
"result": [
{ "id": "all", "name": "Todas", "icon": "🏪" },
{ "id": "lanches", "name": "Lanches", "icon": "🍔" },
{ "id": "pizza", "name": "Pizza", "icon": "🍕" }
]
}
List Stores (Smart Listing)
GET /api/app/stores
Headers:
Authorization: Bearer <Users_JWT_Token>(Customer obrigatório)
Lists stores based on user location, filtered by distance.
Query Parameters:
lat(Required): User Latitude (e.g.,-23.550520)lng(Required): User Longitude (e.g.,-46.633308)category(Optional): Filter by category name (e.g.,Lanches)search(Optional): Search by store name
Notes:
- Sem login do customer, a listagem é bloqueada.
- Se
lat/lngnão forem enviados, a API tenta usar o endereço salvo no perfil do customer (address_book.lat_long). - Lojas fora do raio/bairro de entrega não são exibidas.
Response:
{
"error": false,
"result": [
{
"id": "store_123...",
"name": "Burger King",
"logo": "https://...",
"cover": "https://...",
"category": "Lanches",
"rating": 4.8,
"deliveryTime": "30-45 min",
"deliveryFee": 5.99,
"distance": 1.2, // km
"isOpen": true,
"statusLabel": "Aberto"
}
]
}
List User Orders
GET /api/app/orders
Headers:
Authorization: Bearer <JWT>
Response:
{
"error": false,
"result": [
{
"id": "ord_123...",
"total": 54.90,
"status": "completed",
"createdAt": "2024-03-20T10:00:00Z",
"items": [...]
}
]
}
🏪 Store Integration (External API)
Base URL: /api/store/:storeId
1. Store Identity & Status
GET /api/store/:storeId/identity
Headers/Query:
x-user-lat/lat: User Latitudex-user-lng/lng: User Longitude
Response:
{
"error": false,
"result": {
"fantasyName": "Mc Donalds",
"distance": 2.5,
"deliveryTime": "30-45 min",
"minOrder": 15.00
}
}
2. Full Store Info
GET /api/store/:storeId/info
Retorna versão pública para app (sem dados administrativos/financeiros da loja).
Response:
{
"error": false,
"code": "STORE_INFO_RETRIEVED",
"result": {
"isOpen": true,
"statusLabel": "Aberto",
"fantasyName": "Mc Donalds",
"specialty": "Lanches",
"minOrder": 15,
"deliveryTime": "30-45 min",
"logo": "https://...",
"cover": "https://...",
"paymentMethods": {
"paymentOnDelivery": true,
"paymentOnPickup": true,
"acceptCash": true,
"acceptPix": true
},
"openingHours": { "...": "..." },
"address": {
"street": "Rua X",
"neighborhood": "Centro",
"city": "Campinas",
"state": "SP",
"zipcode": "13000-000",
"latitude": -22.9,
"longitude": -47.0
}
}
}
3. Product Catalog
GET /api/store/:storeId/catalog
Retorna categorias com produtos, incluindo diferenciação explícita de pizza.
Response:
{
"error": false,
"result": [
{
"id": "cat_lanches",
"name": "Lanches",
"isPizzaCategory": false,
"products": [
{
"id": "prod_xburger",
"type": "prepared",
"name": "X-Burger",
"description": "Pão, carne e queijo",
"image": "/uploads/products/xburger.jpg",
"price": "25.00",
"addons": "yes",
"addonGroups": []
}
]
},
{
"id": "cat_pizzas",
"name": "Pizzas",
"isPizzaCategory": true,
"pizzaConfig": {
"sizes": [{ "id": "broto", "name": "Broto", "slices": 4, "maxFlavors": 1 }],
"doughs": [{ "id": "tradicional", "name": "Tradicional", "active": true }],
"crusts": [{ "id": "catupiry", "name": "Catupiry", "active": true, "priceModifier": "10.00" }]
},
"products": [
{
"id": "prod_pizza_calabresa",
"type": "pizza",
"name": "Pizza Calabresa",
"description": "Molho, mussarela e calabresa",
"image": "/uploads/products/pizza-calabresa.jpg",
"price": "0.00",
"pizzaPrices": {
"broto": "35.00",
"grande": "55.00"
},
"addons": "yes",
"addonGroups": []
}
]
}
]
}
Como identificar pizza no app:
- Produto pizza:
products[].type === "pizza". - Configuração de montagem/preço por tamanho:
category.isPizzaCategory === true+category.pizzaConfig+product.pizzaPrices.
4. Validate Delivery Address (Checkout)
POST /api/store/:storeId/delivery/validate-address
Use este endpoint ao trocar endereço na tela de pagamento para validar cobertura antes de finalizar.
Body:
{
"address": {
"street": "Avenida das Andorinhas",
"number": "477",
"neighborhood": "Jardim Andorinhas",
"city": "Campinas",
"state": "SP",
"zip": "13101-400",
"lat": -22.918,
"lng": -47.01813
}
}
Resposta Exemplo:
{
"error": false,
"code": "DELIVERY_ADDRESS_VALIDATED",
"result": {
"deliveryAllowed": true,
"reasonCode": "DELIVERY_ALLOWED",
"reasonMessage": "Endereço válido para entrega",
"deliveryMode": "KM",
"distance": 1.3,
"deliveryFee": 8,
"deliveryTime": "35 min",
"sameCity": false,
"matchedKmRange": { "from": 1, "to": 2, "price": 8, "time": 35 },
"matchedNeighborhood": null
}
}
Regras de validação:
KM: valida distância até o limite da última faixa + tolerância de0.5 km.NEIGHBORHOOD: reprova se cidade do endereço for diferente da cidade da loja.NEIGHBORHOOD: aprova se bairro configurado bater, ou se for mesma cidade (fallback).
5. Create Order (Checkout)
POST /api/store/:storeId/orders
Body:
{
"customer": {
"name": "Daniel Loverde",
"phone": "11999999999",
"email": "daniel@example.com",
"asaasId": "cus_000005165985" // Opcional.
},
// Nota: O usuário DEVE estar autenticado via Bearer Token.
// Os dados de 'customer' enviados aqui são usados preferencialmente para
// registrar os dados de entrega/cobrança deste pedido específico no Asaas,
// mas o 'userId' e o histórico são vinculados ao token do usuário logado.
"items": [
{
"productId": "prod_123",
"name": "X-Burger",
"qty": 2,
"price": 25.00,
"addons": [
{
"addonId": "addon_egg",
"name": "Ovo",
"price": 2.50,
"qty": 2
}
]
}
],
"total": 50.00,
"paymentMethod": "PIX", // "PIX" | "CREDIT_CARD" | "DEBIT_CARD" | "MONEY"
"deliveryType": "DELIVERY", // "DELIVERY" | "PICKUP"
"address": {
"street": "Rua Exemplo",
"number": "123",
"neighborhood": "Centro"
}
}
Regras para items[].addons:
qtydo adicional é aceito no backend (ex.:2 ovos).- Se
qtynão for enviado ou vier inválido, a API assume1. qtymínimo efetivo é1.
Response:
{
"error": false,
"code": "ORDER_CREATED",
"result": {
"id": "ord_987...",
"shortId": "1234",
"status": "PAYMENT_PENDING",
"paymentStatus": "PENDING",
"paymentMethod": "PIX",
"paymentPayload": {
"copyPaste": "000201010212...",
"qrCodeImage": "iVBORw0KGgoAAAANSUhEUgAA...",
"expirationDate": "2026-02-14T22:30:00.000Z"
},
"payment": {
"method": "PIX",
"status": "PENDING",
"pix": {
"copyPaste": "000201010212...",
"qrCodeImage": "iVBORw0KGgoAAAANSUhEUgAA...",
"expirationDate": "2026-02-14T22:30:00.000Z"
}
}
}
}
Observação de segurança: o Atomenta não retorna mais links de checkout/fatura do Asaas no payload de criação do pedido.
6. Realtime de Status do Pedido (Socket.IO)
Use este canal para acompanhar mudança de status do pedido em tempo real (sem depender de push notification).
Socket Endpoint:
ws://<host>:<port>/socket.io/(em produção, usarwss://se houver TLS no balanceador)
Auth no handshake:
- Enviar o JWT do customer em
auth.token(mesmo token doAuthorization: Bearer ...das APIs HTTP).
Exemplo de conexão (conceitual):
{
"auth": {
"token": "Bearer <Users_JWT_Token>"
}
}
Eventos recebidos pelo app:
order_update: alteração geral de status do pedido.order_cancelled: cancelamento confirmado, com motivo e metadados de estorno.delivery_order_cancelled: evento dedicado para telas de OTP/entrega interromperem o fluxo imediatamente.
Payload típico de order_cancelled:
{
"event": "order_cancelled",
"emittedAt": "2026-03-05T18:00:00.000Z",
"orderId": "ffdc47b4-6a55-4713-aea9-45169e4cf0d7",
"shortId": "3778",
"storeId": "store_1772117366848_wmqw4",
"userId": "cust_uuid_001",
"status": "CANCELED",
"cancelledBy": "store",
"cancelledAt": "2026-03-05T18:00:00.000Z",
"cancelReasonCode": "STORE_UNAVAILABLE",
"cancelReasonDetail": "Falta de insumo crítico para finalizar o pedido",
"refundStatus": "failed",
"refundIdempotencyKey": "refund:ffdc47b4-...",
"refundProviderRef": null,
"refundError": "Falha ao solicitar estorno automático"
}
7. Fallback oficial (Polling)
Se o socket cair, o app deve continuar consultando o status até estado final.
Endpoint:
GET /api/public/orders/:orderId
Sugestão de estratégia:
- primeiros 60s: a cada
3s - próximos 2min: a cada
5s - depois: a cada
10s - parar em status final (
COMPLETED,CANCELED,REFUNDED) ou ao sair da tela.
8. Cancelamento de Pedido (Loja/Customer)
Cancelamento pela loja (Store API):
POST /api/store/:storeId/orders/:orderId/cancel
Cancelamento pelo customer:
POST /api/customer/orders/:orderId/cancel
Request body (ambos):
{
"reasonCode": "CUSTOMER_REQUEST",
"reasonDetail": "Cliente solicitou cancelamento antes da entrega"
}
Motivos aceitos (reasonCode):
STORE_UNAVAILABLECUSTOMER_REQUESTDELIVERY_ISSUE
Regras atuais de cancelamento:
- Permitido em:
PAYMENT_PENDING,PENDING,ACCEPTED,PREPARING,READY,DELIVERING. - Bloqueado em:
COMPLETEDeCANCELED. - Motoboy não cancela pedido.
- Ao cancelar, o backend invalida
otp,confirmOtpecustomerOtp.
Concorrência e idempotência (ponta a ponta):
- Cancelamento é serializado por
orderId(lock por pedido). - Estorno automático usa lock + chave idempotente de estorno para evitar duplicidade.
- Em segunda tentativa após cancelamento efetivado, a API retorna
409 ORDER_ALREADY_CANCELED.
Campos relevantes no retorno:
cancelledBy,cancelledAt,cancelReasonCode,cancelReasonDetailrefundStatus,refundIdempotencyKey,refundProviderRef
9. Catálogo Oficial de Tags de Review
9.1 Matriz Completa de Endpoints (Reviews + Tags)
Público/App (Customer):
GET /api/public/reviews/tags→ catálogo oficial de tags e regras de validação.POST /api/public/orders/:orderId/review→ cria/atualiza avaliação do pedido concluído.GET /api/public/store/:storeId/reviews→ lista reviews públicos da loja.
Store/Backoffice (analytics e operação):
GET /api/store/:storeId/reviews→ listagem detalhada + métricas de reviews da loja.POST /api/store/:storeId/reviews/:reviewId/reply→ resposta oficial da loja para avaliação.POST /api/store/:storeId/reviews/:reviewId/dispute→ contestação da avaliação.GET /api/store/reviews/app/nps→ NPS do app (geral/por filtros).GET /api/store/reviews/app/nps/platform→ NPS por plataforma (ios,android,web).GET /api/store/reviews/observability/overview→ funil técnico (sucesso/rejeição/erro).GET /api/store/reviews/observability/alerts→ alertas operacionais (ex.: pico de reviews negativas).
Observação de base URL:
- No app, consumir sempre via domínio/API oficial do ecossistema (PediFoods/Atomenta), mantendo o Atomenta como orquestrador.
O app deve buscar este endpoint para renderizar as tags válidas e enviar somente os id retornados.
Endpoint:
GET /api/public/reviews/tags
Headers:
Accept: application/json
Response (resumo):
{
"error": false,
"result": {
"version": "2026-03-01",
"order": {
"positive": [{ "id": "flavor", "label": "Sabor" }],
"improvement": [{ "id": "wrong_items", "label": "Itens errados" }],
"rules": {
"positiveAllowedWhenRateGte": 5,
"improvementAllowedWhenRateLte": 4
}
},
"delivery": {
"sentiments": [
{ "id": "positive", "allowedTags": ["politeness", "on_time"] },
{ "id": "negative", "allowedTags": ["delay", "rude"] }
],
"positive": [{ "id": "politeness", "label": "Educação" }],
"negative": [{ "id": "delay", "label": "Atraso" }]
},
"app": {
"nps": { "min": 0, "max": 10 },
"platforms": ["ios", "android", "web"]
}
}
}
Regra de integração:
- Não hardcodear tags no app; usar o catálogo do backend.
- Enviar no POST de review apenas os
idretornados em cada bloco.
10. Enviar Avaliação do Pedido
Permite o customer enviar review da loja a partir de um pedido finalizado.
Endpoint:
POST /api/public/orders/:orderId/review
Headers:
Authorization: Bearer <Users_JWT_Token>(obrigatório)Accept: application/jsonContent-Type: application/json
Body:
{
"orderRate": 5,
"orderComment": "Pedido chegou certinho e bem embalado.",
"orderPositiveTags": ["flavor", "temperature"],
"orderImprovementTags": [],
"deliverySentiment": "positive",
"deliveryPositiveTags": ["on_time", "politeness"],
"deliveryNegativeTags": [],
"appNps": 10,
"platform": "ios",
"rate": 5,
"message": "Pedido chegou certinho e bem embalado."
}
Regras de negócio atuais:
- Só aceita review para pedido com status
COMPLETED. - O
orderIddeve existir. storeId,userId,clientNameeorderIddo review são derivados do pedido no backend (não enviar no body).- Campos obrigatórios para integração nova:
orderRate,deliverySentiment,appNps,platform. - Compatibilidade:
rate/messageainda são aceitos como fallback. - App deve manter o rascunho local do formulário em caso de erro HTTP para permitir reenvio sem redigitar.
Response (sucesso):
{
"error": false,
"result": {
"id": "rev_abc123",
"storeId": "store_1772117366848_wmqw4",
"userId": "cust_uuid_001",
"clientName": "Customer 002",
"rate": 5,
"message": "Pedido chegou certinho e bem embalado.",
"orderRate": 5,
"orderComment": "Pedido chegou certinho e bem embalado.",
"deliveryFeedback": "positive",
"platform": "ios",
"editableUntil": "2026-03-06T17:15:00.000Z",
"storeReplyUntil": "2026-03-06T17:15:00.000Z",
"reviewWindowExpiresAt": "2026-03-06T16:10:00.000Z",
"orderId": "ffdc47b4-6a55-4713-aea9-45169e4cf0d7",
"date": "2026-03-01T17:15:00.000Z"
}
}
Erros esperados:
400quandoorderIdnão for enviado.400quando o pedido não existir ou ainda não estiver concluído (Apenas pedidos concluídos podem ser avaliados).400REVIEW_WINDOW_EXPIREDquando passou da janela inicial de 5 dias para criar review.400REVIEW_EDIT_WINDOW_EXPIREDquando tentar alterar review após 5 dias da criação.400INVALID_REVIEW_PAYLOAD/INVALID_REVIEW_TAGS/INVALID_DELIVERY_SENTIMENT_TAGSpara payload inválido.401se o token JWT for inválido/ausente.500em falha interna (Erro ao enviar avaliação).
Exemplos de validação (cenários):
Exemplo válido (nota alta + entrega positiva):
{
"orderRate": 5,
"orderComment": "Perfeito.",
"orderPositiveTags": ["flavor", "temperature"],
"orderImprovementTags": [],
"deliverySentiment": "positive",
"deliveryPositiveTags": ["on_time", "politeness"],
"deliveryNegativeTags": [],
"appNps": 10,
"platform": "android"
}
Exemplo inválido (nota 5 com orderImprovementTags):
{
"orderRate": 5,
"orderImprovementTags": ["temperature"],
"deliverySentiment": "positive",
"appNps": 8,
"platform": "ios"
}
Retorno esperado: 400 INVALID_REVIEW_TAGS.
Exemplo inválido (entrega positiva com tags negativas):
{
"orderRate": 4,
"orderImprovementTags": ["temperature"],
"deliverySentiment": "positive",
"deliveryNegativeTags": ["delay"],
"appNps": 7,
"platform": "web"
}
Retorno esperado: 400 INVALID_DELIVERY_SENTIMENT_TAGS.
11. Analytics de Reviews (Store/API)
Para dashboard da loja e análise de produto, usar:
-
GET /api/store/:storeId/reviews- filtros opcionais:
startDate,endDate,minRate,maxRate,deliverySentiment,platform - retorno inclui métricas de estrelas, blocos de pedido/entrega, janelas (
editableUntil,storeReplyUntil) eappNpsagregado.
- filtros opcionais:
-
POST /api/store/:storeId/reviews/:reviewId/reply- body obrigatório:
reply(texto da resposta da loja). - regra: respeita janela de resposta (
storeReplyUntil).
- body obrigatório:
-
POST /api/store/:storeId/reviews/:reviewId/dispute- body obrigatório:
reason(motivo da contestação).
- body obrigatório:
-
GET /api/store/reviews/app/nps- filtros opcionais:
startDate,endDate,storeId,platform - retorno: volume NPS, média e score.
- filtros opcionais:
-
GET /api/store/reviews/app/nps/platform- filtros opcionais:
startDate,endDate,storeId - retorno: NPS separado em
ios,android,web.
- filtros opcionais:
-
GET /api/store/reviews/observability/overview- filtros opcionais:
startDate,endDate,storeId - retorno: tentativas, sucesso/rejeição/erro, taxa de sucesso e conversão por pedidos concluídos.
- filtros opcionais:
-
GET /api/store/reviews/observability/alerts- filtro opcional:
storeId - retorno: alertas de pico, ex.:
NEGATIVE_REVIEWS_SPIKE.
- filtro opcional:
Compatibilidade Store:
- O painel
/store/reviewssegue funcional com os campos legados (rate,message,itemFeedback,improvementFeedback,deliveryFeedback). - Campos novos coexistem para evolução gradual sem quebrar o fluxo atual.