{
  "openapi": "3.1.0",
  "info": {
    "title": "API Devskin Marketplace",
    "version": "1.1.0",
    "summary": "Pedidos, estoque, webhooks e MCP do ERP Devskin Marketplace.",
    "description": "API pública do **Devskin Marketplace** (ERP para quem vende online). Com ela, um **site próprio** (loja feita sob medida, WooCommerce, etc.) manda os pedidos para o ERP e mantém o **estoque igual nos dois lados**; sistemas externos também podem **ler** pedidos, produtos e números da loja.\n\n## Visão geral\n\n| O que | Como |\n|---|---|\n| Endereço base | `https://api-marketplace.devskin.com/api` |\n| Formato | JSON (UTF-8) — envie `Content-Type: application/json` |\n| Autenticação | Header `X-API-Key` com a chave da loja (rotas do painel: `Authorization: Bearer <JWT>`) |\n| Versão | `v1` (no caminho: `/api/v1/...`) |\n\nA API tem quatro partes:\n\n- **Site próprio** (`/v1/store/...`) — o site **envia pedidos** (criar e atualizar status) e **lê/acerta o estoque** por SKU. Os pedidos entram no ERP no canal \"site próprio\", junto com os do Mercado Livre, Shopee, Amazon e TikTok Shop — prontos para nota fiscal e etiqueta, com baixa de estoque.\n- **Leitura** (`/v1/orders`, `/v1/products`, `/v1/revenue`, ...) — consultas somente leitura para relatórios e integrações.\n- **Automações e blog** (`/v1/store/me`, `/v1/store/orders/{id}`, `/v1/store/customers/tags`, `/v1/store/notifications/email`, `/v1/store/webhooks`, `/v1/store/blog/...`) — para sistemas como o **Devskin Marketing** agirem na loja e publicarem no blog, só com a chave.\n- **Financeiro** (`/v1/store/finance/...`) — cobranças com Pix/boleto/cartão, inadimplentes, contas a pagar, extrato e conciliação, centros de custo, impostos estimados por regime, notas de serviço (NFS-e) e o pacote do mês para o contador.\n- **Painel** (`/stores/{storeId}/...`) — gestão de chaves e webhooks por automação, com o login do painel (token JWT).\n\nQuando o estoque muda por outro motivo (venda em outro canal, cancelamento, ajuste no painel), o ERP **avisa o seu site** com o webhook `stock.updated`. E dá para **conectar uma IA** (Claude, Cursor...) à loja pelo servidor **MCP** — veja a seção *Conectar uma IA (MCP)*.\n\nToda resposta segue o mesmo formato:\n\n```json\n{ \"success\": true, \"data\": { \"...\": \"...\" } }\n```\n\n```json\n{ \"success\": false, \"message\": \"Explicação do erro\" }\n```\n\n## Criar sua chave de API\n\n**Pelo painel (o jeito mais simples):**\n\n1. Entre no painel em [admin-marketplace.devskin.com](https://admin-marketplace.devskin.com/login).\n2. No menu, abra **Canais de venda › Meu site** (tela *Conectar meu site*).\n3. Toque em **Criar chave**. A chave completa (`dsk_` + 64 caracteres) aparece **uma única vez** — copie e guarde num lugar seguro (por exemplo, numa variável de ambiente do servidor do seu site).\n4. Pronto: use a chave no header `X-API-Key`. Depois da primeira chamada, a tela mostra **\"Seu site está conectado\"**.\n5. Quer mandar tudo para quem cuida do site? Toque em **Copiar tudo para mandar ao programador** — o texto já vem com a chave, exemplos e o link desta documentação.\n\nTocar em **Criar chave nova** desliga a chave anterior na hora (o site precisa passar a usar a nova).\n\nA chave de *Meu site* vem com os escopos `orders:write`, `inventory`, `orders`, `products` e `mcp:read`.\n\n**Chaves com outros escopos:** em **Configurações › API Keys** (planos com acesso à API) você cria chaves com nome, escopos e validade. Pelo painel elas saem com acesso total (`*`). A mesma gestão existe por API em `/stores/{storeId}/api-keys` (seção *Painel — Chaves de API*), onde dá para escolher os escopos.\n\n| Escopo | Libera |\n|---|---|\n| `orders:write` | `POST /v1/store/orders` |\n| `inventory` | `GET /v1/store/inventory`, `PUT /v1/store/inventory/{sku}` |\n| `orders` | `GET /v1/orders`, `GET /v1/orders/{id}` |\n| `products` | `GET /v1/products` |\n| `revenue` | `GET /v1/revenue` |\n| `customers` | `GET /v1/customers` |\n| `analytics` | `GET /v1/analytics/overview` |\n| `mcp` ou `mcp:read` | ferramentas de **leitura** do MCP |\n| `mcp:write` | ferramentas de leitura **e** de ação do MCP |\n| `orders:write` (automações) | também `PATCH /v1/store/orders/{id}` e `POST /v1/store/orders/{id}/notes` |\n| `customers:write` | `POST /v1/store/customers/tags` (e leitura das etiquetas) |\n| `notifications:write` | `POST /v1/store/notifications/email` |\n| `webhooks:write` | `/v1/store/webhooks` (a integração cadastra o próprio webhook) |\n| `blog:read` | `GET /v1/store/blog/...` |\n| `blog:write` | criar/atualizar posts em `/v1/store/blog/posts` (e ler) |\n| `finance` | leitura do financeiro em `/v1/store/finance/...` (cobranças, contas, extrato, impostos, centros de custo, NFS-e, pacote contábil) |\n| `finance:write` | criar/alterar no financeiro (cobrar, dar baixa, lançar conta, conciliar, emitir/cancelar NFS-e) |\n| `*` | tudo acima |\n\n## Autenticação\n\nEnvie a chave em **todas** as chamadas, no header `X-API-Key`:\n\n```bash\ncurl https://api-marketplace.devskin.com/api/v1/store/inventory?sku=KIT-01 \\\n  -H \"X-API-Key: dsk_sua_chave_aqui\"\n```\n\n| Situação | Status | `message` |\n|---|---|---|\n| Header ausente | `401` | `API key required. Use X-API-Key header.` |\n| Chave errada ou desligada | `401` | `Invalid or revoked API key` |\n| Chave vencida | `401` | `API key expired` |\n| Chave sem o escopo da rota | `403` | `API key does not have the '<escopo>' scope` |\n\nA chave dá acesso aos dados da loja: use **somente no servidor**, nunca no JavaScript do navegador nem em aplicativo.\n\n**Testar nesta página:** clique em qualquer rota, toque em **Test Request**, cole a chave no campo `X-API-Key` (fica salva neste navegador) e envie. As chamadas vão para a produção, com os dados reais da sua loja.\n\n**Rotas do painel** (`/stores/{storeId}/...`) usam o login da pessoa, não a chave: faça `POST /auth/login` com e-mail e senha, pegue `data.token` e envie `Authorization: Bearer <token>` (vale 30 dias). Servem para automação e para o próprio painel; o `storeId` aparece em `data.stores[].id` na resposta do login.\n\n## Fluxo recomendado para um site próprio\n\n1. **Mesmo SKU nos dois lados.** O ERP liga cada item do pedido ao produto pelo **SKU** (primeiro o SKU da variação, depois o do produto). Item com SKU que não existe no ERP entra no pedido em `unmapped_items` e **não baixa estoque**.\n2. **Envie o pedido a cada criação e a cada mudança de status** com `POST /v1/store/orders`, sempre com o **mesmo `id`** (o número/id do pedido no seu site). O primeiro envio cria o pedido e baixa o estoque; os próximos só atualizam o status.\n3. **Receba o webhook `stock.updated`** no endereço cadastrado e atualize o estoque do SKU no seu site para o valor de `data.stock` (é o estoque final, não a diferença).\n4. **Confira o estoque** de tempos em tempos com `GET /v1/store/inventory` (ex.: uma vez por dia), porque um aviso pode falhar e alterações feitas direto no cadastro do produto no painel não geram aviso.\n5. Se o **seu site** for a fonte da verdade numa contagem de estoque, mande a quantidade exata com `PUT /v1/store/inventory/{sku}`. Esse acerto **não** gera webhook de volta para o seu site, mas é repassado aos marketplaces ligados ao produto.\n\nVendas feitas pelo próprio site (pedido enviado pela API) e acertos feitos pela API **não** disparam `stock.updated` para o site — assim não há eco.\n\n## Idempotência\n\n- O pedido é identificado pelo par **loja + `id` enviado**. Reenviar o mesmo `id` **não duplica**: atualiza o pedido existente. Pode repetir a chamada com segurança se der erro de rede ou tempo esgotado.\n- Ao **atualizar**, o ERP só muda **status do pedido**, **status do pagamento** e completa dados do comprador que estavam vazios. **Itens, valores e endereço não são alterados** depois da criação.\n- O número do pedido no ERP é `SP-<código da loja>-<id>` (ex.: `SP-8E2B4C-1001`). Use `id` com no máximo **40 caracteres** (acima disso a API responde 400).\n- A resposta é sempre `201` — tanto ao criar quanto ao atualizar.\n- `PUT /v1/store/inventory/{sku}` também é idempotente: define a quantidade exata.\n\n## Status aceitos\n\nO campo `status` aceita português ou inglês (sem diferença de maiúsculas). Valor não reconhecido ou ausente vale como `pendente`.\n\n| Você envia | Status do pedido | Pagamento |\n|---|---|---|\n| `pendente`, `pending`, `aguardando_pagamento` | `pending` | `pending` |\n| `pago`, `paid`, `aprovado`, `processing` | `processing` | `paid` |\n| `enviado`, `shipped` | `shipped` | `paid` |\n| `entregue`, `delivered` | `delivered` | `paid` |\n| `cancelado`, `cancelled`, `canceled` | `cancelled` | (não muda) |\n| `reembolsado`, `refunded` | `refunded` | `refunded` |\n\nRegras ao atualizar:\n\n- O status **só avança**: `pending` → `processing` → `shipped` → `delivered`. Enviar um status \"anterior\" é ignorado (sem erro).\n- `cancelled` e `refunded` são **finais**: depois deles nada muda.\n- Ao cancelar/reembolsar um pedido que já existia, o estoque que ele baixou **volta** automaticamente (uma única vez).\n- Pagamento `paid` não volta para `pending`; `refunded` é final.\n- Pedido que **já chega** cancelado/reembolsado no primeiro envio é criado sem baixar estoque.\n\n## Configurar webhooks\n\nWebhook é um aviso que o ERP manda para o **seu servidor** (um `POST` JSON num endereço https seu) quando algo acontece na loja.\n\n**Aviso de estoque para o site (pelo painel):**\n\n1. No seu site, crie um endereço que aceite `POST` (ex.: `https://seusite.com/webhooks/estoque`) e confira a assinatura (exemplos abaixo).\n2. No painel, abra **Canais de venda › Meu site**, passo 3, cole o endereço e toque em **Salvar endereço** (precisa começar com `https://`).\n3. Copie o **segredo da assinatura** que aparece — ele só é mostrado nesse momento.\n4. Esse cadastro recebe só o evento `stock.updated`. Se o endereço falhar, a tela mostra quantas falhas houve; salvar de novo religa e zera o contador.\n\n**Outros eventos (pedidos, pagamentos, carrinho...):** em **Configurações › Webhooks** (planos com webhooks) cadastre um endereço e marque os eventos. Lá também dá para **testar**, ver as **entregas** e **reenviar**. A mesma gestão existe por API em `/stores/{storeId}/webhooks-config` (seção *Painel — Webhooks*).\n\n**Catálogo de eventos** (detalhes e exemplo de cada um na seção *Webhooks* desta página):\n\n| Evento | Quando acontece |\n|---|---|\n| `stock.updated` | O estoque de um produto/variação mudou (venda no site Devskin ou em marketplace, cancelamento, ajuste no estoque do painel). Não dispara para mudanças vindas do seu site pela API. |\n| `order.created` | Pedido criado no checkout da loja Devskin. |\n| `order.pending`, `order.processing`, `order.shipped`, `order.delivered`, `order.cancelled` | Status do pedido mudado no painel (ou pela IA via MCP). |\n| `order.shipped` | Também quando o pedido é marcado como enviado com código de rastreio. |\n| `order.cancelled` | Também quando o próprio cliente cancela o pedido. |\n| `order.refunded` | Reembolso feito no painel. |\n| `payment.confirmed` | Pagamento aprovado (cartão/Stripe ou Pix/OpenPix). |\n| `payment.failed` | Pagamento recusado. |\n| `payment.refunded` | Pagamento estornado no Stripe. |\n| `shipping.updated` | A etiqueta do Melhor Envio mudou de situação (postado, entregue...). |\n| `cart.abandoned` | Carrinho parado há mais de 1 hora (verificado a cada 30 minutos). |\n| `test` | Botão **Testar** do painel. |\n\nUm cadastro com o evento `*` recebe todos. Pedidos que chegam de marketplaces ou do seu site pela API **não** disparam `order.created`.\n\nCabeçalhos enviados:\n\n| Header | Valor |\n|---|---|\n| `Content-Type` | `application/json` |\n| `X-Webhook-Event` | nome do evento, ex.: `stock.updated` |\n| `X-Webhook-Signature` | `sha256=` + HMAC-SHA256 (hex) do corpo, com o segredo |\n| `X-Webhook-Delivery` | id único do evento (igual em todas as tentativas; também em `delivery_id` no corpo) |\n| `User-Agent` | `Devskin-Webhook/1.0` |\n\nCorpo (envelope igual para todos os eventos — muda só `data`):\n\n```json\n{\n  \"event\": \"stock.updated\",\n  \"data\": {\n    \"product_id\": \"6f1c2a9e-1d2b-4c3d-9e8f-0a1b2c3d4e5f\",\n    \"variant_id\": null,\n    \"sku\": \"KIT-01\",\n    \"stock\": 24,\n    \"delta\": -1,\n    \"reason\": \"venda_canal\"\n  },\n  \"timestamp\": \"2026-10-18T14:03:12.481Z\",\n  \"webhook_id\": \"0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d\"\n}\n```\n\n`webhook_id` é o id do **cadastro** do webhook (o mesmo em todos os envios), não um id único do evento. O corpo também traz `store_id` (a loja) e `delivery_id` (id único do evento, para ignorar repetição). Quando o evento tem pedido ou cliente, `data` vem completado com `customer` (nome, e-mail, telefone), `order` (número, status, total, rastreio) e `store` (nome e site) — só os campos que faltavam.\n\n**Entrega e novas tentativas**\n\n- Responda com qualquer status **2xx** em até **10 segundos**. Outro status, erro de conexão ou demora contam como falha.\n- Em caso de falha, o ERP tenta de novo **mais 2 vezes** (após ~2 s e ~4 s) — no máximo 3 tentativas por evento.\n- Cada tentativa que falha soma 1 no contador de falhas do endereço. Com **10 falhas seguidas** o webhook é **desligado**. Uma entrega com sucesso zera o contador. Para religar: em *Meu site*, salve o endereço de novo; nos demais, ative em *Configurações › Webhooks* (ou `PUT /stores/{storeId}/webhooks-config/{id}` com `is_active: true`).\n- Não há garantia de ordem entre eventos. Como `stock` é o valor final, aplique sempre o aviso mais recente (compare `timestamp`) e confira com `GET /v1/store/inventory` em caso de dúvida.\n- Responda rápido (ex.: grave numa fila) e processe depois.\n\n### Verificar a assinatura\n\nCalcule o HMAC-SHA256 do **corpo bruto** (exatamente os bytes recebidos, antes de converter o JSON) usando o **segredo** como chave (o texto do segredo, do jeito que aparece no painel), em hexadecimal, com o prefixo `sha256=`. Compare com o header `X-Webhook-Signature` usando comparação de tempo constante. Recuse (`401`) se não bater.\n\n**Node.js (Express)**\n\n```javascript\nconst crypto = require('crypto');\nconst express = require('express');\nconst app = express();\nconst SECRET = process.env.DEVSKIN_WEBHOOK_SECRET;\n\n// express.raw: precisamos do corpo bruto para conferir a assinatura\napp.post('/webhooks/estoque', express.raw({ type: 'application/json' }), (req, res) => {\n  const received = String(req.get('X-Webhook-Signature') || '');\n  const expected = 'sha256=' + crypto.createHmac('sha256', SECRET).update(req.body).digest('hex');\n  const ok = received.length === expected.length &&\n    crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));\n  if (!ok) return res.status(401).send('assinatura inválida');\n\n  const { event, data } = JSON.parse(req.body.toString('utf8'));\n  if (event === 'stock.updated') {\n    // atualize o estoque do SKU data.sku para data.stock no seu site\n  }\n  res.sendStatus(200);\n});\n```\n\n**PHP**\n\n```php\n<?php\n$secret = getenv('DEVSKIN_WEBHOOK_SECRET');\n$body = file_get_contents('php://input'); // corpo bruto\n$received = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';\n$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);\n\nif (!hash_equals($expected, $received)) {\n    http_response_code(401);\n    exit('assinatura inválida');\n}\n\n$payload = json_decode($body, true);\nif ($payload['event'] === 'stock.updated') {\n    $sku = $payload['data']['sku'];\n    $stock = (int) $payload['data']['stock'];\n    // atualize o estoque do $sku para $stock no seu site\n}\nhttp_response_code(200);\n```\n\n**Python (Flask)**\n\n```python\nimport hmac, hashlib, os\nfrom flask import Flask, request, abort\n\napp = Flask(__name__)\nSECRET = os.environ[\"DEVSKIN_WEBHOOK_SECRET\"].encode()\n\n@app.post(\"/webhooks/estoque\")\ndef estoque():\n    body = request.get_data()  # corpo bruto (bytes)\n    expected = \"sha256=\" + hmac.new(SECRET, body, hashlib.sha256).hexdigest()\n    received = request.headers.get(\"X-Webhook-Signature\", \"\")\n    if not hmac.compare_digest(expected, received):\n        abort(401)\n    payload = request.get_json()\n    if payload[\"event\"] == \"stock.updated\":\n        sku, stock = payload[\"data\"][\"sku\"], int(payload[\"data\"][\"stock\"])\n        # atualize o estoque do sku para stock no seu site\n    return \"\", 200\n```\n\nA assinatura não inclui data/hora: para se proteger de reenvio malicioso de um aviso antigo, ignore avisos com `timestamp` muito antigo (ex.: mais de 5 minutos) ou já aplicados.\n\n## Limites e boas práticas\n\n- **Tamanho do corpo:** até 10 MB por requisição.\n- **Listagens:** `GET /v1/orders` e `GET /v1/products` usam `page` e `limit` (máximo **100** por página). `GET /v1/store/inventory` sem `sku` devolve até **1000** linhas, sem paginação.\n- **Ritmo:** não há limite rígido por chave hoje, mas mande um pedido por vez, evite laços apertados e use espera crescente (1 s, 2 s, 4 s...) ao repetir depois de erro `5xx` ou falha de rede.\n- **Repetir é seguro:** o envio de pedido e o acerto de estoque são idempotentes.\n- **Rastreio:** toda resposta traz o header `X-Request-ID`. Você pode mandar o seu (até 64 caracteres: letras, números, `-` e `_`) e ele volta igual — informe esse valor ao suporte se algo der errado.\n- **Valores:** use ponto como separador decimal (`89.90`). Moeda padrão `BRL`.\n- **Datas:** ISO 8601, ex.: `2026-10-18T14:03:12-03:00`.\n- **Segurança:** guarde chave e segredo em variáveis de ambiente; troque a chave se ela vazar (criar uma nova desliga a antiga); aceite webhook só com assinatura válida e via https.\n\n## Changelog\n\n**v1.2 — novembro de 2026 (financeiro completo)**\n\n- Financeiro por chave: `/v1/store/finance/receivables`, `/overdue`, `/payables`, `/transactions`, `/cost-centers`, `/taxes`, `/accounting/package`, `/service-invoices`.\n- Novos escopos: `finance` e `finance:write`.\n- MCP: ferramentas do financeiro (leitura e ação).\n\n**v1.1 — outubro de 2026 (integração com o Devskin Marketing)**\n\n- `GET /v1/store/me`: de qual loja é a chave.\n- Automações: `PATCH /v1/store/orders/{id}`, `POST /v1/store/orders/{id}/notes`, `POST|GET /v1/store/customers/tags`, `POST /v1/store/notifications/email`.\n- Webhooks pela própria chave: `GET|POST /v1/store/webhooks`, `PUT|DELETE /v1/store/webhooks/{id}`, `POST /v1/store/webhooks/{id}/test`.\n- Blog da loja: `GET /v1/store/blog/categories`, `GET|POST /v1/store/blog/posts`, `GET|PUT /v1/store/blog/posts/{id}` (idempotente por `external_id`).\n- Novos escopos: `customers:write`, `notifications:write`, `webhooks:write`, `blog:read`, `blog:write`.\n- Webhooks: corpo ganhou `store_id` e `delivery_id` (header `X-Webhook-Delivery`, igual em todas as tentativas); `data` vem completado com `customer`, `order` e `store` quando faltam; `cart.abandoned` traz `cart_url`.\n\n**v1 — outubro de 2026**\n\n- API do site próprio: `POST /v1/store/orders`, `GET /v1/store/inventory`, `PUT /v1/store/inventory/{sku}`.\n- Webhook `stock.updated` com assinatura HMAC-SHA256, configurado na tela *Conectar meu site*.\n- Rotas de leitura: pedidos, produtos, faturamento, clientes e visão geral.\n- Servidor MCP (`POST /mcp/rpc`) aceita a chave da loja (`dsk_...`) com escopos `mcp:read` / `mcp:write`.\n- Gestão de chaves e webhooks por API (rotas do painel).\n- Esta documentação (OpenAPI 3.1) — baixe o arquivo em [openapi.json](./openapi.json).\n",
    "contact": {
      "name": "Devskin Marketplace",
      "url": "https://marketplace.devskin.com/contact.html"
    },
    "termsOfService": "https://marketplace.devskin.com/terms.html"
  },
  "servers": [
    {
      "url": "https://api-marketplace.devskin.com/api",
      "description": "Produção"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "tags": [
    {
      "name": "Site próprio — Pedidos",
      "description": "O seu site envia pedidos para o ERP. Escopo `orders:write`."
    },
    {
      "name": "Site próprio — Estoque",
      "description": "Ler e acertar estoque por SKU. Escopo `inventory`."
    },
    {
      "name": "Leitura",
      "description": "Consultas somente leitura (escopos `orders`, `products`, `revenue`, `customers`, `analytics`)."
    },
    {
      "name": "Conectar uma IA (MCP)",
      "description": "**MCP** (Model Context Protocol) é o padrão aberto que deixa um assistente de IA — Claude, Cursor, ChatGPT e outros — usar ferramentas de sistemas externos. Ligando a sua loja por MCP, você pergunta em português \"quanto vendi este mês?\", \"quais produtos estão acabando?\" ou \"marca o pedido X como enviado\" e a IA consulta (ou age) direto no ERP, com os dados reais da loja.\n\n**Endereço do servidor:** `https://api-marketplace.devskin.com/api/mcp/rpc` — JSON-RPC 2.0 sobre HTTP (*MCP Streamable HTTP*, só `POST`; `GET` responde `405`).\n\n### 1. Criar uma chave com acesso ao MCP\n\n1. **Só leitura (recomendado para começar):** a chave de **Canais de venda › Meu site** já vem com o escopo `mcp:read`. Toque em **Criar chave** e copie.\n2. **Leitura e ações** (criar produto, mudar status de pedido): crie uma chave em **Configurações › API Keys** (acesso total `*`) ou pela API `POST /stores/{storeId}/api-keys` com `\"scopes\": [\"mcp:write\"]`.\n3. Guarde a chave: ela aparece uma única vez.\n\nEnvie a chave em `Authorization: Bearer dsk_...` **ou** em `X-API-Key: dsk_...`. A loja é a da chave (não precisa de `x-store-id`) e as ações são feitas em nome do dono da loja.\n\n| Escopo da chave | O que a IA pode fazer |\n|---|---|\n| `mcp` ou `mcp:read` | Ferramentas de leitura |\n| `mcp:write` | Leitura + ferramentas de ação (`create_product`, `update_order_status`, `get_store_link`) |\n| `*` | Tudo |\n\n### 2. Ligar no seu assistente\n\n**Claude Desktop** — em *Configurações › Desenvolvedor › Editar configuração*, no arquivo `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"devskin-marketplace\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"-y\", \"mcp-remote\",\n        \"https://api-marketplace.devskin.com/api/mcp/rpc\",\n        \"--header\", \"Authorization: Bearer ${DEVSKIN_KEY}\"\n      ],\n      \"env\": { \"DEVSKIN_KEY\": \"dsk_sua_chave_aqui\" }\n    }\n  }\n}\n```\n\nFeche e abra o Claude Desktop de novo. (Precisa do Node.js instalado para o `npx`.)\n\n**Claude Code** — no terminal:\n\n```bash\nclaude mcp add --transport http devskin-marketplace \\\n  https://api-marketplace.devskin.com/api/mcp/rpc \\\n  --header \"Authorization: Bearer dsk_sua_chave_aqui\"\n```\n\n**Cursor** — em `~/.cursor/mcp.json` (ou `.cursor/mcp.json` no projeto):\n\n```json\n{\n  \"mcpServers\": {\n    \"devskin-marketplace\": {\n      \"url\": \"https://api-marketplace.devskin.com/api/mcp/rpc\",\n      \"headers\": { \"Authorization\": \"Bearer dsk_sua_chave_aqui\" }\n    }\n  }\n}\n```\n\nDepois é só conversar: \"liste meus pedidos pendentes\", \"quais produtos estão com estoque baixo?\".\n\n### 3. Ferramentas disponíveis\n\nFerramentas de **leitura** (escopo `mcp`, `mcp:read`, `mcp:write` ou `*`):\n\n| Ferramenta | O que faz | Argumentos |\n|---|---|---|\n| `get_store_overview` | Resumo da loja: produtos, pedidos pagos, faturamento, avaliações, cursos, clientes | — |\n| `list_products` | Até 25 produtos com preço, estoque, status, categoria, tipo e vendas | `status` (`active`, `draft`, `archived`), `type` (`physical`, `digital`, `course`, `service`) — opcionais |\n| `get_product_details` | Produto completo: variações, imagens, avaliações, vendas, estoque | `product_id` (obrigatório) |\n| `list_orders` | Até 25 pedidos mais recentes com status, total, cliente e pagamento | `status` (`pending`, `processing`, `shipped`, `delivered`, `cancelled`, `refunded`) — opcional |\n| `get_order_details` | Pedido completo: itens, entrega, pagamento, cliente | `order_id` (obrigatório) |\n| `get_sales_analytics` | Faturamento, nº de pedidos, ticket médio, produtos mais vendidos, por status | `period` (`today`, `week`, `month`, `year`; padrão `month`) |\n| `list_reviews` | Avaliações com nota, cliente e respostas | `rating` (nota mínima 1–5) — opcional |\n| `list_customers` | Clientes com nº de pedidos e total gasto | — |\n| `list_courses` | Cursos com matrículas, módulos e aulas | — |\n| `get_course_details` | Curso com módulos, aulas e matrículas | `course_id` (obrigatório) |\n| `list_blog_posts` | Posts do blog com status, visualizações e categoria | — |\n| `list_coupons` | Cupons com uso e validade | — |\n| `list_categories` | Categorias com quantidade de produtos | — |\n| `get_inventory_alerts` | Produtos com estoque baixo, zerado ou em excesso | — |\n| `list_affiliates` | Afiliados com comissões e indicações | — |\n| `get_abandoned_carts` | Carrinhos abandonados com valor e cliente | — |\n| `finance_overview` | Saldos das contas conectadas, cobranças vencidas, contas a pagar e extrato a conciliar | — |\n| `list_receivables` | Cobranças com valor de hoje e link de pagamento | `status` (`pendentes`, `vencida`, `a_vencer`, `paga`, `cancelada`, `todas`), `search` |\n| `list_overdue_customers` | Inadimplentes por cliente, faixa de atraso, promessa e link do WhatsApp | `bucket` (`1-15`, `16-30`, `31-60`, `61-90`, `90+`) |\n| `list_payables` | Contas a pagar | `status` (`pendentes`, `vencida`, `paga`, `todas`), `month` (AAAA-MM) |\n| `list_bank_transactions` | Lançamentos do extrato e sugestões de conciliação | `status` (`pendente`, `sugestao`, `conciliada`, `ignorada`), `from`, `to` |\n| `tax_estimate` | Impostos estimados do mês pelo regime (regras de 2026 e 2027) | `month` |\n| `list_tax_guides` | Guias de impostos do mês: estimado, guia, vencimento, pago | `month` |\n| `list_employees` | Funcionários | `status`, `search` |\n| `payroll_month` | Folha do mês por funcionário | `month` |\n| `payroll_simulate` | Simula líquido e custo de um salário | `base_salary`; `dependents`, `inputs` |\n| `cash_flow_forecast` | Fluxo de caixa projetado | `days`, `group` |\n| `trial_balance` | Balancete e DRE do mês | `month` |\n| `payables_waiting_approval` | Contas esperando aprovação | — |\n| `cost_center_report` | Resultado por centro de custo | `from`, `to` |\n| `list_service_invoices` | Notas de serviço (NFS-e) | `month`, `status` |\n| `accounting_summary` | Resumo contábil do mês | `month` |\n| `year_end_summary` | Fechamento do ano: resultado, lucro distribuível, sócios e obrigações | `year` |\n| `list_partners` | Sócios da empresa | — |\n| `franchise_overview` | Painel da rede de franquias | `month` |\n| `list_franchise_units` | Unidades franqueadas | `status`, `search` |\n\nFerramentas de **ação** (escopo `mcp:write` ou `*`):\n\n| Ferramenta | O que faz | Argumentos |\n|---|---|---|\n| `create_product` | Cria um produto como **rascunho** (você revisa e publica no painel). Respeita o limite de produtos do plano | `name` e `price` (reais) obrigatórios; `description`, `stock` (padrão 0), `type` (`physical`, `digital`, `service`; padrão `physical`) |\n| `update_order_status` | Muda o status de um pedido (mesmas regras do painel; dispara o webhook `order.<status>`) | `order_id`, `status` (`processing`, `shipped`, `delivered`, `cancelled`) obrigatórios; `notes` |\n| `get_store_link` | Link público da loja para mandar aos clientes (só lê, mas exige `mcp:write`) | — |\n| `create_receivable` | Cria cobrança com link de Pix/boleto/cartão | `customer_name`, `description`, `amount`, `due_date` obrigatórios; `customer_email`, `customer_phone`, `customer_document`, `methods`, `cost_center_id` |\n| `mark_receivable_paid` | Dá baixa numa cobrança recebida por fora | `receivable_id`; `amount`, `paid_at`, `method` |\n| `create_payable` | Lança conta a pagar (ou já paga) | `description`, `amount`; `due_date`, `category`, `paid`, `cost_center_id` |\n| `emit_service_invoice` | Emite a NFS-e de uma cobrança | `receivable_id` |\n| `record_partner_movement` | Lança pró-labore, lucros, aporte ou empréstimo de sócio (IR de lucros calculado) | `partner_id`, `kind`, `amount`; `date`, `reference_year` |\n| `declare_franchise_revenue` | Lança o faturamento do mês de uma unidade e gera a cobrança de royalties/fundo | `unit_id`, `month`, `revenue` |\n| `generate_tax_guides` | Gera as guias de impostos do mês (viram contas a pagar) | `month` |\n| `confirm_reconciliation_suggestions` | Confirma as sugestões fortes de conciliação | — |\n\nFiltros de `status`, `type` e `period` fora da lista são ignorados. A resposta de cada ferramenta é um texto (JSON) de até 8.000 caracteres.\n\n### 4. Testar com curl\n\n`initialize` e `tools/list` não exigem chave; `tools/call` exige.\n\n```bash\n# 1) handshake\ncurl -s https://api-marketplace.devskin.com/api/mcp/rpc \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-06-18\"}}'\n\n# 2) listar as ferramentas\ncurl -s https://api-marketplace.devskin.com/api/mcp/rpc \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/list\"}'\n\n# 3) chamar uma ferramenta\ncurl -s https://api-marketplace.devskin.com/api/mcp/rpc \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Authorization: Bearer dsk_sua_chave_aqui\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"tools/call\",\"params\":{\"name\":\"list_orders\",\"arguments\":{\"status\":\"pending\"}}}'\n```\n\nErros JSON-RPC:\n\n| `error.code` | HTTP | Quando |\n|---|---|---|\n| `-32601` | 200 | Método não suportado (aceitos: `initialize`, `ping`, `tools/list`, `tools/call`, `notifications/*`) |\n| `-32001` | 401 | `Não autorizado` — chave ausente, errada, desligada ou vencida |\n| `-32602` | 200 | `Ferramenta não encontrada` |\n| `-32003` | 403 | A chave não tem o escopo da ferramenta |\n| `-32603` | 500 | `Erro interno` |\n\nSe a ferramenta falhar (ex.: pedido não encontrado ao mudar status), a resposta é `200` com `result.isError: true` e o motivo em `result.content[0].text`.\n"
    },
    {
      "name": "Painel — Login",
      "description": "Login do painel para usar as rotas de gestão (`Authorization: Bearer <JWT>`)."
    },
    {
      "name": "Painel — Chaves de API",
      "description": "Gestão de chaves por automação. Login do painel (JWT) + plano com acesso à API."
    },
    {
      "name": "Painel — Webhooks",
      "description": "Gestão de webhooks por automação. Login do painel (JWT) + plano com webhooks. Formato da entrega e verificação da assinatura em *Configurar webhooks*."
    },
    {
      "name": "Painel — Meu site",
      "description": "O que a tela *Canais de venda › Meu site* faz, por API. Login do painel (JWT); não depende do plano."
    },
    {
      "name": "Webhooks",
      "description": "Eventos que o ERP envia para o seu servidor."
    },
    {
      "name": "Automações — Pedidos e clientes",
      "description": "Para sistemas de automação (ex.: fluxos do **Devskin Marketing**) agirem na loja da chave: descobrir a loja (`/v1/store/me`), mudar status e rastreio, anotar no pedido, etiquetar cliente e mandar e-mail ao comprador pelo e-mail da loja. Escopos `orders:write`, `customers:write`, `notifications:write`."
    },
    {
      "name": "Automações — Webhooks por chave",
      "description": "A própria integração cadastra o webhook dela, só com a chave (sem login do painel). Escopo `webhooks:write`. Precisa do recurso de webhooks no plano."
    },
    {
      "name": "Blog da loja",
      "description": "Criar, atualizar e ler os posts do blog da loja (`<site>/blog`). Escopos `blog:read` e `blog:write`. Use `external_id` para publicar de novo sem duplicar."
    },
    {
      "name": "Financeiro — Cobranças e contas",
      "description": "Cobranças (contas a receber) com link de Pix, boleto e cartão, inadimplentes e contas a pagar. Escopos `finance` (ler) e `finance:write`."
    },
    {
      "name": "Financeiro — Clientes",
      "description": "Carteira de clientes do financeiro: ficha PF/PJ com contatos, etiquetas, condições padrão (forma de cobrança, vencimento, multa/juros, centro de custo, NFS-e), limite de crédito, situação (arquivar não apaga), mescla de fichas repetidas, importação por CSV e posição financeira com links de pagamento."
    },
    {
      "name": "Financeiro — Contratos e assinatura",
      "description": "Contratos de clientes: o sistema gera e mantém as parcelas (cada parcela é uma cobrança normal, com link Pix/boleto/cartão, lembretes e NFS-e ao pagar). Modelos parcelado, recorrente (com antecedência) e avulso; multa, juros pró-rata, carência e desconto por pontualidade; aditivo e reajuste só nas parcelas futuras ainda não enviadas; acordo das atrasadas; ficha do cliente (PF ou empresa, com contatos); assinatura digital pelo Devskin Sign — as cobranças só são criadas quando todos assinam."
    },
    {
      "name": "Financeiro — Extrato e conciliação",
      "description": "Lançamentos do extrato das contas conectadas (Asaas, Stripe e banco por OFX/CSV) e a conciliação com cobranças e contas."
    },
    {
      "name": "Financeiro — Notas de serviço (NFS-e)",
      "description": "Nota fiscal de serviço: Barueri (webservice da prefeitura) ou Emissor Nacional (gov.br/nfse), escolhido pela cidade e pelo regime da empresa."
    },
    {
      "name": "Financeiro — Impostos, centros de custo e contábil",
      "description": "Estimativa de impostos por regime (MEI, Simples, Presumido, Real; regras de 2026 e 2027), centros de custo e o pacote do mês para o contador (ZIP com XMLs e planilhas)."
    },
    {
      "name": "Financeiro — Franquias",
      "description": "Para franqueadores: unidades, contratos (vigência e COF), royalties, fundo de propaganda e taxas, faturamento declarado por unidade e cobranças geradas automaticamente."
    },
    {
      "name": "Financeiro — Funcionários e folha",
      "description": "Funcionários e folha do mês: horas extras, DSR, adicional noturno, INSS/IRRF (tabelas 2026), VT, FGTS e encargos por regime. Fechar a folha gera as contas a pagar (salários, FGTS, DCTFWeb)."
    },
    {
      "name": "Financeiro — Projetos & Equipe",
      "description": "Alocação mensal de colaboradores por projeto (centro de custo): meses, alocações, fechar o mês (gera contas a pagar e cobranças), resultado por projeto/cliente/pessoa e histórico. Escopos `finance` (ler) e `finance:write`."
    }
  ],
  "x-tagGroups": [
    {
      "name": "Site próprio",
      "tags": [
        "Site próprio — Pedidos",
        "Site próprio — Estoque"
      ]
    },
    {
      "name": "Leitura",
      "tags": [
        "Leitura"
      ]
    },
    {
      "name": "Financeiro",
      "tags": [
        "Financeiro — Cobranças e contas",
        "Financeiro — Extrato e conciliação",
        "Financeiro — Notas de serviço (NFS-e)",
        "Financeiro — Impostos, centros de custo e contábil",
        "Financeiro — Franquias",
        "Financeiro — Funcionários e folha"
      ]
    },
    {
      "name": "Automações e blog",
      "tags": [
        "Automações — Pedidos e clientes",
        "Automações — Webhooks por chave",
        "Blog da loja"
      ]
    },
    {
      "name": "IA",
      "tags": [
        "Conectar uma IA (MCP)"
      ]
    },
    {
      "name": "Painel (gestão)",
      "tags": [
        "Painel — Login",
        "Painel — Chaves de API",
        "Painel — Webhooks",
        "Painel — Meu site"
      ]
    },
    {
      "name": "Webhooks",
      "tags": [
        "Webhooks"
      ]
    }
  ],
  "paths": {
    "/v1/store/orders": {
      "post": {
        "tags": [
          "Site próprio — Pedidos"
        ],
        "operationId": "enviarPedidoSite",
        "summary": "Enviar pedido do site (criar ou atualizar)",
        "x-scopes": [
          "orders:write"
        ],
        "description": "**Escopo:** `orders:write`\n\nCria o pedido no canal **site próprio** (número `SP-<código da loja>-<id>`) ou, se o `id` já foi enviado antes, **atualiza** o status. Chame a cada pedido novo e a cada mudança de status.\n\n**Na criação:**\n- Cada item é ligado ao produto pelo `sku` (SKU da variação primeiro, depois do produto).\n- O estoque dos itens ligados **baixa na hora** (só produtos com controle de estoque ligado; o estoque pode ficar negativo). Itens sem produto vão para `unmapped_items`.\n- Pedido que já chega `cancelado`/`reembolsado` não baixa estoque.\n- A baixa é repassada aos marketplaces onde o produto está anunciado; **não** gera `stock.updated` para o seu site.\n\n**Nas próximas vezes (mesmo `id`):** só status, pagamento e dados do comprador que estavam vazios. Itens, valores e endereço **não mudam**. O status só avança (`pending` → `processing` → `shipped` → `delivered`); `cancelled`/`refunded` são finais e devolvem o estoque que o pedido baixou.\n\nResponde `201` tanto ao criar quanto ao atualizar.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SiteOrderInput"
              },
              "examples": {
                "pago": {
                  "summary": "Pedido pago (exemplo do painel)",
                  "value": {
                    "id": "1001",
                    "status": "pago",
                    "customer": {
                      "name": "Maria Silva",
                      "email": "maria@email.com",
                      "phone": "11999999999",
                      "document": "12345678909"
                    },
                    "shipping_address": {
                      "street": "Rua A",
                      "number": "10",
                      "neighborhood": "Centro",
                      "city": "São Paulo",
                      "state": "SP",
                      "zipcode": "01001000"
                    },
                    "items": [
                      {
                        "sku": "KIT-01",
                        "name": "Kit relaxante",
                        "quantity": 1,
                        "price": 89.9
                      }
                    ],
                    "shipping": 15,
                    "discount": 0,
                    "total": 104.9
                  }
                },
                "mudarStatus": {
                  "summary": "Atualizar para enviado",
                  "description": "Reenvie o mesmo `id` com o novo status. `items` continua obrigatório (com pelo menos 1 item), mas não é alterado.",
                  "value": {
                    "id": "1001",
                    "status": "enviado",
                    "items": [
                      {
                        "sku": "KIT-01",
                        "name": "Kit relaxante",
                        "quantity": 1,
                        "price": 89.9
                      }
                    ]
                  }
                },
                "cancelar": {
                  "summary": "Cancelar (devolve o estoque)",
                  "value": {
                    "id": "1001",
                    "status": "cancelado",
                    "items": [
                      {
                        "sku": "KIT-01",
                        "quantity": 1,
                        "price": 89.9
                      }
                    ]
                  }
                },
                "variacoes": {
                  "summary": "Com variações e data da venda",
                  "value": {
                    "id": "WC-58231",
                    "created_at": "2026-10-18T10:15:00-03:00",
                    "status": "aguardando_pagamento",
                    "customer": {
                      "name": "João Souza",
                      "email": "joao@email.com",
                      "phone": "(21) 98888-7777",
                      "document": "987.654.321-00"
                    },
                    "shipping_address": {
                      "street": "Av. Atlântica",
                      "number": "1500",
                      "complement": "Bloco B",
                      "neighborhood": "Copacabana",
                      "city": "Rio de Janeiro",
                      "state": "RJ",
                      "zipcode": "22021-000"
                    },
                    "items": [
                      {
                        "sku": "CAM-P-AZUL",
                        "name": "Camiseta Azul P",
                        "quantity": 2,
                        "price": 59.9
                      },
                      {
                        "sku": "VELA-99",
                        "name": "Vela aromática",
                        "quantity": 1,
                        "price": 19.9
                      }
                    ],
                    "shipping": 22.5,
                    "discount": 10,
                    "currency": "BRL"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Pedido criado ou atualizado.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteOrderResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Todos os itens ligados",
                    "value": {
                      "success": true,
                      "data": {
                        "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                        "order_number": "SP-8E2B4C-1001",
                        "status": "processing",
                        "payment_status": "paid",
                        "unmapped_items": []
                      },
                      "message": "Pedido recebido."
                    }
                  },
                  "semSku": {
                    "summary": "Item com SKU que não existe no ERP",
                    "value": {
                      "success": true,
                      "data": {
                        "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                        "order_number": "SP-WC-58231",
                        "status": "pending",
                        "payment_status": "pending",
                        "unmapped_items": [
                          {
                            "title": "Vela aromática",
                            "sku": "VELA-99",
                            "quantity": 1,
                            "unit_price": 19.9,
                            "external_item_id": null,
                            "external_variation_id": null
                          }
                        ]
                      },
                      "message": "Pedido recebido. Alguns itens não têm produto com o mesmo SKU aqui — o estoque deles não foi baixado."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Faltou `id` ou `items`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semId": {
                    "summary": "Sem id",
                    "value": {
                      "success": false,
                      "message": "Informe o \"id\" do pedido no seu site."
                    }
                  },
                  "semItens": {
                    "summary": "Sem itens",
                    "value": {
                      "success": false,
                      "message": "O pedido precisa de pelo menos um item em \"items\"."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `orders:write`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'orders:write' scope"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível salvar o pedido."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/inventory": {
      "get": {
        "tags": [
          "Site próprio — Estoque"
        ],
        "operationId": "lerEstoque",
        "summary": "Ler estoque por SKU",
        "x-scopes": [
          "inventory"
        ],
        "description": "**Escopo:** `inventory`\n\nEstoque atual de produtos e variações. Produto com variações aparece uma linha por variação. Com `sku`, devolve só as linhas com aquele SKU exato (lista vazia se não existir — não é erro). Sem `sku`, devolve a loja toda, até 1000 registros, sem paginação.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sku",
            "in": "query",
            "required": false,
            "description": "SKU exato (produto ou variação).",
            "schema": {
              "type": "string"
            },
            "example": "KIT-01"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Linhas de estoque.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InventoryList"
                },
                "examples": {
                  "umSku": {
                    "summary": "Um SKU",
                    "value": {
                      "success": true,
                      "data": [
                        {
                          "sku": "KIT-01",
                          "product_id": "6f1c2a9e-1d2b-4c3d-9e8f-0a1b2c3d4e5f",
                          "variant_id": null,
                          "name": "Kit relaxante",
                          "stock": 24
                        }
                      ]
                    }
                  },
                  "variacoes": {
                    "summary": "Loja toda (com variações)",
                    "value": {
                      "success": true,
                      "data": [
                        {
                          "sku": "KIT-01",
                          "product_id": "6f1c2a9e-1d2b-4c3d-9e8f-0a1b2c3d4e5f",
                          "variant_id": null,
                          "name": "Kit relaxante",
                          "stock": 24
                        },
                        {
                          "sku": "CAM-P-AZUL",
                          "product_id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
                          "variant_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
                          "name": "Camiseta — Azul P",
                          "stock": 7
                        }
                      ]
                    }
                  },
                  "vazio": {
                    "summary": "SKU não encontrado",
                    "value": {
                      "success": true,
                      "data": []
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `inventory`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'inventory' scope"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível ler o estoque."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/inventory/{sku}": {
      "put": {
        "tags": [
          "Site próprio — Estoque"
        ],
        "operationId": "acertarEstoque",
        "summary": "Acertar estoque (quantidade exata)",
        "x-scopes": [
          "inventory"
        ],
        "description": "**Escopo:** `inventory`\n\nDefine a quantidade exata do SKU (ex.: depois de uma contagem). Procura primeiro uma **variação** com esse SKU na loja, depois um **produto**. Grava no histórico de estoque (\"Atualizado pelo site próprio\") e repassa o novo valor aos marketplaces ligados ao produto. **Não** gera webhook `stock.updated` de volta para o seu site. Idempotente.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "sku",
            "in": "path",
            "required": true,
            "description": "SKU do produto ou variação (codifique caracteres especiais na URL).",
            "schema": {
              "type": "string"
            },
            "example": "KIT-01"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InventorySetInput"
              },
              "examples": {
                "contagem": {
                  "summary": "Contagem de estoque",
                  "value": {
                    "stock": 25
                  }
                },
                "zerar": {
                  "summary": "Zerar",
                  "value": {
                    "stock": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Estoque atualizado.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InventorySetResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Atualizado",
                    "value": {
                      "success": true,
                      "data": {
                        "sku": "KIT-01",
                        "stock": 25
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`stock` ausente, negativo ou não numérico.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalido": {
                    "summary": "Quantidade inválida",
                    "value": {
                      "success": false,
                      "message": "Informe \"stock\" (número inteiro, 0 ou mais)."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `inventory`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'inventory' scope"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Nenhum produto/variação com o SKU nesta loja.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "naoExiste": {
                    "summary": "SKU não existe",
                    "value": {
                      "success": false,
                      "message": "Nenhum produto com o SKU \"KIT-01\" nesta loja."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível atualizar o estoque."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/orders": {
      "get": {
        "tags": [
          "Leitura"
        ],
        "operationId": "listarPedidos",
        "summary": "Listar pedidos",
        "x-scopes": [
          "orders"
        ],
        "description": "**Escopo:** `orders`\n\nPedidos da loja (todos os canais), do mais novo para o mais antigo, paginados.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filtra pelo status do pedido.",
            "schema": {
              "$ref": "#/components/schemas/OrderStatus"
            },
            "example": "processing"
          },
          {
            "name": "date_from",
            "in": "query",
            "required": false,
            "description": "Criados a partir desta data/hora (ISO 8601).",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-10-01T00:00:00-03:00"
          },
          {
            "name": "date_to",
            "in": "query",
            "required": false,
            "description": "Criados até esta data/hora (ISO 8601).",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "example": "2026-10-31T23:59:59-03:00"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Página de pedidos.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderList"
                },
                "examples": {
                  "ok": {
                    "summary": "Página 1",
                    "value": {
                      "success": true,
                      "data": {
                        "data": [
                          {
                            "id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                            "store_id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
                            "customer_id": null,
                            "order_number": "SP-8E2B4C-1001",
                            "status": "processing",
                            "payment_status": "paid",
                            "subtotal": "89.90",
                            "discount_amount": "0.00",
                            "shipping_amount": "15.00",
                            "tax_amount": "0.00",
                            "total": "104.90",
                            "currency": "BRL",
                            "shipping_address": {
                              "name": "Maria Silva",
                              "phone": "11999999999",
                              "cpf": "12345678909",
                              "street": "Rua A",
                              "number": "10",
                              "complement": "",
                              "neighborhood": "Centro",
                              "city": "São Paulo",
                              "state": "SP",
                              "zipcode": "01001000",
                              "country": "BR",
                              "address": "Rua A, 10"
                            },
                            "billing_address": null,
                            "shipping_method": null,
                            "tracking_code": null,
                            "tracking_url": null,
                            "shipping_carrier": null,
                            "shipping_service": null,
                            "shipping_label_url": null,
                            "shipping_label_id": null,
                            "platform_commission": null,
                            "seller_amount": null,
                            "coupon_id": null,
                            "coupon_code": null,
                            "affiliate_id": null,
                            "notes": null,
                            "shipped_at": null,
                            "delivered_at": null,
                            "cancelled_at": null,
                            "channel": "site_proprio",
                            "external_order_id": "1001",
                            "buyer_name": "Maria Silva",
                            "buyer_document": "12345678909",
                            "buyer_email": "maria@email.com",
                            "buyer_phone": "11999999999",
                            "unmapped_items": null,
                            "created_at": "2026-10-18T13:15:00.000Z",
                            "updated_at": "2026-10-18T13:15:02.000Z"
                          }
                        ],
                        "pagination": {
                          "total": 57,
                          "page": 1,
                          "limit": 20,
                          "totalPages": 3,
                          "hasMore": true
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `orders`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'orders' scope"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Internal error"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/orders/{id}": {
      "get": {
        "tags": [
          "Leitura"
        ],
        "operationId": "verPedido",
        "summary": "Ver um pedido",
        "x-scopes": [
          "orders"
        ],
        "description": "**Escopo:** `orders`\n\nUm pedido pelo id do ERP (`order_id` devolvido no envio). Não traz os itens.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id do pedido no ERP.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Pedido.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderDetail"
                },
                "examples": {
                  "ok": {
                    "summary": "Pedido",
                    "value": {
                      "success": true,
                      "data": {
                        "order": {
                          "id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                          "store_id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
                          "customer_id": null,
                          "order_number": "SP-8E2B4C-1001",
                          "status": "processing",
                          "payment_status": "paid",
                          "subtotal": "89.90",
                          "discount_amount": "0.00",
                          "shipping_amount": "15.00",
                          "tax_amount": "0.00",
                          "total": "104.90",
                          "currency": "BRL",
                          "shipping_address": {
                            "name": "Maria Silva",
                            "phone": "11999999999",
                            "cpf": "12345678909",
                            "street": "Rua A",
                            "number": "10",
                            "complement": "",
                            "neighborhood": "Centro",
                            "city": "São Paulo",
                            "state": "SP",
                            "zipcode": "01001000",
                            "country": "BR",
                            "address": "Rua A, 10"
                          },
                          "billing_address": null,
                          "shipping_method": null,
                          "tracking_code": null,
                          "tracking_url": null,
                          "shipping_carrier": null,
                          "shipping_service": null,
                          "shipping_label_url": null,
                          "shipping_label_id": null,
                          "platform_commission": null,
                          "seller_amount": null,
                          "coupon_id": null,
                          "coupon_code": null,
                          "affiliate_id": null,
                          "notes": null,
                          "shipped_at": null,
                          "delivered_at": null,
                          "cancelled_at": null,
                          "channel": "site_proprio",
                          "external_order_id": "1001",
                          "buyer_name": "Maria Silva",
                          "buyer_document": "12345678909",
                          "buyer_email": "maria@email.com",
                          "buyer_phone": "11999999999",
                          "unmapped_items": null,
                          "created_at": "2026-10-18T13:15:00.000Z",
                          "updated_at": "2026-10-18T13:15:02.000Z"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `orders`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'orders' scope"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Pedido não existe nesta loja.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "naoExiste": {
                    "summary": "Não encontrado",
                    "value": {
                      "success": false,
                      "message": "Order not found"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Internal error"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/revenue": {
      "get": {
        "tags": [
          "Leitura"
        ],
        "operationId": "faturamento",
        "summary": "Faturamento por dia",
        "x-scopes": [
          "revenue"
        ],
        "description": "**Escopo:** `revenue` (não incluso na chave de *Meu site*)\n\nSoma dos **pagamentos aprovados** no período, por dia. Considera só pagamentos processados pela loja Devskin (checkout); pedidos de marketplace e do site próprio não entram.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "Últimos 7, 30 ou 90 dias, ou 1 ano. Outro valor = 30 dias.",
            "schema": {
              "type": "string",
              "enum": [
                "7d",
                "30d",
                "90d",
                "1y"
              ],
              "default": "30d"
            },
            "example": "30d"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Faturamento.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Revenue"
                },
                "examples": {
                  "ok": {
                    "summary": "30 dias",
                    "value": {
                      "success": true,
                      "data": {
                        "period": "30d",
                        "total": 4280.5,
                        "daily": [
                          {
                            "date": "2026-10-16",
                            "total": "389.70",
                            "count": 4
                          },
                          {
                            "date": "2026-10-17",
                            "total": "104.90",
                            "count": 1
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `revenue`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'revenue' scope"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Internal error"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/products": {
      "get": {
        "tags": [
          "Leitura"
        ],
        "operationId": "listarProdutos",
        "summary": "Listar produtos",
        "x-scopes": [
          "products"
        ],
        "description": "**Escopo:** `products`\n\nProdutos da loja (qualquer status), do mais novo para o mais antigo, paginados. Para estoque por variação use `GET /v1/store/inventory`.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Página de produtos.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductList"
                },
                "examples": {
                  "ok": {
                    "summary": "Página 1",
                    "value": {
                      "success": true,
                      "data": {
                        "data": [
                          {
                            "id": "6f1c2a9e-1d2b-4c3d-9e8f-0a1b2c3d4e5f",
                            "store_id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
                            "category_id": null,
                            "name": "Kit relaxante",
                            "slug": "kit-relaxante",
                            "description": "<p>Kit com 3 itens.</p>",
                            "short_description": null,
                            "type": "physical",
                            "price": "89.90",
                            "compare_at_price": "119.90",
                            "cost_price": "40.00",
                            "currency": "BRL",
                            "sku": "KIT-01",
                            "barcode": null,
                            "stock": 24,
                            "track_stock": true,
                            "weight": "0.50",
                            "width": "20.00",
                            "height": "10.00",
                            "length": "30.00",
                            "status": "active",
                            "is_featured": false,
                            "seo_title": null,
                            "seo_description": null,
                            "affiliate_enabled": false,
                            "affiliate_commission_type": null,
                            "affiliate_commission_value": null,
                            "course_id": null,
                            "video_url": null,
                            "sort_order": 0,
                            "created_by": null,
                            "seller_id": null,
                            "ncm": "33074900",
                            "cest": null,
                            "cfop": null,
                            "origem": "0",
                            "unidade": "UN",
                            "created_at": "2026-09-02T12:00:00.000Z",
                            "updated_at": "2026-10-18T13:15:02.000Z"
                          }
                        ],
                        "pagination": {
                          "total": 87,
                          "page": 1,
                          "limit": 20,
                          "totalPages": 5,
                          "hasMore": true
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `products`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'products' scope"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Internal error"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/customers": {
      "get": {
        "tags": [
          "Leitura"
        ],
        "operationId": "listarClientes",
        "summary": "Listar clientes (indisponível)",
        "x-scopes": [
          "customers"
        ],
        "description": "**Escopo:** `customers` (não incluso na chave de *Meu site*)\n\n> **Indisponível no momento:** esta rota está respondendo `500 Internal error` (problema conhecido, em correção). Para clientes, use a ferramenta `list_customers` do MCP ou os dados de comprador (`buyer_*`) em `GET /v1/orders`.\n\nQuando corrigida, devolve os compradores distintos dos pedidos da loja, paginados.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Clientes (formato previsto).",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerList"
                },
                "examples": {
                  "ok": {
                    "summary": "Formato previsto",
                    "value": {
                      "success": true,
                      "data": {
                        "items": [
                          {
                            "customer_name": "Maria Silva",
                            "customer_email": "maria@email.com",
                            "customer_phone": "11999999999"
                          }
                        ],
                        "total": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `customers`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'customers' scope"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Internal error"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/analytics/overview": {
      "get": {
        "tags": [
          "Leitura"
        ],
        "operationId": "visaoGeral",
        "summary": "Visão geral da loja",
        "x-scopes": [
          "analytics"
        ],
        "description": "**Escopo:** `analytics` (não incluso na chave de *Meu site*)\n\nTotais da loja e do mês atual. Faturamento considera só pagamentos aprovados no checkout da loja Devskin.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Totais.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalyticsOverview"
                },
                "examples": {
                  "ok": {
                    "summary": "Totais",
                    "value": {
                      "success": true,
                      "data": {
                        "total_orders": 312,
                        "monthly_orders": 41,
                        "total_revenue": 58210.4,
                        "monthly_revenue": 6120,
                        "total_products": 87
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `analytics`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'analytics' scope"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Internal error"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/mcp/rpc": {
      "post": {
        "tags": [
          "Conectar uma IA (MCP)"
        ],
        "operationId": "mcpRpc",
        "summary": "Servidor MCP (JSON-RPC 2.0)",
        "description": "Ponto único do servidor MCP. Normalmente quem chama é o seu assistente de IA (veja o passo a passo acima), mas dá para testar aqui.\n\n- `initialize`, `ping`, `tools/list`: **não** exigem chave.\n- `tools/call`: exige a chave da loja em `Authorization: Bearer dsk_...` **ou** `X-API-Key: dsk_...`, com escopo `mcp`/`mcp:read` (leitura) ou `mcp:write` (ações). Também aceita o login do painel (`Authorization: Bearer <JWT>` + header `x-store-id`).\n- Erros de protocolo vêm em `error`; falha da ferramenta vem em `result.isError`.",
        "security": [
          {
            "ApiKeyAuth": []
          },
          {
            "McpBearer": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "x-store-id",
            "in": "header",
            "required": false,
            "description": "Só com login do painel (JWT): qual loja usar. Padrão: a primeira loja da pessoa. Ignorado com chave `dsk_`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              },
              "examples": {
                "initialize": {
                  "summary": "initialize",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 1,
                    "method": "initialize",
                    "params": {
                      "protocolVersion": "2025-06-18"
                    }
                  }
                },
                "toolsList": {
                  "summary": "tools/list",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 2,
                    "method": "tools/list"
                  }
                },
                "listOrders": {
                  "summary": "tools/call — list_orders",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 3,
                    "method": "tools/call",
                    "params": {
                      "name": "list_orders",
                      "arguments": {
                        "status": "pending"
                      }
                    }
                  }
                },
                "analytics": {
                  "summary": "tools/call — get_sales_analytics",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 4,
                    "method": "tools/call",
                    "params": {
                      "name": "get_sales_analytics",
                      "arguments": {
                        "period": "month"
                      }
                    }
                  }
                },
                "alertas": {
                  "summary": "tools/call — get_inventory_alerts",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 5,
                    "method": "tools/call",
                    "params": {
                      "name": "get_inventory_alerts",
                      "arguments": {}
                    }
                  }
                },
                "createProduct": {
                  "summary": "tools/call — create_product (mcp:write)",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 6,
                    "method": "tools/call",
                    "params": {
                      "name": "create_product",
                      "arguments": {
                        "name": "Vela aromática",
                        "price": 19.9,
                        "stock": 10,
                        "type": "physical"
                      }
                    }
                  }
                },
                "updateStatus": {
                  "summary": "tools/call — update_order_status (mcp:write)",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 7,
                    "method": "tools/call",
                    "params": {
                      "name": "update_order_status",
                      "arguments": {
                        "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                        "status": "shipped"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resposta JSON-RPC (sucesso, falha da ferramenta, método não suportado ou ferramenta inexistente).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                },
                "examples": {
                  "initialize": {
                    "summary": "initialize",
                    "value": {
                      "jsonrpc": "2.0",
                      "id": 1,
                      "result": {
                        "protocolVersion": "2025-06-18",
                        "capabilities": {
                          "tools": {}
                        },
                        "serverInfo": {
                          "name": "devskin-marketplace",
                          "version": "1.0.0"
                        }
                      }
                    }
                  },
                  "toolsList": {
                    "summary": "tools/list (trecho)",
                    "value": {
                      "jsonrpc": "2.0",
                      "id": 2,
                      "result": {
                        "tools": [
                          {
                            "name": "list_orders",
                            "description": "List orders with status, total, customer, payment status.",
                            "inputSchema": {
                              "type": "object",
                              "properties": {
                                "status": {
                                  "type": "string",
                                  "description": "Filter: pending, processing, shipped, delivered, cancelled, refunded"
                                }
                              },
                              "required": []
                            },
                            "annotations": {
                              "readOnlyHint": true
                            }
                          },
                          {
                            "name": "update_order_status",
                            "description": "Muda o status de um pedido: processing (preparando), shipped (enviado), delivered (entregue) ou cancelled (cancelado).",
                            "inputSchema": {
                              "type": "object",
                              "properties": {
                                "order_id": {
                                  "type": "string"
                                },
                                "status": {
                                  "type": "string",
                                  "enum": [
                                    "processing",
                                    "shipped",
                                    "delivered",
                                    "cancelled"
                                  ]
                                },
                                "notes": {
                                  "type": "string"
                                }
                              },
                              "required": [
                                "order_id",
                                "status"
                              ]
                            },
                            "annotations": {
                              "readOnlyHint": false
                            }
                          }
                        ]
                      }
                    }
                  },
                  "toolCall": {
                    "summary": "tools/call",
                    "value": {
                      "jsonrpc": "2.0",
                      "id": 3,
                      "result": {
                        "content": [
                          {
                            "type": "text",
                            "text": "[{\"id\":\"8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e\",\"number\":\"LOJA96192042K7Q2\",\"status\":\"pending\",\"paymentStatus\":\"pending\",\"total\":104.9,\"currency\":\"BRL\",\"items\":1,\"customer\":\"Maria Silva\",\"email\":\"maria@email.com\",\"createdAt\":\"2026-10-18T13:15:00.000Z\"}]"
                          }
                        ]
                      }
                    }
                  },
                  "toolError": {
                    "summary": "Falha da ferramenta",
                    "value": {
                      "jsonrpc": "2.0",
                      "id": 7,
                      "result": {
                        "content": [
                          {
                            "type": "text",
                            "text": "Erro: order.notFound"
                          }
                        ],
                        "isError": true
                      }
                    }
                  },
                  "metodo": {
                    "summary": "Método não suportado",
                    "value": {
                      "jsonrpc": "2.0",
                      "id": 9,
                      "error": {
                        "code": -32601,
                        "message": "Método não suportado"
                      }
                    }
                  },
                  "semFerramenta": {
                    "summary": "Ferramenta não encontrada",
                    "value": {
                      "jsonrpc": "2.0",
                      "id": 9,
                      "error": {
                        "code": -32602,
                        "message": "Ferramenta não encontrada"
                      }
                    }
                  }
                }
              }
            }
          },
          "202": {
            "description": "Notificação (`notifications/*`) recebida. Sem corpo."
          },
          "401": {
            "description": "`tools/call` sem chave válida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                },
                "examples": {
                  "naoAutorizado": {
                    "summary": "Não autorizado",
                    "value": {
                      "jsonrpc": "2.0",
                      "id": 3,
                      "error": {
                        "code": -32001,
                        "message": "Não autorizado"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo da ferramenta.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                },
                "examples": {
                  "leitura": {
                    "summary": "Sem mcp:read",
                    "value": {
                      "jsonrpc": "2.0",
                      "id": 3,
                      "error": {
                        "code": -32003,
                        "message": "A chave não tem permissão para esta ferramenta (precisa do escopo mcp:read)."
                      }
                    }
                  },
                  "escrita": {
                    "summary": "Sem mcp:write",
                    "value": {
                      "jsonrpc": "2.0",
                      "id": 6,
                      "error": {
                        "code": -32003,
                        "message": "A chave não tem permissão para esta ferramenta (precisa do escopo mcp:write)."
                      }
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "Chamada com `GET` (use `POST`).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "get": {
                    "summary": "GET",
                    "value": {
                      "error": "Use POST (MCP Streamable HTTP, JSON-RPC 2.0)."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro interno.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                },
                "examples": {
                  "interno": {
                    "summary": "Erro interno",
                    "value": {
                      "jsonrpc": "2.0",
                      "id": 3,
                      "error": {
                        "code": -32603,
                        "message": "Erro interno"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/auth/login": {
      "post": {
        "tags": [
          "Painel — Login"
        ],
        "operationId": "login",
        "summary": "Entrar (obter o token do painel)",
        "description": "Troca e-mail e senha do painel por um **token JWT** (vale 30 dias) para as rotas `/stores/{storeId}/...`. A resposta traz as lojas da pessoa (`data.stores[].id` = `storeId`). Use só em automação sua, guardando a senha com segurança.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginInput"
              },
              "examples": {
                "ok": {
                  "summary": "Login",
                  "value": {
                    "email": "voce@sualoja.com",
                    "password": "sua-senha"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Logado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoginResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Login",
                    "value": {
                      "success": true,
                      "message": "Login realizado com sucesso",
                      "data": {
                        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Ii4uLiJ9.assinatura",
                        "user": {
                          "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                          "name": "Ana Lojista",
                          "email": "voce@sualoja.com",
                          "role": "user"
                        },
                        "stores": [
                          {
                            "id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
                            "name": "Loja da Ana",
                            "slug": "loja-da-ana",
                            "status": "active",
                            "project_type": "store"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Faltou e-mail ou senha.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "faltou": {
                    "summary": "Campos",
                    "value": {
                      "success": false,
                      "message": "Todos os campos são obrigatórios"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "E-mail ou senha errados.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "errado": {
                    "summary": "Credenciais",
                    "value": {
                      "success": false,
                      "message": "Credenciais inválidas"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Conta desativada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "desativada": {
                    "summary": "Desativada",
                    "value": {
                      "success": false,
                      "message": "Conta desativada"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Erro interno do servidor"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stores/{storeId}/api-keys": {
      "parameters": [
        {
          "$ref": "#/components/parameters/StoreId"
        }
      ],
      "get": {
        "tags": [
          "Painel — Chaves de API"
        ],
        "operationId": "listarChaves",
        "summary": "Listar chaves de API",
        "description": "Todas as chaves da loja (ativas e revogadas), sem a chave completa. Exige plano com **acesso à API** (`api_access_enabled`) e ser membro da loja.",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "responses": {
          "200": {
            "description": "Chaves.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "keys": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/ApiKey"
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "ok": {
                    "summary": "Chaves",
                    "value": {
                      "success": true,
                      "data": {
                        "keys": [
                          {
                            "id": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                            "name": "Site próprio",
                            "key_prefix": "dsk_8f3a2b1c",
                            "last_used_at": "2026-10-18T14:03:12.481Z",
                            "expires_at": null,
                            "is_active": true,
                            "scopes": [
                              "orders:write",
                              "inventory",
                              "orders",
                              "products",
                              "mcp:read"
                            ],
                            "created_at": "2026-10-10T12:00:00.000Z"
                          },
                          {
                            "id": "d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f8a",
                            "name": "Planilha de vendas",
                            "key_prefix": "dsk_1b2c3d4e",
                            "last_used_at": null,
                            "expires_at": "2027-12-31T23:59:59.000Z",
                            "is_active": true,
                            "scopes": [
                              "orders",
                              "revenue"
                            ],
                            "created_at": "2026-10-12T12:00:00.000Z"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja ou plano sem o recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  },
                  "semPlano": {
                    "summary": "Sem assinatura",
                    "value": {
                      "success": false,
                      "code": "PLAN_REQUIRED",
                      "message": "Assinatura ativa necessária para acessar este recurso"
                    }
                  },
                  "recurso": {
                    "summary": "Plano sem o recurso",
                    "value": {
                      "success": false,
                      "code": "FEATURE_NOT_AVAILABLE",
                      "message": "Este recurso não está disponível no seu plano atual. Faça upgrade para acessar.",
                      "feature": "api_access_enabled",
                      "current_plan": "Grátis"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Loja não encontrada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "loja": {
                    "summary": "Loja não existe",
                    "value": {
                      "success": false,
                      "message": "Loja não encontrada"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Erro interno do servidor"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Painel — Chaves de API"
        ],
        "operationId": "criarChave",
        "summary": "Criar chave de API",
        "description": "Cria uma chave `dsk_...` com os escopos escolhidos. **A chave completa (`raw_key`) só aparece nesta resposta.** Sem `scopes`, a chave tem acesso total (`*`). Exige plano com acesso à API.\n\n**Regras:** só administradores da loja. `scopes` (opcional, padrão `[\"*\"]`) aceita: `*`, `orders`, `orders:write`, `inventory`, `products`, `revenue`, `customers`, `analytics`, `mcp`, `mcp:read`, `mcp:write`. A chave completa (`raw_key`) aparece só nesta resposta.",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApiKeyCreateInput"
              },
              "examples": {
                "leitura": {
                  "summary": "Relatórios (só leitura)",
                  "value": {
                    "name": "Planilha de vendas",
                    "scopes": [
                      "orders",
                      "products",
                      "revenue",
                      "analytics"
                    ]
                  }
                },
                "mcp": {
                  "summary": "IA com ações (MCP)",
                  "value": {
                    "name": "Claude",
                    "scopes": [
                      "mcp:write"
                    ]
                  }
                },
                "total": {
                  "summary": "Acesso total com validade",
                  "value": {
                    "name": "Integração ERP antigo",
                    "expires_at": "2027-12-31T23:59:59Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Chave criada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreated"
                },
                "examples": {
                  "ok": {
                    "summary": "Criada",
                    "value": {
                      "success": true,
                      "data": {
                        "key": {
                          "id": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f",
                          "store_id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
                          "name": "Claude",
                          "key_prefix": "dsk_8f3a2b1c",
                          "scopes": [
                            "mcp:write"
                          ],
                          "expires_at": null,
                          "is_active": true,
                          "created_at": "2026-10-18T14:03:12.481Z",
                          "updated_at": "2026-10-18T14:03:12.481Z"
                        },
                        "raw_key": "dsk_8f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a"
                      },
                      "message": "Save this API key now. It will not be shown again."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Faltou `name`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semNome": {
                    "summary": "Sem nome",
                    "value": {
                      "success": false,
                      "message": "Name required"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja ou plano sem o recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  },
                  "semPlano": {
                    "summary": "Sem assinatura",
                    "value": {
                      "success": false,
                      "code": "PLAN_REQUIRED",
                      "message": "Assinatura ativa necessária para acessar este recurso"
                    }
                  },
                  "recurso": {
                    "summary": "Plano sem o recurso",
                    "value": {
                      "success": false,
                      "code": "FEATURE_NOT_AVAILABLE",
                      "message": "Este recurso não está disponível no seu plano atual. Faça upgrade para acessar.",
                      "feature": "api_access_enabled",
                      "current_plan": "Grátis"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Loja não encontrada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "loja": {
                    "summary": "Loja não existe",
                    "value": {
                      "success": false,
                      "message": "Loja não encontrada"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Erro interno do servidor"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stores/{storeId}/api-keys/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/StoreId"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Id da chave.",
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "example": "c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f"
        }
      ],
      "delete": {
        "tags": [
          "Painel — Chaves de API"
        ],
        "operationId": "revogarChave",
        "summary": "Revogar chave",
        "description": "Desliga a chave na hora (ela passa a responder `401 Invalid or revoked API key`). O registro continua na lista como inativo.\n\n**Regras:** só administradores da loja. `scopes` (opcional, padrão `[\"*\"]`) aceita: `*`, `orders`, `orders:write`, `inventory`, `products`, `revenue`, `customers`, `analytics`, `mcp`, `mcp:read`, `mcp:write`. A chave completa (`raw_key`) aparece só nesta resposta.",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "responses": {
          "200": {
            "description": "Revogada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "ok": {
                    "summary": "Revogada",
                    "value": {
                      "success": true,
                      "message": "API key revoked"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja ou plano sem o recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  },
                  "semPlano": {
                    "summary": "Sem assinatura",
                    "value": {
                      "success": false,
                      "code": "PLAN_REQUIRED",
                      "message": "Assinatura ativa necessária para acessar este recurso"
                    }
                  },
                  "recurso": {
                    "summary": "Plano sem o recurso",
                    "value": {
                      "success": false,
                      "code": "FEATURE_NOT_AVAILABLE",
                      "message": "Este recurso não está disponível no seu plano atual. Faça upgrade para acessar.",
                      "feature": "api_access_enabled",
                      "current_plan": "Grátis"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Chave ou loja não encontrada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "chave": {
                    "summary": "Chave não existe",
                    "value": {
                      "success": false,
                      "message": "API key not found"
                    }
                  },
                  "loja": {
                    "summary": "Loja não existe",
                    "value": {
                      "success": false,
                      "message": "Loja não encontrada"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Erro interno do servidor"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stores/{storeId}/webhooks-config": {
      "parameters": [
        {
          "$ref": "#/components/parameters/StoreId"
        }
      ],
      "get": {
        "tags": [
          "Painel — Webhooks"
        ],
        "operationId": "listarWebhooks",
        "summary": "Listar webhooks",
        "description": "Todos os webhooks da loja (inclusive o de estoque criado em *Meu site*), com o segredo. Exige plano com **webhooks** (`webhooks_enabled`).",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "responses": {
          "200": {
            "description": "Webhooks.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "webhooks": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Webhook"
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "ok": {
                    "summary": "Webhooks",
                    "value": {
                      "success": true,
                      "data": {
                        "webhooks": [
                          {
                            "id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d",
                            "store_id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
                            "url": "https://seusite.com/webhooks/devskin",
                            "events": [
                              "order.created",
                              "payment.confirmed"
                            ],
                            "secret": "9c1f0e2d3b4a5968778695a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4",
                            "is_active": true,
                            "last_triggered_at": "2026-10-18T14:03:12.481Z",
                            "failure_count": 0,
                            "created_at": "2026-10-01T12:00:00.000Z",
                            "updated_at": "2026-10-18T14:03:12.481Z"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja ou plano sem o recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  },
                  "semPlano": {
                    "summary": "Sem assinatura",
                    "value": {
                      "success": false,
                      "code": "PLAN_REQUIRED",
                      "message": "Assinatura ativa necessária para acessar este recurso"
                    }
                  },
                  "recurso": {
                    "summary": "Plano sem o recurso",
                    "value": {
                      "success": false,
                      "code": "FEATURE_NOT_AVAILABLE",
                      "message": "Este recurso não está disponível no seu plano atual. Faça upgrade para acessar.",
                      "feature": "webhooks_enabled",
                      "current_plan": "Grátis"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Loja não encontrada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "loja": {
                    "summary": "Loja não existe",
                    "value": {
                      "success": false,
                      "message": "Loja não encontrada"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Erro interno do servidor"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Painel — Webhooks"
        ],
        "operationId": "criarWebhook",
        "summary": "Criar webhook",
        "description": "Cadastra um endereço para receber os eventos escolhidos. Gera um segredo novo (64 caracteres hex) e devolve em `data.secret`. Use `https://`.\n\n**Regras:** só administradores da loja. A `url` precisa começar com `https://` e ser um endereço público (localhost e rede interna são recusados). `events` aceita só os nomes do catálogo (ou `*`). O `secret` aparece apenas na criação — a listagem não o devolve.",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookCreateInput"
              },
              "examples": {
                "pedidos": {
                  "summary": "Pedidos e pagamentos",
                  "value": {
                    "url": "https://seusite.com/webhooks/devskin",
                    "events": [
                      "order.created",
                      "order.shipped",
                      "order.cancelled",
                      "payment.confirmed"
                    ]
                  }
                },
                "estoque": {
                  "summary": "Só estoque",
                  "value": {
                    "url": "https://seusite.com/webhooks/estoque",
                    "events": [
                      "stock.updated"
                    ]
                  }
                },
                "tudo": {
                  "summary": "Todos os eventos",
                  "value": {
                    "url": "https://hooks.exemplo.com/devskin",
                    "events": [
                      "*"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Criado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "webhook": {
                          "$ref": "#/components/schemas/Webhook"
                        },
                        "secret": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "ok": {
                    "summary": "Criado",
                    "value": {
                      "success": true,
                      "data": {
                        "webhook": {
                          "id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d",
                          "store_id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
                          "url": "https://seusite.com/webhooks/devskin",
                          "events": [
                            "order.created",
                            "order.shipped",
                            "order.cancelled",
                            "payment.confirmed"
                          ],
                          "secret": "9c1f0e2d3b4a5968778695a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4",
                          "is_active": true,
                          "last_triggered_at": null,
                          "failure_count": 0,
                          "created_at": "2026-10-01T12:00:00.000Z",
                          "updated_at": "2026-10-18T14:03:12.481Z"
                        },
                        "secret": "9c1f0e2d3b4a5968778695a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Faltou `url` ou `events`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "faltou": {
                    "summary": "Campos",
                    "value": {
                      "success": false,
                      "message": "URL and events are required"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja ou plano sem o recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  },
                  "semPlano": {
                    "summary": "Sem assinatura",
                    "value": {
                      "success": false,
                      "code": "PLAN_REQUIRED",
                      "message": "Assinatura ativa necessária para acessar este recurso"
                    }
                  },
                  "recurso": {
                    "summary": "Plano sem o recurso",
                    "value": {
                      "success": false,
                      "code": "FEATURE_NOT_AVAILABLE",
                      "message": "Este recurso não está disponível no seu plano atual. Faça upgrade para acessar.",
                      "feature": "webhooks_enabled",
                      "current_plan": "Grátis"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Loja não encontrada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "loja": {
                    "summary": "Loja não existe",
                    "value": {
                      "success": false,
                      "message": "Loja não encontrada"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Erro interno do servidor"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stores/{storeId}/webhooks-config/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/StoreId"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Id do webhook.",
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "example": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
        }
      ],
      "put": {
        "tags": [
          "Painel — Webhooks"
        ],
        "operationId": "editarWebhook",
        "summary": "Editar webhook",
        "description": "Muda endereço, eventos ou liga/desliga.\n\n**Regras:** só administradores da loja. A `url` precisa começar com `https://` e ser um endereço público (localhost e rede interna são recusados). `events` aceita só os nomes do catálogo (ou `*`). O `secret` aparece apenas na criação — a listagem não o devolve.",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdateInput"
              },
              "examples": {
                "religar": {
                  "summary": "Religar",
                  "value": {
                    "is_active": true
                  }
                },
                "eventos": {
                  "summary": "Trocar eventos",
                  "value": {
                    "events": [
                      "order.created",
                      "stock.updated"
                    ]
                  }
                },
                "url": {
                  "summary": "Trocar endereço",
                  "value": {
                    "url": "https://seusite.com/webhooks/novo"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "webhook": {
                          "$ref": "#/components/schemas/Webhook"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "ok": {
                    "summary": "Atualizado",
                    "value": {
                      "success": true,
                      "data": {
                        "webhook": {
                          "id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d",
                          "store_id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
                          "url": "https://seusite.com/webhooks/devskin",
                          "events": [
                            "order.created",
                            "payment.confirmed"
                          ],
                          "secret": "9c1f0e2d3b4a5968778695a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4",
                          "is_active": true,
                          "last_triggered_at": "2026-10-18T14:03:12.481Z",
                          "failure_count": 0,
                          "created_at": "2026-10-01T12:00:00.000Z",
                          "updated_at": "2026-10-18T14:03:12.481Z"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja ou plano sem o recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  },
                  "semPlano": {
                    "summary": "Sem assinatura",
                    "value": {
                      "success": false,
                      "code": "PLAN_REQUIRED",
                      "message": "Assinatura ativa necessária para acessar este recurso"
                    }
                  },
                  "recurso": {
                    "summary": "Plano sem o recurso",
                    "value": {
                      "success": false,
                      "code": "FEATURE_NOT_AVAILABLE",
                      "message": "Este recurso não está disponível no seu plano atual. Faça upgrade para acessar.",
                      "feature": "webhooks_enabled",
                      "current_plan": "Grátis"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook ou loja não encontrado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "webhook": {
                    "summary": "Webhook não existe",
                    "value": {
                      "success": false,
                      "message": "Webhook not found"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Erro interno do servidor"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Painel — Webhooks"
        ],
        "operationId": "apagarWebhook",
        "summary": "Apagar webhook",
        "description": "Remove o cadastro. Se for o de estoque de *Meu site*, o site deixa de receber `stock.updated` até salvar o endereço de novo.\n\nSó administradores da loja.",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "responses": {
          "200": {
            "description": "Apagado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                },
                "examples": {
                  "ok": {
                    "summary": "Apagado",
                    "value": {
                      "success": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja ou plano sem o recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  },
                  "semPlano": {
                    "summary": "Sem assinatura",
                    "value": {
                      "success": false,
                      "code": "PLAN_REQUIRED",
                      "message": "Assinatura ativa necessária para acessar este recurso"
                    }
                  },
                  "recurso": {
                    "summary": "Plano sem o recurso",
                    "value": {
                      "success": false,
                      "code": "FEATURE_NOT_AVAILABLE",
                      "message": "Este recurso não está disponível no seu plano atual. Faça upgrade para acessar.",
                      "feature": "webhooks_enabled",
                      "current_plan": "Grátis"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook ou loja não encontrado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "webhook": {
                    "summary": "Webhook não existe",
                    "value": {
                      "success": false,
                      "message": "Webhook not found"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Erro interno do servidor"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stores/{storeId}/webhooks-config/{id}/events": {
      "parameters": [
        {
          "$ref": "#/components/parameters/StoreId"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Id do webhook.",
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "example": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
        }
      ],
      "get": {
        "tags": [
          "Painel — Webhooks"
        ],
        "operationId": "entregasWebhook",
        "summary": "Histórico de entregas",
        "description": "Cada tentativa de entrega (inclusive as novas tentativas), da mais recente para a mais antiga.",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Entregas.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/WebhookDelivery"
                          }
                        },
                        "pagination": {
                          "$ref": "#/components/schemas/Pagination"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "ok": {
                    "summary": "Entregas",
                    "value": {
                      "success": true,
                      "data": {
                        "data": [
                          {
                            "id": "e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b",
                            "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d",
                            "event": "stock.updated",
                            "payload": {
                              "product_id": "6f1c2a9e-1d2b-4c3d-9e8f-0a1b2c3d4e5f",
                              "variant_id": null,
                              "sku": "KIT-01",
                              "stock": 24,
                              "delta": -1,
                              "reason": "venda_canal"
                            },
                            "response_status": 200,
                            "response_body": "ok",
                            "success": true,
                            "triggered_at": "2026-10-18T14:03:12.481Z",
                            "created_at": "2026-10-18T14:03:12.481Z",
                            "updated_at": "2026-10-18T14:03:12.481Z"
                          }
                        ],
                        "pagination": {
                          "total": 1,
                          "page": 1,
                          "limit": 20,
                          "totalPages": 1,
                          "hasMore": false
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja ou plano sem o recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  },
                  "semPlano": {
                    "summary": "Sem assinatura",
                    "value": {
                      "success": false,
                      "code": "PLAN_REQUIRED",
                      "message": "Assinatura ativa necessária para acessar este recurso"
                    }
                  },
                  "recurso": {
                    "summary": "Plano sem o recurso",
                    "value": {
                      "success": false,
                      "code": "FEATURE_NOT_AVAILABLE",
                      "message": "Este recurso não está disponível no seu plano atual. Faça upgrade para acessar.",
                      "feature": "webhooks_enabled",
                      "current_plan": "Grátis"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Loja não encontrada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "loja": {
                    "summary": "Loja não existe",
                    "value": {
                      "success": false,
                      "message": "Loja não encontrada"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Erro interno do servidor"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stores/{storeId}/webhooks-config/{id}/test": {
      "parameters": [
        {
          "$ref": "#/components/parameters/StoreId"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Id do webhook.",
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "example": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
        }
      ],
      "post": {
        "tags": [
          "Painel — Webhooks"
        ],
        "operationId": "testarWebhook",
        "summary": "Enviar evento de teste",
        "description": "Envia agora um evento `test` assinado para o endereço. A resposta não diz se o seu servidor aceitou — veja o histórico de entregas.\n\nSó administradores da loja.",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "responses": {
          "200": {
            "description": "Teste enviado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "ok": {
                    "summary": "Enviado",
                    "value": {
                      "success": true,
                      "message": "Test event sent"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja ou plano sem o recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  },
                  "semPlano": {
                    "summary": "Sem assinatura",
                    "value": {
                      "success": false,
                      "code": "PLAN_REQUIRED",
                      "message": "Assinatura ativa necessária para acessar este recurso"
                    }
                  },
                  "recurso": {
                    "summary": "Plano sem o recurso",
                    "value": {
                      "success": false,
                      "code": "FEATURE_NOT_AVAILABLE",
                      "message": "Este recurso não está disponível no seu plano atual. Faça upgrade para acessar.",
                      "feature": "webhooks_enabled",
                      "current_plan": "Grátis"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook ou loja não encontrado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "webhook": {
                    "summary": "Webhook não existe",
                    "value": {
                      "success": false,
                      "message": "Webhook not found"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Erro interno do servidor"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stores/{storeId}/webhooks-config/{id}/regenerate-secret": {
      "parameters": [
        {
          "$ref": "#/components/parameters/StoreId"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Id do webhook.",
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "example": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
        }
      ],
      "post": {
        "tags": [
          "Painel — Webhooks"
        ],
        "operationId": "novoSegredo",
        "summary": "Gerar novo segredo",
        "description": "Troca o segredo da assinatura na hora. Atualize o seu servidor logo em seguida: os próximos envios já usam o novo.\n\nSó administradores da loja.",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "responses": {
          "200": {
            "description": "Novo segredo.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "secret": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "ok": {
                    "summary": "Novo segredo",
                    "value": {
                      "success": true,
                      "data": {
                        "secret": "4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja ou plano sem o recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  },
                  "semPlano": {
                    "summary": "Sem assinatura",
                    "value": {
                      "success": false,
                      "code": "PLAN_REQUIRED",
                      "message": "Assinatura ativa necessária para acessar este recurso"
                    }
                  },
                  "recurso": {
                    "summary": "Plano sem o recurso",
                    "value": {
                      "success": false,
                      "code": "FEATURE_NOT_AVAILABLE",
                      "message": "Este recurso não está disponível no seu plano atual. Faça upgrade para acessar.",
                      "feature": "webhooks_enabled",
                      "current_plan": "Grátis"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook ou loja não encontrado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "webhook": {
                    "summary": "Webhook não existe",
                    "value": {
                      "success": false,
                      "message": "Webhook not found"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Erro interno do servidor"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stores/{storeId}/webhooks-config/{id}/events/{eventId}/retry": {
      "parameters": [
        {
          "$ref": "#/components/parameters/StoreId"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Id do webhook.",
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "example": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
        },
        {
          "name": "eventId",
          "in": "path",
          "required": true,
          "description": "Id da entrega (do histórico).",
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "example": "e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b"
        }
      ],
      "post": {
        "tags": [
          "Painel — Webhooks"
        ],
        "operationId": "reenviarEntrega",
        "summary": "Reenviar uma entrega",
        "description": "Envia de novo o mesmo `data` daquela entrega (com novo `timestamp` e nova assinatura). Gera um novo registro no histórico.\n\nSó administradores da loja.",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "responses": {
          "200": {
            "description": "Reenviado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "ok": {
                    "summary": "Reenviado",
                    "value": {
                      "success": true,
                      "message": "Event retried"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja ou plano sem o recurso.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  },
                  "semPlano": {
                    "summary": "Sem assinatura",
                    "value": {
                      "success": false,
                      "code": "PLAN_REQUIRED",
                      "message": "Assinatura ativa necessária para acessar este recurso"
                    }
                  },
                  "recurso": {
                    "summary": "Plano sem o recurso",
                    "value": {
                      "success": false,
                      "code": "FEATURE_NOT_AVAILABLE",
                      "message": "Este recurso não está disponível no seu plano atual. Faça upgrade para acessar.",
                      "feature": "webhooks_enabled",
                      "current_plan": "Grátis"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook, entrega ou loja não encontrado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "webhook": {
                    "summary": "Webhook não existe",
                    "value": {
                      "success": false,
                      "message": "Webhook not found"
                    }
                  },
                  "entrega": {
                    "summary": "Entrega não existe",
                    "value": {
                      "success": false,
                      "message": "Event not found"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Erro interno do servidor"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stores/{storeId}/connect-site/status": {
      "parameters": [
        {
          "$ref": "#/components/parameters/StoreId"
        }
      ],
      "get": {
        "tags": [
          "Painel — Meu site"
        ],
        "operationId": "statusMeuSite",
        "summary": "Situação da conexão do site",
        "description": "O que a tela *Meu site* mostra: se há chave, se o site já chamou a API e o webhook de estoque. Qualquer membro da loja; não depende do plano.",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "responses": {
          "200": {
            "description": "Situação.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectSiteStatus"
                },
                "examples": {
                  "ok": {
                    "summary": "Conectado",
                    "value": {
                      "success": true,
                      "data": {
                        "has_key": true,
                        "key_prefix": "dsk_8f3a2b1c",
                        "last_used_at": "2026-10-18T14:03:12.481Z",
                        "connected": true,
                        "webhook": {
                          "url": "https://seusite.com/webhooks/estoque",
                          "is_active": true,
                          "last_triggered_at": "2026-10-18T14:03:12.481Z",
                          "failure_count": 0
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Loja não encontrada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "loja": {
                    "summary": "Loja não existe",
                    "value": {
                      "success": false,
                      "message": "Loja não encontrada"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Erro ao carregar"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stores/{storeId}/connect-site/key": {
      "parameters": [
        {
          "$ref": "#/components/parameters/StoreId"
        }
      ],
      "post": {
        "tags": [
          "Painel — Meu site"
        ],
        "operationId": "chaveMeuSite",
        "summary": "Criar chave do site",
        "description": "Mesmo que **Criar chave** na tela: desliga a chave \"Site próprio\" anterior e cria outra com os escopos `orders:write`, `inventory`, `orders`, `products`, `mcp:read`. A chave completa só aparece aqui. Exige papel **admin** ou dono.",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "responses": {
          "201": {
            "description": "Chave criada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "raw_key": {
                          "type": "string"
                        },
                        "key_prefix": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "ok": {
                    "summary": "Criada",
                    "value": {
                      "success": true,
                      "data": {
                        "raw_key": "dsk_8f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a",
                        "key_prefix": "dsk_8f3a2b1c"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja, papel abaixo de admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Loja não encontrada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "loja": {
                    "summary": "Loja não existe",
                    "value": {
                      "success": false,
                      "message": "Loja não encontrada"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível criar a chave"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stores/{storeId}/connect-site/webhook": {
      "parameters": [
        {
          "$ref": "#/components/parameters/StoreId"
        }
      ],
      "put": {
        "tags": [
          "Painel — Meu site"
        ],
        "operationId": "webhookMeuSite",
        "summary": "Salvar endereço do aviso de estoque",
        "description": "Mesmo que **Salvar endereço** na tela. Na primeira vez cria o webhook `stock.updated` e devolve o segredo; depois só troca o endereço, religa e zera as falhas (`secret: null`). Exige papel **admin** ou dono; não depende do plano.",
        "security": [
          {
            "PanelJWT": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "pattern": "^https://",
                    "description": "Precisa começar com `https://`.",
                    "example": "https://seusite.com/webhooks/estoque"
                  }
                }
              },
              "examples": {
                "ok": {
                  "summary": "Endereço",
                  "value": {
                    "url": "https://seusite.com/webhooks/estoque"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Salvo.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "url": {
                          "type": "string"
                        },
                        "secret": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Só na primeira vez."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "criado": {
                    "summary": "Primeira vez",
                    "value": {
                      "success": true,
                      "data": {
                        "url": "https://seusite.com/webhooks/estoque",
                        "secret": "9c1f0e2d3b4a5968778695a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4"
                      }
                    }
                  },
                  "atualizado": {
                    "summary": "Já existia",
                    "value": {
                      "success": true,
                      "data": {
                        "url": "https://seusite.com/webhooks/estoque",
                        "secret": null
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Endereço sem https.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "https": {
                    "summary": "Sem https",
                    "value": {
                      "success": false,
                      "message": "Use um endereço que comece com https://"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem login ou token inválido/vencido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semToken": {
                    "summary": "Sem Authorization",
                    "value": {
                      "success": false,
                      "message": "Autenticação necessária"
                    }
                  },
                  "invalido": {
                    "summary": "Token inválido",
                    "value": {
                      "success": false,
                      "message": "Token inválido"
                    }
                  },
                  "vencido": {
                    "summary": "Token vencido",
                    "value": {
                      "success": false,
                      "message": "Token expirado"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem acesso à loja, papel abaixo de admin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "acesso": {
                    "summary": "Não é membro da loja",
                    "value": {
                      "success": false,
                      "message": "Acesso negado a esta loja"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Loja não encontrada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "loja": {
                    "summary": "Loja não existe",
                    "value": {
                      "success": false,
                      "message": "Loja não encontrada"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível salvar"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/me": {
      "get": {
        "tags": [
          "Automações — Pedidos e clientes"
        ],
        "operationId": "lojaDaChave",
        "summary": "De qual loja é esta chave",
        "x-scopes": [],
        "description": "**Escopo:** qualquer chave válida\n\nDevolve a loja da chave (id, nome, endereço do site e do blog) e os escopos da chave. Use para **testar a conexão** e descobrir o `storeId` sem pedir à pessoa.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Loja da chave.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoreMe"
                },
                "examples": {
                  "ok": {
                    "summary": "Loja",
                    "value": {
                      "success": true,
                      "data": {
                        "store": {
                          "id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
                          "name": "Minha Loja",
                          "slug": "minha-loja",
                          "logo": null,
                          "url": "https://admin-marketplace.devskin.com/s/minha-loja",
                          "blog_url": "https://admin-marketplace.devskin.com/s/minha-loja/blog"
                        },
                        "key": {
                          "name": "Devskin Marketing",
                          "prefix": "dsk_9f8e7d6c",
                          "scopes": [
                            "*"
                          ],
                          "expires_at": null
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível ler os dados da loja."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/orders/{id}": {
      "patch": {
        "tags": [
          "Automações — Pedidos e clientes"
        ],
        "operationId": "atualizarPedidoAutomacao",
        "summary": "Mudar status, rastreio ou anotar no pedido",
        "x-scopes": [
          "orders:write"
        ],
        "description": "**Escopo:** `orders:write`\n\nMesma regra do painel: com `tracking_code` o pedido vira **enviado** e o cliente recebe e-mail; `delivered` avisa o cliente; `cancelled` devolve o estoque e o cupom. Gera os webhooks `order.*`. `note` é **acrescentada** às anotações (não apaga as antigas). Mandar o mesmo status de novo não faz nada (idempotente).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id (UUID) **ou** número do pedido desta loja.",
            "schema": {
              "type": "string"
            },
            "example": "DS-1001"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderPatchInput"
              },
              "examples": {
                "enviado": {
                  "summary": "Enviado com rastreio",
                  "value": {
                    "tracking_code": "BR123456789BR",
                    "tracking_url": "https://rastreamento.correios.com.br/app/index.php"
                  }
                },
                "status": {
                  "summary": "Mudar status",
                  "value": {
                    "status": "processing",
                    "note": "Pagamento conferido pela automação",
                    "source": "Devskin Marketing"
                  }
                },
                "nota": {
                  "summary": "Só anotar",
                  "value": {
                    "note": "Cliente pediu embrulho para presente"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pedido atualizado.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderPatchResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Atualizado",
                    "value": {
                      "success": true,
                      "message": "Pedido atualizado.",
                      "data": {
                        "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                        "order_number": "DS-1001",
                        "status": "shipped",
                        "payment_status": "paid",
                        "tracking_code": "BR123456789BR",
                        "tracking_url": null,
                        "notes": null
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Corpo inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "vazio": {
                    "summary": "Nada para mudar",
                    "value": {
                      "success": false,
                      "message": "Envie pelo menos um: \"status\", \"tracking_code\" ou \"note\"."
                    }
                  },
                  "status": {
                    "summary": "Status errado",
                    "value": {
                      "success": false,
                      "message": "Status inválido. Use: pending, processing, shipped, delivered, cancelled."
                    }
                  },
                  "digital": {
                    "summary": "Pedido sem produto físico",
                    "value": {
                      "success": false,
                      "message": "orders.not_shippable"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `orders:write`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'orders:write' scope"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Pedido não é desta loja.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "naoExiste": {
                    "summary": "Não encontrado",
                    "value": {
                      "success": false,
                      "message": "Pedido não encontrado nesta loja."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível atualizar o pedido."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/orders/{id}/notes": {
      "post": {
        "tags": [
          "Automações — Pedidos e clientes"
        ],
        "operationId": "anotarPedido",
        "summary": "Anotar no pedido",
        "x-scopes": [
          "orders:write"
        ],
        "description": "**Escopo:** `orders:write`\n\nAcrescenta uma linha às anotações do pedido (`[data · origem] texto`).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id (UUID) **ou** número do pedido desta loja.",
            "schema": {
              "type": "string"
            },
            "example": "DS-1001"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderNoteInput"
              },
              "examples": {
                "nota": {
                  "summary": "Anotação",
                  "value": {
                    "note": "Cliente abriu o e-mail de carrinho abandonado",
                    "source": "Devskin Marketing"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Anotação salva.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderNoteResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Salva",
                    "value": {
                      "success": true,
                      "message": "Anotação salva.",
                      "data": {
                        "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                        "order_number": "DS-1001",
                        "notes": "[18/10/2026, 14:03:12 · Devskin Marketing] Cliente abriu o e-mail de carrinho abandonado"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`note` ausente, grande demais, ou anotações cheias.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "vazio": {
                    "summary": "Sem texto",
                    "value": {
                      "success": false,
                      "message": "Informe \"note\"."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `orders:write`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'orders:write' scope"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Pedido não é desta loja.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "naoExiste": {
                    "summary": "Não encontrado",
                    "value": {
                      "success": false,
                      "message": "Pedido não encontrado nesta loja."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível salvar a anotação."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/customers/tags": {
      "post": {
        "tags": [
          "Automações — Pedidos e clientes"
        ],
        "operationId": "etiquetarCliente",
        "summary": "Etiquetar cliente",
        "x-scopes": [
          "customers:write"
        ],
        "description": "**Escopo:** `customers:write`\n\nPõe uma ou mais etiquetas num cliente **desta loja** (tem conta e comprou/teve carrinho aqui, ou é comprador de um pedido de canal). Idempotente: a mesma etiqueta não duplica. As etiquetas aparecem no detalhe do cliente da API do painel (`GET /stores/{storeId}/customers/{id}` → `data.tags`).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerTagInput"
              },
              "examples": {
                "email": {
                  "summary": "Por e-mail",
                  "value": {
                    "email": "maria@exemplo.com",
                    "tag": "carrinho-abandonado",
                    "source": "devskin_marketing"
                  }
                },
                "varias": {
                  "summary": "Várias",
                  "value": {
                    "customer_id": "5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d",
                    "tags": [
                      "vip",
                      "comprou-2x"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Etiqueta salva.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerTagResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Salva",
                    "value": {
                      "success": true,
                      "message": "Etiqueta salva.",
                      "data": {
                        "customer": {
                          "id": null,
                          "email": "maria@exemplo.com",
                          "name": "Maria Silva"
                        },
                        "tags": [
                          "carrinho-abandonado"
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Faltou cliente ou etiqueta.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semTag": {
                    "summary": "Sem etiqueta",
                    "value": {
                      "success": false,
                      "message": "Informe \"tag\" (texto até 60 letras) ou \"tags\" (lista)."
                    }
                  },
                  "semCliente": {
                    "summary": "Sem cliente",
                    "value": {
                      "success": false,
                      "message": "Informe o \"email\" ou o \"customer_id\" do cliente."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `customers:write`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'customers:write' scope"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Não é cliente desta loja.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "naoCliente": {
                    "summary": "Não encontrado",
                    "value": {
                      "success": false,
                      "message": "Cliente não encontrado nesta loja (precisa ter comprado ou ter carrinho aqui)."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível salvar a etiqueta."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Automações — Pedidos e clientes"
        ],
        "operationId": "verEtiquetas",
        "summary": "Ver etiquetas",
        "x-scopes": [
          "customers",
          "customers:write"
        ],
        "description": "**Escopo:** `customers` ou `customers:write`\n\nEtiquetas de um cliente (`email` ou `customer_id`) ou clientes com uma etiqueta (`tag`). Até 500 linhas.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "email",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "maria@exemplo.com"
          },
          {
            "name": "customer_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "tag",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "vip"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Etiquetas.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerTagList"
                },
                "examples": {
                  "ok": {
                    "summary": "Lista",
                    "value": {
                      "success": true,
                      "data": [
                        {
                          "email": "maria@exemplo.com",
                          "customer_id": null,
                          "tag": "vip",
                          "source": "devskin_marketing",
                          "created_at": "2026-10-18T14:03:12.000Z"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Nenhum filtro.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semFiltro": {
                    "summary": "Sem filtro",
                    "value": {
                      "success": false,
                      "message": "Informe \"email\", \"customer_id\" ou \"tag\"."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `customers`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'customers' scope"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível ler as etiquetas."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/notifications/email": {
      "post": {
        "tags": [
          "Automações — Pedidos e clientes"
        ],
        "operationId": "emailComprador",
        "summary": "Mandar e-mail ao comprador",
        "x-scopes": [
          "notifications:write"
        ],
        "description": "**Escopo:** `notifications:write`\n\nManda um e-mail no **modelo visual da loja** (logo, cor e rodapé de Configurações › E-mail), pelo SMTP da loja (se configurado) ou o da plataforma. Só para **clientes desta loja**: a API não manda e-mail para endereços quaisquer. Texto simples (sem HTML).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BuyerEmailInput"
              },
              "examples": {
                "pedido": {
                  "summary": "Comprador do pedido",
                  "value": {
                    "order_id": "DS-1001",
                    "subject": "Seu pedido saiu para entrega",
                    "message": "Oi, Maria!\n\nSeu pedido já está a caminho.",
                    "button_url": "https://admin-marketplace.devskin.com/s/minha-loja/account/orders",
                    "button_label": "Ver pedido"
                  }
                },
                "cliente": {
                  "summary": "Cliente por e-mail",
                  "value": {
                    "to": "maria@exemplo.com",
                    "subject": "Você esqueceu itens no carrinho",
                    "message": "Seus produtos ainda estão esperando por você."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "E-mail enviado.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BuyerEmailResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Enviado",
                    "value": {
                      "success": true,
                      "message": "E-mail enviado.",
                      "data": {
                        "to": "maria@exemplo.com",
                        "name": "Maria Silva",
                        "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Faltou assunto, texto ou destinatário.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "assunto": {
                    "summary": "Sem assunto",
                    "value": {
                      "success": false,
                      "message": "Informe o assunto em \"subject\"."
                    }
                  },
                  "dest": {
                    "summary": "Sem destinatário",
                    "value": {
                      "success": false,
                      "message": "Informe \"order_id\", \"customer_id\" ou \"to\" (e-mail do cliente)."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `notifications:write`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'notifications:write' scope"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Pedido ou cliente não é desta loja.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "naoCliente": {
                    "summary": "Não é cliente",
                    "value": {
                      "success": false,
                      "message": "Destinatário não é cliente desta loja (precisa ter comprado ou ter carrinho aqui)."
                    }
                  },
                  "pedido": {
                    "summary": "Pedido",
                    "value": {
                      "success": false,
                      "message": "Pedido não encontrado nesta loja."
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "O pedido não tem e-mail do comprador.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "semEmail": {
                    "summary": "Sem e-mail",
                    "value": {
                      "success": false,
                      "message": "Este pedido não tem e-mail do comprador."
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "O servidor de e-mail recusou ou está fora.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "smtp": {
                    "summary": "Falha no envio",
                    "value": {
                      "success": false,
                      "message": "O e-mail não pôde ser enviado agora. Confira o e-mail da loja em Configurações › E-mail."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível enviar o e-mail."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/webhooks": {
      "get": {
        "tags": [
          "Automações — Webhooks por chave"
        ],
        "operationId": "listarWebhooksChave",
        "summary": "Listar webhooks da loja",
        "x-scopes": [
          "webhooks:write"
        ],
        "description": "**Escopo:** `webhooks:write`\n\nWebhooks da loja da chave (sem o segredo).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Lista.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookListResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Lista",
                    "value": {
                      "success": true,
                      "data": {
                        "webhooks": [
                          {
                            "id": "a7b8c9d0-e1f2-4a3b-9c4d-5e6f7a8b9c0d",
                            "store_id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
                            "url": "https://marketing-api.devskin.com/api/integrations/marketplace/webhook/9c1e...",
                            "events": [
                              "order.created",
                              "cart.abandoned"
                            ],
                            "is_active": true,
                            "failure_count": 0,
                            "last_triggered_at": null
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem o escopo `webhooks:write`, ou o plano não tem webhooks.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'webhooks:write' scope"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível listar os webhooks."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Automações — Webhooks por chave"
        ],
        "operationId": "cadastrarWebhookChave",
        "summary": "Cadastrar (ou recadastrar) webhook",
        "x-scopes": [
          "webhooks:write"
        ],
        "description": "**Escopo:** `webhooks:write`\n\nCadastra o endereço que vai receber os avisos. Se **a mesma URL** já existe na loja, atualiza os eventos, liga de novo, zera as falhas e gera **segredo novo** (responde `200` com `created: false`). URL só `https://` pública. O segredo aparece só nesta resposta.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookCreateInput"
              },
              "examples": {
                "marketing": {
                  "summary": "Automações do Marketing",
                  "value": {
                    "url": "https://marketing-api.devskin.com/api/integrations/marketplace/webhook/9c1e4b...",
                    "events": [
                      "order.created",
                      "order.shipped",
                      "cart.abandoned",
                      "payment.confirmed"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Criado.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookRegisterResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Criado",
                    "value": {
                      "success": true,
                      "message": "Guarde o segredo agora: ele não aparece de novo.",
                      "data": {
                        "webhook": {
                          "id": "a7b8c9d0-e1f2-4a3b-9c4d-5e6f7a8b9c0d",
                          "store_id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
                          "url": "https://marketing-api.devskin.com/api/integrations/marketplace/webhook/9c1e...",
                          "events": [
                            "order.created",
                            "cart.abandoned"
                          ],
                          "is_active": true,
                          "failure_count": 0,
                          "last_triggered_at": null
                        },
                        "secret": "4f3c2b1a...",
                        "created": true
                      }
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "A URL já existia: atualizado, com segredo novo (`created: false`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookRegisterResult"
                }
              }
            }
          },
          "400": {
            "description": "URL ou eventos inválidos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "url": {
                    "summary": "URL",
                    "value": {
                      "success": false,
                      "message": "Use uma URL que comece com https://"
                    }
                  },
                  "evento": {
                    "summary": "Evento",
                    "value": {
                      "success": false,
                      "message": "Evento(s) desconhecido(s): order.foo. Válidos: ..."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem o escopo `webhooks:write`, ou o plano não tem webhooks.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'webhooks:write' scope"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível cadastrar o webhook."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/webhooks/{id}": {
      "put": {
        "tags": [
          "Automações — Webhooks por chave"
        ],
        "operationId": "atualizarWebhookChave",
        "summary": "Atualizar webhook",
        "x-scopes": [
          "webhooks:write"
        ],
        "description": "**Escopo:** `webhooks:write`\n\nMuda URL, eventos ou liga/desliga. Ligar de novo zera as falhas.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id do webhook.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "a7b8c9d0-e1f2-4a3b-9c4d-5e6f7a8b9c0d"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdateInput"
              },
              "examples": {
                "desligar": {
                  "summary": "Desligar",
                  "value": {
                    "is_active": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualizado.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookItemResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Atualizado",
                    "value": {
                      "success": true,
                      "data": {
                        "webhook": {
                          "id": "a7b8c9d0-e1f2-4a3b-9c4d-5e6f7a8b9c0d",
                          "store_id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
                          "url": "https://marketing-api.devskin.com/api/integrations/marketplace/webhook/9c1e...",
                          "events": [
                            "order.created",
                            "cart.abandoned"
                          ],
                          "is_active": true,
                          "failure_count": 0,
                          "last_triggered_at": null
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "URL ou eventos inválidos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "url": {
                    "summary": "URL",
                    "value": {
                      "success": false,
                      "message": "Use uma URL que comece com https://"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem o escopo `webhooks:write`, ou o plano não tem webhooks.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'webhooks:write' scope"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Não é desta loja.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "naoExiste": {
                    "summary": "Não encontrado",
                    "value": {
                      "success": false,
                      "message": "Webhook não encontrado nesta loja."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível atualizar o webhook."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Automações — Webhooks por chave"
        ],
        "operationId": "removerWebhookChave",
        "summary": "Remover webhook",
        "x-scopes": [
          "webhooks:write"
        ],
        "description": "**Escopo:** `webhooks:write`\n\nApaga o cadastro (ex.: ao desconectar a integração).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id do webhook.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "a7b8c9d0-e1f2-4a3b-9c4d-5e6f7a8b9c0d"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Removido.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "message": "Webhook removido."
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem o escopo `webhooks:write`, ou o plano não tem webhooks.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'webhooks:write' scope"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Não é desta loja.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "naoExiste": {
                    "summary": "Não encontrado",
                    "value": {
                      "success": false,
                      "message": "Webhook não encontrado nesta loja."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível remover o webhook."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/webhooks/{id}/test": {
      "post": {
        "tags": [
          "Automações — Webhooks por chave"
        ],
        "operationId": "testarWebhookChave",
        "summary": "Testar webhook",
        "x-scopes": [
          "webhooks:write"
        ],
        "description": "**Escopo:** `webhooks:write`\n\nManda o evento `test` agora e diz se o destino respondeu 2xx.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id do webhook.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "a7b8c9d0-e1f2-4a3b-9c4d-5e6f7a8b9c0d"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Resultado do teste.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookTestResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Entregue",
                    "value": {
                      "success": true,
                      "message": "Teste entregue.",
                      "data": {
                        "delivered": true,
                        "response_status": 200
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Sem o escopo `webhooks:write`, ou o plano não tem webhooks.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ErrorResponse"
                    },
                    {
                      "$ref": "#/components/schemas/PlanErrorResponse"
                    }
                  ]
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'webhooks:write' scope"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Não é desta loja.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "naoExiste": {
                    "summary": "Não encontrado",
                    "value": {
                      "success": false,
                      "message": "Webhook não encontrado nesta loja."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível enviar o teste."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/blog/categories": {
      "get": {
        "tags": [
          "Blog da loja"
        ],
        "operationId": "categoriasBlog",
        "summary": "Categorias do blog",
        "x-scopes": [
          "blog:read",
          "blog:write"
        ],
        "description": "**Escopo:** `blog:read` ou `blog:write`\n\nCategorias do blog da loja, na ordem do painel.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Categorias.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogCategoryList"
                },
                "examples": {
                  "ok": {
                    "summary": "Lista",
                    "value": {
                      "success": true,
                      "data": [
                        {
                          "id": "d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f7a",
                          "name": "Dicas",
                          "slug": "dicas",
                          "description": null,
                          "is_active": true,
                          "sort_order": 0
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `blog:read`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'blog:read' scope"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível ler as categorias."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/blog/posts": {
      "get": {
        "tags": [
          "Blog da loja"
        ],
        "operationId": "listarPostsBlog",
        "summary": "Listar posts",
        "x-scopes": [
          "blog:read",
          "blog:write"
        ],
        "description": "**Escopo:** `blog:read` ou `blog:write`\n\nPosts da loja, do mais novo para o mais antigo. Com `external_id` (+ `external_source`) acha o post que você já mandou.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "published",
                "archived"
              ]
            }
          },
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "external_source",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "api"
            }
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Posts.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogPostList"
                },
                "examples": {
                  "ok": {
                    "summary": "Lista",
                    "value": {
                      "success": true,
                      "data": {
                        "data": [
                          {
                            "id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                            "title": "5 dicas para escolher o tênis certo",
                            "slug": "5-dicas-para-escolher-o-tenis-certo",
                            "excerpt": "Conforto, tamanho e uso.",
                            "content": "<h2>1. Tamanho</h2><p>...</p>",
                            "cover_image_url": "https://cdn.exemplo.com/capa.jpg",
                            "og_image": "https://cdn.exemplo.com/capa.jpg",
                            "seo_title": "Como escolher tênis | Minha Loja",
                            "seo_description": "Guia rápido para acertar no tênis.",
                            "tags": [
                              "tênis",
                              "guia"
                            ],
                            "category": {
                              "id": "d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f7a",
                              "name": "Dicas",
                              "slug": "dicas"
                            },
                            "status": "published",
                            "is_featured": false,
                            "published_at": "2026-10-18T14:03:12.000Z",
                            "external_source": "devskin_marketing",
                            "external_id": "b2f1...",
                            "views": 0,
                            "url": "https://admin-marketplace.devskin.com/s/minha-loja/blog/5-dicas-para-escolher-o-tenis-certo",
                            "created": true,
                            "created_at": "2026-10-18T14:03:12.000Z",
                            "updated_at": "2026-10-18T14:03:12.000Z"
                          }
                        ],
                        "pagination": {
                          "total": 1,
                          "page": 1,
                          "limit": 20,
                          "totalPages": 1,
                          "hasMore": false
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Filtro inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "status": {
                    "summary": "Status",
                    "value": {
                      "success": false,
                      "message": "\"status\" inválido. Use draft, published ou archived."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `blog:read`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'blog:read' scope"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível listar os posts."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Blog da loja"
        ],
        "operationId": "criarPostBlog",
        "summary": "Criar (ou atualizar pelo external_id) um post",
        "x-scopes": [
          "blog:write"
        ],
        "description": "**Escopo:** `blog:write`\n\nCria o post no blog da loja. Com `external_id` já usado nesta loja (mesma `external_source`) **atualiza** o post (responde `200`, `created: false`) — publicar de novo nunca duplica. `published` aparece na hora em `<site>/blog/<slug>`; a resposta traz a `url` pública. `category` (nome) cria a categoria se faltar.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogPostInput"
              },
              "examples": {
                "publicar": {
                  "summary": "Publicar agora",
                  "value": {
                    "external_id": "b2f1...",
                    "external_source": "devskin_marketing",
                    "title": "5 dicas para escolher o tênis certo",
                    "content": "<h2>1. Tamanho</h2><p>...</p>",
                    "excerpt": "Conforto, tamanho e uso.",
                    "cover_image_url": "https://cdn.exemplo.com/capa.jpg",
                    "seo_title": "Como escolher tênis | Minha Loja",
                    "seo_description": "Guia rápido para acertar no tênis.",
                    "tags": [
                      "tênis",
                      "guia"
                    ],
                    "category": "Dicas",
                    "status": "published"
                  }
                },
                "rascunho": {
                  "summary": "Rascunho",
                  "value": {
                    "title": "Ideia de post",
                    "content": "<p>Rascunho</p>"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Criado.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogPostResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Criado",
                    "value": {
                      "success": true,
                      "message": "Post criado.",
                      "data": {
                        "id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                        "title": "5 dicas para escolher o tênis certo",
                        "slug": "5-dicas-para-escolher-o-tenis-certo",
                        "excerpt": "Conforto, tamanho e uso.",
                        "content": "<h2>1. Tamanho</h2><p>...</p>",
                        "cover_image_url": "https://cdn.exemplo.com/capa.jpg",
                        "og_image": "https://cdn.exemplo.com/capa.jpg",
                        "seo_title": "Como escolher tênis | Minha Loja",
                        "seo_description": "Guia rápido para acertar no tênis.",
                        "tags": [
                          "tênis",
                          "guia"
                        ],
                        "category": {
                          "id": "d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f7a",
                          "name": "Dicas",
                          "slug": "dicas"
                        },
                        "status": "published",
                        "is_featured": false,
                        "published_at": "2026-10-18T14:03:12.000Z",
                        "external_source": "devskin_marketing",
                        "external_id": "b2f1...",
                        "views": 0,
                        "url": "https://admin-marketplace.devskin.com/s/minha-loja/blog/5-dicas-para-escolher-o-tenis-certo",
                        "created": true,
                        "created_at": "2026-10-18T14:03:12.000Z",
                        "updated_at": "2026-10-18T14:03:12.000Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "Já existia com esse `external_id`: atualizado (`created: false`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogPostResult"
                }
              }
            }
          },
          "400": {
            "description": "Campo inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "titulo": {
                    "summary": "Sem título",
                    "value": {
                      "success": false,
                      "message": "Informe o \"title\"."
                    }
                  },
                  "conteudo": {
                    "summary": "Sem conteúdo",
                    "value": {
                      "success": false,
                      "message": "Informe o \"content\" (HTML do artigo)."
                    }
                  },
                  "agenda": {
                    "summary": "Data futura",
                    "value": {
                      "success": false,
                      "message": "Agendamento não é aceito aqui: mande o post na hora de publicar (ou como draft)."
                    }
                  },
                  "categoria": {
                    "summary": "Categoria",
                    "value": {
                      "success": false,
                      "message": "Categoria não encontrada nesta loja (\"category_id\")."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `blog:write`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'blog:write' scope"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Dois envios ao mesmo tempo com o mesmo `external_id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "corrida": {
                    "summary": "Repetir",
                    "value": {
                      "success": false,
                      "message": "Este post já está sendo criado (mesmo \"external_id\"). Tente de novo em instantes."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível salvar o post."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/blog/posts/{id}": {
      "get": {
        "tags": [
          "Blog da loja"
        ],
        "operationId": "verPostBlog",
        "summary": "Ver um post",
        "x-scopes": [
          "blog:read",
          "blog:write"
        ],
        "description": "**Escopo:** `blog:read` ou `blog:write`\n\nUm post da loja, com o conteúdo.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id do post no ERP.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "responses": {
          "200": {
            "description": "Post.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogPostResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Post",
                    "value": {
                      "success": true,
                      "data": {
                        "id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                        "title": "5 dicas para escolher o tênis certo",
                        "slug": "5-dicas-para-escolher-o-tenis-certo",
                        "excerpt": "Conforto, tamanho e uso.",
                        "content": "<h2>1. Tamanho</h2><p>...</p>",
                        "cover_image_url": "https://cdn.exemplo.com/capa.jpg",
                        "og_image": "https://cdn.exemplo.com/capa.jpg",
                        "seo_title": "Como escolher tênis | Minha Loja",
                        "seo_description": "Guia rápido para acertar no tênis.",
                        "tags": [
                          "tênis",
                          "guia"
                        ],
                        "category": {
                          "id": "d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f7a",
                          "name": "Dicas",
                          "slug": "dicas"
                        },
                        "status": "published",
                        "is_featured": false,
                        "published_at": "2026-10-18T14:03:12.000Z",
                        "external_source": "devskin_marketing",
                        "external_id": "b2f1...",
                        "views": 0,
                        "url": "https://admin-marketplace.devskin.com/s/minha-loja/blog/5-dicas-para-escolher-o-tenis-certo",
                        "created": true,
                        "created_at": "2026-10-18T14:03:12.000Z",
                        "updated_at": "2026-10-18T14:03:12.000Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `blog:read`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'blog:read' scope"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Não é desta loja.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "naoExiste": {
                    "summary": "Não encontrado",
                    "value": {
                      "success": false,
                      "message": "Post não encontrado nesta loja."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível ler o post."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Blog da loja"
        ],
        "operationId": "atualizarPostBlog",
        "summary": "Atualizar um post",
        "x-scopes": [
          "blog:write"
        ],
        "description": "**Escopo:** `blog:write`\n\nMuda só os campos enviados. O `slug` só muda se você mandar `slug`.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id do post no ERP.",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f"
          },
          {
            "$ref": "#/components/parameters/RequestId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BlogPostInput"
              },
              "examples": {
                "despublicar": {
                  "summary": "Voltar para rascunho",
                  "value": {
                    "status": "draft"
                  }
                },
                "seo": {
                  "summary": "Ajustar SEO",
                  "value": {
                    "seo_title": "Tênis: como escolher",
                    "seo_description": "Guia rápido."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualizado.",
            "headers": {
              "X-Request-ID": {
                "description": "Id da requisição (o seu, se enviou um válido).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogPostResult"
                },
                "examples": {
                  "ok": {
                    "summary": "Atualizado",
                    "value": {
                      "success": true,
                      "message": "Post atualizado.",
                      "data": {
                        "id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
                        "title": "5 dicas para escolher o tênis certo",
                        "slug": "5-dicas-para-escolher-o-tenis-certo",
                        "excerpt": "Conforto, tamanho e uso.",
                        "content": "<h2>1. Tamanho</h2><p>...</p>",
                        "cover_image_url": "https://cdn.exemplo.com/capa.jpg",
                        "og_image": "https://cdn.exemplo.com/capa.jpg",
                        "seo_title": "Como escolher tênis | Minha Loja",
                        "seo_description": "Guia rápido para acertar no tênis.",
                        "tags": [
                          "tênis",
                          "guia"
                        ],
                        "category": {
                          "id": "d4e5f6a7-b8c9-4d0e-8f1a-2b3c4d5e6f7a",
                          "name": "Dicas",
                          "slug": "dicas"
                        },
                        "status": "published",
                        "is_featured": false,
                        "published_at": "2026-10-18T14:03:12.000Z",
                        "external_source": "devskin_marketing",
                        "external_id": "b2f1...",
                        "views": 0,
                        "url": "https://admin-marketplace.devskin.com/s/minha-loja/blog/5-dicas-para-escolher-o-tenis-certo",
                        "created": true,
                        "created_at": "2026-10-18T14:03:12.000Z",
                        "updated_at": "2026-10-18T14:03:12.000Z"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Campo inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "titulo": {
                    "summary": "Sem título",
                    "value": {
                      "success": false,
                      "message": "Informe o \"title\"."
                    }
                  },
                  "conteudo": {
                    "summary": "Sem conteúdo",
                    "value": {
                      "success": false,
                      "message": "Informe o \"content\" (HTML do artigo)."
                    }
                  },
                  "agenda": {
                    "summary": "Data futura",
                    "value": {
                      "success": false,
                      "message": "Agendamento não é aceito aqui: mande o post na hora de publicar (ou como draft)."
                    }
                  },
                  "categoria": {
                    "summary": "Categoria",
                    "value": {
                      "success": false,
                      "message": "Categoria não encontrada nesta loja (\"category_id\")."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, desligada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "ausente": {
                    "summary": "Sem header X-API-Key",
                    "value": {
                      "success": false,
                      "message": "API key required. Use X-API-Key header."
                    }
                  },
                  "invalida": {
                    "summary": "Chave errada ou desligada",
                    "value": {
                      "success": false,
                      "message": "Invalid or revoked API key"
                    }
                  },
                  "vencida": {
                    "summary": "Chave vencida",
                    "value": {
                      "success": false,
                      "message": "API key expired"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "A chave não tem o escopo `blog:write`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "escopo": {
                    "summary": "Sem escopo",
                    "value": {
                      "success": false,
                      "message": "API key does not have the 'blog:write' scope"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Não é desta loja.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "naoExiste": {
                    "summary": "Não encontrado",
                    "value": {
                      "success": false,
                      "message": "Post não encontrado nesta loja."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Erro inesperado no servidor. Pode repetir mais tarde.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "erro": {
                    "summary": "Erro interno",
                    "value": {
                      "success": false,
                      "message": "Não foi possível salvar o post."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/orders/external/{externalId}/invoice": {
      "get": {
        "tags": [
          "Site próprio — Pedidos"
        ],
        "operationId": "consultarNotaPedidoSite",
        "summary": "Consultar a nota fiscal do pedido",
        "x-scopes": [
          "orders:write"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "externalId",
            "in": "path",
            "required": true,
            "description": "O `id` do pedido no seu site (o mesmo enviado em POST /v1/store/orders).",
            "schema": {
              "type": "string",
              "maxLength": 40
            },
            "example": "1001"
          }
        ],
        "description": "**Escopo:** `orders:write`\n\nDevolve a NF-e de venda do pedido (ou `null`), o status do pedido e o rastreio.",
        "responses": {
          "200": {
            "description": "Nota do pedido",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "order_id": {
                          "type": "string"
                        },
                        "order_number": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string"
                        },
                        "tracking_code": {
                          "type": "string",
                          "nullable": true
                        },
                        "invoice": {
                          "type": "object",
                          "nullable": true,
                          "properties": {
                            "id": {
                              "type": "string",
                              "format": "uuid"
                            },
                            "status": {
                              "type": "string",
                              "enum": [
                                "autorizada",
                                "processando",
                                "rejeitada",
                                "externa"
                              ],
                              "description": "`externa` = nota emitida em outro sistema (informada no campo invoice do pedido)."
                            },
                            "number": {
                              "type": "integer"
                            },
                            "serie": {
                              "type": "integer"
                            },
                            "access_key": {
                              "type": "string",
                              "description": "Chave de acesso (44 dígitos). Use no frete (ex.: Melhor Envio) para a etiqueta sair com a DANFE."
                            },
                            "environment": {
                              "type": "string",
                              "enum": [
                                "producao",
                                "homologacao"
                              ]
                            },
                            "authorized_at": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "message": {
                              "type": "string",
                              "nullable": true,
                              "description": "Motivo, quando rejeitada."
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Erro (mensagem em `message`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "message": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Site próprio — Pedidos"
        ],
        "operationId": "emitirNotaPedidoSite",
        "summary": "Emitir a NF-e do pedido",
        "x-scopes": [
          "orders:write"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "externalId",
            "in": "path",
            "required": true,
            "description": "O `id` do pedido no seu site (o mesmo enviado em POST /v1/store/orders).",
            "schema": {
              "type": "string",
              "maxLength": 40
            },
            "example": "1001"
          }
        ],
        "description": "**Escopo:** `orders:write`\n\nEmite a NF-e de venda do pedido com os dados fiscais da loja (mesma regra do botão *Emitir nota* do painel). Uma nota por pedido: se já existir, devolve a existente. Pedido com nota de outro sistema (campo `invoice` no envio do pedido) responde `409` para não duplicar.\n\nCom a nota autorizada, o cliente recebe a nota por e-mail (se a loja deixou ligado).\n\n**Ordem recomendada:** enviar o pedido → emitir a nota → comprar o frete usando `access_key` → enviar a etiqueta (POST .../label).",
        "responses": {
          "201": {
            "description": "Nota emitida",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "order_number": {
                          "type": "string"
                        },
                        "invoice": {
                          "type": "object",
                          "nullable": true,
                          "properties": {
                            "id": {
                              "type": "string",
                              "format": "uuid"
                            },
                            "status": {
                              "type": "string",
                              "enum": [
                                "autorizada",
                                "processando",
                                "rejeitada",
                                "externa"
                              ],
                              "description": "`externa` = nota emitida em outro sistema (informada no campo invoice do pedido)."
                            },
                            "number": {
                              "type": "integer"
                            },
                            "serie": {
                              "type": "integer"
                            },
                            "access_key": {
                              "type": "string",
                              "description": "Chave de acesso (44 dígitos). Use no frete (ex.: Melhor Envio) para a etiqueta sair com a DANFE."
                            },
                            "environment": {
                              "type": "string",
                              "enum": [
                                "producao",
                                "homologacao"
                              ]
                            },
                            "authorized_at": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "message": {
                              "type": "string",
                              "nullable": true,
                              "description": "Motivo, quando rejeitada."
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "O pedido já tinha nota",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "order_number": {
                          "type": "string"
                        },
                        "invoice": {
                          "type": "object",
                          "nullable": true,
                          "properties": {
                            "id": {
                              "type": "string",
                              "format": "uuid"
                            },
                            "status": {
                              "type": "string",
                              "enum": [
                                "autorizada",
                                "processando",
                                "rejeitada",
                                "externa"
                              ],
                              "description": "`externa` = nota emitida em outro sistema (informada no campo invoice do pedido)."
                            },
                            "number": {
                              "type": "integer"
                            },
                            "serie": {
                              "type": "integer"
                            },
                            "access_key": {
                              "type": "string",
                              "description": "Chave de acesso (44 dígitos). Use no frete (ex.: Melhor Envio) para a etiqueta sair com a DANFE."
                            },
                            "environment": {
                              "type": "string",
                              "enum": [
                                "producao",
                                "homologacao"
                              ]
                            },
                            "authorized_at": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "message": {
                              "type": "string",
                              "nullable": true,
                              "description": "Motivo, quando rejeitada."
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Erro (mensagem em `message`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "message": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Erro (mensagem em `message`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "message": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Erro (mensagem em `message`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "message": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/orders/external/{externalId}/danfe": {
      "get": {
        "tags": [
          "Site próprio — Pedidos"
        ],
        "operationId": "baixarDanfePedidoSite",
        "summary": "Baixar a DANFE (PDF)",
        "x-scopes": [
          "orders:write"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "externalId",
            "in": "path",
            "required": true,
            "description": "O `id` do pedido no seu site (o mesmo enviado em POST /v1/store/orders).",
            "schema": {
              "type": "string",
              "maxLength": 40
            },
            "example": "1001"
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "a6",
                "a4"
              ],
              "default": "a6"
            },
            "description": "`a6` = DANFE simplificada 10×15 (etiqueta térmica); `a4` = DANFE completa."
          }
        ],
        "description": "**Escopo:** `orders:write`\n\nPDF da nota autorizada do pedido.",
        "responses": {
          "200": {
            "description": "PDF",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "Erro (mensagem em `message`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "message": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/orders/external/{externalId}/label": {
      "post": {
        "tags": [
          "Site próprio — Pedidos"
        ],
        "operationId": "enviarEtiquetaPedidoSite",
        "summary": "Enviar a etiqueta de envio comprada pelo site",
        "x-scopes": [
          "orders:write"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "externalId",
            "in": "path",
            "required": true,
            "description": "O `id` do pedido no seu site (o mesmo enviado em POST /v1/store/orders).",
            "schema": {
              "type": "string",
              "maxLength": 40
            },
            "example": "1001"
          }
        ],
        "description": "**Escopo:** `orders:write`\n\nGuarda no pedido a etiqueta que o seu site comprou (Melhor Envio, Correios, transportadora). Os botões **Etiqueta** e **Etiqueta + nota** do painel passam a imprimir essa etiqueta (10×15 ou A4, conforme a loja escolheu) junto com a DANFE.\n\nMande o PDF em `pdf_base64` **ou** um link `https` público em `url` (até 5 MB). Reenviar substitui a etiqueta.\n\nNão marca o pedido como enviado nem avisa o cliente: para isso use `PATCH /v1/store/orders/{id}` com `tracking_code`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "pdf_base64": {
                    "type": "string",
                    "description": "PDF da etiqueta em base64."
                  },
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Link https público do PDF (alternativa ao pdf_base64)."
                  },
                  "tracking_code": {
                    "type": "string",
                    "maxLength": 100
                  },
                  "tracking_url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "carrier": {
                    "type": "string",
                    "maxLength": 60,
                    "example": "Correios"
                  }
                }
              },
              "examples": {
                "base64": {
                  "summary": "PDF em base64",
                  "value": {
                    "pdf_base64": "JVBERi0xLjQK...",
                    "tracking_code": "ME123456789BR",
                    "carrier": "Correios"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Etiqueta salva",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "order_number": {
                          "type": "string"
                        },
                        "label_url": {
                          "type": "string"
                        },
                        "tracking_code": {
                          "type": "string",
                          "nullable": true
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Erro (mensagem em `message`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "message": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Erro (mensagem em `message`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "message": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/receivables": {
      "get": {
        "tags": [
          "Financeiro — Cobranças e contas"
        ],
        "operationId": "listarCobrancas",
        "summary": "Listar cobranças",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nLista as cobranças com o valor de hoje (multa e juros), o link de pagamento e o link do WhatsApp com a mensagem pronta.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Situação",
            "schema": {
              "type": "string",
              "enum": [
                "pendentes",
                "vencida",
                "a_vencer",
                "paga",
                "todas",
                "cancelada",
                "estornada"
              ]
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Cliente, descrição ou nº",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cost_center_id",
            "in": "query",
            "required": false,
            "description": "Centro de custo (`none` = sem centro)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Máx. 200",
            "schema": {
              "type": "integer"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "Financeiro — Cobranças e contas"
        ],
        "operationId": "criarCobranca",
        "summary": "Criar cobrança",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nCria a cobrança (parcelada ou mensal, se pedir). Sai pela conta Asaas da loja quando ela está conectada para cobrar; senão pela conta da plataforma.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "customer_name",
                  "description",
                  "amount",
                  "due_date"
                ],
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "link",
                      "external"
                    ],
                    "default": "link",
                    "description": "link = cobrança com link de pagamento; external = boleto emitido fora (só acompanhar e lembrar)"
                  },
                  "customer_name": {
                    "type": "string"
                  },
                  "customer_email": {
                    "type": "string"
                  },
                  "customer_phone": {
                    "type": "string",
                    "description": "Celular com DDD (WhatsApp)"
                  },
                  "customer_document": {
                    "type": "string",
                    "description": "CPF/CNPJ (obrigatório para Pix/boleto)"
                  },
                  "description": {
                    "type": "string"
                  },
                  "amount": {
                    "type": "number",
                    "example": 150.0
                  },
                  "due_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "methods": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "pix",
                        "boleto",
                        "credit_card"
                      ]
                    }
                  },
                  "installments": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 24
                  },
                  "recurrence": {
                    "type": "string",
                    "enum": [
                      "none",
                      "monthly"
                    ]
                  },
                  "fine_percent": {
                    "type": "number"
                  },
                  "interest_percent": {
                    "type": "number",
                    "description": "Juros ao mês (%)"
                  },
                  "cost_center_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "nfse_mode": {
                    "type": "string",
                    "enum": [
                      "auto",
                      "manual",
                      "off"
                    ],
                    "description": "Nota de serviço: auto = sai ao pagar"
                  },
                  "send_now": {
                    "type": "boolean",
                    "description": "Manda o link por e-mail agora"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/receivables/{id}": {
      "get": {
        "tags": [
          "Financeiro — Cobranças e contas"
        ],
        "operationId": "verCobranca",
        "summary": "Ver cobrança",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nDetalhes, histórico de lembretes e tentativas de pagamento.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      },
      "put": {
        "tags": [
          "Financeiro — Cobranças e contas"
        ],
        "operationId": "editarCobranca",
        "summary": "Editar cobrança",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nEdita dados da cobrança em aberto. Centro de custo, nota de serviço e observação mudam mesmo depois de paga.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "link",
                      "external"
                    ],
                    "default": "link",
                    "description": "link = cobrança com link de pagamento; external = boleto emitido fora (só acompanhar e lembrar)"
                  },
                  "customer_name": {
                    "type": "string"
                  },
                  "customer_email": {
                    "type": "string"
                  },
                  "customer_phone": {
                    "type": "string",
                    "description": "Celular com DDD (WhatsApp)"
                  },
                  "customer_document": {
                    "type": "string",
                    "description": "CPF/CNPJ (obrigatório para Pix/boleto)"
                  },
                  "description": {
                    "type": "string"
                  },
                  "amount": {
                    "type": "number",
                    "example": 150.0
                  },
                  "due_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "methods": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "pix",
                        "boleto",
                        "credit_card"
                      ]
                    }
                  },
                  "installments": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 24
                  },
                  "recurrence": {
                    "type": "string",
                    "enum": [
                      "none",
                      "monthly"
                    ]
                  },
                  "fine_percent": {
                    "type": "number"
                  },
                  "interest_percent": {
                    "type": "number",
                    "description": "Juros ao mês (%)"
                  },
                  "cost_center_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "nfse_mode": {
                    "type": "string",
                    "enum": [
                      "auto",
                      "manual",
                      "off"
                    ],
                    "description": "Nota de serviço: auto = sai ao pagar"
                  },
                  "send_now": {
                    "type": "boolean",
                    "description": "Manda o link por e-mail agora"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/receivables/{id}/pay": {
      "post": {
        "tags": [
          "Financeiro — Cobranças e contas"
        ],
        "operationId": "baixarCobranca",
        "summary": "Dar baixa (recebida por fora)",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nMarca como recebida. Se a nota de serviço automática estiver ligada, ela é emitida.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "amount": {
                    "type": "number"
                  },
                  "paid_at": {
                    "type": "string",
                    "format": "date"
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "pix",
                      "transferencia",
                      "dinheiro",
                      "cartao",
                      "boleto",
                      "outro"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/receivables/{id}/cancel": {
      "post": {
        "tags": [
          "Financeiro — Cobranças e contas"
        ],
        "operationId": "cancelarCobranca",
        "summary": "Cancelar cobrança",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nO link para de funcionar e os lembretes param.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/store/finance/overdue": {
      "get": {
        "tags": [
          "Financeiro — Cobranças e contas"
        ],
        "operationId": "inadimplentes",
        "summary": "Inadimplentes por cliente",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nClientes com cobranças vencidas: total de hoje, dias de atraso, faixa (1-15, 16-30, 31-60, 61-90, 90+), último contato, promessa de pagamento e `whatsapp_url` com todas as cobranças e links numa mensagem só.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "bucket",
            "in": "query",
            "required": false,
            "description": "Faixa de atraso",
            "schema": {
              "type": "string",
              "enum": [
                "1-15",
                "16-30",
                "31-60",
                "61-90",
                "90+"
              ]
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Ordem",
            "schema": {
              "type": "string",
              "enum": [
                "due",
                "late",
                "name"
              ]
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Nome, e-mail ou documento",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/payables": {
      "get": {
        "tags": [
          "Financeiro — Cobranças e contas"
        ],
        "operationId": "listarContasPagar",
        "summary": "Listar contas a pagar",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nContas a pagar e pagas.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Situação",
            "schema": {
              "type": "string",
              "enum": [
                "pendentes",
                "aberta",
                "vencida",
                "paga",
                "todas",
                "cancelada"
              ]
            }
          },
          {
            "name": "month",
            "in": "query",
            "required": false,
            "description": "Competência AAAA-MM",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Categoria",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cost_center_id",
            "in": "query",
            "required": false,
            "description": "Centro de custo (`none` = sem centro)",
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "Financeiro — Cobranças e contas"
        ],
        "operationId": "criarContaPagar",
        "summary": "Lançar conta a pagar",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nLança a conta (ou já paga com `paid: true`).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "description",
                  "amount"
                ],
                "properties": {
                  "description": {
                    "type": "string"
                  },
                  "amount": {
                    "type": "number"
                  },
                  "due_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "category": {
                    "type": "string",
                    "enum": [
                      "mercadoria",
                      "embalagem",
                      "frete_envio",
                      "anuncios_marketing",
                      "plataformas_ferramentas",
                      "impostos",
                      "taxas_bancarias",
                      "salarios_prolabore",
                      "aluguel_contas",
                      "servicos",
                      "outros"
                    ]
                  },
                  "competence_month": {
                    "type": "string",
                    "example": "2026-11"
                  },
                  "paid": {
                    "type": "boolean"
                  },
                  "paid_at": {
                    "type": "string",
                    "format": "date"
                  },
                  "supplier_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "cost_center_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "recurrence": {
                    "type": "string",
                    "enum": [
                      "none",
                      "monthly"
                    ]
                  },
                  "attachment_url": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/payables/{id}/pay": {
      "post": {
        "tags": [
          "Financeiro — Cobranças e contas"
        ],
        "operationId": "pagarConta",
        "summary": "Marcar conta como paga",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\n",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "paid_at": {
                    "type": "string",
                    "format": "date"
                  },
                  "amount": {
                    "type": "number"
                  },
                  "payment_method": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/transactions": {
      "get": {
        "tags": [
          "Financeiro — Extrato e conciliação"
        ],
        "operationId": "listarExtrato",
        "summary": "Lançamentos do extrato",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nLançamentos das contas conectadas. `amount` positivo = entrada, negativo = saída. `suggestion` traz o candidato achado (confirme com `/confirm`).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Situação",
            "schema": {
              "type": "string",
              "enum": [
                "pendente",
                "sugestao",
                "conciliada",
                "ignorada"
              ]
            }
          },
          {
            "name": "connection_id",
            "in": "query",
            "required": false,
            "description": "Conta",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "required": false,
            "description": "Entradas/saídas",
            "schema": {
              "type": "string",
              "enum": [
                "in",
                "out"
              ]
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "De (AAAA-MM-DD)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Até (AAAA-MM-DD)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Descrição ou valor",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/transactions/{id}/confirm": {
      "post": {
        "tags": [
          "Financeiro — Extrato e conciliação"
        ],
        "operationId": "conciliarLancamento",
        "summary": "Conciliar lançamento",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nLiga o lançamento à cobrança/conta sugerida (sem corpo) ou à escolhida. Cobrança/conta em aberto recebe a baixa junto.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "match_type": {
                    "type": "string",
                    "enum": [
                      "receivable",
                      "expense",
                      "payment"
                    ]
                  },
                  "match_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "note": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/transactions/{id}/categorize": {
      "post": {
        "tags": [
          "Financeiro — Extrato e conciliação"
        ],
        "operationId": "classificarLancamento",
        "summary": "Classificar lançamento",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nSem registro para ligar: saída vira conta paga na categoria (menos transferência, retirada de sócio e empréstimo); entrada vira outra receita, transferência, aporte etc.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "category"
                ],
                "properties": {
                  "category": {
                    "type": "string",
                    "description": "Entradas: receita_servicos, receita_vendas, repasse_marketplace, transferencia, rendimento, aporte_socio, emprestimo, estorno_recebido, outras_receitas. Saídas: categorias de conta a pagar ou transferencia, retirada_socio, emprestimo_pagamento, estorno_cliente."
                  },
                  "description": {
                    "type": "string"
                  },
                  "cost_center_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "supplier_id": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/cost-centers": {
      "get": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "listarCentrosCusto",
        "summary": "Centros de custo",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nLista os centros ativos (`all=1` inclui os arquivados).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "all",
            "in": "query",
            "required": false,
            "description": "1 = todos",
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "criarCentroCusto",
        "summary": "Criar centro de custo",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\n",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "code": {
                    "type": "string"
                  },
                  "kind": {
                    "type": "string",
                    "enum": [
                      "area",
                      "projeto",
                      "cliente",
                      "unidade",
                      "produto"
                    ]
                  },
                  "parent_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "budget_monthly": {
                    "type": "number"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/cost-centers/report": {
      "get": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "resultadoCentroCusto",
        "summary": "Resultado por centro de custo",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nReceitas (cobranças recebidas), despesas (contas pagas, sem compra de mercadoria) e saídas do extrato por centro, com margem e uso do orçamento.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "De (AAAA-MM-DD)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Até (AAAA-MM-DD)",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/taxes": {
      "get": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "impostosEstimados",
        "summary": "Impostos estimados do mês",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nEstimativa pelo regime cadastrado: MEI (DAS fixo), Simples (anexo, faixa pelo RBT12 e Fator R), Presumido (PIS/Cofins cumulativos, ISS, IRPJ/CSLL trimestral) ou Real. Em 2026 mostra CBS 0,9% e IBS 0,1% informativos; de 2027 em diante a CBS substitui PIS/Cofins. Desconta as retenções das notas de serviço.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "query",
            "required": false,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/accounting/package": {
      "get": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "pacoteContador",
        "summary": "Pacote do mês para o contador (ZIP)",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nZIP com: XMLs das NF-e/NFC-e (e cancelamentos/CC-e), XMLs das NFS-e, XMLs das notas de entrada, planilhas (recebimentos, contas pagas, em aberto, extrato conciliado, vendas, notas) e lançamentos contábeis sugeridos (Data;Débito;Crédito;Valor;Histórico;Documento) com o plano de contas da loja.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Arquivo ZIP",
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "query",
            "required": false,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/service-invoices": {
      "get": {
        "tags": [
          "Financeiro — Notas de serviço (NFS-e)"
        ],
        "operationId": "listarNfse",
        "summary": "Listar notas de serviço",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\n",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "query",
            "required": false,
            "description": "Competência AAAA-MM",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Situação",
            "schema": {
              "type": "string",
              "enum": [
                "processando",
                "autorizada",
                "rejeitada",
                "erro",
                "cancelada",
                "teste_ok"
              ]
            }
          },
          {
            "name": "receivable_id",
            "in": "query",
            "required": false,
            "description": "Cobrança",
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "Financeiro — Notas de serviço (NFS-e)"
        ],
        "operationId": "emitirNfse",
        "summary": "Emitir nota de serviço avulsa",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nEmite a NFS-e. Retenções federais (IRRF, PIS, Cofins, CSLL) quando o cliente é empresa e a loja é Presumido/Real.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount",
                  "taker"
                ],
                "properties": {
                  "amount": {
                    "type": "number"
                  },
                  "description": {
                    "type": "string"
                  },
                  "service_id": {
                    "type": "string",
                    "description": "Serviço configurado na loja"
                  },
                  "competence": {
                    "type": "string",
                    "format": "date"
                  },
                  "iss_withheld": {
                    "type": "boolean"
                  },
                  "retentions": {
                    "type": "object",
                    "properties": {
                      "irrf": {
                        "type": "number"
                      },
                      "pis": {
                        "type": "number"
                      },
                      "cofins": {
                        "type": "number"
                      },
                      "csll": {
                        "type": "number"
                      },
                      "inss": {
                        "type": "number"
                      }
                    }
                  },
                  "taker": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "doc": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "address": {
                        "type": "object",
                        "properties": {
                          "cep": {
                            "type": "string"
                          },
                          "logradouro": {
                            "type": "string"
                          },
                          "numero": {
                            "type": "string"
                          },
                          "complemento": {
                            "type": "string"
                          },
                          "bairro": {
                            "type": "string"
                          },
                          "cidade": {
                            "type": "string"
                          },
                          "uf": {
                            "type": "string"
                          },
                          "codigo_municipio": {
                            "type": "string",
                            "description": "IBGE (7 dígitos)"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/service-invoices/from-receivable/{receivableId}": {
      "post": {
        "tags": [
          "Financeiro — Notas de serviço (NFS-e)"
        ],
        "operationId": "emitirNfseCobranca",
        "summary": "Emitir nota de uma cobrança",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nUsa os dados da cobrança (cliente, valor, descrição) e o último endereço usado para o documento do cliente. Pode mandar `taker`/`description` para completar.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "receivableId",
            "in": "path",
            "required": true,
            "description": "Id da cobrança",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "description": {
                    "type": "string"
                  },
                  "service_id": {
                    "type": "string"
                  },
                  "taker": {
                    "type": "object"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/service-invoices/{id}/cancel": {
      "post": {
        "tags": [
          "Financeiro — Notas de serviço (NFS-e)"
        ],
        "operationId": "cancelarNfse",
        "summary": "Cancelar nota de serviço",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\n",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "reason"
                ],
                "properties": {
                  "reason": {
                    "type": "string",
                    "minLength": 15
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/service-invoices/{id}/xml": {
      "get": {
        "tags": [
          "Financeiro — Notas de serviço (NFS-e)"
        ],
        "operationId": "xmlNfse",
        "summary": "Baixar XML da nota",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\n",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/store/finance/service-invoices/{id}/pdf": {
      "get": {
        "tags": [
          "Financeiro — Notas de serviço (NFS-e)"
        ],
        "operationId": "pdfNfse",
        "summary": "Baixar PDF da nota",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\n",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Id",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/store/finance/partners": {
      "get": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "listarSocios",
        "summary": "Sócios",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nSócios com participação e pró-labore.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        }
      },
      "post": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "criarSocio",
        "summary": "Cadastrar sócio",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\n",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "document": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string"
                  },
                  "share_percent": {
                    "type": "number"
                  },
                  "is_admin": {
                    "type": "boolean"
                  },
                  "pro_labore": {
                    "type": "number"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/partner-movements": {
      "get": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "listarMovimentosSocios",
        "summary": "Movimentos com sócios",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nPró-labore, lucros, aportes e empréstimos.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "year",
            "in": "query",
            "required": false,
            "description": "Ano",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "partner_id",
            "in": "query",
            "required": false,
            "description": "Sócio",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "lucros, pro_labore, aporte, emprestimo, devolucao",
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "lancarMovimentoSocio",
        "summary": "Lançar movimento com sócio",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nDistribuição de lucros com retenção automática de 10% de IR quando o total do mês para o mesmo sócio passa de R$ 50 mil (Lei 15.270/2025, a partir de 2026; lucros apurados até 2025 ficam sem retenção). Pró-labore com INSS de 11% sugerido.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "partner_id",
                  "kind",
                  "amount"
                ],
                "properties": {
                  "partner_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "kind": {
                    "type": "string",
                    "enum": [
                      "lucros",
                      "pro_labore",
                      "aporte",
                      "emprestimo",
                      "devolucao"
                    ]
                  },
                  "amount": {
                    "type": "number"
                  },
                  "date": {
                    "type": "string",
                    "format": "date"
                  },
                  "reference_year": {
                    "type": "integer"
                  },
                  "irrf": {
                    "type": "number"
                  },
                  "inss": {
                    "type": "number"
                  },
                  "notes": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/year-end": {
      "get": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "fechamentoAno",
        "summary": "Fechamento do ano",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nDRE do ano, lucro distribuível sem tributação (Presumido/Simples/MEI sem escrituração), totais por sócio, avisos e obrigações anuais.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "year",
            "in": "query",
            "required": false,
            "description": "Ano",
            "schema": {
              "type": "integer"
            }
          }
        ]
      }
    },
    "/v1/store/finance/franchises/overview": {
      "get": {
        "tags": [
          "Financeiro — Franquias"
        ],
        "operationId": "painelFranquias",
        "summary": "Painel da rede",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nUnidades ativas, faturamento da rede, royalties e fundo, inadimplência por unidade, ranking, sem declaração e contratos vencendo.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "query",
            "required": false,
            "description": "AAAA-MM (padrão: mês passado)",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/franchises/units": {
      "get": {
        "tags": [
          "Financeiro — Franquias"
        ],
        "operationId": "listarUnidades",
        "summary": "Unidades franqueadas",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\n",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "implantacao, ativa, suspensa, encerrada",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Nome, código, cidade",
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "Financeiro — Franquias"
        ],
        "operationId": "criarUnidade",
        "summary": "Cadastrar unidade",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nUnidade, franqueado, contrato e taxas (royalties % ou fixo com mínimo, fundo de propaganda, outras taxas, taxa inicial).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/franchises/units/{id}": {
      "get": {
        "tags": [
          "Financeiro — Franquias"
        ],
        "operationId": "verUnidade",
        "summary": "Ver unidade",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nUnidade com contrato, declarações e cobranças.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/store/finance/franchises/units/{id}/reports": {
      "post": {
        "tags": [
          "Financeiro — Franquias"
        ],
        "operationId": "declararFaturamento",
        "summary": "Declarar faturamento do mês",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nGrava o faturamento do mês da unidade e gera (ou corrige, se ainda em aberto) a cobrança de royalties, fundo e taxas.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "month",
                  "revenue"
                ],
                "properties": {
                  "month": {
                    "type": "string",
                    "example": "2026-10"
                  },
                  "revenue": {
                    "type": "number"
                  },
                  "notes": {
                    "type": "string"
                  },
                  "attachment_url": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/tax-guides": {
      "get": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "guiasImpostos",
        "summary": "Guias de impostos do mês",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nEstimado × valor da guia × pago por tributo (DAS, DARF de PIS/Cofins/IRPJ/CSLL com código de receita, ISS...), com vencimento.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "month",
            "in": "query",
            "required": false,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        }
      }
    },
    "/v1/store/finance/tax-guides/generate": {
      "post": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "gerarGuias",
        "summary": "Gerar guias do mês",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nGera as guias pela estimativa (IRPJ/CSLL trimestrais só em mar/jun/set/dez). Cada guia vira conta a pagar com aviso de vencimento.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "month": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        }
      }
    },
    "/v1/store/finance/tax-guides/{id}/pay": {
      "post": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "pagarGuia",
        "summary": "Marcar guia como paga",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "paid_at": {
                    "type": "string",
                    "format": "date"
                  },
                  "amount": {
                    "type": "number"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        }
      }
    },
    "/v1/store/finance/employees": {
      "get": {
        "tags": [
          "Financeiro — Funcionários e folha"
        ],
        "operationId": "listarFuncionarios",
        "summary": "Funcionários",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\n",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        }
      },
      "post": {
        "tags": [
          "Financeiro — Funcionários e folha"
        ],
        "operationId": "criarFuncionario",
        "summary": "Cadastrar funcionário",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\n",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "base_salary"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "cpf": {
                    "type": "string"
                  },
                  "role": {
                    "type": "string"
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "clt",
                      "estagio",
                      "autonomo",
                      "pj"
                    ]
                  },
                  "base_salary": {
                    "type": "number"
                  },
                  "weekly_hours": {
                    "type": "number"
                  },
                  "dependents": {
                    "type": "integer"
                  },
                  "cost_center_id": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/payroll/{month}": {
      "get": {
        "tags": [
          "Financeiro — Funcionários e folha"
        ],
        "operationId": "folhaMes",
        "summary": "Folha do mês",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nProventos, descontos, líquido, FGTS, encargos e custo por funcionário.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "2026-11"
            }
          }
        ]
      }
    },
    "/v1/store/finance/payroll/{month}/items/{employeeId}": {
      "put": {
        "tags": [
          "Financeiro — Funcionários e folha"
        ],
        "operationId": "lancarFolha",
        "summary": "Lançar horas extras, faltas, comissões...",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nHoras extras 50%/100% e noturnas em horas, faltas, comissões, bônus e descontos. O cálculo (DSR, INSS, IRRF, VT, FGTS) é refeito.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "2026-11"
            }
          },
          {
            "name": "employeeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/payroll/{month}/close": {
      "post": {
        "tags": [
          "Financeiro — Funcionários e folha"
        ],
        "operationId": "fecharFolha",
        "summary": "Fechar a folha",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nGera as contas a pagar: salários líquidos (5º dia útil), FGTS e DCTFWeb (dia 20).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "2026-11"
            }
          }
        ]
      }
    },
    "/v1/store/finance/payroll-simulate": {
      "post": {
        "tags": [
          "Financeiro — Funcionários e folha"
        ],
        "operationId": "simularSalario",
        "summary": "Simular salário",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nLíquido, INSS, IRRF (2026, isenção até R$ 5 mil), FGTS e custo da empresa.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "base_salary"
                ],
                "properties": {
                  "base_salary": {
                    "type": "number"
                  },
                  "dependents": {
                    "type": "integer"
                  },
                  "inputs": {
                    "type": "object"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/cash-flow": {
      "get": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "fluxoCaixa",
        "summary": "Fluxo de caixa projetado",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nSaldo de hoje + entradas previstas − saídas previstas por período, com o primeiro dia de saldo negativo.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "required": false,
            "description": "30, 60 ou 90",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group",
            "in": "query",
            "required": false,
            "description": "day, week ou month",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include_doubtful",
            "in": "query",
            "required": false,
            "description": "1 = inclui cobranças vencidas há mais de 30 dias",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/accounting/trial-balance": {
      "get": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "balancete",
        "summary": "Balancete de verificação",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nSaldo anterior, débitos, créditos e saldo por conta (escrituração sugerida pelo regime de caixa), com a DRE.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "query",
            "required": false,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "year",
            "in": "query",
            "required": false,
            "description": "AAAA (acumulado)",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/accounting/ledger": {
      "get": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "razao",
        "summary": "Livro razão",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nLançamentos e saldo de uma conta.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "query",
            "required": false,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "account",
            "in": "query",
            "required": false,
            "description": "código da conta",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/accounting/journal": {
      "get": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "diario",
        "summary": "Livro diário",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nPartidas dobradas do período.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "query",
            "required": false,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/reports/{id}.{format}": {
      "get": {
        "tags": [
          "Financeiro — Impostos, centros de custo e contábil"
        ],
        "operationId": "baixarRelatorioFinanceiro",
        "summary": "Relatório do financeiro/contabilidade em Excel, PDF ou CSV",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nRelatório pronto para o contador em Excel (.xlsx, com abas, moeda R$, datas e totais), PDF (A4, com resumo, cabeçalho repetido e páginas numeradas) ou CSV (`;` e vírgula decimal, UTF-8 com BOM). Gerado no servidor com os mesmos números das telas. Os filtros vão na query, com os mesmos nomes das listas.\n\n| id | Relatório | Filtros (query) |\n|---|---|---|\n| `financial` | Resultado do período (DRE das vendas, canais, dia a dia, lucro por produto) | `from`, `to` (AAAA-MM-DD), `channel`, `allocation` |\n| `receivables` | Cobranças (até 5000 linhas) | `status`, `kind`, `from`, `to`, `search`, `cost_center_id`, `customer_id`, `customer_document`, `customer_email` |\n| `collections` | Inadimplentes por cliente e cobranças vencidas | `bucket`, `search`, `sort` |\n| `payables` | Contas a pagar (até 5000 linhas) | `status`, `month`, `from`, `to`, `category`, `cost_type`, `supplier_id`, `cost_center_id`, `search`, `approval` |\n| `bank_transactions` | Extrato e conciliação (até 5000 linhas) | `connection_id`, `status`, `direction`, `from`, `to`, `search` |\n| `cash_flow` | Fluxo de caixa projetado | `days` (30/60/90), `group` (day/week/month), `include_doubtful` |\n| `cost_centers` | Resultado por centro de custo | `from`, `to` |\n| `taxes` | Impostos estimados e guias do mês | `month` |\n| `trial_balance` | Balancete de verificação + DRE | `month` ou `year` ou `from`/`to` (AAAA-MM) |\n| `ledger` | Livro razão (todas as contas ou uma) | `month`/`year`/`from`/`to`, `account` |\n| `journal` | Livro diário | `month`/`year`/`from`/`to` |\n| `year_end` | Fechamento do ano (DRE, sócios, obrigações) | `year` |\n| `service_invoices` | Notas de serviço (até 300 mais recentes) | `month`, `status`, `search` |\n| `payroll` | Folha de pagamento do mês | `month` |\n| `franchises` | Franquias: ranking, inadimplentes, quem não declarou, contratos | `month` |\n\nExemplo: `GET /v1/store/finance/reports/receivables.xlsx?status=vencida`. Nome do arquivo no `Content-Disposition` (ex.: `cobrancas-2026-11.xlsx`).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Qual relatório",
            "schema": {
              "type": "string",
              "enum": [
                "financial",
                "receivables",
                "collections",
                "payables",
                "bank_transactions",
                "cash_flow",
                "cost_centers",
                "taxes",
                "trial_balance",
                "ledger",
                "journal",
                "year_end",
                "service_invoices",
                "payroll",
                "franchises"
              ]
            }
          },
          {
            "name": "format",
            "in": "path",
            "required": true,
            "description": "Formato do arquivo",
            "schema": {
              "type": "string",
              "enum": [
                "xlsx",
                "pdf",
                "csv"
              ]
            }
          },
          {
            "name": "month",
            "in": "query",
            "required": false,
            "description": "AAAA-MM (impostos, folha, franquias, notas de serviço, contabilidade)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "year",
            "in": "query",
            "required": false,
            "description": "AAAA (fechamento do ano, contabilidade)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Início do período (AAAA-MM-DD; na contabilidade AAAA-MM)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fim do período (AAAA-MM-DD; na contabilidade AAAA-MM)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Situação (mesmos valores da lista correspondente)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Busca por texto",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Arquivo do relatório",
            "content": {
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Formato ou filtro inválido (JSON com `message`)"
          },
          "401": {
            "description": "Chave inválida"
          },
          "403": {
            "description": "Sem escopo"
          },
          "404": {
            "description": "Relatório não encontrado"
          }
        }
      }
    },
    "/v1/store/finance/contracts": {
      "get": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "listarContratos",
        "summary": "Listar contratos",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nContratos com MRR, a receber, atraso e encargos, mais o resumo (MRR, ativos, inadimplência, encargos recebidos no mês e em aberto) e alertas (vencendo, reajuste, assinatura pendente).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "vigentes",
                "todos",
                "rascunho",
                "aguardando_assinatura",
                "ativo",
                "suspenso",
                "encerrado",
                "cancelado"
              ]
            }
          },
          {
            "name": "client_id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expiring",
            "in": "query",
            "description": "Terminam nos próximos N dias",
            "schema": {
              "type": "integer"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "criarContrato",
        "summary": "Criar contrato",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nCria o contrato (rascunho). Com `require_signature=false` e `activate=true`, já ativa e gera as cobranças.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "client_id": {
                    "type": "string"
                  },
                  "client": {
                    "type": "object",
                    "description": "Cliente novo: person_type (pf|pj), name, document, email, phone, address, legal_name, trade_name, municipal_registration, billing_email, contacts[]"
                  },
                  "title": {
                    "type": "string",
                    "example": "Suporte mensal"
                  },
                  "description": {
                    "type": "string"
                  },
                  "start_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "end_date": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date",
                    "description": "Vazio = prazo indeterminado"
                  },
                  "billing_model": {
                    "type": "string",
                    "enum": [
                      "parcelado",
                      "recorrente",
                      "avulso"
                    ]
                  },
                  "amount": {
                    "type": "number",
                    "description": "Valor da parcela/mensalidade"
                  },
                  "total_amount": {
                    "type": "number",
                    "description": "Parcelado: valor total (a diferença de centavos vai na última)"
                  },
                  "installments_count": {
                    "type": "integer"
                  },
                  "down_payment": {
                    "type": "number"
                  },
                  "down_payment_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "frequency": {
                    "type": "string",
                    "enum": [
                      "monthly",
                      "quarterly",
                      "semiannual",
                      "annual"
                    ]
                  },
                  "lead_months": {
                    "type": "integer",
                    "description": "Recorrente: gerar as cobranças dos próximos N meses (padrão 3)"
                  },
                  "due_day": {
                    "type": "integer"
                  },
                  "first_due_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "custom_schedule": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "due_date": {
                          "type": "string",
                          "format": "date"
                        },
                        "amount": {
                          "type": "number"
                        },
                        "description": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "billing_kind": {
                    "type": "string",
                    "enum": [
                      "link",
                      "external"
                    ]
                  },
                  "methods": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "pix",
                        "boleto",
                        "credit_card"
                      ]
                    }
                  },
                  "charges": {
                    "type": "object",
                    "description": "Encargos: multa e juros ao mês (pró-rata por dia). Pessoa física: multa até 2% e juros até 1% a.m. (CDC). Empresa (CNPJ): até 10% e 10% a.m.",
                    "properties": {
                      "fine_percent": {
                        "type": "number",
                        "example": 2
                      },
                      "interest_percent": {
                        "type": "number",
                        "example": 1
                      },
                      "grace_days": {
                        "type": "integer",
                        "description": "Dias de tolerância sem encargos"
                      },
                      "discount": {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "percent",
                              "amount"
                            ]
                          },
                          "value": {
                            "type": "number"
                          },
                          "days_before": {
                            "type": "integer"
                          }
                        }
                      },
                      "correction": {
                        "type": "object",
                        "properties": {
                          "index": {
                            "type": "string"
                          },
                          "note": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  },
                  "nfse_mode": {
                    "type": "string",
                    "enum": [
                      "auto",
                      "manual",
                      "off"
                    ]
                  },
                  "nfse_service_id": {
                    "type": "string"
                  },
                  "nfse_description": {
                    "type": "string"
                  },
                  "reminder_days": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    }
                  },
                  "reminder_channels": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "email",
                        "whatsapp"
                      ]
                    }
                  },
                  "adjust": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string",
                        "enum": [
                          "index",
                          "fixed"
                        ]
                      },
                      "index": {
                        "type": "string",
                        "enum": [
                          "IPCA",
                          "IGP-M",
                          "INPC",
                          "IGP-DI",
                          "outro"
                        ]
                      },
                      "percent": {
                        "type": "number"
                      }
                    }
                  },
                  "require_signature": {
                    "type": "boolean",
                    "description": "Padrão true: só gera cobranças depois de assinado"
                  },
                  "activate": {
                    "type": "boolean"
                  },
                  "cost_center_id": {
                    "type": "string"
                  },
                  "category": {
                    "type": "string"
                  }
                },
                "required": [
                  "title",
                  "start_date",
                  "billing_model"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/preview": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "previsualizarContrato",
        "summary": "Pré-visualizar parcelas",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nMostra as parcelas (datas e valores com os centavos certos) antes de salvar. Mesmo corpo de criar contrato.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "client_id": {
                    "type": "string"
                  },
                  "client": {
                    "type": "object",
                    "description": "Cliente novo: person_type (pf|pj), name, document, email, phone, address, legal_name, trade_name, municipal_registration, billing_email, contacts[]"
                  },
                  "title": {
                    "type": "string",
                    "example": "Suporte mensal"
                  },
                  "description": {
                    "type": "string"
                  },
                  "start_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "end_date": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date",
                    "description": "Vazio = prazo indeterminado"
                  },
                  "billing_model": {
                    "type": "string",
                    "enum": [
                      "parcelado",
                      "recorrente",
                      "avulso"
                    ]
                  },
                  "amount": {
                    "type": "number",
                    "description": "Valor da parcela/mensalidade"
                  },
                  "total_amount": {
                    "type": "number",
                    "description": "Parcelado: valor total (a diferença de centavos vai na última)"
                  },
                  "installments_count": {
                    "type": "integer"
                  },
                  "down_payment": {
                    "type": "number"
                  },
                  "down_payment_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "frequency": {
                    "type": "string",
                    "enum": [
                      "monthly",
                      "quarterly",
                      "semiannual",
                      "annual"
                    ]
                  },
                  "lead_months": {
                    "type": "integer",
                    "description": "Recorrente: gerar as cobranças dos próximos N meses (padrão 3)"
                  },
                  "due_day": {
                    "type": "integer"
                  },
                  "first_due_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "custom_schedule": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "due_date": {
                          "type": "string",
                          "format": "date"
                        },
                        "amount": {
                          "type": "number"
                        },
                        "description": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "billing_kind": {
                    "type": "string",
                    "enum": [
                      "link",
                      "external"
                    ]
                  },
                  "methods": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "pix",
                        "boleto",
                        "credit_card"
                      ]
                    }
                  },
                  "charges": {
                    "type": "object",
                    "description": "Encargos: multa e juros ao mês (pró-rata por dia). Pessoa física: multa até 2% e juros até 1% a.m. (CDC). Empresa (CNPJ): até 10% e 10% a.m.",
                    "properties": {
                      "fine_percent": {
                        "type": "number",
                        "example": 2
                      },
                      "interest_percent": {
                        "type": "number",
                        "example": 1
                      },
                      "grace_days": {
                        "type": "integer",
                        "description": "Dias de tolerância sem encargos"
                      },
                      "discount": {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "percent",
                              "amount"
                            ]
                          },
                          "value": {
                            "type": "number"
                          },
                          "days_before": {
                            "type": "integer"
                          }
                        }
                      },
                      "correction": {
                        "type": "object",
                        "properties": {
                          "index": {
                            "type": "string"
                          },
                          "note": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  },
                  "nfse_mode": {
                    "type": "string",
                    "enum": [
                      "auto",
                      "manual",
                      "off"
                    ]
                  },
                  "nfse_service_id": {
                    "type": "string"
                  },
                  "nfse_description": {
                    "type": "string"
                  },
                  "reminder_days": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    }
                  },
                  "reminder_channels": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "email",
                        "whatsapp"
                      ]
                    }
                  },
                  "adjust": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string",
                        "enum": [
                          "index",
                          "fixed"
                        ]
                      },
                      "index": {
                        "type": "string",
                        "enum": [
                          "IPCA",
                          "IGP-M",
                          "INPC",
                          "IGP-DI",
                          "outro"
                        ]
                      },
                      "percent": {
                        "type": "number"
                      }
                    }
                  },
                  "require_signature": {
                    "type": "boolean",
                    "description": "Padrão true: só gera cobranças depois de assinado"
                  },
                  "activate": {
                    "type": "boolean"
                  },
                  "cost_center_id": {
                    "type": "string"
                  },
                  "category": {
                    "type": "string"
                  }
                },
                "required": [
                  "title",
                  "start_date",
                  "billing_model"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/simulate-charges": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "simularEncargos",
        "summary": "Simular multa e juros",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nEx.: parcela de R$ 1.000 com 15 dias de atraso, multa 2% e juros 1% a.m. = R$ 1.025.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "amount": {
                    "type": "number"
                  },
                  "days_late": {
                    "type": "integer"
                  },
                  "fine_percent": {
                    "type": "number"
                  },
                  "interest_percent": {
                    "type": "number"
                  },
                  "grace_days": {
                    "type": "integer"
                  },
                  "discount": {
                    "type": "object"
                  },
                  "doc_type": {
                    "type": "string",
                    "enum": [
                      "cpf",
                      "cnpj"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}": {
      "get": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "verContrato",
        "summary": "Ver contrato",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nContrato com parcelas (original, multa, juros, total hoje), atrasadas, assinatura, reajustes/aditivos, arquivos e linha do tempo.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      },
      "put": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "alterarContrato",
        "summary": "Alterar contrato",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nRascunho: tudo. Ativo: só dados que não mudam valores (título, centro de custo, nota, avisos, reajuste, fim). Valor/vencimento: use o aditivo.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/activate": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "ativarContrato",
        "summary": "Ativar e gerar cobranças",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nAtiva o contrato e gera as parcelas. `without_signature=true` ativa sem assinatura digital; `include_past=true` cobra também as já vencidas.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "without_signature": {
                    "type": "boolean"
                  },
                  "include_past": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/generate": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "gerarParcelas",
        "summary": "Gerar parcelas agora",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nGera o que falta (idempotente: nunca duplica). Competência em mês fechado é pulada e registrada.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/suspend": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "suspenderContrato",
        "summary": "Suspender",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nPara de criar novas cobranças.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/resume": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "retomarContrato",
        "summary": "Retomar",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nVolta a gerar; o que venceu durante a suspensão não é cobrado.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/end-preview": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "previaEncerrar",
        "summary": "Prévia do encerramento",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nO que será cancelado (futuras em aberto) e o que fica (pagas e vencidas).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string"
                  },
                  "end_date": {
                    "type": "string",
                    "format": "date"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/end": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "encerrarContrato",
        "summary": "Encerrar ou cancelar",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nCancela as cobranças futuras em aberto (`cancel_open`) e mantém as pagas.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "encerrado",
                      "cancelado"
                    ]
                  },
                  "end_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "cancel_open": {
                    "type": "boolean"
                  },
                  "reason": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/amend-preview": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "previaAditivo",
        "summary": "Prévia do aditivo",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nQuais parcelas mudam e quais ficam iguais (já pagas, vencidas ou enviadas ao cliente).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "amount": {
                    "type": "number"
                  },
                  "due_day": {
                    "type": "integer"
                  },
                  "end_date": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date"
                  },
                  "effective_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "reason": {
                    "type": "string"
                  },
                  "send_for_signature": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/amend": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "aditivo",
        "summary": "Aditivo",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nMuda valor, dia de vencimento ou fim só nas parcelas futuras em aberto e não enviadas. Com `send_for_signature`, só vale depois de assinado.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "amount": {
                    "type": "number"
                  },
                  "due_day": {
                    "type": "integer"
                  },
                  "end_date": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date"
                  },
                  "effective_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "reason": {
                    "type": "string"
                  },
                  "send_for_signature": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/readjust": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "reajustar",
        "summary": "Reajuste anual",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nIPCA/IGP-M informado ou % fixo, aplicado nas parcelas futuras ainda não emitidas/enviadas, com histórico. `dry_run` simula.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "index",
                      "fixed"
                    ]
                  },
                  "index": {
                    "type": "string"
                  },
                  "percent": {
                    "type": "number"
                  },
                  "effective_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "dry_run": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "percent"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/renegotiate-preview": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "previaAcordo",
        "summary": "Prévia do acordo",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nSoma das atrasadas (com ou sem encargos) dividida nas novas parcelas.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "receivable_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "waive_fees": {
                    "type": "boolean"
                  },
                  "installments": {
                    "type": "integer"
                  },
                  "first_due_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "reason": {
                    "type": "string"
                  }
                },
                "required": [
                  "first_due_date"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/renegotiate": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "acordo",
        "summary": "Acordo (renegociação)",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nCancela as atrasadas e cria as parcelas do acordo; fica na linha do tempo e no histórico.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "receivable_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "waive_fees": {
                    "type": "boolean"
                  },
                  "installments": {
                    "type": "integer"
                  },
                  "first_due_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "reason": {
                    "type": "string"
                  }
                },
                "required": [
                  "first_due_date"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/waive-fees": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "isentarEncargos",
        "summary": "Isentar encargos",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nZera multa e juros de uma parcela em aberto. Motivo obrigatório.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "receivable_id": {
                    "type": "string"
                  },
                  "reason": {
                    "type": "string"
                  }
                },
                "required": [
                  "receivable_id",
                  "reason"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/whatsapp": {
      "get": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "whatsappContrato",
        "summary": "WhatsApp de cobrança",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nLink do WhatsApp com a mensagem das parcelas atrasadas e o valor de hoje.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/store/finance/contracts/{id}/document.pdf": {
      "get": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "pdfContrato",
        "summary": "PDF do contrato",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nContrato gerado com as variáveis, o cronograma e a cláusula de encargos (application/pdf).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/store/finance/contracts/{id}/signature": {
      "get": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "statusAssinatura",
        "summary": "Status da assinatura",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nEtapa, status do documento no Devskin Sign e de cada signatário (visualizou, assinou, recusou) e links de assinatura.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/store/finance/contracts/{id}/signature/send": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "enviarAssinatura",
        "summary": "Enviar para assinatura",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nEnvia ao Devskin Sign o arquivo anexado (`source=file`, PDF ou Word), o PDF gerado (`generated`) ou um modelo do Sign (`template`). O contrato fica aguardando assinatura e só gera as cobranças quando todos assinarem.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "source": {
                    "type": "string",
                    "enum": [
                      "file",
                      "generated",
                      "template"
                    ]
                  },
                  "file_id": {
                    "type": "string"
                  },
                  "template_id": {
                    "type": "string"
                  },
                  "field_values": {
                    "type": "object"
                  },
                  "signers": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        },
                        "phone": {
                          "type": "string"
                        },
                        "role": {
                          "type": "string",
                          "enum": [
                            "cliente",
                            "empresa",
                            "testemunha"
                          ]
                        },
                        "order": {
                          "type": "integer"
                        }
                      },
                      "required": [
                        "name",
                        "email"
                      ]
                    }
                  },
                  "sequential": {
                    "type": "boolean"
                  },
                  "message": {
                    "type": "string"
                  },
                  "expires_in_days": {
                    "type": "integer"
                  }
                },
                "required": [
                  "signers"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/signature/remind": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "lembrarAssinatura",
        "summary": "Lembrar quem falta assinar",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\n",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "recipient_id": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/signature/cancel": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "cancelarAssinatura",
        "summary": "Cancelar envio",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nO contrato volta a rascunho.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/contracts/{id}/signature/refresh": {
      "post": {
        "tags": [
          "Financeiro — Contratos e assinatura"
        ],
        "operationId": "atualizarAssinatura",
        "summary": "Consultar status agora",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nConsulta o Devskin Sign (o webhook já atualiza sozinho).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/clients": {
      "get": {
        "tags": [
          "Financeiro — Clientes"
        ],
        "operationId": "listarClientes",
        "summary": "Buscar clientes",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nFichas de cliente e clientes que já têm cobrança. Busca rápida (assistente). Para a carteira completa com números use `/clients/portfolio`.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "Financeiro — Clientes"
        ],
        "operationId": "criarCliente",
        "summary": "Criar ficha do cliente",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nPessoa física ou empresa (com contatos: financeiro, representante legal, testemunha). Mesmo CPF/CNPJ devolve a ficha existente.\n\nCom `strict: true`, CPF/CNPJ ou e-mail que já existe na carteira volta **409** `code: duplicate` com a ficha em `data.duplicates`. Aceita `tags`, `notes`, `credit_limit` e `defaults` (condições padrão).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Já existe cliente com este CPF/CNPJ ou e-mail (`code: duplicate`, com `strict: true`)"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "person_type": {
                    "type": "string",
                    "enum": [
                      "pf",
                      "pj"
                    ]
                  },
                  "name": {
                    "type": "string"
                  },
                  "document": {
                    "type": "string",
                    "description": "CPF ou CNPJ"
                  },
                  "email": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  },
                  "legal_name": {
                    "type": "string"
                  },
                  "trade_name": {
                    "type": "string"
                  },
                  "state_registration": {
                    "type": "string"
                  },
                  "municipal_registration": {
                    "type": "string",
                    "description": "Vai na NFS-e do tomador"
                  },
                  "billing_email": {
                    "type": "string",
                    "description": "Recebe cobranças e notas"
                  },
                  "address": {
                    "type": "object",
                    "properties": {
                      "cep": {
                        "type": "string"
                      },
                      "logradouro": {
                        "type": "string"
                      },
                      "numero": {
                        "type": "string"
                      },
                      "complemento": {
                        "type": "string"
                      },
                      "bairro": {
                        "type": "string"
                      },
                      "cidade": {
                        "type": "string"
                      },
                      "uf": {
                        "type": "string"
                      },
                      "codigo_municipio": {
                        "type": "string"
                      }
                    }
                  },
                  "contacts": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "title": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        },
                        "phone": {
                          "type": "string"
                        },
                        "roles": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "enum": [
                              "financeiro",
                              "representante",
                              "testemunha"
                            ]
                          }
                        }
                      }
                    }
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "notes": {
                    "type": "string"
                  },
                  "credit_limit": {
                    "type": "number",
                    "nullable": true
                  },
                  "defaults": {
                    "type": "object",
                    "description": "Condições padrão usadas em contratos e cobranças novas",
                    "properties": {
                      "methods": {
                        "type": "array",
                        "items": {
                          "type": "string",
                          "enum": [
                            "pix",
                            "boleto",
                            "credit_card"
                          ]
                        }
                      },
                      "billing_kind": {
                        "type": "string",
                        "enum": [
                          "link",
                          "external"
                        ]
                      },
                      "due_day": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 31
                      },
                      "fine_percent": {
                        "type": "number",
                        "description": "PF até 2%, PJ até 10%"
                      },
                      "interest_percent": {
                        "type": "number",
                        "description": "ao mês; PF até 1%, PJ até 10%"
                      },
                      "grace_days": {
                        "type": "integer"
                      },
                      "cost_center_id": {
                        "type": "string"
                      },
                      "nfse_auto": {
                        "type": "boolean"
                      },
                      "nfse_email": {
                        "type": "string",
                        "format": "email"
                      }
                    }
                  },
                  "strict": {
                    "type": "boolean",
                    "description": "true: CPF/CNPJ ou e-mail repetido volta 409 `code: duplicate` com `data.duplicates` (sem strict, completa a ficha existente com o mesmo CPF/CNPJ)"
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/clients/cnpj/{cnpj}": {
      "get": {
        "tags": [
          "Financeiro — Clientes"
        ],
        "operationId": "consultarCnpj",
        "summary": "Consultar CNPJ",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nRazão social, nome fantasia, endereço e sócios (BrasilAPI). Sem resposta: `found=false` e preenchimento manual.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "cnpj",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/clients/{id}": {
      "get": {
        "tags": [
          "Financeiro — Clientes"
        ],
        "operationId": "fichaCliente",
        "summary": "Ficha do cliente",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nDados, contratos, todas as cobranças (pagas, em aberto, atrasadas com total de hoje), notas fiscais, arquivos e histórico.\n\nInclui `metrics` (contratos, MRR, a receber, atraso com total de hoje), `credit` (limite de crédito), `primary_contact`, `merged_clients` e `sales_link` (vínculo com o cliente de Vendas).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "Mês fechado pela contabilidade (`code: PERIOD_LOCKED`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      },
      "put": {
        "tags": [
          "Financeiro — Clientes"
        ],
        "operationId": "alterarCliente",
        "summary": "Alterar ficha",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\n\n\nAceita `tags`, `notes`, `credit_limit` e `defaults`. CPF/CNPJ de outra ficha volta 409 `code: duplicate` (use a mescla).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "409": {
            "description": "CPF/CNPJ já usado em outra ficha (`code: duplicate`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "person_type": {
                    "type": "string",
                    "enum": [
                      "pf",
                      "pj"
                    ]
                  },
                  "name": {
                    "type": "string"
                  },
                  "document": {
                    "type": "string",
                    "description": "CPF ou CNPJ"
                  },
                  "email": {
                    "type": "string"
                  },
                  "phone": {
                    "type": "string"
                  },
                  "legal_name": {
                    "type": "string"
                  },
                  "trade_name": {
                    "type": "string"
                  },
                  "state_registration": {
                    "type": "string"
                  },
                  "municipal_registration": {
                    "type": "string",
                    "description": "Vai na NFS-e do tomador"
                  },
                  "billing_email": {
                    "type": "string",
                    "description": "Recebe cobranças e notas"
                  },
                  "address": {
                    "type": "object",
                    "properties": {
                      "cep": {
                        "type": "string"
                      },
                      "logradouro": {
                        "type": "string"
                      },
                      "numero": {
                        "type": "string"
                      },
                      "complemento": {
                        "type": "string"
                      },
                      "bairro": {
                        "type": "string"
                      },
                      "cidade": {
                        "type": "string"
                      },
                      "uf": {
                        "type": "string"
                      },
                      "codigo_municipio": {
                        "type": "string"
                      }
                    }
                  },
                  "contacts": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "title": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        },
                        "phone": {
                          "type": "string"
                        },
                        "roles": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "enum": [
                              "financeiro",
                              "representante",
                              "testemunha"
                            ]
                          }
                        }
                      }
                    }
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/clients/portfolio": {
      "get": {
        "tags": [
          "Financeiro — Clientes"
        ],
        "operationId": "carteiraClientes",
        "summary": "Carteira de clientes",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nLista com números de cada cliente: contratos ativos, receita recorrente (MRR), a receber, atrasadas e total de hoje (com multa/juros), limite de crédito e contato principal (com link do WhatsApp). `summary` traz os indicadores da carteira; `tags` as etiquetas usadas. Arquivados ficam fora, a não ser com `status=arquivado` ou `todos`.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "404": {
            "description": "Cliente não encontrado"
          }
        },
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "nome, razão social, CPF/CNPJ, e-mail ou telefone"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ativo",
                "inativo",
                "arquivado",
                "todos"
              ]
            }
          },
          {
            "name": "person_type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pf",
                "pj"
              ]
            }
          },
          {
            "name": "with_contract",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "só com contrato ativo"
          },
          {
            "name": "overdue",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "só inadimplentes"
          },
          {
            "name": "tag",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "name",
                "overdue",
                "open",
                "mrr",
                "recent"
              ]
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ]
      }
    },
    "/v1/store/finance/clients/cep/{cep}": {
      "get": {
        "tags": [
          "Financeiro — Clientes"
        ],
        "operationId": "consultarCep",
        "summary": "Consultar CEP",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nEndereço pelo CEP (ViaCEP, consultado pelo servidor com tempo limite). `found: false` quando não encontra ou a consulta está fora do ar.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "404": {
            "description": "Cliente não encontrado"
          }
        },
        "parameters": [
          {
            "name": "cep",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/clients/{id}/position": {
      "get": {
        "tags": [
          "Financeiro — Clientes"
        ],
        "operationId": "posicaoCliente",
        "summary": "Posição financeira do cliente",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nExtrato do cliente: cobranças em aberto e atrasadas com total de hoje e links de pagamento, `message` pronta e `whatsapp_url`.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "404": {
            "description": "Cliente não encontrado"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/store/finance/clients/{id}/status": {
      "post": {
        "tags": [
          "Financeiro — Clientes"
        ],
        "operationId": "situacaoCliente",
        "summary": "Mudar situação do cliente",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\n`ativo`, `inativo` ou `arquivado`. Arquivar **não apaga nada**: o cliente sai da lista padrão e não recebe contrato nem cobrança nova (409 `code: has_contracts` se houver contrato em andamento).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "404": {
            "description": "Cliente não encontrado"
          },
          "409": {
            "description": "Contrato em andamento (`code: has_contracts`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "status"
                ],
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "ativo",
                      "inativo",
                      "arquivado"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/clients/{id}/archive": {
      "post": {
        "tags": [
          "Financeiro — Clientes"
        ],
        "operationId": "arquivarCliente",
        "summary": "Arquivar cliente",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nAtalho para `status: arquivado` (nada é apagado).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "404": {
            "description": "Cliente não encontrado"
          },
          "409": {
            "description": "Contrato em andamento (`code: has_contracts`)"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ]
      }
    },
    "/v1/store/finance/clients/merge": {
      "post": {
        "tags": [
          "Financeiro — Clientes"
        ],
        "operationId": "mesclarClientes",
        "summary": "Mesclar fichas",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nContratos, cobranças, arquivos e linha do tempo de `source_id` passam para `target_id`; a ficha de origem fica arquivada com `merged_into` (nada é apagado). CPF/CNPJ diferentes não mesclam. `dry_run: true` só mostra o que muda.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "404": {
            "description": "Cliente não encontrado"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "source_id",
                  "target_id"
                ],
                "properties": {
                  "source_id": {
                    "type": "string"
                  },
                  "target_id": {
                    "type": "string"
                  },
                  "dry_run": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/clients/import": {
      "post": {
        "tags": [
          "Financeiro — Clientes"
        ],
        "operationId": "importarClientes",
        "summary": "Importar clientes (CSV)",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nTexto CSV (separado por `;`, `,` ou tab; primeira linha com os títulos: Nome, Razão social, CPF/CNPJ, E-mail, Telefone, CEP, Cidade, UF, Etiquetas, Observações...). `dry_run: true` devolve a prévia (novo, já existe, repetido no arquivo, inválido); sem dry_run grava os novos (e completa os existentes com `update_existing: true`). Até 2000 linhas.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          },
          "404": {
            "description": "Cliente não encontrado"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text"
                ],
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "dry_run": {
                    "type": "boolean"
                  },
                  "update_existing": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/projects/months": {
      "get": {
        "tags": [
          "Financeiro — Projetos & Equipe"
        ],
        "operationId": "listarMesesProjetos",
        "summary": "Meses de Projetos & Equipe",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nMeses com status (aberto/fechado), origem (planilha/sistema) e totais: faturamento, impostos, comissão, custo, lucro, margem (fração), horas, pessoas e projetos.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        }
      }
    },
    "/v1/store/finance/projects/months/{month}": {
      "get": {
        "tags": [
          "Financeiro — Projetos & Equipe"
        ],
        "operationId": "mesProjetos",
        "summary": "Mês por projeto",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nProjetos do mês (centro de custo, cliente) com totais e as alocações de cada pessoa.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/projects/months/{month}/open": {
      "post": {
        "tags": [
          "Financeiro — Projetos & Equipe"
        ],
        "operationId": "abrirMesProjetos",
        "summary": "Abrir mês",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nAbre o mês copiando a escala do mês anterior (ou `copy_from`) com horas zeradas; fixo/escopo copia o valor.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "copy_from": {
                    "type": "string",
                    "description": "AAAA-MM"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/projects/months/{month}/allocations": {
      "post": {
        "tags": [
          "Financeiro — Projetos & Equipe"
        ],
        "operationId": "criarAlocacao",
        "summary": "Adicionar alocação",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nSó em mês aberto. O servidor calcula custo, faturamento, imposto, lucro e margem.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cost_center_id": {
                    "type": "string"
                  },
                  "employee_id": {
                    "type": "string"
                  },
                  "person_name": {
                    "type": "string",
                    "description": "vaga sem pessoa"
                  },
                  "role": {
                    "type": "string"
                  },
                  "billing_mode": {
                    "type": "string",
                    "enum": [
                      "hora",
                      "fixo",
                      "escopo",
                      "interno"
                    ]
                  },
                  "cost_rate": {
                    "type": "number"
                  },
                  "cost_hours": {
                    "type": "string",
                    "description": "decimal ou h:mm"
                  },
                  "salary": {
                    "type": "number"
                  },
                  "extra": {
                    "type": "number"
                  },
                  "client_rate": {
                    "type": "number"
                  },
                  "client_hours": {
                    "type": "string"
                  },
                  "revenue_amount": {
                    "type": "number",
                    "description": "fixo/escopo"
                  },
                  "tax_rate": {
                    "type": "number",
                    "description": "0.18"
                  },
                  "commission": {
                    "type": "number"
                  },
                  "paid_status": {
                    "type": "string",
                    "enum": [
                      "pago",
                      "pendente",
                      "nao",
                      "outro"
                    ]
                  },
                  "category": {
                    "type": "string",
                    "enum": [
                      "equipe",
                      "pro_labore",
                      "interno"
                    ]
                  },
                  "notes": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/projects/months/{month}/allocations/{id}": {
      "put": {
        "tags": [
          "Financeiro — Projetos & Equipe"
        ],
        "operationId": "alterarAlocacao",
        "summary": "Alterar alocação",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nSó em mês aberto; envie só os campos que mudam.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cost_center_id": {
                    "type": "string"
                  },
                  "employee_id": {
                    "type": "string"
                  },
                  "person_name": {
                    "type": "string",
                    "description": "vaga sem pessoa"
                  },
                  "role": {
                    "type": "string"
                  },
                  "billing_mode": {
                    "type": "string",
                    "enum": [
                      "hora",
                      "fixo",
                      "escopo",
                      "interno"
                    ]
                  },
                  "cost_rate": {
                    "type": "number"
                  },
                  "cost_hours": {
                    "type": "string",
                    "description": "decimal ou h:mm"
                  },
                  "salary": {
                    "type": "number"
                  },
                  "extra": {
                    "type": "number"
                  },
                  "client_rate": {
                    "type": "number"
                  },
                  "client_hours": {
                    "type": "string"
                  },
                  "revenue_amount": {
                    "type": "number",
                    "description": "fixo/escopo"
                  },
                  "tax_rate": {
                    "type": "number",
                    "description": "0.18"
                  },
                  "commission": {
                    "type": "number"
                  },
                  "paid_status": {
                    "type": "string",
                    "enum": [
                      "pago",
                      "pendente",
                      "nao",
                      "outro"
                    ]
                  },
                  "category": {
                    "type": "string",
                    "enum": [
                      "equipe",
                      "pro_labore",
                      "interno"
                    ]
                  },
                  "notes": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Financeiro — Projetos & Equipe"
        ],
        "operationId": "removerAlocacao",
        "summary": "Remover alocação",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nSó em mês aberto e sem conta/cobrança gerada.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/projects/months/{month}/close-preview": {
      "post": {
        "tags": [
          "Financeiro — Projetos & Equipe"
        ],
        "operationId": "previaFecharMesProjetos",
        "summary": "Prévia do fechamento",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nQuantas contas a pagar e cobranças serão criadas e o total de cada.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "payables": {
                    "type": "boolean"
                  },
                  "receivables": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/projects/months/{month}/close": {
      "post": {
        "tags": [
          "Financeiro — Projetos & Equipe"
        ],
        "operationId": "fecharMesProjetos",
        "summary": "Fechar mês",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nGera contas a pagar (uma por pessoa × projeto com custo) e cobranças (uma por projeto com faturamento, para o cliente ligado ao centro de custo). Não duplica. Respeita o mês fechado pela contabilidade.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "payables": {
                    "type": "boolean"
                  },
                  "receivables": {
                    "type": "boolean"
                  },
                  "payable_due_date": {
                    "type": "string"
                  },
                  "receivable_due_date": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/projects/months/{month}/reopen": {
      "post": {
        "tags": [
          "Financeiro — Projetos & Equipe"
        ],
        "operationId": "reabrirMesProjetos",
        "summary": "Reabrir mês",
        "x-scopes": [
          "finance:write"
        ],
        "description": "**Escopo:** `finance:write`\n\nCancela as contas e cobranças geradas que ainda estão em aberto. Conta paga ou cobrança recebida bloqueia.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "month",
            "in": "path",
            "required": true,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {}
              }
            }
          }
        }
      }
    },
    "/v1/store/finance/projects/report": {
      "get": {
        "tags": [
          "Financeiro — Projetos & Equipe"
        ],
        "operationId": "relatorioProjetos",
        "summary": "Resultado por projeto, cliente, pessoa, cargo ou mês",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nPeríodo em meses (padrão: 12 últimos com dados), com série mensal.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "AAAA-MM",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group",
            "in": "query",
            "required": false,
            "description": "project | client | person | role | month",
            "schema": {
              "type": "string",
              "enum": [
                "project",
                "client",
                "person",
                "role",
                "month"
              ]
            }
          },
          {
            "name": "cost_center_id",
            "in": "query",
            "required": false,
            "description": "inclui subprojetos",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "employee_id",
            "in": "query",
            "required": false,
            "description": "",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/projects/centers/{id}/history": {
      "get": {
        "tags": [
          "Financeiro — Projetos & Equipe"
        ],
        "operationId": "historicoProjeto",
        "summary": "Histórico do projeto",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nSérie mensal, quem trabalhou e as alocações (com subprojetos).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/projects/people/{employeeId}/history": {
      "get": {
        "tags": [
          "Financeiro — Projetos & Equipe"
        ],
        "operationId": "historicoPessoa",
        "summary": "Histórico da pessoa",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nSérie mensal, em quais projetos e as alocações.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        },
        "parameters": [
          {
            "name": "employeeId",
            "in": "path",
            "required": true,
            "description": "",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/v1/store/finance/projects/imports": {
      "get": {
        "tags": [
          "Financeiro — Projetos & Equipe"
        ],
        "operationId": "importacoesProjetos",
        "summary": "Importações da planilha",
        "x-scopes": [
          "finance"
        ],
        "description": "**Escopo:** `finance`\n\nHistórico das importações da planilha de alocação (a importação em si é feita na tela).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos (mensagem em `message`)"
          },
          "401": {
            "description": "Chave ausente ou inválida"
          },
          "403": {
            "description": "A chave não tem o escopo"
          }
        }
      }
    }
  },
  "webhooks": {
    "stock.updated": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_stock_updated",
        "security": [],
        "summary": "stock.updated — estoque mudou",
        "description": "O estoque de um produto ou variação mudou. **Grave `data.stock` no SKU `data.sku`** (é o valor final).\n\nDispara em: venda no checkout da loja Devskin (`venda_site`), venda em marketplace (`venda_canal`), devolução por cancelamento/estorno/pagamento recusado (`cancelamento`) e ajuste na tela de estoque do painel (`ajuste_manual`).\n\n**Não** dispara para mudanças vindas do site próprio (pedidos e acertos pela API) nem quando o número de estoque é editado direto no cadastro do produto — por isso, confira com `GET /v1/store/inventory` de tempos em tempos.\n\nÉ o evento do cadastro de *Meu site*.",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "stock.updated"
            },
            "example": "stock.updated"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "stock.updated"
                      },
                      "data": {
                        "$ref": "#/components/schemas/StockUpdatedData"
                      }
                    }
                  }
                ]
              },
              "examples": {
                "venda": {
                  "summary": "Venda no Mercado Livre",
                  "value": {
                    "event": "stock.updated",
                    "data": {
                      "product_id": "6f1c2a9e-1d2b-4c3d-9e8f-0a1b2c3d4e5f",
                      "variant_id": null,
                      "sku": "KIT-01",
                      "stock": 24,
                      "delta": -1,
                      "reason": "venda_canal"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                },
                "variacao": {
                  "summary": "Variação vendida na loja Devskin",
                  "value": {
                    "event": "stock.updated",
                    "data": {
                      "product_id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
                      "variant_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
                      "sku": "CAM-P-AZUL",
                      "stock": 5,
                      "delta": -2,
                      "reason": "venda_site"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                },
                "cancelamento": {
                  "summary": "Cancelamento devolveu estoque",
                  "value": {
                    "event": "stock.updated",
                    "data": {
                      "product_id": "6f1c2a9e-1d2b-4c3d-9e8f-0a1b2c3d4e5f",
                      "variant_id": null,
                      "sku": "KIT-01",
                      "stock": 25,
                      "delta": 1,
                      "reason": "cancelamento"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                },
                "ajuste": {
                  "summary": "Ajuste no painel",
                  "value": {
                    "event": "stock.updated",
                    "data": {
                      "product_id": "6f1c2a9e-1d2b-4c3d-9e8f-0a1b2c3d4e5f",
                      "variant_id": null,
                      "sku": "KIT-01",
                      "stock": 40,
                      "delta": 15,
                      "reason": "ajuste_manual"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "order.created": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_order_created",
        "security": [],
        "summary": "order.created — pedido criado",
        "description": "Pedido criado no **checkout da loja Devskin**. Pedidos de marketplace e do site próprio não disparam este evento.",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "order.created"
            },
            "example": "order.created"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "order.created"
                      },
                      "data": {
                        "type": "object",
                        "properties": {
                          "order_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "order_number": {
                            "type": "string"
                          },
                          "customer_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid"
                          },
                          "customer": {
                            "$ref": "#/components/schemas/CustomerRef"
                          },
                          "store": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "name": {
                                "type": "string"
                              }
                            }
                          },
                          "subtotal": {
                            "type": "number"
                          },
                          "discount_amount": {
                            "type": "number"
                          },
                          "shipping_amount": {
                            "type": "number"
                          },
                          "total": {
                            "type": "number"
                          },
                          "payment_gateway": {
                            "type": "string",
                            "example": "stripe"
                          },
                          "payment_method": {
                            "type": "string",
                            "example": "pix"
                          },
                          "items": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "product_id": {
                                  "type": "string",
                                  "format": "uuid"
                                },
                                "name": {
                                  "type": "string"
                                },
                                "price": {
                                  "type": "number"
                                },
                                "quantity": {
                                  "type": "integer"
                                },
                                "total": {
                                  "type": "number"
                                }
                              }
                            }
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    }
                  }
                ]
              },
              "examples": {
                "ok": {
                  "summary": "Pedido criado",
                  "value": {
                    "event": "order.created",
                    "data": {
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "order_number": "LOJA96192042K7Q2",
                      "customer_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                      "customer": {
                        "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                        "name": "Maria Silva",
                        "email": "maria@email.com",
                        "phone": "11999999999"
                      },
                      "store": {
                        "id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
                        "name": "Loja da Ana"
                      },
                      "subtotal": 89.9,
                      "discount_amount": 0,
                      "shipping_amount": 15,
                      "total": 104.9,
                      "payment_gateway": "openpix",
                      "payment_method": "pix",
                      "items": [
                        {
                          "product_id": "6f1c2a9e-1d2b-4c3d-9e8f-0a1b2c3d4e5f",
                          "name": "Kit relaxante",
                          "price": 89.9,
                          "quantity": 1,
                          "total": 89.9
                        }
                      ],
                      "created_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "order.pending": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_order_pending",
        "security": [],
        "summary": "order.pending — voltou para pendente",
        "description": "Status do pedido mudado para `pending` no painel (ou pela IA com `update_order_status`).",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "order.pending"
            },
            "example": "order.pending"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "order.pending"
                      },
                      "data": {
                        "type": "object",
                        "properties": {
                          "order_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "order_number": {
                            "type": "string"
                          },
                          "customer_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid"
                          },
                          "customer": {
                            "$ref": "#/components/schemas/CustomerRef"
                          },
                          "previous_status": {
                            "$ref": "#/components/schemas/OrderStatus"
                          },
                          "new_status": {
                            "$ref": "#/components/schemas/OrderStatus"
                          },
                          "updated_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    }
                  }
                ]
              },
              "examples": {
                "ok": {
                  "summary": "Pendente",
                  "value": {
                    "event": "order.pending",
                    "data": {
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "order_number": "LOJA96192042K7Q2",
                      "customer_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                      "customer": {
                        "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                        "name": "Maria Silva",
                        "email": "maria@email.com",
                        "phone": "11999999999"
                      },
                      "previous_status": "processing",
                      "new_status": "pending",
                      "updated_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "order.processing": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_order_processing",
        "security": [],
        "summary": "order.processing — em preparo",
        "description": "Status do pedido mudado para `processing` no painel (ou pela IA com `update_order_status`).",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "order.processing"
            },
            "example": "order.processing"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "order.processing"
                      },
                      "data": {
                        "type": "object",
                        "properties": {
                          "order_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "order_number": {
                            "type": "string"
                          },
                          "customer_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid"
                          },
                          "customer": {
                            "$ref": "#/components/schemas/CustomerRef"
                          },
                          "previous_status": {
                            "$ref": "#/components/schemas/OrderStatus"
                          },
                          "new_status": {
                            "$ref": "#/components/schemas/OrderStatus"
                          },
                          "updated_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    }
                  }
                ]
              },
              "examples": {
                "ok": {
                  "summary": "Em preparo",
                  "value": {
                    "event": "order.processing",
                    "data": {
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "order_number": "LOJA96192042K7Q2",
                      "customer_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                      "customer": {
                        "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                        "name": "Maria Silva",
                        "email": "maria@email.com",
                        "phone": "11999999999"
                      },
                      "previous_status": "pending",
                      "new_status": "processing",
                      "updated_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "order.invoiced": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_order_invoiced",
        "security": [],
        "summary": "order.invoiced — nota fiscal autorizada",
        "description": "A NF-e de venda do pedido foi autorizada (emitida pelo painel, pela API ou automaticamente). Use `data.order.external_id` para achar o pedido no seu site e `data.invoice.access_key` para comprar o frete com a nota.",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "order.invoiced"
            },
            "example": "order.invoiced"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "const": "order.invoiced"
                      },
                      "data": {
                        "type": "object",
                        "properties": {
                          "order_id": {
                            "type": "string"
                          },
                          "order": {
                            "type": "object",
                            "description": "Resumo do pedido. `external_id` = o \"id\" que o seu site mandou em POST /v1/store/orders.",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "number": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string"
                              },
                              "channel": {
                                "type": "string"
                              },
                              "external_id": {
                                "type": "string",
                                "nullable": true
                              },
                              "tracking_code": {
                                "type": "string",
                                "nullable": true
                              }
                            }
                          },
                          "invoice": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "number": {
                                "type": "integer"
                              },
                              "serie": {
                                "type": "integer"
                              },
                              "access_key": {
                                "type": "string"
                              },
                              "environment": {
                                "type": "string"
                              },
                              "authorized_at": {
                                "type": "string",
                                "format": "date-time"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                ]
              },
              "example": {
                "event": "order.invoiced",
                "timestamp": "2026-11-03T13:26:04Z",
                "webhook_id": "...",
                "data": {
                  "order_id": "67fc…",
                  "order": {
                    "id": "67fc…",
                    "number": "SP-ABC123-1001",
                    "status": "processing",
                    "channel": "site_proprio",
                    "external_id": "1001"
                  },
                  "invoice": {
                    "number": 7,
                    "serie": 2,
                    "access_key": "3526…1841",
                    "environment": "producao"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "order.label_created": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_order_label_created",
        "security": [],
        "summary": "order.label_created — etiqueta comprada no painel",
        "description": "A etiqueta de envio do pedido foi comprada no painel (Melhor Envio da loja). Marque o frete como contratado no seu site para não comprar de novo. `data.label.id` é o id do envio no Melhor Envio.",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "order.label_created"
            },
            "example": "order.label_created"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "const": "order.label_created"
                      },
                      "data": {
                        "type": "object",
                        "properties": {
                          "order_id": {
                            "type": "string"
                          },
                          "order": {
                            "type": "object",
                            "description": "Resumo do pedido. `external_id` = o \"id\" que o seu site mandou em POST /v1/store/orders.",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "number": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string"
                              },
                              "channel": {
                                "type": "string"
                              },
                              "external_id": {
                                "type": "string",
                                "nullable": true
                              },
                              "tracking_code": {
                                "type": "string",
                                "nullable": true
                              }
                            }
                          },
                          "label": {
                            "type": "object",
                            "properties": {
                              "provider": {
                                "type": "string",
                                "example": "melhor_envio"
                              },
                              "id": {
                                "type": "string"
                              },
                              "service": {
                                "type": "string"
                              },
                              "price": {
                                "type": "number",
                                "nullable": true
                              },
                              "with_invoice": {
                                "type": "boolean"
                              },
                              "tracking_code": {
                                "type": "string",
                                "nullable": true
                              },
                              "tracking_url": {
                                "type": "string",
                                "nullable": true
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                ]
              },
              "example": {
                "event": "order.label_created",
                "timestamp": "2026-11-03T14:02:11Z",
                "webhook_id": "...",
                "data": {
                  "order_id": "67fc…",
                  "order": {
                    "number": "SP-ABC123-1001",
                    "channel": "site_proprio",
                    "external_id": "1001"
                  },
                  "label": {
                    "provider": "melhor_envio",
                    "id": "a3232a40-…",
                    "service": "1",
                    "price": 53.77,
                    "with_invoice": true,
                    "tracking_code": null
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "order.shipped": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_order_shipped",
        "security": [],
        "summary": "order.shipped — enviado",
        "description": "Dois momentos: status mudado para `shipped` no painel/IA (formato de mudança de status) **ou** pedido marcado como enviado com código de rastreio (formato com `tracking_code`).",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "order.shipped"
            },
            "example": "order.shipped"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "order.shipped"
                      },
                      "data": {
                        "oneOf": [
                          {
                            "type": "object",
                            "properties": {
                              "order_id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "order_number": {
                                "type": "string"
                              },
                              "customer_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "format": "uuid"
                              },
                              "customer": {
                                "$ref": "#/components/schemas/CustomerRef"
                              },
                              "previous_status": {
                                "$ref": "#/components/schemas/OrderStatus"
                              },
                              "new_status": {
                                "$ref": "#/components/schemas/OrderStatus"
                              },
                              "updated_at": {
                                "type": "string",
                                "format": "date-time"
                              }
                            }
                          },
                          {
                            "type": "object",
                            "description": "Enviado com rastreio.",
                            "properties": {
                              "order_id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "order_number": {
                                "type": "string"
                              },
                              "tracking_code": {
                                "type": "string"
                              },
                              "tracking_url": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "shipped_at": {
                                "type": "string",
                                "format": "date-time"
                              }
                            }
                          }
                        ]
                      }
                    }
                  }
                ]
              },
              "examples": {
                "status": {
                  "summary": "Mudança de status",
                  "value": {
                    "event": "order.shipped",
                    "data": {
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "order_number": "LOJA96192042K7Q2",
                      "customer_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                      "customer": {
                        "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                        "name": "Maria Silva",
                        "email": "maria@email.com",
                        "phone": "11999999999"
                      },
                      "previous_status": "processing",
                      "new_status": "shipped",
                      "updated_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                },
                "rastreio": {
                  "summary": "Com rastreio",
                  "value": {
                    "event": "order.shipped",
                    "data": {
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "order_number": "LOJA96192042K7Q2",
                      "tracking_code": "AA123456789BR",
                      "tracking_url": "https://rastreamento.correios.com.br/app/index.php?objeto=AA123456789BR",
                      "shipped_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "order.delivered": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_order_delivered",
        "security": [],
        "summary": "order.delivered — entregue",
        "description": "Status do pedido mudado para `delivered` no painel (ou pela IA com `update_order_status`).",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "order.delivered"
            },
            "example": "order.delivered"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "order.delivered"
                      },
                      "data": {
                        "type": "object",
                        "properties": {
                          "order_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "order_number": {
                            "type": "string"
                          },
                          "customer_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid"
                          },
                          "customer": {
                            "$ref": "#/components/schemas/CustomerRef"
                          },
                          "previous_status": {
                            "$ref": "#/components/schemas/OrderStatus"
                          },
                          "new_status": {
                            "$ref": "#/components/schemas/OrderStatus"
                          },
                          "updated_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    }
                  }
                ]
              },
              "examples": {
                "ok": {
                  "summary": "Entregue",
                  "value": {
                    "event": "order.delivered",
                    "data": {
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "order_number": "LOJA96192042K7Q2",
                      "customer_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                      "customer": {
                        "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                        "name": "Maria Silva",
                        "email": "maria@email.com",
                        "phone": "11999999999"
                      },
                      "previous_status": "shipped",
                      "new_status": "delivered",
                      "updated_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "order.cancelled": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_order_cancelled",
        "security": [],
        "summary": "order.cancelled — cancelado",
        "description": "Dois momentos: status mudado para `cancelled` no painel/IA (formato de mudança de status) **ou** o próprio cliente cancelou o pedido (formato com `refunded`).",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "order.cancelled"
            },
            "example": "order.cancelled"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "order.cancelled"
                      },
                      "data": {
                        "oneOf": [
                          {
                            "type": "object",
                            "properties": {
                              "order_id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "order_number": {
                                "type": "string"
                              },
                              "customer_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "format": "uuid"
                              },
                              "customer": {
                                "$ref": "#/components/schemas/CustomerRef"
                              },
                              "previous_status": {
                                "$ref": "#/components/schemas/OrderStatus"
                              },
                              "new_status": {
                                "$ref": "#/components/schemas/OrderStatus"
                              },
                              "updated_at": {
                                "type": "string",
                                "format": "date-time"
                              }
                            }
                          },
                          {
                            "type": "object",
                            "description": "Cancelado pelo cliente.",
                            "properties": {
                              "order_id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "order_number": {
                                "type": "string"
                              },
                              "customer_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "format": "uuid"
                              },
                              "refunded": {
                                "type": "boolean",
                                "description": "Se o pagamento já tinha sido feito (e foi estornado)."
                              },
                              "cancelled_at": {
                                "type": "string",
                                "format": "date-time"
                              }
                            }
                          }
                        ]
                      }
                    }
                  }
                ]
              },
              "examples": {
                "painel": {
                  "summary": "Cancelado no painel",
                  "value": {
                    "event": "order.cancelled",
                    "data": {
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "order_number": "LOJA96192042K7Q2",
                      "customer_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                      "customer": {
                        "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                        "name": "Maria Silva",
                        "email": "maria@email.com",
                        "phone": "11999999999"
                      },
                      "previous_status": "pending",
                      "new_status": "cancelled",
                      "updated_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                },
                "cliente": {
                  "summary": "Cancelado pelo cliente",
                  "value": {
                    "event": "order.cancelled",
                    "data": {
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "order_number": "LOJA96192042K7Q2",
                      "customer_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                      "refunded": true,
                      "cancelled_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "order.refunded": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_order_refunded",
        "security": [],
        "summary": "order.refunded — reembolsado",
        "description": "Reembolso feito no painel.",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "order.refunded"
            },
            "example": "order.refunded"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "order.refunded"
                      },
                      "data": {
                        "type": "object",
                        "properties": {
                          "order_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "order_number": {
                            "type": "string"
                          },
                          "refund_amount": {
                            "type": [
                              "number",
                              "string"
                            ],
                            "description": "Valor reembolsado (o informado, ou o valor do pagamento)."
                          },
                          "refunded_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    }
                  }
                ]
              },
              "examples": {
                "ok": {
                  "summary": "Reembolsado",
                  "value": {
                    "event": "order.refunded",
                    "data": {
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "order_number": "LOJA96192042K7Q2",
                      "refund_amount": "104.90",
                      "refunded_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "payment.confirmed": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_payment_confirmed",
        "security": [],
        "summary": "payment.confirmed — pagamento aprovado",
        "description": "Pagamento aprovado (cartão via Stripe ou Pix via OpenPix). O formato varia conforme a origem da confirmação.",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "payment.confirmed"
            },
            "example": "payment.confirmed"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "payment.confirmed"
                      },
                      "data": {
                        "oneOf": [
                          {
                            "type": "object",
                            "description": "Formato completo (checkout e Pix/OpenPix).",
                            "properties": {
                              "payment_id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "order_id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "order_number": {
                                "type": "string"
                              },
                              "customer_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "format": "uuid"
                              },
                              "customer": {
                                "$ref": "#/components/schemas/CustomerRef"
                              },
                              "gateway": {
                                "type": "string",
                                "example": "openpix"
                              },
                              "method": {
                                "type": "string",
                                "example": "pix"
                              },
                              "amount": {
                                "type": "string",
                                "pattern": "^-?\\d+(\\.\\d{1,2})?$",
                                "example": "104.90",
                                "description": "Valor decimal em texto (ex.: \"104.90\")."
                              },
                              "currency": {
                                "type": "string",
                                "example": "BRL"
                              },
                              "paid_at": {
                                "type": "string",
                                "format": "date-time"
                              }
                            }
                          },
                          {
                            "type": "object",
                            "description": "Formato curto (confirmação pelo webhook do Stripe).",
                            "properties": {
                              "payment_id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "order_id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "gateway": {
                                "type": "string",
                                "example": "stripe"
                              },
                              "method": {
                                "type": "string",
                                "example": "credit_card"
                              },
                              "amount": {
                                "type": "string",
                                "pattern": "^-?\\d+(\\.\\d{1,2})?$",
                                "example": "104.90",
                                "description": "Valor decimal em texto (ex.: \"104.90\")."
                              },
                              "currency": {
                                "type": "string",
                                "example": "BRL"
                              },
                              "paid_at": {
                                "type": "string",
                                "format": "date-time"
                              }
                            }
                          }
                        ]
                      }
                    }
                  }
                ]
              },
              "examples": {
                "pix": {
                  "summary": "Pix (formato completo)",
                  "value": {
                    "event": "payment.confirmed",
                    "data": {
                      "payment_id": "f0e1d2c3-b4a5-4968-8776-655443322110",
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "order_number": "LOJA96192042K7Q2",
                      "customer_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                      "customer": {
                        "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                        "name": "Maria Silva",
                        "email": "maria@email.com",
                        "phone": "11999999999"
                      },
                      "gateway": "openpix",
                      "method": "pix",
                      "amount": "104.90",
                      "currency": "BRL",
                      "paid_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                },
                "stripe": {
                  "summary": "Stripe (formato curto)",
                  "value": {
                    "event": "payment.confirmed",
                    "data": {
                      "payment_id": "f0e1d2c3-b4a5-4968-8776-655443322110",
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "gateway": "stripe",
                      "method": "credit_card",
                      "amount": "104.90",
                      "currency": "BRL",
                      "paid_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "payment.failed": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_payment_failed",
        "security": [],
        "summary": "payment.failed — pagamento recusado",
        "description": "Pagamento recusado. O estoque baixado pelo pedido volta (gera `stock.updated` com `cancelamento`).",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "payment.failed"
            },
            "example": "payment.failed"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "payment.failed"
                      },
                      "data": {
                        "oneOf": [
                          {
                            "type": "object",
                            "description": "Formato completo (checkout e Pix/OpenPix).",
                            "properties": {
                              "payment_id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "order_id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "order_number": {
                                "type": "string"
                              },
                              "customer_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "format": "uuid"
                              },
                              "customer": {
                                "$ref": "#/components/schemas/CustomerRef"
                              },
                              "gateway": {
                                "type": "string",
                                "example": "openpix"
                              },
                              "method": {
                                "type": "string",
                                "example": "pix"
                              },
                              "amount": {
                                "type": "string",
                                "pattern": "^-?\\d+(\\.\\d{1,2})?$",
                                "example": "104.90",
                                "description": "Valor decimal em texto (ex.: \"104.90\")."
                              },
                              "currency": {
                                "type": "string",
                                "example": "BRL"
                              },
                              "failure_message": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "failed_at": {
                                "type": "string",
                                "format": "date-time"
                              }
                            }
                          },
                          {
                            "type": "object",
                            "description": "Formato curto (confirmação pelo webhook do Stripe).",
                            "properties": {
                              "payment_id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "order_id": {
                                "type": "string",
                                "format": "uuid"
                              },
                              "gateway": {
                                "type": "string",
                                "example": "stripe"
                              },
                              "method": {
                                "type": "string",
                                "example": "credit_card"
                              },
                              "amount": {
                                "type": "string",
                                "pattern": "^-?\\d+(\\.\\d{1,2})?$",
                                "example": "104.90",
                                "description": "Valor decimal em texto (ex.: \"104.90\")."
                              },
                              "currency": {
                                "type": "string",
                                "example": "BRL"
                              },
                              "failed_at": {
                                "type": "string",
                                "format": "date-time"
                              }
                            }
                          }
                        ]
                      }
                    }
                  }
                ]
              },
              "examples": {
                "checkout": {
                  "summary": "Checkout (formato completo)",
                  "value": {
                    "event": "payment.failed",
                    "data": {
                      "payment_id": "f0e1d2c3-b4a5-4968-8776-655443322110",
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "order_number": "LOJA96192042K7Q2",
                      "customer_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                      "customer": {
                        "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                        "name": "Maria Silva",
                        "email": "maria@email.com",
                        "phone": "11999999999"
                      },
                      "gateway": "stripe",
                      "method": "credit_card",
                      "amount": "104.90",
                      "currency": "BRL",
                      "failure_message": "Your card was declined.",
                      "failed_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                },
                "stripe": {
                  "summary": "Stripe (formato curto)",
                  "value": {
                    "event": "payment.failed",
                    "data": {
                      "payment_id": "f0e1d2c3-b4a5-4968-8776-655443322110",
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "gateway": "stripe",
                      "method": "credit_card",
                      "amount": "104.90",
                      "currency": "BRL",
                      "failed_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "payment.refunded": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_payment_refunded",
        "security": [],
        "summary": "payment.refunded — pagamento estornado",
        "description": "Estorno registrado no Stripe.",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "payment.refunded"
            },
            "example": "payment.refunded"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "payment.refunded"
                      },
                      "data": {
                        "type": "object",
                        "description": "Formato curto (confirmação pelo webhook do Stripe).",
                        "properties": {
                          "payment_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "order_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "gateway": {
                            "type": "string",
                            "example": "stripe"
                          },
                          "method": {
                            "type": "string",
                            "example": "credit_card"
                          },
                          "amount": {
                            "type": "string",
                            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
                            "example": "104.90",
                            "description": "Valor decimal em texto (ex.: \"104.90\")."
                          },
                          "currency": {
                            "type": "string",
                            "example": "BRL"
                          },
                          "refunded_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    }
                  }
                ]
              },
              "examples": {
                "ok": {
                  "summary": "Estornado",
                  "value": {
                    "event": "payment.refunded",
                    "data": {
                      "payment_id": "f0e1d2c3-b4a5-4968-8776-655443322110",
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "gateway": "stripe",
                      "method": "credit_card",
                      "amount": "104.90",
                      "currency": "BRL",
                      "refunded_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "shipping.updated": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_shipping_updated",
        "security": [],
        "summary": "shipping.updated — etiqueta mudou",
        "description": "A etiqueta do Melhor Envio do pedido mudou de situação (postada, entregue...).",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "shipping.updated"
            },
            "example": "shipping.updated"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "shipping.updated"
                      },
                      "data": {
                        "type": "object",
                        "properties": {
                          "order_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "order_number": {
                            "type": "string"
                          },
                          "tracking_code": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "status": {
                            "$ref": "#/components/schemas/OrderStatus"
                          },
                          "melhor_envio_event": {
                            "type": "string",
                            "description": "Evento original do Melhor Envio.",
                            "example": "order.posted"
                          }
                        }
                      }
                    }
                  }
                ]
              },
              "examples": {
                "ok": {
                  "summary": "Postado",
                  "value": {
                    "event": "shipping.updated",
                    "data": {
                      "order_id": "8e2b4c6d-1a3f-4b5c-8d7e-9f0a1b2c3d4e",
                      "order_number": "LOJA96192042K7Q2",
                      "tracking_code": "AA123456789BR",
                      "status": "shipped",
                      "melhor_envio_event": "order.posted"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "cart.abandoned": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_cart_abandoned",
        "security": [],
        "summary": "cart.abandoned — carrinho abandonado",
        "description": "Carrinho da loja Devskin sem mudança há mais de 1 hora (verificação a cada 30 minutos).",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "cart.abandoned"
            },
            "example": "cart.abandoned"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "cart.abandoned"
                      },
                      "data": {
                        "type": "object",
                        "properties": {
                          "cart_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "user_id": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "uuid"
                          },
                          "session_id": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "items": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "product_id": {
                                  "type": "string",
                                  "format": "uuid"
                                },
                                "quantity": {
                                  "type": "integer"
                                }
                              }
                            }
                          },
                          "abandoned_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    }
                  }
                ]
              },
              "examples": {
                "ok": {
                  "summary": "Abandonado",
                  "value": {
                    "event": "cart.abandoned",
                    "data": {
                      "cart_id": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
                      "user_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                      "session_id": null,
                      "items": [
                        {
                          "product_id": "6f1c2a9e-1d2b-4c3d-9e8f-0a1b2c3d4e5f",
                          "quantity": 1
                        }
                      ],
                      "abandoned_at": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    },
    "test": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "webhook_test",
        "security": [],
        "summary": "test — evento de teste",
        "description": "Enviado pelo botão **Testar** (ou `POST /stores/{storeId}/webhooks-config/{id}/test`). Use para conferir endereço e assinatura.",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "description": "Nome do evento.",
            "schema": {
              "type": "string",
              "const": "test"
            },
            "example": "test"
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "description": "`sha256=` + HMAC-SHA256 (hex) do corpo bruto, com o segredo do webhook como chave. Veja *Verificar a assinatura*.",
            "schema": {
              "type": "string",
              "pattern": "^sha256=[0-9a-f]{64}$"
            },
            "example": "sha256=5d41402abc4b2a76b9719d911017c592ae2b7f9b1c3e8a6f0d2c4b6a8e0f1a2b"
          },
          {
            "name": "User-Agent",
            "in": "header",
            "required": true,
            "description": "Sempre `Devskin-Webhook/1.0`.",
            "schema": {
              "type": "string",
              "const": "Devskin-Webhook/1.0"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WebhookEnvelope"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "event": {
                        "type": "string",
                        "const": "test"
                      },
                      "data": {
                        "type": "object",
                        "properties": {
                          "test": {
                            "type": "boolean",
                            "const": true
                          },
                          "message": {
                            "type": "string"
                          },
                          "timestamp": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    }
                  }
                ]
              },
              "examples": {
                "ok": {
                  "summary": "Teste",
                  "value": {
                    "event": "test",
                    "data": {
                      "test": true,
                      "message": "This is a test webhook event from Devskin Marketplace",
                      "timestamp": "2026-10-18T14:03:12.481Z"
                    },
                    "timestamp": "2026-10-18T14:03:12.481Z",
                    "webhook_id": "0b7d6c1e-8a2f-4e3b-9c4d-5e6f7a8b9c0d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Recebido. Responda em até 10 s. Qualquer outro status (ou demora) é falha: o ERP tenta de novo após ~2 s e ~4 s (até 3 tentativas) e, com 10 falhas seguidas, desliga o webhook."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Chave da loja (`dsk_` + 64 caracteres). Crie em **Canais de venda › Meu site** ou **Configurações › API Keys**."
      },
      "McpBearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Só no MCP: a mesma chave `dsk_...` em `Authorization: Bearer`."
      },
      "PanelJWT": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Token do login do painel (`POST /auth/login` → `data.token`). Só para as rotas `/stores/{storeId}/...`."
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "description": "Formato de erro de todas as rotas REST.",
        "required": [
          "success",
          "message"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": false,
            "example": false
          },
          "message": {
            "type": "string",
            "description": "Explicação do erro (rotas do painel respondem em pt ou en conforme `Accept-Language`).",
            "example": "Invalid or revoked API key"
          },
          "request_id": {
            "type": "string",
            "description": "Só em erros inesperados (500 do servidor). Igual ao header `X-Request-ID`.",
            "example": "5b0e7a52-0f7c-4a7e-9e0a-2b8f3c1d4e5f"
          }
        }
      },
      "PlanErrorResponse": {
        "type": "object",
        "description": "Recurso não incluído no plano da loja.",
        "required": [
          "success",
          "code",
          "message"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": false
          },
          "code": {
            "type": "string",
            "enum": [
              "PLAN_REQUIRED",
              "FEATURE_NOT_AVAILABLE"
            ],
            "description": "`PLAN_REQUIRED`: loja sem assinatura ativa. `FEATURE_NOT_AVAILABLE`: o plano atual não inclui o recurso."
          },
          "message": {
            "type": "string",
            "example": "Este recurso não está disponível no seu plano atual. Faça upgrade para acessar."
          },
          "feature": {
            "type": "string",
            "enum": [
              "api_access_enabled",
              "webhooks_enabled"
            ],
            "description": "Só em `FEATURE_NOT_AVAILABLE`."
          },
          "current_plan": {
            "type": "string",
            "description": "Só em `FEATURE_NOT_AVAILABLE`.",
            "example": "Grátis"
          }
        }
      },
      "SiteCustomer": {
        "type": "object",
        "description": "Comprador. Vira os dados de comprador do pedido (nota fiscal e etiqueta usam estes campos).",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Nome completo. Também vira o destinatário da entrega se `shipping_address.name` não vier.",
            "example": "Maria Silva"
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 255,
            "example": "maria@email.com"
          },
          "phone": {
            "type": "string",
            "maxLength": 40,
            "description": "Telefone com DDD (só números ou formatado). Sempre usado como telefone da entrega.",
            "example": "11999999999"
          },
          "document": {
            "type": "string",
            "maxLength": 30,
            "description": "CPF ou CNPJ (só números ou formatado). Necessário para emitir a nota fiscal. Sempre usado como documento da entrega.",
            "example": "12345678909"
          }
        }
      },
      "SiteAddress": {
        "type": "object",
        "description": "Endereço de entrega (formato brasileiro).",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Destinatário. Padrão: `customer.name`.",
            "example": "Maria Silva"
          },
          "street": {
            "type": "string",
            "maxLength": 255,
            "description": "Logradouro (rua, avenida...).",
            "example": "Rua A"
          },
          "number": {
            "type": "string",
            "maxLength": 30,
            "example": "10"
          },
          "complement": {
            "type": "string",
            "maxLength": 255,
            "example": "Apto 42"
          },
          "neighborhood": {
            "type": "string",
            "maxLength": 255,
            "description": "Bairro.",
            "example": "Centro"
          },
          "city": {
            "type": "string",
            "maxLength": 255,
            "example": "São Paulo"
          },
          "state": {
            "type": "string",
            "maxLength": 60,
            "description": "UF (sigla).",
            "example": "SP"
          },
          "zipcode": {
            "type": "string",
            "maxLength": 20,
            "description": "CEP. Caracteres fora de letras, números e hífen são removidos.",
            "example": "01001000"
          },
          "country": {
            "type": "string",
            "maxLength": 10,
            "default": "BR",
            "example": "BR"
          },
          "full": {
            "type": "string",
            "maxLength": 255,
            "description": "Opcional: endereço numa linha só, usado quando `street` não vier.",
            "example": "Rua A, 10 - Centro, São Paulo/SP"
          }
        }
      },
      "SiteOrderItem": {
        "type": "object",
        "required": [
          "sku",
          "quantity",
          "price"
        ],
        "properties": {
          "sku": {
            "type": "string",
            "maxLength": 100,
            "description": "SKU igual ao cadastrado no ERP (primeiro procura nas variações, depois nos produtos da loja). Sem correspondência, o item vai para `unmapped_items` e não baixa estoque.",
            "example": "KIT-01"
          },
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Nome do item no seu site (aceita também `title`).",
            "example": "Kit relaxante"
          },
          "quantity": {
            "type": "integer",
            "minimum": 1,
            "default": 1,
            "description": "Quantidade. Valor inválido ou menor que 1 vale 1.",
            "example": 1
          },
          "price": {
            "type": "number",
            "minimum": 0,
            "description": "Preço unitário em reais (ponto decimal).",
            "example": 89.9
          }
        }
      },
      "SiteOrderStatus": {
        "type": "string",
        "description": "Status no seu site (português ou inglês, sem diferença de maiúsculas). Valor fora da lista vale `pendente`.\n\n| Valor | Pedido | Pagamento |\n|---|---|---|\n| `pendente`, `pending`, `aguardando_pagamento` | pending | pending |\n| `pago`, `paid`, `aprovado`, `processing` | processing | paid |\n| `enviado`, `shipped` | shipped | paid |\n| `entregue`, `delivered` | delivered | paid |\n| `cancelado`, `cancelled`, `canceled` | cancelled | (não muda) |\n| `reembolsado`, `refunded` | refunded | refunded |",
        "enum": [
          "pendente",
          "pending",
          "aguardando_pagamento",
          "pago",
          "paid",
          "aprovado",
          "processing",
          "enviado",
          "shipped",
          "entregue",
          "delivered",
          "cancelado",
          "cancelled",
          "canceled",
          "reembolsado",
          "refunded"
        ],
        "default": "pendente",
        "example": "pago"
      },
      "SiteOrderInput": {
        "type": "object",
        "required": [
          "id",
          "items"
        ],
        "description": "Pedido do seu site. Na **primeira** vez cria o pedido completo; nas próximas (mesmo `id`) só atualiza status, pagamento e dados do comprador que estavam vazios.",
        "properties": {
          "id": {
            "type": [
              "string",
              "integer"
            ],
            "maxLength": 40,
            "description": "Id/número do pedido no seu site — chave de idempotência. Aceita também `external_id`. Vira o número `SP-<código da loja>-<id>` no ERP.",
            "example": "1001"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Data real da venda no seu site (ISO 8601). Padrão: agora. Só vale na criação.",
            "example": "2026-10-18T10:15:00-03:00"
          },
          "status": {
            "$ref": "#/components/schemas/SiteOrderStatus"
          },
          "customer": {
            "$ref": "#/components/schemas/SiteCustomer"
          },
          "shipping_address": {
            "$ref": "#/components/schemas/SiteAddress"
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/SiteOrderItem"
            },
            "description": "Itens do pedido (pelo menos 1). Só valem na criação."
          },
          "shipping": {
            "type": "number",
            "minimum": 0,
            "default": 0,
            "description": "Valor do frete em reais (aceita também `shipping_amount`).",
            "example": 15
          },
          "discount": {
            "type": "number",
            "minimum": 0,
            "default": 0,
            "description": "Desconto em reais (aceita também `discount_amount`).",
            "example": 0
          },
          "total": {
            "type": "number",
            "minimum": 0,
            "description": "Total cobrado. Se não vier (ou for 0), o ERP calcula: soma dos itens + frete − desconto.",
            "example": 104.9
          },
          "currency": {
            "type": "string",
            "default": "BRL",
            "example": "BRL"
          }
        }
      },
      "UnmappedItem": {
        "type": "object",
        "description": "Item sem produto com o mesmo SKU na loja (entrou no pedido, sem baixa de estoque).",
        "properties": {
          "title": {
            "type": "string",
            "example": "Vela aromática"
          },
          "sku": {
            "type": [
              "string",
              "null"
            ],
            "example": "VELA-99"
          },
          "quantity": {
            "type": "integer",
            "example": 2
          },
          "unit_price": {
            "type": "number",
            "example": 19.9
          },
          "external_item_id": {
            "type": "null"
          },
          "external_variation_id": {
            "type": "null"
          }
        }
      },
      "SiteOrderResult": {
        "type": "object",
        "required": [
          "success",
          "data",
          "message"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "order_id": {
                "type": "string",
                "format": "uuid",
                "description": "Id do pedido no ERP."
              },
              "order_number": {
                "type": "string",
                "example": "SP-8E2B4C-1001"
              },
              "status": {
                "$ref": "#/components/schemas/OrderStatus"
              },
              "payment_status": {
                "$ref": "#/components/schemas/PaymentStatus"
              },
              "unmapped_items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/UnmappedItem"
                }
              }
            }
          },
          "message": {
            "type": "string",
            "enum": [
              "Pedido recebido.",
              "Pedido recebido. Alguns itens não têm produto com o mesmo SKU aqui — o estoque deles não foi baixado."
            ]
          }
        }
      },
      "OrderStatus": {
        "type": "string",
        "enum": [
          "pending",
          "processing",
          "shipped",
          "delivered",
          "cancelled",
          "refunded"
        ],
        "description": "Status do pedido no ERP.",
        "example": "processing"
      },
      "PaymentStatus": {
        "type": "string",
        "enum": [
          "pending",
          "paid",
          "failed",
          "refunded"
        ],
        "description": "Status do pagamento no ERP.",
        "example": "paid"
      },
      "InventoryRow": {
        "type": "object",
        "properties": {
          "sku": {
            "type": [
              "string",
              "null"
            ],
            "description": "SKU da variação (ou do produto). `null` se o produto não tem SKU.",
            "example": "KIT-01"
          },
          "product_id": {
            "type": "string",
            "format": "uuid"
          },
          "variant_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "`null` para produto sem variações."
          },
          "name": {
            "type": "string",
            "description": "Nome do produto; em variações, \"Produto — Variação\".",
            "example": "Kit relaxante"
          },
          "stock": {
            "type": "integer",
            "description": "Estoque atual (pode ser negativo se vendeu mais do que tinha).",
            "example": 24
          }
        }
      },
      "InventoryList": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InventoryRow"
            }
          }
        }
      },
      "InventorySetInput": {
        "type": "object",
        "required": [
          "stock"
        ],
        "properties": {
          "stock": {
            "type": "integer",
            "minimum": 0,
            "description": "Quantidade exata em estoque (número inteiro, 0 ou mais). Decimais são truncados.",
            "example": 25
          }
        }
      },
      "InventorySetResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "sku": {
                "type": "string",
                "example": "KIT-01"
              },
              "stock": {
                "type": "integer",
                "example": 25
              }
            }
          }
        }
      },
      "Pagination": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer",
            "description": "Total de registros.",
            "example": 57
          },
          "page": {
            "type": "integer",
            "example": 1
          },
          "limit": {
            "type": "integer",
            "example": 20
          },
          "totalPages": {
            "type": "integer",
            "example": 3
          },
          "hasMore": {
            "type": "boolean",
            "example": true
          }
        }
      },
      "Address": {
        "type": "object",
        "description": "Endereço gravado no pedido.",
        "properties": {
          "name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "cpf": {
            "type": "string",
            "description": "CPF/CNPJ."
          },
          "street": {
            "type": "string"
          },
          "number": {
            "type": "string"
          },
          "complement": {
            "type": "string"
          },
          "neighborhood": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "zipcode": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "address": {
            "type": "string",
            "description": "Linha completa."
          }
        }
      },
      "Order": {
        "type": "object",
        "description": "Pedido (todas as colunas do pedido; não inclui os itens).",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "store_id": {
            "type": "string",
            "format": "uuid"
          },
          "customer_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Cliente da loja Devskin; `null` em pedidos de canal/site próprio."
          },
          "order_number": {
            "type": "string",
            "description": "Número do pedido. Prefixos: `SP-` site próprio, `ML-` Mercado Livre, `SPE-` Shopee, `AMZ-` Amazon, `TTS-` TikTok Shop.",
            "example": "SP-8E2B4C-1001"
          },
          "status": {
            "$ref": "#/components/schemas/OrderStatus"
          },
          "payment_status": {
            "$ref": "#/components/schemas/PaymentStatus"
          },
          "subtotal": {
            "type": "string",
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "89.90",
            "description": "Valor decimal em texto (ex.: \"104.90\")."
          },
          "discount_amount": {
            "type": "string",
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "0.00",
            "description": "Valor decimal em texto (ex.: \"104.90\")."
          },
          "shipping_amount": {
            "type": "string",
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "15.00",
            "description": "Valor decimal em texto (ex.: \"104.90\")."
          },
          "tax_amount": {
            "type": "string",
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "0.00",
            "description": "Valor decimal em texto (ex.: \"104.90\")."
          },
          "total": {
            "type": "string",
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "104.90",
            "description": "Valor decimal em texto (ex.: \"104.90\")."
          },
          "currency": {
            "type": "string",
            "example": "BRL"
          },
          "shipping_address": {
            "$ref": "#/components/schemas/Address",
            "type": [
              "object",
              "null"
            ]
          },
          "billing_address": {
            "type": [
              "object",
              "null"
            ],
            "description": "Endereço de cobrança (mesmo formato), quando houver."
          },
          "shipping_method": {
            "type": [
              "string",
              "null"
            ]
          },
          "tracking_code": {
            "type": [
              "string",
              "null"
            ],
            "example": "AA123456789BR"
          },
          "tracking_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "shipping_carrier": {
            "type": [
              "string",
              "null"
            ]
          },
          "shipping_service": {
            "type": [
              "string",
              "null"
            ]
          },
          "shipping_label_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "shipping_label_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "platform_commission": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "0.00",
            "description": "Valor decimal em texto (ex.: \"104.90\")."
          },
          "seller_amount": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "104.90",
            "description": "Valor decimal em texto (ex.: \"104.90\")."
          },
          "coupon_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "coupon_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "affiliate_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "shipped_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "delivered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "cancelled_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "channel": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "site",
              "site_proprio",
              "mercado_livre",
              "shopee",
              "amazon",
              "tiktok",
              null
            ],
            "description": "Canal de venda."
          },
          "external_order_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Id do pedido no canal (no site próprio, o `id` que você enviou).",
            "example": "1001"
          },
          "buyer_name": {
            "type": [
              "string",
              "null"
            ],
            "example": "Maria Silva"
          },
          "buyer_document": {
            "type": [
              "string",
              "null"
            ],
            "example": "12345678909"
          },
          "buyer_email": {
            "type": [
              "string",
              "null"
            ],
            "example": "maria@email.com"
          },
          "buyer_phone": {
            "type": [
              "string",
              "null"
            ],
            "example": "11999999999"
          },
          "unmapped_items": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/UnmappedItem"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "OrderList": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Order"
                }
              },
              "pagination": {
                "$ref": "#/components/schemas/Pagination"
              }
            }
          }
        }
      },
      "OrderDetail": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "order": {
                "$ref": "#/components/schemas/Order"
              }
            }
          }
        }
      },
      "Product": {
        "type": "object",
        "description": "Produto (todas as colunas do produto; variações e imagens não vêm nesta rota).",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "store_id": {
            "type": "string",
            "format": "uuid"
          },
          "category_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "example": "Kit relaxante"
          },
          "slug": {
            "type": "string",
            "example": "kit-relaxante"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "short_description": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "physical",
              "digital",
              "course",
              "service"
            ]
          },
          "price": {
            "type": "string",
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "89.90",
            "description": "Valor decimal em texto (ex.: \"104.90\")."
          },
          "compare_at_price": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "119.90",
            "description": "Valor decimal em texto (ex.: \"104.90\")."
          },
          "cost_price": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "40.00",
            "description": "Valor decimal em texto (ex.: \"104.90\")."
          },
          "currency": {
            "type": "string",
            "example": "BRL"
          },
          "sku": {
            "type": [
              "string",
              "null"
            ],
            "example": "KIT-01"
          },
          "barcode": {
            "type": [
              "string",
              "null"
            ]
          },
          "stock": {
            "type": "integer",
            "example": 24
          },
          "track_stock": {
            "type": "boolean",
            "description": "Se o estoque é controlado (vendas baixam estoque)."
          },
          "weight": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "0.50",
            "description": "Peso (kg)."
          },
          "width": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "20.00",
            "description": "Largura (cm)."
          },
          "height": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "10.00",
            "description": "Altura (cm)."
          },
          "length": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "30.00",
            "description": "Comprimento (cm)."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "active",
              "archived"
            ]
          },
          "is_featured": {
            "type": "boolean"
          },
          "seo_title": {
            "type": [
              "string",
              "null"
            ]
          },
          "seo_description": {
            "type": [
              "string",
              "null"
            ]
          },
          "affiliate_enabled": {
            "type": "boolean"
          },
          "affiliate_commission_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "affiliate_commission_value": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^-?\\d+(\\.\\d{1,2})?$",
            "example": "10.00",
            "description": "Valor decimal em texto (ex.: \"104.90\")."
          },
          "course_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "video_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "sort_order": {
            "type": "integer"
          },
          "created_by": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "seller_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "ncm": {
            "type": [
              "string",
              "null"
            ],
            "description": "NCM (nota fiscal).",
            "example": "33074900"
          },
          "cest": {
            "type": [
              "string",
              "null"
            ]
          },
          "cfop": {
            "type": [
              "string",
              "null"
            ]
          },
          "origem": {
            "type": [
              [
                "string",
                "integer"
              ],
              "null"
            ],
            "description": "Origem da mercadoria (nota fiscal)."
          },
          "unidade": {
            "type": [
              "string",
              "null"
            ],
            "example": "UN"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ProductList": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Product"
                }
              },
              "pagination": {
                "$ref": "#/components/schemas/Pagination"
              }
            }
          }
        }
      },
      "Revenue": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "period": {
                "type": "string",
                "description": "O valor recebido em `period` (devolvido como veio).",
                "example": "30d"
              },
              "total": {
                "type": "number",
                "description": "Soma dos pagamentos aprovados no período.",
                "example": 4280.5
              },
              "daily": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "date": {
                      "type": "string",
                      "format": "date",
                      "example": "2026-10-17"
                    },
                    "total": {
                      "type": "string",
                      "pattern": "^-?\\d+(\\.\\d{1,2})?$",
                      "example": "389.70",
                      "description": "Soma do dia (texto decimal)."
                    },
                    "count": {
                      "type": "integer",
                      "description": "Pagamentos no dia.",
                      "example": 4
                    }
                  }
                }
              }
            }
          }
        }
      },
      "CustomerList": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "items": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "customer_name": {
                      "type": "string"
                    },
                    "customer_email": {
                      "type": "string"
                    },
                    "customer_phone": {
                      "type": "string"
                    }
                  }
                }
              },
              "total": {
                "type": "integer"
              }
            }
          }
        }
      },
      "AnalyticsOverview": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "total_orders": {
                "type": "integer",
                "description": "Pedidos da loja (todos os canais e status).",
                "example": 312
              },
              "monthly_orders": {
                "type": "integer",
                "description": "Pedidos criados desde o dia 1º do mês.",
                "example": 41
              },
              "total_revenue": {
                "type": "number",
                "description": "Soma de todos os pagamentos aprovados.",
                "example": 58210.4
              },
              "monthly_revenue": {
                "type": "number",
                "description": "Pagamentos aprovados desde o dia 1º do mês.",
                "example": 6120
              },
              "total_products": {
                "type": "integer",
                "example": 87
              }
            }
          }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "type": [
              "integer",
              "string",
              "null"
            ],
            "description": "Devolvido igual na resposta.",
            "example": 1
          },
          "method": {
            "type": "string",
            "enum": [
              "initialize",
              "ping",
              "tools/list",
              "tools/call",
              "notifications/initialized"
            ],
            "description": "`notifications/*` responde `202` sem corpo."
          },
          "params": {
            "type": "object",
            "description": "`initialize`: `{ protocolVersion }`. `tools/call`: `{ name, arguments }`.",
            "properties": {
              "protocolVersion": {
                "type": "string",
                "description": "Só em `initialize`. Devolvido igual (padrão `2025-06-18`).",
                "example": "2025-06-18"
              },
              "name": {
                "type": "string",
                "description": "Só em `tools/call`: nome da ferramenta.",
                "example": "list_orders"
              },
              "arguments": {
                "type": "object",
                "description": "Só em `tools/call`: argumentos da ferramenta (veja a tabela de ferramentas).",
                "additionalProperties": true,
                "example": {
                  "status": "pending"
                }
              }
            }
          }
        }
      },
      "McpTool": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "list_orders"
          },
          "description": {
            "type": "string"
          },
          "inputSchema": {
            "type": "object",
            "description": "JSON Schema dos argumentos.",
            "additionalProperties": true
          },
          "annotations": {
            "type": "object",
            "properties": {
              "readOnlyHint": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "type": [
              "integer",
              "string",
              "null"
            ]
          },
          "result": {
            "type": "object",
            "description": "Presente em caso de sucesso. Formato depende do método.",
            "properties": {
              "protocolVersion": {
                "type": "string",
                "description": "`initialize`."
              },
              "capabilities": {
                "type": "object",
                "description": "`initialize`.",
                "properties": {
                  "tools": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Vazio: o servidor oferece ferramentas."
                  }
                }
              },
              "serverInfo": {
                "type": "object",
                "description": "`initialize`.",
                "properties": {
                  "name": {
                    "type": "string",
                    "example": "devskin-marketplace"
                  },
                  "version": {
                    "type": "string",
                    "example": "1.0.0"
                  }
                }
              },
              "tools": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/McpTool"
                },
                "description": "`tools/list`."
              },
              "content": {
                "type": "array",
                "description": "`tools/call`: resposta da ferramenta (texto, até 8.000 caracteres).",
                "items": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "const": "text"
                    },
                    "text": {
                      "type": "string"
                    }
                  }
                }
              },
              "isError": {
                "type": "boolean",
                "description": "`tools/call`: `true` quando a ferramenta falhou (motivo em `content[0].text`)."
              }
            }
          },
          "error": {
            "type": "object",
            "description": "Presente em caso de erro.",
            "properties": {
              "code": {
                "type": "integer",
                "enum": [
                  -32601,
                  -32001,
                  -32602,
                  -32003,
                  -32603
                ]
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "LoginInput": {
        "type": "object",
        "required": [
          "email",
          "password"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "example": "voce@sualoja.com"
          },
          "password": {
            "type": "string",
            "format": "password",
            "example": "sua-senha"
          }
        }
      },
      "LoginResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string",
            "example": "Login realizado com sucesso"
          },
          "data": {
            "type": "object",
            "properties": {
              "token": {
                "type": "string",
                "description": "JWT do painel (vale 30 dias). Use em `Authorization: Bearer <token>`.",
                "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Ii4uLiJ9.assinatura"
              },
              "user": {
                "type": "object",
                "description": "Dados da pessoa (sem senha).",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "name": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string"
                  },
                  "role": {
                    "type": "string"
                  }
                }
              },
              "stores": {
                "type": "array",
                "description": "Lojas em que a pessoa é membro ativo — use `id` como `storeId`.",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "name": {
                      "type": "string"
                    },
                    "slug": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "project_type": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "example": "Planilha de vendas"
          },
          "key_prefix": {
            "type": "string",
            "description": "Primeiros 12 caracteres da chave (para reconhecer).",
            "example": "dsk_8f3a2b1c"
          },
          "last_used_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "is_active": {
            "type": "boolean"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "orders",
              "products"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiKeyCreateInput": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Nome para reconhecer a chave.",
            "example": "Planilha de vendas"
          },
          "scopes": {
            "type": "array",
            "default": [
              "*"
            ],
            "description": "Escopos da chave. Sem este campo, a chave tem acesso total (`*`). Valores com efeito: `*`, `orders`, `orders:write`, `inventory`, `products`, `revenue`, `customers`, `analytics`, `mcp`, `mcp:read`, `mcp:write`, `customers:write`, `notifications:write`, `webhooks:write`, `blog:read`, `blog:write`.",
            "items": {
              "type": "string",
              "enum": [
                "*",
                "orders",
                "orders:write",
                "inventory",
                "products",
                "revenue",
                "customers",
                "analytics",
                "mcp",
                "mcp:read",
                "mcp:write",
                "customers:write",
                "notifications:write",
                "webhooks:write",
                "blog:read",
                "blog:write"
              ]
            },
            "example": [
              "orders",
              "products",
              "mcp:read"
            ]
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Validade (opcional). Depois dela a chave responde `401 API key expired`.",
            "example": "2027-12-31T23:59:59Z"
          }
        }
      },
      "ApiKeyCreated": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string",
            "example": "Save this API key now. It will not be shown again."
          },
          "data": {
            "type": "object",
            "properties": {
              "key": {
                "type": "object",
                "description": "Registro da chave criada.",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "store_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "name": {
                    "type": "string"
                  },
                  "key_prefix": {
                    "type": "string"
                  },
                  "scopes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "expires_at": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time"
                  },
                  "is_active": {
                    "type": "boolean"
                  },
                  "last_used_at": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time"
                  },
                  "created_at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "updated_at": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              },
              "raw_key": {
                "type": "string",
                "description": "A chave completa — **só aparece aqui**.",
                "example": "dsk_8f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a"
              }
            }
          }
        }
      },
      "WebhookEventName": {
        "type": "string",
        "description": "Eventos emitidos hoje (`*` = todos). Outros nomes são recusados com 400.",
        "enum": [
          "*",
          "stock.updated",
          "order.created",
          "order.pending",
          "order.processing",
          "order.shipped",
          "order.delivered",
          "order.cancelled",
          "order.refunded",
          "payment.confirmed",
          "payment.failed",
          "payment.refunded",
          "shipping.updated",
          "cart.abandoned"
        ]
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "store_id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "example": "https://seusite.com/webhooks/devskin"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEventName"
            },
            "example": [
              "order.created",
              "payment.confirmed"
            ]
          },
          "secret": {
            "type": "string",
            "description": "Segredo da assinatura HMAC.",
            "example": "9c1f0e2d3b4a5968778695a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4"
          },
          "is_active": {
            "type": "boolean"
          },
          "last_triggered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "failure_count": {
            "type": "integer",
            "description": "Falhas seguidas (10 = desligado).",
            "example": 0
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WebhookCreateInput": {
        "type": "object",
        "required": [
          "url",
          "events"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Endereço que recebe os POSTs. Use https.",
            "example": "https://seusite.com/webhooks/devskin"
          },
          "events": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/WebhookEventName"
            },
            "example": [
              "order.created",
              "payment.confirmed",
              "stock.updated"
            ]
          }
        }
      },
      "WebhookUpdateInput": {
        "type": "object",
        "description": "Envie só o que quer mudar.",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "example": "https://seusite.com/webhooks/novo"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEventName"
            },
            "example": [
              "*"
            ]
          },
          "is_active": {
            "type": "boolean",
            "description": "`true` religa um webhook desligado por falhas (o contador de falhas não é zerado aqui).",
            "example": true
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "description": "Registro de uma tentativa de entrega.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "webhook_id": {
            "type": "string",
            "format": "uuid"
          },
          "event": {
            "type": "string",
            "example": "stock.updated"
          },
          "payload": {
            "type": "object",
            "description": "O `data` enviado.",
            "additionalProperties": true,
            "example": {
              "product_id": "6f1c2a9e-1d2b-4c3d-9e8f-0a1b2c3d4e5f",
              "variant_id": null,
              "sku": "KIT-01",
              "stock": 24,
              "delta": -1,
              "reason": "venda_canal"
            }
          },
          "response_status": {
            "type": "integer",
            "description": "Status HTTP que seu servidor respondeu (0 = sem resposta/tempo esgotado).",
            "example": 200
          },
          "response_body": {
            "type": "string",
            "description": "Até 2.000 caracteres da resposta.",
            "example": "ok"
          },
          "success": {
            "type": "boolean"
          },
          "triggered_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ConnectSiteStatus": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "has_key": {
                "type": "boolean"
              },
              "key_prefix": {
                "type": [
                  "string",
                  "null"
                ],
                "example": "dsk_8f3a2b1c"
              },
              "last_used_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "connected": {
                "type": "boolean",
                "description": "`true` depois da primeira chamada com a chave."
              },
              "webhook": {
                "type": [
                  "object",
                  "null"
                ],
                "properties": {
                  "url": {
                    "type": "string"
                  },
                  "is_active": {
                    "type": "boolean"
                  },
                  "last_triggered_at": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time"
                  },
                  "failure_count": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        }
      },
      "WebhookEnvelope": {
        "type": "object",
        "required": [
          "event",
          "data",
          "timestamp",
          "webhook_id"
        ],
        "description": "Corpo de todo webhook. Assinado com HMAC-SHA256 (header `X-Webhook-Signature`).",
        "properties": {
          "event": {
            "type": "string",
            "description": "Nome do evento (igual ao header `X-Webhook-Event`)."
          },
          "data": {
            "type": "object",
            "description": "Dados do evento (formato de cada evento abaixo).",
            "additionalProperties": true
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "Momento do envio (UTC). Cada nova tentativa tem um novo valor."
          },
          "webhook_id": {
            "type": "string",
            "format": "uuid",
            "description": "Id do cadastro do webhook (não é id único do evento)."
          },
          "store_id": {
            "type": "string",
            "format": "uuid",
            "description": "Loja que gerou o evento."
          },
          "delivery_id": {
            "type": "string",
            "format": "uuid",
            "description": "Id único do evento: **igual em todas as tentativas** do mesmo aviso (também no header `X-Webhook-Delivery`). Use para ignorar repetição."
          }
        }
      },
      "StockUpdatedData": {
        "type": "object",
        "required": [
          "product_id",
          "variant_id",
          "sku",
          "stock",
          "delta",
          "reason"
        ],
        "properties": {
          "product_id": {
            "type": "string",
            "format": "uuid"
          },
          "variant_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "`null` quando o produto não tem variações."
          },
          "sku": {
            "type": [
              "string",
              "null"
            ],
            "description": "SKU da variação (ou do produto). Use para achar o item no seu site.",
            "example": "KIT-01"
          },
          "stock": {
            "type": "integer",
            "description": "**Estoque final** depois da mudança — grave este valor.",
            "example": 24
          },
          "delta": {
            "type": "integer",
            "description": "Quanto mudou (negativo = saiu).",
            "example": -1
          },
          "reason": {
            "type": "string",
            "enum": [
              "venda_site",
              "venda_canal",
              "cancelamento",
              "ajuste_manual"
            ],
            "description": "`venda_site`: venda na loja Devskin · `venda_canal`: venda em marketplace · `cancelamento`: estoque devolvido por cancelamento/estorno/pagamento recusado · `ajuste_manual`: ajuste na tela de estoque do painel."
          }
        }
      },
      "CustomerRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          }
        }
      },
      "StoreMe": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "store": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "name": {
                    "type": "string"
                  },
                  "slug": {
                    "type": "string"
                  },
                  "logo": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Site público da loja (domínio próprio verificado e principal; senão o da plataforma em /s/<slug>)."
                  },
                  "blog_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Página do blog da loja."
                  }
                }
              },
              "key": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "prefix": {
                    "type": "string",
                    "description": "Começo da chave (para reconhecer)."
                  },
                  "scopes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "expires_at": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time"
                  }
                }
              }
            }
          }
        }
      },
      "OrderPatchInput": {
        "type": "object",
        "description": "Mande pelo menos um campo. Código de rastreio marca como **enviado** (`shipped`).",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "processing",
              "shipped",
              "delivered",
              "cancelled"
            ],
            "description": "Novo status. Reembolso não é feito por aqui (use o painel)."
          },
          "tracking_code": {
            "type": "string",
            "maxLength": 100,
            "description": "Código de rastreio. Marca o pedido como enviado e avisa o cliente por e-mail."
          },
          "tracking_url": {
            "type": "string",
            "description": "Link do rastreio (http/https). Só com `tracking_code`."
          },
          "note": {
            "type": "string",
            "maxLength": 2000,
            "description": "Anotação acrescentada às anotações do pedido (com data e origem)."
          },
          "source": {
            "type": "string",
            "maxLength": 40,
            "description": "Quem anotou (aparece na anotação). Padrão `API`.",
            "example": "Devskin Marketing"
          }
        }
      },
      "OrderPatchResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "order_id": {
                "type": "string",
                "format": "uuid"
              },
              "order_number": {
                "type": "string"
              },
              "status": {
                "$ref": "#/components/schemas/OrderStatus"
              },
              "payment_status": {
                "$ref": "#/components/schemas/PaymentStatus"
              },
              "tracking_code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "tracking_url": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "notes": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      },
      "OrderNoteInput": {
        "type": "object",
        "required": [
          "note"
        ],
        "properties": {
          "note": {
            "type": "string",
            "maxLength": 2000
          },
          "source": {
            "type": "string",
            "maxLength": 40
          }
        }
      },
      "OrderNoteResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "order_id": {
                "type": "string",
                "format": "uuid"
              },
              "order_number": {
                "type": "string"
              },
              "notes": {
                "type": "string"
              }
            }
          }
        }
      },
      "CustomerTagInput": {
        "type": "object",
        "description": "Informe `email` **ou** `customer_id`, e `tag` **ou** `tags`.",
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "customer_id": {
            "type": "string",
            "format": "uuid"
          },
          "tag": {
            "type": "string",
            "maxLength": 60
          },
          "tags": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "string",
              "maxLength": 60
            }
          },
          "source": {
            "type": "string",
            "maxLength": 40,
            "description": "Origem da etiqueta (padrão `api`)."
          }
        }
      },
      "CustomerTagResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "customer": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "uuid"
                  },
                  "email": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  }
                }
              },
              "tags": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Todas as etiquetas do cliente nesta loja."
              }
            }
          }
        }
      },
      "CustomerTagList": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "email": {
                  "type": "string"
                },
                "customer_id": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "tag": {
                  "type": "string"
                },
                "source": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "created_at": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          }
        }
      },
      "BuyerEmailInput": {
        "type": "object",
        "required": [
          "subject",
          "message"
        ],
        "description": "Diga para quem com `order_id`, `customer_id` **ou** `to`. O destinatário precisa ser cliente da loja.",
        "properties": {
          "order_id": {
            "type": "string",
            "description": "Id (UUID) ou número do pedido: o e-mail vai para o comprador dele."
          },
          "customer_id": {
            "type": "string",
            "format": "uuid"
          },
          "to": {
            "type": "string",
            "format": "email",
            "description": "E-mail de um cliente da loja."
          },
          "subject": {
            "type": "string",
            "maxLength": 200
          },
          "message": {
            "type": "string",
            "maxLength": 10000,
            "description": "Texto simples. Linha em branco separa parágrafos."
          },
          "button_url": {
            "type": "string",
            "description": "Botão opcional no e-mail (https)."
          },
          "button_label": {
            "type": "string",
            "maxLength": 40
          }
        }
      },
      "BuyerEmailResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "to": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "order_id": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      },
      "WebhookRegisterResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "webhook": {
                "$ref": "#/components/schemas/Webhook"
              },
              "secret": {
                "type": "string",
                "description": "Segredo para conferir a assinatura. **Só aparece aqui.**"
              },
              "created": {
                "type": "boolean",
                "description": "`false` quando a mesma URL já existia (foi atualizada e ganhou segredo novo)."
              }
            }
          }
        }
      },
      "WebhookListResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "webhooks": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          }
        }
      },
      "WebhookItemResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "webhook": {
                "$ref": "#/components/schemas/Webhook"
              }
            }
          }
        }
      },
      "WebhookTestResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "properties": {
              "delivered": {
                "type": "boolean"
              },
              "response_status": {
                "type": [
                  "integer",
                  "null"
                ]
              }
            }
          }
        }
      },
      "BlogPostInput": {
        "type": "object",
        "description": "Na criação: `title` e `content` obrigatórios. Na atualização mande só o que muda.",
        "properties": {
          "external_id": {
            "type": "string",
            "maxLength": 100,
            "description": "Id do post no SEU sistema. Mandar de novo com o mesmo valor atualiza o mesmo post."
          },
          "external_source": {
            "type": "string",
            "maxLength": 40,
            "description": "Nome curto do seu sistema (letras, números, `-`, `_`). Padrão `api`.",
            "example": "devskin_marketing"
          },
          "title": {
            "type": "string",
            "maxLength": 255
          },
          "slug": {
            "type": "string",
            "description": "Opcional. Se já existir na loja, ganha `-2`, `-3`..."
          },
          "content": {
            "type": "string",
            "description": "HTML do artigo (scripts, iframes e atributos on* são removidos)."
          },
          "excerpt": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 5000
          },
          "cover_image_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Imagem de capa (URL http/https, até 500)."
          },
          "og_image": {
            "type": [
              "string",
              "null"
            ],
            "description": "Imagem de compartilhamento. Padrão: a capa."
          },
          "seo_title": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255
          },
          "seo_description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 1000
          },
          "tags": {
            "type": "array",
            "maxItems": 30,
            "items": {
              "type": "string",
              "maxLength": 60
            }
          },
          "category_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid",
            "description": "Categoria desta loja."
          },
          "category": {
            "type": [
              "string",
              "null"
            ],
            "description": "Ou o NOME da categoria: se não existir, é criada."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "published",
              "archived"
            ],
            "description": "Padrão `draft`. Também aceita `publish`."
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Data de publicação (agora ou no passado). Agendamento para o futuro **não** é aceito: mande o post na hora de publicar."
          },
          "is_featured": {
            "type": "boolean"
          }
        }
      },
      "BlogPostOut": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "excerpt": {
            "type": [
              "string",
              "null"
            ]
          },
          "content": {
            "type": [
              "string",
              "null"
            ]
          },
          "cover_image_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "og_image": {
            "type": [
              "string",
              "null"
            ]
          },
          "seo_title": {
            "type": [
              "string",
              "null"
            ]
          },
          "seo_description": {
            "type": [
              "string",
              "null"
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "category": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "slug": {
                "type": "string"
              }
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "published",
              "archived"
            ]
          },
          "is_featured": {
            "type": "boolean"
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "external_source": {
            "type": [
              "string",
              "null"
            ]
          },
          "external_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "views": {
            "type": "integer"
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Página pública do post (só quando publicado)."
          },
          "created": {
            "type": "boolean",
            "description": "Só no POST: `true` = criado, `false` = atualizado pelo external_id."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BlogPostResult": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string"
          },
          "data": {
            "$ref": "#/components/schemas/BlogPostOut"
          }
        }
      },
      "BlogPostList": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "object",
            "properties": {
              "data": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BlogPostOut"
                }
              },
              "pagination": {
                "$ref": "#/components/schemas/Pagination"
              }
            }
          }
        }
      },
      "BlogCategoryList": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "const": true
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "name": {
                  "type": "string"
                },
                "slug": {
                  "type": "string"
                },
                "description": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "is_active": {
                  "type": "boolean"
                },
                "sort_order": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "parameters": {
      "StoreId": {
        "name": "storeId",
        "in": "path",
        "required": true,
        "description": "Id da loja (vem em `data.stores[].id` no login).",
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b"
      },
      "Page": {
        "name": "page",
        "in": "query",
        "required": false,
        "description": "Página (começa em 1).",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        },
        "example": 1
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Itens por página (1 a 100).",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 20
        },
        "example": 20
      },
      "RequestId": {
        "name": "X-Request-ID",
        "in": "header",
        "required": false,
        "description": "Opcional: seu id de rastreio (até 64 caracteres `A-Z a-z 0-9 _ -`). Volta igual no header da resposta.",
        "schema": {
          "type": "string",
          "maxLength": 64,
          "pattern": "^[A-Za-z0-9_-]+$"
        },
        "example": "pedido-1001-tentativa-1"
      }
    }
  }
}