Files
LCEssentials/API_Store_External.md
Daniel Arantes Loverde a12cfb6bf3 Lixo
2026-04-28 09:26:08 -03:00

16 KiB

Atomenta API - Store Management & External Guide (Pedi Foods Edition)

Este documento é o guia definitivo e completo para parceiros e aplicações externas (como pedifoods.com.br) que consomem a API da plataforma Atomenta para gestão de lojas. Esta API reflete 100% das funcionalidades do painel administrativo.

🔐 Autenticação e Headers

Todas as chamadas devem usar autenticação híbrida.

Headers Obrigatórios:

  • Accept: application/json
  • Atomenta-Token: 550e8400-e29b-41d4-a716-446655440008 (Escopo: Store Management)
  • Authorization: Bearer <JWT_TOKEN>

🏬 Gestão de Identidade e Lojas

1. Listar Lojas do Usuário

GET /api/store/list - Retorna todas as lojas vinculadas ao token do usuário.

2. Informações Completas da Loja (Settings)

GET /api/store/:storeId/info - Retorna a configuração completa da loja, incluindo dados bancários, horários e flags de pagamento.

Resposta Exemplo:

{
  "error": false,
  "result": {
    "isOpen": true,
    "statusLabel": "Aberto Agora",
    "isManualOpen": true,
    "fantasyName": "Pizzaria do Arantes",
    "razaoSocial": "Loverde Co LTDA",
    "document": "12.345.678/0001-99",
    "documentType": "CNPJ",
    "email": "loja@loverde.com.br",
    "phone": "11988776655",
    "paymentMethods": {
       "paymentOnDelivery": true,
       "acceptCash": true,
       "acceptCreditVisa": true,
       "acceptCreditMaster": true,
       "acceptCreditElo": true,
       "acceptVoucherAlelo": true,
       "acceptPix": true
    },
    "bankInfo": {
       "bankName": "Banco do Brasil",
       "accountType": "Corrente",
       "agency": "1234",
       "account": "56789-0",
       "pixKey": "12345678000199"
    },
    "openingHours": {
       "monday": [{"open": "18:00", "close": "23:00"}],
       "friday": [{"open": "11:00", "close": "15:00"}, {"open": "18:00", "close": "00:00"}]
    },
    "address": {
       "street": "Av. Brasil, 1000",
       "latitude": -23.55052,
       "longitude": -46.633308
    }
  }
}

📊 Dashboard Real-time (Portal Parity)

3. Dashboard e Monitoramento

GET /api/store/:storeId/dashboard

Resposta Detalhada (100% Parity):

{
  "error": false,
  "result": {
    "orderFlow": {
      "urgencys": [ { "id": "ORD-123", "clientName": "Daniel", "minutes": 45, "status": "PREPARING" } ],
      "received": [ /* Pedidos Pendentes */ ],
      "inProgress": [ /* Pedidos Em Preparo */ ],
      "readyTo": [ /* Pedidos Prontos para Entrega/Retirada */ ],
      "inRoute": [ /* Pedidos em Rota */ ],
      "delivered": [ /* Pedidos Finalizados na Sessão */ ]
    },
    "payments": {
      "totalSelledToday": 2450.00,
      "growthToday": 15.5,
      "avgTicket": 65.20,
      "growthPeriod": 8.5
    },
    "alerts": {
      "pendingOver3Minutes": 2,
      "delayedInProgress": 1
    }
  }
}

🍴 Catálogo e Menu (Complex Payloads)

3.1 Catálogo Consolidado (App)

GET /api/store/:storeId/catalog

Resposta:

{
  "error": false,
  "code": "STORE_CATALOG_RETRIEVED",
  "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": []
        }
      ]
    }
  ]
}

Regra de identificação de pizza:

  • Item pizza: products[].type === "pizza".
  • Configuração de montagem vem em category.pizzaConfig.
  • Preço por tamanho vem em product.pizzaPrices.

GET /api/store/:storeId/catalog/categories

Resposta:

{
  "error": false,
  "code": "CATEGORIES_RETRIEVED",
  "result": [
    { "id": "cat_1", "name": "Pizzas", "isActive": true }
  ],
  "message": "Categorias recuperadas com sucesso"
}

5. Criar Categoria (Ex.: Pizza)

POST /api/store/:storeId/catalog/categories

{
  "name": "Pizzas Salgadas",
  "isPizzaCategory": true,
  "pizzaConfig": {
    "sizes": [
      { "id": "small", "name": "Broto", "slices": 4, "maxFlavors": 1 },
      { "id": "large", "name": "Grande", "slices": 8, "maxFlavors": 3 }
    ],
    "doughs": [ { "id": "tradicional", "name": "Tradicional", "price": 0 } ],
    "crusts": [ { "id": "catupiry", "name": "Borda de Catupiry", "price": 10.00 } ]
  }
}

6. Atualizar Categoria

PUT /api/store/:storeId/catalog/categories/:id

7. Excluir Categoria

DELETE /api/store/:storeId/catalog/categories/:id

8. Produtos Tipo Combo ou Pizza

POST /api/store/:storeId/catalog/products

{
  "type": "pizza",
  "name": "Pizza de Calabresa",
  "categoryId": "cat_pizzas",
  "pizzaPrices": {
    "small": "35.00",
    "large": "55.00"
  },
  "addonGroups": [
    {
       "name": "Remover Ingredientes",
       "minSelectors": 0, "maxSelectors": 5,
       "items": [ { "name": "Sem Cebola", "price": 0 } ]
    }
  ]
}

📦 Histórico e Detalhes do Pedido

9. Histórico com Filtros

GET /api/store/:storeId/orders/history?start=2024-01-01&end=2024-01-31&q=Ana

Objeto de Pedido Completo (result.list[0]):

{
  "id": "order_guid",
  "shortId": "1234",
  "clientName": "Arantes Loverde",
  "totalValue": 120.50,
  "netValue": 112.40,
  "pediFoodsFee": 1.00,
  "status": "COMPLETED",
  "createdAt": "2024-01-08T15:00:00Z",
  "confirmOtp": "12345678",
  "deliveryEstimate": "35-50 min",
  "deliveryTypeLabel": "Entrega Própria",
  "timeline": [
    { "status": "PENDING", "time": "15:00:00", "message": "Pedido criado" },
    { "status": "ACCEPTED", "time": "15:02:00", "message": "Chef aceitou o pedido" },
    { "status": "COMPLETED", "time": "15:45:00", "message": "Entregue ao cliente" }
  ],
  "items": [
     { "name": "Pizza Grande", "price": 55.00, "choices": ["Borda Catupiry", "Meio Calabresa", "Meio Mussarela"] }
  ]
}

Important

O campo confirmOtp (8 dígitos) é o código que o motoboy deve utilizar para iniciar a confirmação. O customerOtp (4 dígitos do cliente) NÃO é retornado via API por questões de segurança.


### 10. Detalhes de um Pedido Individual
**GET** `/api/store/:storeId/orders/:orderId`

Retorna o objeto completo do pedido (parity 100% com o painel).

---

## 💰 Financeiro Detalhado

### 11. Resumo de Performance e Gateway
**GET** `/api/store/:storeId/financial/summary`

**Resposta:**
```json
{
  "error": false,
  "result": {
    "performance": {
      "totalSelledAllTime": 150230.50,
      "avgTicket": 72.00
    },
    "gateway": {
      "balance": { "balance": 1500.00, "available": 1200.00 },
      "transfers": [
        { "id": "TRANS-1", "date": "2024-01-05", "value": 500.00, "status": "DONE" }
      ]
    }
  }
}

Reviews e Avaliações

12. Métricas e Respostas

GET /api/store/:storeId/reviews

Resposta:

{
  "error": false,
  "result": {
    "metrics": {
       "averageRate": "4.1",
       "totalReviews": 260,
       "starsDistribution": { "5": 121, "4": 60, "3": 23, "2": 15, "1": 39 },
       "itemFeedback": {
          "flavor": 207,
          "ingredients": 94,
          "packaging": 35,
          "temperature": 29,
          "appearance": 23
       },
       "improvementFeedback": {
          "quantity": 128,
          "temperature": 89,
          "packaging": 42,
          "ingredients": 23,
          "flavor": 13
       },
       "deliveryFeedback": {
          "positive": 102,
          "negative": 60
       }
    },
    "list": [
      {
        "id": "rev_1",
        "clientName": "Ana",
        "rate": 5,
        "message": "Melhor pizza!",
        "reply": "Obrigado Ana!",
        "repliedAt": "2024-01-08T16:00:00Z"
      }
    ]
  }
}

9. Contestar Avaliação

POST /api/store/:storeId/reviews/:reviewId/dispute

{ "reason": "Cliente agressivo e mensagem falsa sobre o produto." }

🖼️ Upload de Ativos e Galeria

POST /api/store/:storeId/assets/upload (Form-data: file) -> Retorna URL absoluta.

GET /api/store/:storeId/assets -> Retorna lista de URLs absolutas de todas as imagens da loja (logo, capa e produtos).


POST /api/store/:storeId/catalog/products/reorder (Payload: { "ids": ["p1", "p2", ...] }) POST /api/store/:storeId/catalog/categories/reorder (Payload: { "ids": ["c1", "c2", ...] })


🛵 Fluxo de Entrega Pedi Foods (2-Step OTP)

Campo Tipo Descrição
otp String Legacy OTP (4 digits).
confirmOtp String Novo: Código de 8 dígitos para o motoboy. (Use este para o fluxo de 2 etapas)
deliveryEstimate String Tempo estimado de entrega (ex: "30-45 min").
pediFoodsFee Number Taxa de serviço Pedi Foods calculada.

8. Entrega e Confirmação (Motoboy Flow)

Novos endpoints públicos para confirmação de entrega em duas etapas.

8.1. Página de Confirmação

GET /delivery/confirm/:orderId Renderiza a página para o motoboy iniciar o processo.

8.2. Validar Motoboy (Passo 1)

POST /delivery/confirm/:orderId/validate-motoboy Valida o código de 8 dígitos (confirmOtp).

Payload:

{ "otp": "12345678" }

8.3. Validar Cliente (Passo 2)

POST /delivery/confirm/:orderId/validate-customer Valida o código de 4 dígitos (customerOtp) e finaliza o pedido (COMPLETED).

Payload:

{ "otp": "1234" }

Para garantir a segurança da entrega, o sistema utiliza um fluxo de confirmação em duas etapas via página pública:

  1. URL de Confirmação: https://atomenta.loverde.com.br/delivery/confirm/:orderRealId
  2. Passo 1 (Motoboy): O entregador insere o confirmOtp (8 dígitos) visível no painel da loja.
  3. Passo 2 (Cliente): Após validar o código do motoboy, o sistema solicita o customerOtp (4 dígitos) que o cliente possui em seu app/notificação.
  4. Finalização: A validação bem-sucedida do segundo código altera o status do pedido para COMPLETED automaticamente.

Endpoints utilizados pela página pública (CORS habilitado para domínios parceiros):

  • POST /delivery/confirm/:orderId/validate-motoboy { "otp": "String(8)" }
  • POST /delivery/confirm/:orderId/validate-customer { "otp": "String(4)" }

🛒 Checkout e Criação de Pedido

10.0 Validar Endereço de Entrega (Checkout)

POST /api/store/:storeId/delivery/validate-address

Endpoint para validar cobertura de entrega no checkout, quando o cliente troca o endereço antes do pagamento.

Payload:

{
  "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:

  • KM: aprova somente até o limite da última faixa + 0.5 km de tolerância.
  • NEIGHBORHOOD: reprova se a cidade do endereço for diferente da cidade da loja.
  • NEIGHBORHOOD: aprova com bairro configurado ou com fallback de mesma cidade.

10. Criar Novo Pedido (Public)

POST /api/public/orders

Este endpoint é utilizado pelo front-end de checkout (Pedi Foods) para criar o pedido no sistema da loja.

Payload:

{
  "storeId": "store_123456",
  "userId": "user_guid_or_guest",
  "clientName": "João Silva",
  "clientPhone": "11999999999",
  "deliveryType": "DELIVERY", // ou "PICKUP"
  "address": {
    "street": "Rua das Flores",
    "number": "123",
    "neighborhood": "Centro",
    "city": "São Paulo",
    "state": "SP",
    "zip": "01000-000",
    "complement": "Apt 10",
    "lat": -23.55,
    "lng": -46.63
  },
  "paymentMethod": "PIX", // "CREDIT_CARD", "DEBIT_CARD", "CASH"
  "itemsTotal": 50.00,
  "deliveryFee": 5.00,
  "serviceFee": 0.00,
  "discount": 0.00,
  "total": 55.00,
  "items": [
    {
      "id": "prod_1",
      "name": "Pizza",
      "price": 50.00,
      "qty": 1,
      "image": "...",
      "addons": [
        {
          "addonId": "addon_bacon",
          "name": "Bacon",
          "price": 4.00,
          "qty": 2
        }
      ]
    }
  ]
}

Regras para items[].addons:

  • qty do adicional é suportado (ex.: 2x bacon/ovo).
  • Se qty não for enviado ou vier inválido, a API assume 1.
  • qty mínimo efetivo é 1.

Resposta Sucesso:

{
  "error": false,
  "result": {
    "id": "order_guid",
    "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 links de checkout/fatura do Asaas no response de criação de pedido.

10.1 Realtime de Status de Pedido (Socket.IO)

Para atualização em tempo real do checkout/app (sem depender de push), usar Socket.IO.

Socket endpoint:

  • ws://<host>:<port>/socket.io/ (usar wss:// em produção com TLS)

Auth no handshake:

  • Enviar JWT no campo auth.token.
  • Exemplo: Bearer <JWT_TOKEN>.

Evento para o cliente:

  • order_update

Payload típico do evento:

{
  "id": "order_guid",
  "shortId": "1234",
  "storeId": "store_123456",
  "userId": "user_guid",
  "status": "CONFIRMED",
  "paymentStatus": "CONFIRMED",
  "updatedAt": "2026-02-15T20:10:00.000Z"
}

10.2 Fallback de Status (Polling)

Caso não haja conexão socket, consultar status por HTTP até estado final.

Endpoint:

  • GET /api/public/orders/:orderId

Recomendação de intervalo:

  • 0-60s: 3s
  • 60-180s: 5s
  • acima de 180s: 10s
  • parar em status final (COMPLETED, CANCELED, REFUNDED).

11. Listar Lojas (Public App)

GET /api/public/stores

Endpoint utilizado pelo aplicativo Pedi Foods para listar todas as lojas disponíveis para o cliente.

Resposta Sucesso:

{
  "error": false,
  "result": [
    {
      "id": "company_guid",
      "storeId": "store_123456",
      "name": "Pizzaria do Arantes",
      "logo": "https://...",
      "cover": "https://...",
      "category": "Restaurante",
      "isOpen": true,
      "statusLabel": "Aberto Agora",
      "rating": 4.8,
      "deliveryTime": "30-45 min",
      "deliveryFee": 5.00
    }
  ]
}

📝 Gestão de Contratos (Store)

12. Verificar Status do Contrato

GET /api/store/:storeId/contract/status Retorna o ID e o status do contrato mais recente da loja.

Resposta Exemplo:

{
  "error": false,
  "result": {
    "id": "contract_guid",
    "status": "draft" // ou "signed"
  }
}

13. Assinar Contrato

POST /api/store/:storeId/contract/sign Assina o contrato draft atual da loja.

Payload:

{
  "method": "typed", 
  "typedName": "João Silva", // Obrigatório se method === "typed"
  "signatureDataUrl": "data:image/png;base64,..." // Obrigatório se method === "draw"
}

14. Visualizar PDF do Contrato

GET /api/store/contract/:contractId/pdf Retorna o stream do arquivo PDF do contrato (draft ou assinado).

Autor: Daniel Arantes Loverde