{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "info": {
    "title": "Hermes Publisher API",
    "version": "1.3.0",
    "summary": "API oficial para automação editorial, criação, aprovação e publicação do Hermes Studio.",
    "description": "A Hermes Publisher API conecta agentes, integrações e o próprio Studio ao fluxo editorial da equipe Jan Val Ellam. O contrato cobre projetos, calendário, criação de mídia, aprovação, e-mails, conexões sociais e artefatos para IA.\n\n\n\n## Primeiros passos\n\n\n\n1. Para uso interativo, autentique o colaborador no Supabase hospedado na mesma origem. Para integrações, crie um token pessoal na área de Acessos da API.\n\n2. Envie a sessão Supabase ou o token pessoal em `Authorization: Bearer <access_token>`. Tokens pessoais começam com `hms_live_`.\n\n3. Consulte `GET /api/me` para confirmar o membro ativo e descobrir suas capabilities.\n\n4. Execute somente operações permitidas pelas capabilities retornadas.\n\n5. Em mutações colaborativas, leia o recurso imediatamente antes e preserve os tokens de concorrência.\n\n\n\n## Autenticação e autorização\n\n\n\nRotas protegidas aceitam uma sessão Supabase válida ou um token pessoal `hms_live_`, sempre vinculados a um membro ativo em `team_members`. Operações marcadas com `x-session-only: true` aceitam **somente** sessão Supabase interativa. Algumas operações exigem ainda a capability indicada por `x-required-capability`.\n\n\n\n## Acesso individual à API\n\n\n\nA sessão Supabase do Studio usa exclusivamente o cargo `access_level` (`criador`, `lider` ou `admin`) para calcular suas capabilities. O campo `api_access_level` **não limita nem desativa a sessão do Studio**.\n\n\n\nSomente tokens pessoais usam o nível individual `nenhum`, `leitor`, `criador`, `lider` ou `admin`. Eles são criados por uma sessão interativa, valem de 1 a 90 dias, armazenam apenas SHA-256 no servidor e revelam o segredo uma única vez. As capabilities efetivas do PAT são a interseção entre seus scopes, o `api_access_level` atual e o cargo `access_level` atual do Studio, que funciona como teto. O servidor recalcula essa interseção em toda requisição, por isso rebaixamentos entram em vigor imediatamente. O valor bruto, o header Authorization e corpos de requisição nunca aparecem na auditoria.\n\n\n\nArtefatos em `/api/ai/*`, o health check, o callback OAuth e a mídia pública não exigem Bearer. Segredos de provedores, chaves internas e refresh tokens permanecem exclusivamente no servidor.\n\n\n\n## Concorrência segura (CAS)\n\n\n\n- **Eventos:** use `api_revision` como `expected_revision` em rascunhos e envios.\n\n- **Projetos:** use `api_revision`/`revision` e, quando disponível, `updated_at` em operações semânticas.\n\n- **E-mails:** use `updated_at` como `expected_updated_at` para editar ou excluir.\n\n\n\nSe outra pessoa alterar o recurso primeiro, a API responde `409 Conflict`. Releia o recurso e reavalie a alteração; nunca sobrescreva o estado atual com um snapshot antigo.\n\n\n\n## Idempotência\n\n\n\nMutações que exibem o header opcional `Idempotency-Key` aceitam repetição segura. Use uma chave única de 8 a 128 caracteres por intenção e repita **a mesma chave com o mesmo payload** após timeout. Reutilizar a chave com conteúdo diferente retorna `409`.\n\n\n\n## Erros\n\n\n\nErros JSON usam `{ \"error\": \"mensagem\", \"code\": \"CODIGO_ESTAVEL\", \"details\": {} }`. O campo `code` deve orientar lógica de cliente; a mensagem é destinada a diagnóstico humano. Respostas OAuth em navegador e downloads podem usar outros tipos de conteúdo, documentados por operação.\n\n\n\n## Horários, segurança e compatibilidade\n\n\n\nDatas editoriais informadas como dia/mês/ano/hora são interpretadas no horário de Brasília. IDs de mídia e URLs públicas devem vir do próprio Hermes. Nunca envie chaves de provedor, credenciais de infraestrutura, tokens pessoais, sessões ou HTML de e-mail para logs.",
    "contact": {
      "name": "Time Hermes Studio",
      "url": "https://socialmedia.janvalellam.com.br/ai-mode.html"
    },
    "license": {
      "name": "Proprietary"
    },
    "x-release-date": "2026-08-22"
  },
  "servers": [
    {
      "url": "https://socialmedia.janvalellam.com.br",
      "description": "Produção"
    }
  ],
  "externalDocs": {
    "description": "Central do Modo IA, clientes e downloads oficiais",
    "url": "https://socialmedia.janvalellam.com.br/ai-mode.html"
  },
  "tags": [
    {
      "name": "System",
      "description": "Disponibilidade do serviço e entrega pública de mídia persistida no Hermes."
    },
    {
      "name": "AI Contract",
      "description": "Contrato, manifesto, Skill, CLI e instruções públicas para agentes e ferramentas de desenvolvimento."
    },
    {
      "name": "MCP",
      "description": "Endpoint oficial MCP Streamable HTTP, stateless, autenticado e limitado a ferramentas explícitas."
    },
    {
      "name": "OAuth",
      "description": "Conexão, diagnóstico e publicação em provedores sociais sem expor tokens ao cliente."
    },
    {
      "name": "Identity",
      "description": "Identidade do colaborador autenticado, vínculo ativo e capabilities efetivas."
    },
    {
      "name": "API Access",
      "description": "Níveis individuais, tokens pessoais com escopo, revogação e auditoria de acesso à API."
    },
    {
      "name": "Configuration",
      "description": "Configurações e skills versionadas com histórico auditável."
    },
    {
      "name": "Intelligence",
      "description": "Pesquisa no Cérebro, geração de roteiros e insights para planejamento editorial."
    },
    {
      "name": "Creative",
      "description": "Geração e armazenamento de artes, carrosséis e vídeos, além de upload binário."
    },
    {
      "name": "Workflow",
      "description": "Demandas, tarefas, rascunhos, anexos, submissão e decisão de aprovação."
    },
    {
      "name": "Projects",
      "description": "Projetos colaborativos alterados por operações semânticas, com histórico, CAS e idempotência."
    },
    {
      "name": "Email Drafts",
      "description": "Layouts de e-mail colaborativos: listagem leve, edição e exclusão protegidas por CAS."
    },
    {
      "name": "Members",
      "description": "Convites, níveis de acesso e desligamento seguro sem apagar conteúdo ou autoria."
    },
    {
      "name": "Platforms",
      "description": "Gastos de Aplicativos: senha de cada ferramenta da equipe, cifrada no banco e lida uma por vez por administrador em sessão."
    },
    {
      "name": "Sales",
      "description": "Painel de Vendas: receita por fonte, produtos e custos de mídia, sempre agregados e sem dados pessoais."
    }
  ],
  "x-tagGroups": [
    {
      "name": "Comece aqui",
      "tags": [
        "System",
        "Identity",
        "API Access",
        "AI Contract",
        "MCP"
      ]
    },
    {
      "name": "Conteúdo e operação",
      "tags": [
        "Workflow",
        "Projects",
        "Email Drafts",
        "Creative",
        "Intelligence",
        "Sales"
      ]
    },
    {
      "name": "Administração e canais",
      "tags": [
        "OAuth",
        "Configuration",
        "Members",
        "Platforms"
      ]
    }
  ],
  "paths": {
    "/api/ai/openapi.json": {
      "get": {
        "operationId": "getAiOpenApi",
        "tags": [
          "AI Contract"
        ],
        "summary": "Baixar o contrato OpenAPI 3.1",
        "description": "Fonte pública das rotas, autenticação, capabilities, corpos e respostas do Hermes Publisher.\n\nUse este documento como fonte canônica para gerar clientes, validar payloads e descobrir códigos de resposta. O JSON e o YAML descrevem exatamente o mesmo contrato.",
        "security": [],
        "x-artifact-file": "openapi/hermes-publisher.openapi.json",
        "responses": {
          "200": {
            "description": "Contrato OpenAPI 3.1.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {},
                  "additionalProperties": true
                },
                "example": {}
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Artefato ausente no build.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "artefato de IA indisponivel"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/ai/openapi.json'"
          }
        ]
      }
    },
    "/api/ai/openapi.yaml": {
      "get": {
        "operationId": "getAiOpenApiYaml",
        "tags": [
          "AI Contract"
        ],
        "summary": "Baixar o contrato OpenAPI 3.1 em YAML",
        "security": [],
        "x-artifact-file": "openapi/hermes-publisher.openapi.yaml",
        "responses": {
          "200": {
            "description": "Contrato OpenAPI 3.1 em YAML.",
            "content": {
              "application/yaml": {
                "schema": {
                  "type": "string"
                },
                "example": "openapi: 3.1.0\ninfo:\n  title: Hermes Publisher API\n"
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Artefato ausente no build.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "artefato de IA indisponivel"
                }
              }
            }
          }
        },
        "description": "Versão YAML do contrato canônico, indicada para Scalar, Swagger UI, Postman, geradores de SDK e assistentes de código.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/ai/openapi.yaml'"
          }
        ]
      }
    },
    "/api/ai/llms.txt": {
      "get": {
        "operationId": "getAiLlms",
        "tags": [
          "AI Contract"
        ],
        "summary": "Baixar o índice conciso para LLMs",
        "security": [],
        "x-artifact-file": "docs/ai/llms.txt",
        "responses": {
          "200": {
            "description": "Índice conciso gerado do OpenAPI.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Operação concluída."
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Artefato ausente no build.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "artefato de IA indisponivel"
                }
              }
            }
          }
        },
        "description": "Índice curto, em texto puro, para descoberta por agentes. Ele aponta para o contrato completo e resume as operações disponíveis.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/ai/llms.txt'"
          }
        ]
      }
    },
    "/api/ai/llms-full.txt": {
      "get": {
        "operationId": "getAiLlmsFull",
        "tags": [
          "AI Contract"
        ],
        "summary": "Baixar a referência completa para LLMs",
        "security": [],
        "x-artifact-file": "docs/ai/llms-full.txt",
        "responses": {
          "200": {
            "description": "Operações e schemas completos gerados do OpenAPI.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Operação concluída."
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Artefato ausente no build.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "artefato de IA indisponivel"
                }
              }
            }
          }
        },
        "description": "Referência expandida para LLMs, com referências locais resolvidas, corpos de requisição, respostas e exemplos de todas as operações.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/ai/llms-full.txt'"
          }
        ]
      }
    },
    "/api/ai/postman.json": {
      "get": {
        "operationId": "getAiPostmanCollection",
        "tags": [
          "AI Contract"
        ],
        "summary": "Baixar a coleção Postman gerada",
        "description": "Contém somente placeholders; nenhum token ou segredo é distribuído.\n\nColeção gerada automaticamente do OpenAPI. Defina `baseUrl` e `accessToken` no ambiente do Postman; o arquivo distribuído não contém credenciais.",
        "security": [],
        "x-artifact-file": "docs/ai/hermes-publisher.postman_collection.json",
        "responses": {
          "200": {
            "description": "Postman Collection v2.1.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {},
                  "additionalProperties": true
                },
                "example": {}
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Artefato ausente no build.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "artefato de IA indisponivel"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/ai/postman.json'"
          }
        ]
      }
    },
    "/api/ai/SKILL.md": {
      "get": {
        "operationId": "getAiSkill",
        "tags": [
          "AI Contract"
        ],
        "summary": "Baixar a skill operacional do Hermes",
        "description": "Instruções de operação segura, roteamento de repositórios e deploy.\n\nInstruções operacionais da skill oficial do Hermes. Use o ZIP quando quiser instalar também referências, metadados e scripts auxiliares.",
        "security": [],
        "x-artifact-file": "skills/hermes-operate-studio/SKILL.md",
        "responses": {
          "200": {
            "description": "Skill Markdown.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                },
                "example": "# Hermes Publisher\n\nDocumentação gerada.\n"
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Artefato ausente no build.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "artefato de IA indisponivel"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/ai/SKILL.md'"
          }
        ]
      }
    },
    "/api/ai/skill.zip": {
      "get": {
        "operationId": "getAiSkillZip",
        "tags": [
          "AI Contract"
        ],
        "summary": "Baixar a skill completa e instalável",
        "description": "ZIP determinístico com SKILL.md, agents/openai.yaml, CLI e referências versionadas.\n\nPacote determinístico da skill oficial. Confira o SHA-256 publicado no manifesto antes de instalar ou atualizar.",
        "security": [],
        "x-artifact-file": "docs/ai/hermes-operate-studio.skill.zip",
        "responses": {
          "200": {
            "description": "Skill ZIP.",
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "contentMediaType": "application/zip"
                },
                "example": "<arquivo ZIP binário>"
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Artefato ausente no build.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "artefato de IA indisponivel"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/ai/skill.zip'"
          }
        ]
      }
    },
    "/api/ai/manifest.json": {
      "get": {
        "operationId": "getAiManifest",
        "tags": [
          "AI Contract"
        ],
        "summary": "Baixar o manifesto verificável dos artefatos",
        "security": [],
        "x-artifact-file": "docs/ai/manifest.json",
        "responses": {
          "200": {
            "description": "Manifesto com versão, tamanho e SHA-256.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiManifest"
                },
                "example": {
                  "schema_version": 1,
                  "release": {
                    "version": "string",
                    "date": "2026-08-22"
                  },
                  "artifacts": [
                    {
                      "id": "id-exemplo",
                      "path": "string",
                      "url": "https://socialmedia.janvalellam.com.br/media/media-id?exp=1790000000&sig=assinatura",
                      "media_type": "string",
                      "bytes": 1,
                      "sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                    }
                  ],
                  "skills": [
                    {
                      "name": "Exemplo Hermes",
                      "version": "string",
                      "artifact_id": "artifact-id-exemplo",
                      "sha256": "string"
                    }
                  ]
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Artefato ausente no build.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "artefato de IA indisponivel"
                }
              }
            }
          }
        },
        "description": "Lista cada artefato público com URL, MIME type, tamanho e SHA-256. É a fonte para downloads verificáveis e atualização automatizada.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/ai/manifest.json'"
          }
        ]
      }
    },
    "/api/ai/mcp-setup.md": {
      "get": {
        "operationId": "getAiMcpSetup",
        "tags": [
          "AI Contract"
        ],
        "summary": "Baixar instruções de conexão MCP",
        "security": [],
        "x-artifact-file": "docs/ai/mcp-setup.md",
        "responses": {
          "200": {
            "description": "Configuração MCP para clientes compatíveis.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                },
                "example": "# Hermes Publisher\n\nDocumentação gerada.\n"
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Artefato ausente no build.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "artefato de IA indisponivel"
                }
              }
            }
          }
        },
        "description": "Guia de conexão ao MCP stateless do Hermes para clientes compatíveis. Use uma sessão Supabase ativa ou um token pessoal `hms_live_` com os scopes exigidos pelas tools.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/ai/mcp-setup.md'"
          }
        ]
      }
    },
    "/api/ai/cursor.mdc": {
      "get": {
        "operationId": "getAiCursorRules",
        "tags": [
          "AI Contract"
        ],
        "summary": "Baixar regras do Cursor",
        "security": [],
        "x-artifact-file": "docs/ai/cursor/hermes-studio.mdc",
        "responses": {
          "200": {
            "description": "Cursor Rules.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Operação concluída."
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Artefato ausente no build.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "artefato de IA indisponivel"
                }
              }
            }
          }
        },
        "description": "Regras de projeto para configurar o Cursor com o contrato e as práticas seguras do Hermes.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/ai/cursor.mdc'"
          }
        ]
      }
    },
    "/api/ai/claude.md": {
      "get": {
        "operationId": "getAiClaudeInstructions",
        "tags": [
          "AI Contract"
        ],
        "summary": "Baixar instruções para Claude",
        "security": [],
        "x-artifact-file": "docs/ai/claude/CLAUDE.md",
        "responses": {
          "200": {
            "description": "Instruções Claude.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                },
                "example": "# Hermes Publisher\n\nDocumentação gerada.\n"
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Artefato ausente no build.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "artefato de IA indisponivel"
                }
              }
            }
          }
        },
        "description": "Instruções de projeto para Claude, geradas da mesma versão do contrato público.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/ai/claude.md'"
          }
        ]
      }
    },
    "/api/ai/chatgpt.md": {
      "get": {
        "operationId": "getAiChatGptInstructions",
        "tags": [
          "AI Contract"
        ],
        "summary": "Baixar instruções para ChatGPT",
        "security": [],
        "x-artifact-file": "docs/ai/chatgpt/instructions.md",
        "responses": {
          "200": {
            "description": "Instruções ChatGPT.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                },
                "example": "# Hermes Publisher\n\nDocumentação gerada.\n"
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Artefato ausente no build.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "artefato de IA indisponivel"
                }
              }
            }
          }
        },
        "description": "Instruções para projetos e GPTs que operam o Hermes, incluindo limites de segurança, CAS e confirmação de ações destrutivas.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/ai/chatgpt.md'"
          }
        ]
      }
    },
    "/api/ai/hermes.mjs": {
      "get": {
        "operationId": "getAiCli",
        "tags": [
          "AI Contract"
        ],
        "summary": "Baixar a CLI Hermes",
        "security": [],
        "x-artifact-file": "hermes.mjs",
        "responses": {
          "200": {
            "description": "CLI Node.js.",
            "content": {
              "text/javascript": {
                "schema": {
                  "type": "string"
                },
                "example": "#!/usr/bin/env node\n// Hermes CLI\n"
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "description": "Artefato ausente no build.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "artefato de IA indisponivel"
                }
              }
            }
          }
        },
        "description": "CLI Node.js sem dependências externas para autenticar por sessão Supabase, consultar o manifesto e instalar artefatos oficiais com verificação de integridade. Tokens pessoais são destinados ao HTTP/MCP e não são gravados automaticamente pela CLI.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/ai/hermes.mjs'"
          }
        ]
      }
    },
    "/api/health": {
      "get": {
        "operationId": "getHealth",
        "tags": [
          "System"
        ],
        "summary": "Consultar saúde do serviço",
        "security": [],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Indica que o processo HTTP está respondendo."
                    },
                    "service": {
                      "type": "string",
                      "description": "Nome do serviço."
                    },
                    "providers": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "description": "Provedor social registrado no ambiente."
                      }
                    }
                  },
                  "required": [
                    "ok",
                    "service",
                    "providers"
                  ]
                },
                "example": {
                  "ok": true,
                  "service": "hermes-publisher",
                  "providers": [
                    "meta",
                    "youtube"
                  ]
                }
              }
            }
          }
        },
        "description": "Verificação pública e leve do processo HTTP. Um `200` confirma que o serviço responde; não garante a disponibilidade de cada provedor externo.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/health'"
          }
        ]
      }
    },
    "/api/mcp": {
      "post": {
        "operationId": "callHermesMcp",
        "tags": [
          "MCP"
        ],
        "summary": "Chamar o MCP Streamable HTTP do Hermes",
        "description": "Endpoint MCP oficial e stateless. Registra somente tools explícitas e encaminha cada ação para uma rota Hermes fixa com as mesmas guardas de capability, CAS e idempotência.\n\nEnvie mensagens JSON-RPC 2.0 do MCP por HTTP. Cada chamada é stateless, aceita sessão Supabase ou token pessoal `hms_live_` e só expõe ferramentas explícitas com as mesmas autorizações da API REST.",
        "requestBody": {
          "required": true,
          "description": "Mensagem JSON-RPC do protocolo MCP.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              },
              "example": {
                "jsonrpc": "2.0",
                "id": 1,
                "method": "tools/list",
                "params": {}
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resposta MCP JSON-RPC.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {},
                  "additionalProperties": true
                },
                "example": {}
              }
            }
          },
          "202": {
            "description": "Notificação MCP aceita sem resposta de ferramenta."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "405": {
            "description": "Método MCP não suportado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "string",
                  "code": "string",
                  "details": {}
                }
              }
            }
          },
          "415": {
            "description": "Content-Type precisa ser application/json.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "string",
                  "code": "string",
                  "details": {}
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/mcp' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}'"
          }
        ]
      }
    },
    "/media/{id}": {
      "get": {
        "operationId": "getMedia",
        "tags": [
          "System"
        ],
        "summary": "Baixar uma mídia pelo domínio do Hermes",
        "description": "Proxy público necessário para provedores que fazem pull da mídia por URL (Post for Me, TikTok PULL_FROM_URL). Não exige login, mas só abre com a assinatura `sig` e dentro da validade `exp` que o Hermes coloca na URL. O tipo retornado depende do asset.\n\nEntrega um asset armazenado pelo Hermes para visualização ou consumo por provedores sociais. Use sempre a URL completa devolvida pelas operações de mídia: ela leva `exp` e `sig` e vale por 7 dias. Link sem assinatura, adulterado ou vencido recebe 403; peça a mídia de novo para obter um link novo.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/MediaId"
          },
          {
            "name": "exp",
            "in": "query",
            "required": true,
            "description": "Validade do link em segundos Unix, emitida pelo Hermes.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,12}$"
            }
          },
          {
            "name": "sig",
            "in": "query",
            "required": true,
            "description": "Assinatura HMAC do link, emitida pelo Hermes.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bytes da mídia.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "contentMediaType": "application/octet-stream"
                },
                "example": "<bytes binários>"
              }
            }
          },
          "403": {
            "description": "Link sem assinatura, adulterado ou vencido.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "link de mídia expirado ou inválido; gere um novo pelo Hermes"
              }
            }
          },
          "404": {
            "description": "Mídia ou objeto de storage não encontrado; resposta sem corpo."
          },
          "500": {
            "description": "Falha interna; resposta sem corpo."
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/media/id-exemplo?exp=string&sig=string'"
          }
        ]
      }
    },
    "/oauth/_accounts": {
      "get": {
        "operationId": "listOAuthAccounts",
        "tags": [
          "OAuth"
        ],
        "summary": "Listar provedores e contas conectadas",
        "description": "Nunca retorna tokens.\n\nRetorna provedores habilitados e metadados seguros das contas conectadas. Tokens, refresh tokens e segredos nunca aparecem na resposta.",
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "providers": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "description": "Provedor disponível no ambiente."
                      }
                    },
                    "accounts": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {},
                        "additionalProperties": true
                      },
                      "description": "Contas conectadas, sem credenciais."
                    }
                  },
                  "required": [
                    "providers",
                    "accounts"
                  ]
                },
                "example": {
                  "providers": [
                    "meta"
                  ],
                  "accounts": [
                    {}
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "connections_view",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/oauth/_accounts' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/oauth/{provider}/disconnect": {
      "post": {
        "operationId": "disconnectOAuthProvider",
        "tags": [
          "OAuth"
        ],
        "summary": "Desconectar um provedor social",
        "parameters": [
          {
            "$ref": "#/components/parameters/Provider"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResponse"
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "connections",
        "x-session-only": true,
        "description": "Revoga a conexão persistida do provedor para a equipe. Depois da operação, confirme o estado com a consulta de contas antes de iniciar uma nova autorização.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/oauth/meta/disconnect' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>'"
          }
        ]
      }
    },
    "/oauth/tiktok/creator-info": {
      "get": {
        "operationId": "getTikTokCreatorInfo",
        "tags": [
          "OAuth"
        ],
        "summary": "Consultar restrições do criador no TikTok",
        "responses": {
          "200": {
            "description": "Resposta normalizada do TikTok Creator Info.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {},
                  "additionalProperties": true
                },
                "example": {}
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "connections_view",
        "description": "Consulta limites e opções de publicação da conta TikTok conectada, como privacidade e recursos permitidos, antes de preparar um envio.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/oauth/tiktok/creator-info' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/oauth/tiktok/publish": {
      "post": {
        "operationId": "publishTikTokContent",
        "tags": [
          "OAuth"
        ],
        "summary": "Publicar conteúdo no TikTok",
        "description": "Aceita somente IDs de mídia do Hermes; URLs arbitrárias do cliente são rejeitadas pelo desenho da rota.\n\nPublica foto ou vídeo usando exclusivamente IDs de mídia armazenados pelo Hermes. Valide antes as restrições retornadas por Creator Info.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "description": "Formato do post.",
                    "enum": [
                      "PHOTO",
                      "VIDEO"
                    ],
                    "default": "PHOTO"
                  },
                  "caption": {
                    "type": "string",
                    "description": "Legenda."
                  },
                  "mediaIds": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "description": "ID em media_assets."
                    },
                    "description": "IDs na ordem de publicação."
                  },
                  "privacy_level": {
                    "type": "string",
                    "description": "Privacidade solicitada. Em app não auditado o servidor força SELF_ONLY."
                  },
                  "disable_comment": {
                    "type": "boolean",
                    "description": "Desabilitar comentários."
                  },
                  "disable_duet": {
                    "type": "boolean",
                    "description": "Desabilitar duetos."
                  },
                  "disable_stitch": {
                    "type": "boolean",
                    "description": "Desabilitar stitch."
                  },
                  "brand_organic_toggle": {
                    "type": "boolean",
                    "description": "Marcar conteúdo promocional próprio."
                  },
                  "brand_content_toggle": {
                    "type": "boolean",
                    "description": "Marcar conteúdo de marca."
                  },
                  "auto_add_music": {
                    "type": "boolean",
                    "description": "Permitir música automática."
                  }
                },
                "required": [
                  "mediaIds"
                ]
              },
              "example": {
                "type": "PHOTO",
                "caption": "Legenda",
                "mediaIds": [
                  "media-id"
                ],
                "privacy_level": "SELF_ONLY",
                "disable_comment": false,
                "disable_duet": false,
                "disable_stitch": false,
                "brand_organic_toggle": false,
                "brand_content_toggle": false,
                "auto_add_music": false
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Resposta do adaptador TikTok.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {},
                  "additionalProperties": true
                },
                "example": {}
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "publish",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/oauth/tiktok/publish' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"type\":\"PHOTO\",\"caption\":\"Legenda\",\"mediaIds\":[\"media-id\"],\"privacy_level\":\"SELF_ONLY\",\"disable_comment\":false,\"disable_duet\":false,\"disable_stitch\":false,\"brand_organic_toggle\":false,\"brand_content_toggle\":false,\"auto_add_music\":false}'"
          }
        ]
      }
    },
    "/oauth/{provider}/start": {
      "post": {
        "operationId": "startOAuthProvider",
        "tags": [
          "OAuth"
        ],
        "summary": "Iniciar autorização OAuth",
        "description": "Exige administrador com capability connections. Cria state opaco ligado ao usuário/membro e cookie HttpOnly restrito ao callback; retorna a URL para um popup já aberto pelo front.\n\nInicia um fluxo OAuth vinculado ao usuário e membro atuais. Abra a URL retornada no navegador que iniciou a operação para preservar o cookie seguro do callback.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Provider"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "description": "URL de autorização do provedor.",
                      "format": "uri"
                    }
                  },
                  "required": [
                    "url"
                  ]
                },
                "example": {
                  "url": "https://socialmedia.janvalellam.com.br/media/media-id?exp=1790000000&sig=assinatura"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Provedor não suportado.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "rede não suportada: provider"
              }
            }
          },
          "500": {
            "description": "Falha ao iniciar o fluxo OAuth.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Internal Server Error"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "connections",
        "x-session-only": true,
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/oauth/meta/start' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>'"
          }
        ]
      }
    },
    "/oauth/{provider}/callback": {
      "get": {
        "operationId": "completeOAuthProvider",
        "tags": [
          "OAuth"
        ],
        "summary": "Concluir callback OAuth",
        "description": "O state HMAC expira em dez minutos, contém apenas vínculos opacos com usuário/membro e exige o cookie HttpOnly/Secure/SameSite=Lax do navegador iniciador. O cookie é apagado antes da troca do código.\n\nCallback consumido pelo navegador após autorização no provedor. `state` e cookie precisam corresponder ao fluxo iniciado e expiram em dez minutos.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/Provider"
          },
          {
            "name": "code",
            "in": "query",
            "required": true,
            "description": "Código emitido pelo provedor.",
            "schema": {
              "type": "string"
            },
            "example": "provider-authorization-code"
          },
          {
            "name": "state",
            "in": "query",
            "required": true,
            "description": "Estado HMAC emitido pela rota start.",
            "schema": {
              "type": "string"
            },
            "example": "signed-oauth-state"
          }
        ],
        "responses": {
          "200": {
            "description": "Conta conectada; texto para a janela OAuth.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                },
                "example": "Conta conectada!"
              }
            }
          },
          "400": {
            "description": "Estado inválido ou expirado.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Sessão de conexão inválida ou expirada."
              }
            }
          },
          "404": {
            "description": "Provedor não suportado.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "rede não suportada: provider"
              }
            }
          },
          "500": {
            "description": "Falha na troca do código ou persistência.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Erro ao conectar: detalhe"
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/oauth/meta/callback?code=provider-authorization-code&state=signed-oauth-state'"
          }
        ]
      }
    },
    "/oauth/{provider}/status": {
      "get": {
        "operationId": "getOAuthProviderStatus",
        "tags": [
          "OAuth"
        ],
        "summary": "Exibir diagnóstico HTML da conexão",
        "parameters": [
          {
            "$ref": "#/components/parameters/Provider"
          }
        ],
        "responses": {
          "200": {
            "description": "Página HTML de diagnóstico.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                },
                "example": "<!doctype html><html><body>Operação concluída.</body></html>"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Provedor não suportado.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "rede não suportada: provider"
              }
            }
          },
          "500": {
            "description": "Falha na consulta ao provedor.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "example": "Erro: detalhe"
              }
            }
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "connections_view",
        "description": "Página HTML de diagnóstico destinada ao navegador. Para integração programática, prefira a listagem JSON de contas conectadas.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/oauth/meta/status' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/me": {
      "get": {
        "operationId": "getCurrentMember",
        "tags": [
          "Identity"
        ],
        "summary": "Consultar membro autenticado e capacidades",
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "member": {
                      "$ref": "#/components/schemas/MemberIdentity"
                    },
                    "caps": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "description": "Capability liberada."
                      }
                    },
                    "auth": {
                      "$ref": "#/components/schemas/AuthContext"
                    }
                  },
                  "required": [
                    "member",
                    "caps",
                    "auth"
                  ]
                },
                "example": {
                  "member": {
                    "id": "id-exemplo",
                    "user_id": "user-id-exemplo",
                    "name": "Exemplo Hermes",
                    "email": "membro@example.com",
                    "access_level": "nenhum",
                    "team_access_level": "criador",
                    "api_access_level": "nenhum"
                  },
                  "caps": [
                    "string"
                  ],
                  "auth": {
                    "kind": "session",
                    "token_id": "token-id-exemplo"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "description": "Primeira chamada recomendada após autenticar. Em uma sessão Supabase, as capabilities vêm exclusivamente do cargo `access_level` do Studio; em um token pessoal, vêm da interseção entre scopes, nível individual da API e teto do cargo.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/me' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/access/me": {
      "get": {
        "operationId": "getMyApiAccess",
        "tags": [
          "API Access"
        ],
        "summary": "Consultar o próprio acesso individual à API",
        "x-cache-policy": "no-store",
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "member": {
                      "$ref": "#/components/schemas/ApiAccessSelfMember"
                    },
                    "capabilities": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "description": "Capability efetiva disponível para novos tokens."
                      }
                    },
                    "token_count": {
                      "type": "integer",
                      "description": "Quantidade de tokens pessoais ativos.",
                      "minimum": 0,
                      "maximum": 10
                    }
                  },
                  "required": [
                    "member",
                    "capabilities",
                    "token_count"
                  ]
                },
                "example": {
                  "member": {
                    "id": "id-exemplo",
                    "name": "Exemplo Hermes",
                    "email": "membro@example.com",
                    "access_level": "criador",
                    "financeiro": true,
                    "api_access_level": "nenhum",
                    "effective_api_access_level": "nenhum"
                  },
                  "capabilities": [
                    "string"
                  ],
                  "token_count": 0
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-session-only": true,
        "description": "Exige sessão Supabase interativa e nunca aceita token pessoal. Retorna a configuração destinada aos tokens pessoais do membro, o nível efetivo limitado pelo cargo do Studio e a contagem de tokens ativos; essa configuração não limita a própria sessão.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/access/me' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>'"
          }
        ]
      }
    },
    "/api/access/tokens": {
      "get": {
        "operationId": "listMyApiTokens",
        "tags": [
          "API Access"
        ],
        "summary": "Listar os próprios tokens pessoais",
        "x-cache-policy": "no-store",
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tokens": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PersonalApiTokenMetadata"
                      }
                    }
                  },
                  "required": [
                    "tokens"
                  ]
                },
                "example": {
                  "tokens": [
                    {
                      "id": "id-exemplo",
                      "label": "string",
                      "prefix": "string",
                      "scopes": [
                        "string"
                      ],
                      "created_at": "2026-08-22T15:00:00.000Z",
                      "expires_at": "2026-08-22T15:00:00.000Z",
                      "last_used_at": "2026-08-22T15:00:00.000Z",
                      "revoked_at": "2026-08-22T15:00:00.000Z",
                      "status": "active"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-session-only": true,
        "description": "Exige sessão Supabase interativa. Lista somente metadados dos tokens pessoais do próprio membro; o valor secreto e o hash nunca são retornados.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/access/tokens' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>'"
          }
        ]
      },
      "post": {
        "operationId": "createMyApiToken",
        "tags": [
          "API Access"
        ],
        "summary": "Criar um token pessoal com escopo e expiração",
        "x-cache-policy": "no-store",
        "requestBody": {
          "required": true,
          "description": "Defina um rótulo, validade entre 1 e 90 dias e, opcionalmente, scopes dentro do acesso efetivo. Se scopes for omitido, o servidor usa todas as capabilities atuais.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "label": {
                    "type": "string",
                    "description": "Nome legível do uso ou dispositivo.",
                    "minLength": 1,
                    "maxLength": 80
                  },
                  "scopes": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "description": "Capability solicitada.",
                      "pattern": "^[a-z][a-z0-9_.:-]{0,79}$"
                    },
                    "description": "Subconjunto opcional das capabilities efetivas.",
                    "minItems": 1,
                    "maxItems": 64,
                    "uniqueItems": true
                  },
                  "expiresInDays": {
                    "type": "integer",
                    "description": "Validade do token em dias; padrão 30.",
                    "minimum": 1,
                    "maximum": 90,
                    "default": 30
                  },
                  "expires_in_days": {
                    "type": "integer",
                    "description": "Alias compatível de expiresInDays; prefira expiresInDays em novos clientes.",
                    "minimum": 1,
                    "maximum": 90,
                    "deprecated": true
                  }
                },
                "required": [
                  "label"
                ]
              },
              "example": {
                "label": "Automação editorial",
                "scopes": [
                  "projects_view",
                  "projects_edit"
                ],
                "expiresInDays": 30
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Token criado. O campo token aparece somente nesta resposta e deve ser guardado imediatamente.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string",
                      "description": "Segredo pessoal exibido uma única vez.",
                      "pattern": "^hms_live_[A-Za-z0-9_-]{16}\\.[A-Za-z0-9_-]{43}$",
                      "x-sensitive": true
                    },
                    "metadata": {
                      "$ref": "#/components/schemas/PersonalApiTokenMetadata"
                    }
                  },
                  "required": [
                    "token",
                    "metadata"
                  ]
                },
                "example": {
                  "token": "hms_live_<selector>.<secret-shown-once>",
                  "metadata": {
                    "id": "token-id",
                    "label": "Automação editorial",
                    "prefix": "hms_live_EXAMPLE123456789",
                    "scopes": [
                      "projects_view",
                      "projects_edit"
                    ],
                    "created_at": "2026-08-22T12:00:00.000Z",
                    "expires_at": "2026-09-21T12:00:00.000Z",
                    "last_used_at": null,
                    "revoked_at": null,
                    "status": "active"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "description": "Limite de dez tokens ativos por usuário atingido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "cada usuario pode manter no maximo 10 tokens ativos",
                  "code": "API_TOKEN_LIMIT"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-session-only": true,
        "description": "Exige sessão Supabase interativa. Cria um token pessoal com validade de 1 a 90 dias e scopes dentro do acesso efetivo. O segredo `hms_live_` aparece uma única vez nesta resposta e não pode ser recuperado depois.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/access/tokens' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"label\":\"Automação editorial\",\"scopes\":[\"projects_view\",\"projects_edit\"],\"expiresInDays\":30}'"
          }
        ]
      }
    },
    "/api/access/tokens/{tokenId}": {
      "delete": {
        "operationId": "revokeMyApiToken",
        "tags": [
          "API Access"
        ],
        "summary": "Revogar um token pessoal próprio",
        "x-cache-policy": "no-store",
        "parameters": [
          {
            "$ref": "#/components/parameters/ApiTokenId"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Revogação concluída."
                    },
                    "token": {
                      "$ref": "#/components/schemas/PersonalApiTokenMetadata"
                    }
                  },
                  "required": [
                    "ok",
                    "token"
                  ]
                },
                "example": {
                  "ok": true,
                  "token": {
                    "id": "id-exemplo",
                    "label": "string",
                    "prefix": "string",
                    "scopes": [
                      "string"
                    ],
                    "created_at": "2026-08-22T15:00:00.000Z",
                    "expires_at": "2026-08-22T15:00:00.000Z",
                    "last_used_at": "2026-08-22T15:00:00.000Z",
                    "revoked_at": "2026-08-22T15:00:00.000Z",
                    "status": "active"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-session-only": true,
        "description": "Exige sessão Supabase interativa. Revoga um token do próprio membro de forma idempotente; somente metadados seguros permanecem disponíveis para auditoria.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request DELETE \\\n  --url 'https://socialmedia.janvalellam.com.br/api/access/tokens/tokenid-exemplo' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>'"
          }
        ]
      }
    },
    "/api/access/members": {
      "get": {
        "operationId": "listApiAccessMembers",
        "tags": [
          "API Access"
        ],
        "summary": "Listar acessos individuais da equipe",
        "x-cache-policy": "no-store",
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "levels": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ApiAccessLevel"
                      },
                      "description": "Níveis configuráveis em ordem crescente."
                    },
                    "members": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ApiAccessMember"
                      }
                    }
                  },
                  "required": [
                    "levels",
                    "members"
                  ]
                },
                "example": {
                  "levels": [
                    "nenhum"
                  ],
                  "members": [
                    {
                      "id": "id-exemplo",
                      "name": "Exemplo Hermes",
                      "email": "membro@example.com",
                      "access_level": "criador",
                      "api_access_level": "nenhum",
                      "effective_api_access_level": "nenhum",
                      "capabilities": [
                        "string"
                      ],
                      "token_count": 0,
                      "tokens": [
                        {
                          "id": "id-exemplo",
                          "label": "string",
                          "prefix": "string",
                          "scopes": [
                            "string"
                          ],
                          "created_at": "2026-08-22T15:00:00.000Z",
                          "expires_at": "2026-08-22T15:00:00.000Z",
                          "last_used_at": "2026-08-22T15:00:00.000Z",
                          "revoked_at": "2026-08-22T15:00:00.000Z",
                          "status": "active"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "team_admin",
        "x-session-only": true,
        "description": "Exige sessão Supabase de administrador da equipe. Lista membros ativos, cargo do Studio e configuração exclusiva dos tokens pessoais, capabilities efetivas de PAT e metadados de tokens, sem segredo ou hash.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/access/members' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>'"
          }
        ]
      }
    },
    "/api/access/members/{memberId}": {
      "patch": {
        "operationId": "updateMemberApiAccess",
        "tags": [
          "API Access"
        ],
        "summary": "Alterar o nível individual de API de um membro",
        "x-cache-policy": "no-store",
        "parameters": [
          {
            "$ref": "#/components/parameters/MemberId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "api_access_level": {
                    "$ref": "#/components/schemas/ApiAccessLevel"
                  }
                },
                "required": [
                  "api_access_level"
                ]
              },
              "example": {
                "api_access_level": "leitor"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Atualização concluída."
                    },
                    "member": {
                      "$ref": "#/components/schemas/ApiAccessMember"
                    }
                  },
                  "required": [
                    "ok",
                    "member"
                  ]
                },
                "example": {
                  "ok": true,
                  "member": {
                    "id": "id-exemplo",
                    "name": "Exemplo Hermes",
                    "email": "membro@example.com",
                    "access_level": "criador",
                    "api_access_level": "nenhum",
                    "effective_api_access_level": "nenhum",
                    "capabilities": [
                      "string"
                    ],
                    "token_count": 0,
                    "tokens": [
                      {
                        "id": "id-exemplo",
                        "label": "string",
                        "prefix": "string",
                        "scopes": [
                          "string"
                        ],
                        "created_at": "2026-08-22T15:00:00.000Z",
                        "expires_at": "2026-08-22T15:00:00.000Z",
                        "last_used_at": "2026-08-22T15:00:00.000Z",
                        "revoked_at": "2026-08-22T15:00:00.000Z",
                        "status": "active"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "team_admin",
        "x-session-only": true,
        "description": "Exige sessão Supabase de administrador da equipe. O nível da API nunca pode superar o cargo atual no Studio; rebaixamentos reduzem permissões imediatamente e `nenhum` revoga todos os tokens ativos.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request PATCH \\\n  --url 'https://socialmedia.janvalellam.com.br/api/access/members/memberid-exemplo' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"api_access_level\":\"leitor\"}'"
          }
        ]
      }
    },
    "/api/access/members/{memberId}/tokens/{tokenId}": {
      "delete": {
        "operationId": "revokeMemberApiToken",
        "tags": [
          "API Access"
        ],
        "summary": "Revogar um token pessoal como administrador",
        "x-cache-policy": "no-store",
        "parameters": [
          {
            "$ref": "#/components/parameters/MemberId"
          },
          {
            "$ref": "#/components/parameters/ApiTokenId"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Revogação concluída."
                    },
                    "token": {
                      "$ref": "#/components/schemas/PersonalApiTokenMetadata"
                    }
                  },
                  "required": [
                    "ok",
                    "token"
                  ]
                },
                "example": {
                  "ok": true,
                  "token": {
                    "id": "id-exemplo",
                    "label": "string",
                    "prefix": "string",
                    "scopes": [
                      "string"
                    ],
                    "created_at": "2026-08-22T15:00:00.000Z",
                    "expires_at": "2026-08-22T15:00:00.000Z",
                    "last_used_at": "2026-08-22T15:00:00.000Z",
                    "revoked_at": "2026-08-22T15:00:00.000Z",
                    "status": "active"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "team_admin",
        "x-session-only": true,
        "description": "Exige sessão Supabase de administrador da equipe. Revoga exatamente o token indicado de um membro, preservando metadados e trilha de auditoria.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request DELETE \\\n  --url 'https://socialmedia.janvalellam.com.br/api/access/members/memberid-exemplo/tokens/tokenid-exemplo' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>'"
          }
        ]
      }
    },
    "/api/access/catalog": {
      "get": {
        "operationId": "getApiCatalog",
        "tags": [
          "API Access"
        ],
        "summary": "Consultar o catálogo de rotas e ferramentas MCP (Central da API)",
        "x-cache-policy": "no-store",
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": {
                      "type": "integer",
                      "description": "Rotas no contrato."
                    },
                    "com_ferramenta": {
                      "type": "integer",
                      "description": "Rotas com ferramenta MCP."
                    },
                    "mcp_url": {
                      "type": "string",
                      "description": "Endereço do MCP."
                    },
                    "rotas": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {},
                        "additionalProperties": true
                      },
                      "description": "Uma entrada por rota."
                    }
                  },
                  "required": [
                    "total",
                    "rotas"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "total": 1,
                  "com_ferramenta": 1,
                  "mcp_url": "https://socialmedia.janvalellam.com.br/media/media-id?exp=1790000000&sig=assinatura",
                  "rotas": [
                    {}
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "team_admin",
        "x-session-only": true,
        "description": "Catálogo da Central da API: todas as rotas do contrato com área, permissão exigida, nível mínimo que a tem (ou a flag Financeiro), se é só de sessão ou webhook, os parâmetros de caminho e de query e o nome da ferramenta MCP equivalente. Sai do mesmo contrato que gera o MCP. Só administradores, por sessão do Studio.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/access/catalog' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>'"
          }
        ]
      }
    },
    "/api/access/audit": {
      "get": {
        "operationId": "listApiAccessAudit",
        "tags": [
          "API Access"
        ],
        "summary": "Consultar a trilha de auditoria da API",
        "x-cache-policy": "no-store",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Máximo de eventos recentes.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            }
          },
          {
            "name": "member_id",
            "in": "query",
            "required": false,
            "description": "Filtrar pelo membro autor do evento.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "audit": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ApiAuditEvent"
                      }
                    }
                  },
                  "required": [
                    "audit"
                  ]
                },
                "example": {
                  "audit": [
                    {
                      "id": "id-exemplo",
                      "occurred_at": "2026-08-22T15:00:00.000Z",
                      "request_id": "request-id-exemplo",
                      "actor_member_id": "actor-member-id-exemplo",
                      "actor_user_id": "actor-user-id-exemplo",
                      "token_id": "token-id-exemplo",
                      "auth_method": "session",
                      "capability": "string",
                      "action": "string",
                      "resource_type": "string",
                      "resource_id": "resource-id-exemplo",
                      "outcome": "allowed",
                      "status_code": 100,
                      "metadata": {}
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "team_admin",
        "x-session-only": true,
        "description": "Exige sessão Supabase de administrador da equipe. Lista eventos recentes de autorização e gestão sem corpo da requisição, Authorization, segredo, hash de token ou conteúdo sensível.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/access/audit' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>'"
          }
        ]
      }
    },
    "/api/config": {
      "get": {
        "operationId": "getConfig",
        "tags": [
          "Configuration"
        ],
        "summary": "Ler configuração versionada",
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "config": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": {
                        "$ref": "#/components/schemas/ConfigEntry"
                      }
                    }
                  },
                  "required": [
                    "config"
                  ]
                },
                "example": {
                  "config": {}
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "config_view",
        "description": "Lê o valor mais recente de cada configuração versionada. A resposta inclui a versão para auditoria e diagnóstico.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/config' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      },
      "post": {
        "operationId": "setConfig",
        "tags": [
          "Configuration"
        ],
        "summary": "Criar nova versão de uma configuração",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "key": {
                    "type": "string",
                    "description": "Chave."
                  },
                  "value": {}
                },
                "required": [
                  "key",
                  "value"
                ]
              },
              "example": {
                "key": "horarios",
                "value": {
                  "segunda": [
                    "12:00"
                  ]
                }
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "key": {
                      "type": "string",
                      "description": "Chave."
                    },
                    "version": {
                      "type": "integer",
                      "description": "Nova versão."
                    }
                  },
                  "required": [
                    "ok",
                    "key",
                    "version"
                  ]
                },
                "example": {
                  "ok": true,
                  "key": "string",
                  "version": 1
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "config",
        "description": "Publica uma nova versão imutável para uma chave de configuração. Exige a capability `config`; versões anteriores permanecem no histórico.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/config' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"key\":\"horarios\",\"value\":{\"segunda\":[\"12:00\"]}}'"
          }
        ]
      }
    },
    "/api/config/log": {
      "get": {
        "operationId": "getConfigLog",
        "tags": [
          "Configuration"
        ],
        "summary": "Listar histórico de configurações",
        "parameters": [
          {
            "name": "key",
            "in": "query",
            "required": false,
            "description": "Filtrar por chave.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "log": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {},
                        "additionalProperties": true
                      }
                    }
                  },
                  "required": [
                    "log"
                  ]
                },
                "example": {
                  "log": [
                    {}
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "config",
        "description": "Lista o histórico de configurações, opcionalmente filtrado por chave, para auditoria e comparação de versões.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/config/log' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/skills": {
      "get": {
        "operationId": "listSkills",
        "tags": [
          "Configuration"
        ],
        "summary": "Listar skills publicadas",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": false,
            "description": "Filtrar pelo nome exato.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "skills": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Skill"
                      }
                    }
                  },
                  "required": [
                    "skills"
                  ]
                },
                "example": {
                  "skills": [
                    {
                      "name": "Exemplo Hermes",
                      "content": "Conteúdo de exemplo",
                      "version": 1,
                      "updated_at": "2026-08-22T15:00:00.000Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "skills_view",
        "description": "Lista as skills versionadas publicadas no backend, com filtro opcional pelo nome estável.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/skills' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      },
      "post": {
        "operationId": "publishSkill",
        "tags": [
          "Configuration"
        ],
        "summary": "Publicar nova versão de uma skill",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Nome estável."
                  },
                  "content": {
                    "type": "string",
                    "description": "Conteúdo integral da skill."
                  }
                },
                "required": [
                  "name",
                  "content"
                ]
              },
              "example": {
                "name": "hermes-calendar",
                "content": "# Hermes Calendar"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "name": {
                      "type": "string",
                      "description": "Nome."
                    },
                    "version": {
                      "type": "integer",
                      "description": "Nova versão."
                    }
                  },
                  "required": [
                    "ok",
                    "name",
                    "version"
                  ]
                },
                "example": {
                  "ok": true,
                  "name": "Exemplo Hermes",
                  "version": 1
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "config",
        "description": "Publica uma nova versão do conteúdo de uma skill. Não sobrescreve silenciosamente o histórico e exige a capability `config`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/skills' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"name\":\"hermes-calendar\",\"content\":\"# Hermes Calendar\"}'"
          }
        ]
      }
    },
    "/api/rag": {
      "post": {
        "operationId": "searchHermesKnowledge",
        "tags": [
          "Intelligence"
        ],
        "summary": "Buscar contexto e citações no Cérebro",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tema": {
                    "type": "string",
                    "description": "Tema; `termo` é aceito como alias."
                  },
                  "termo": {
                    "type": "string",
                    "description": "Alias de tema."
                  },
                  "n_chunks": {
                    "type": "integer",
                    "description": "Quantidade de chunks de contexto.",
                    "default": 6,
                    "minimum": 1
                  },
                  "n_resultados": {
                    "type": "integer",
                    "description": "Quantidade de resultados.",
                    "default": 4,
                    "minimum": 1
                  }
                }
              },
              "example": {
                "tema": "consciência",
                "n_chunks": 6,
                "n_resultados": 4
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RagResponse"
                },
                "example": {
                  "contexto": "Conteúdo de exemplo",
                  "fontes": "string",
                  "resultados": [
                    {
                      "titulo": "Conteúdo editorial",
                      "fonte": "string",
                      "texto": "Conteúdo de exemplo",
                      "citacao": {
                        "pagina": 1
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "rag",
        "description": "Pesquisa o Cérebro e devolve contexto consolidado, resultados e citações. Preserve as citações ao produzir conteúdo derivado.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/rag' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"tema\":\"consciência\",\"n_chunks\":6,\"n_resultados\":4}'"
          }
        ]
      }
    },
    "/api/roteiro": {
      "post": {
        "operationId": "generateScript",
        "tags": [
          "Intelligence"
        ],
        "summary": "Gerar roteiro com pesquisa e verificação",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tema": {
                    "type": "string",
                    "description": "Tema do roteiro."
                  }
                },
                "required": [
                  "tema"
                ]
              },
              "example": {
                "tema": "O poder da curiosidade"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Roteiro gerado pela camada de inteligência.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {},
                  "additionalProperties": true
                },
                "example": {}
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "roteiro",
        "description": "Gera um roteiro a partir do tema usando a camada de inteligência do Hermes. O formato detalhado pode evoluir e campos adicionais devem ser preservados pelos clientes.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/roteiro' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"tema\":\"O poder da curiosidade\"}'"
          }
        ]
      }
    },
    "/api/vendas/resumo": {
      "get": {
        "operationId": "getSalesSummary",
        "tags": [
          "Sales"
        ],
        "summary": "Consultar o resumo de vendas do período",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "Início do período.",
            "schema": {
              "type": "string",
              "description": "Primeiro dia do período (YYYY-MM-DD, horário de Brasília).",
              "format": "date"
            },
            "example": "2026-08-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Fim do período, no máximo amanhã e até 730 dias depois de `from`.",
            "schema": {
              "type": "string",
              "description": "Último dia do período (YYYY-MM-DD, horário de Brasília).",
              "format": "date"
            },
            "example": "2026-08-31"
          },
          {
            "name": "produtos",
            "in": "query",
            "required": false,
            "description": "Quantos produtos listar por fonte.",
            "schema": {
              "type": "string",
              "description": "`top` (padrão, 15 por fonte) ou `all` (lista completa).",
              "enum": [
                "top",
                "all"
              ]
            },
            "example": "top"
          }
        ],
        "responses": {
          "200": {
            "description": "Resumo agregado do período.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "periodo": {
                      "type": "object",
                      "properties": {
                        "from": {
                          "type": "string",
                          "description": "Início."
                        },
                        "to": {
                          "type": "string",
                          "description": "Fim."
                        },
                        "dias": {
                          "type": "integer",
                          "description": "Dias no período."
                        }
                      },
                      "required": [
                        "from",
                        "to",
                        "dias"
                      ]
                    },
                    "gerado_em": {
                      "type": "string",
                      "description": "Instante de geração.",
                      "format": "date-time"
                    },
                    "cache": {
                      "type": "object",
                      "properties": {
                        "hit": {
                          "type": "boolean",
                          "description": "Se veio do cache do servidor."
                        },
                        "ttl_s": {
                          "type": "integer",
                          "description": "Segundos restantes de cache."
                        }
                      },
                      "required": [
                        "hit",
                        "ttl_s"
                      ]
                    },
                    "atualizado_em": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": {
                        "anyOf": [
                          {
                            "type": "string",
                            "description": "Último sync da tabela."
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "description": "Último sync por tabela de origem."
                    },
                    "totais": {
                      "type": "object",
                      "properties": {
                        "bruto": {
                          "type": "number",
                          "description": "Faturamento bruto em BRL."
                        },
                        "liquido": {
                          "type": "number",
                          "description": "Líquido em BRL (Hotmart valor do produtor, Shopify após descontos e reembolsos, Asaas net, Pagar.me parte do JVE)."
                        },
                        "vendas": {
                          "type": "integer",
                          "description": "Quantidade de vendas."
                        },
                        "ticket_medio": {
                          "anyOf": [
                            {
                              "type": "number",
                              "description": "Bruto dividido por vendas."
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "investimento": {
                          "anyOf": [
                            {
                              "type": "number",
                              "description": "Custos de mídia em BRL."
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "roas": {
                          "anyOf": [
                            {
                              "type": "number",
                              "description": "Bruto dividido por investimento."
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      },
                      "required": [
                        "bruto",
                        "liquido",
                        "vendas"
                      ]
                    },
                    "fontes": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "Bloco por fonte: hotmart, shopify_livros, shopify_eventos, shopify_outros, asaas, pagarme."
                    },
                    "serie": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "dia": {
                            "type": "string",
                            "description": "Dia YYYY-MM-DD."
                          }
                        },
                        "required": [
                          "dia"
                        ],
                        "additionalProperties": true
                      },
                      "description": "Série diária por fonte com custo do dia."
                    },
                    "categorias": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "Bloco por categoria: livros, cursos (com Orbum), eventos e youtube (estimado, convertido do dólar). Cada um com bruto, liquido_jve, comissao_trismegisto, qtd, ticket, composicao por plataforma e fontes_indisponiveis."
                    },
                    "totais_categorias": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "Soma das quatro categorias (inclui o YouTube estimado) com ROAS sobre esse total."
                    },
                    "serie_categorias": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "dia": {
                            "type": "string",
                            "description": "Dia YYYY-MM-DD."
                          }
                        },
                        "required": [
                          "dia"
                        ],
                        "additionalProperties": true
                      },
                      "description": "Série diária de livros, cursos e eventos; o YouTube mensal vem em categorias.youtube.por_mes."
                    },
                    "produtos": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "Top 15 produtos por fonte."
                    },
                    "intl": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "moeda": {
                            "type": "string",
                            "description": "Moeda ISO."
                          }
                        },
                        "required": [
                          "moeda"
                        ],
                        "additionalProperties": true
                      },
                      "description": "Vendas Hotmart fora do BRL, por moeda."
                    },
                    "custos": {
                      "anyOf": [
                        {
                          "type": "object",
                          "properties": {},
                          "additionalProperties": true,
                          "description": "Meta, Google e WhatsApp, por dia e por campanha, com ROAS."
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "avisos": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "description": "Aviso operacional."
                      },
                      "description": "Lacunas e fallbacks aplicados."
                    }
                  },
                  "required": [
                    "periodo",
                    "gerado_em",
                    "totais",
                    "fontes",
                    "serie",
                    "produtos",
                    "intl",
                    "avisos"
                  ]
                },
                "example": {
                  "periodo": {
                    "from": "string",
                    "to": "string",
                    "dias": 1
                  },
                  "gerado_em": "2026-08-22T15:00:00.000Z",
                  "cache": {
                    "hit": true,
                    "ttl_s": 1
                  },
                  "atualizado_em": {},
                  "totais": {
                    "bruto": 1,
                    "liquido": 1,
                    "vendas": 1,
                    "ticket_medio": 1,
                    "investimento": 1,
                    "roas": 1
                  },
                  "fontes": {},
                  "serie": [
                    {
                      "dia": "string"
                    }
                  ],
                  "categorias": {},
                  "totais_categorias": {},
                  "serie_categorias": [
                    {
                      "dia": "string"
                    }
                  ],
                  "produtos": {},
                  "intl": [
                    {
                      "moeda": "string"
                    }
                  ],
                  "custos": {},
                  "avisos": [
                    "string"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "description": "Resumo financeiro consolidado do período (Hotmart, Shopify, Asaas e checkout Pagar.me) mais custos de mídia e ROAS. Exige a capability `vendas`, concedida pela permissão por pessoa `financeiro` (não pelo nível). Datas são dias em horário de Brasília, intervalo máximo de 730 dias; valores desconhecidos vêm como `null`, nunca como zero; a resposta nunca inclui dados pessoais de compradores e fica em cache por cinco minutos no servidor.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/vendas/resumo?from=2026-08-01&to=2026-08-31' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/vendas/comercial": {
      "get": {
        "operationId": "getCommercialSales",
        "tags": [
          "Sales"
        ],
        "summary": "Consultar as vendas do time comercial e a comissão",
        "description": "Vendas com UTM `comercial` na Hotmart, no checkout Pagar.me e no Asaas, pela data do pedido, com a comissão de 4 % sobre as vendas novas (recorrências ficam fora). Mesmas regras da guia Comissão Nina da planilha de acerto. Só agregados, sem dados de compradores.",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "description": "Início do período.",
            "schema": {
              "type": "string",
              "description": "Primeiro dia do período (YYYY-MM-DD, horário de Brasília).",
              "format": "date"
            },
            "example": "2026-09-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "description": "Fim do período, no máximo amanhã e até 730 dias depois de `from`.",
            "schema": {
              "type": "string",
              "description": "Último dia do período (YYYY-MM-DD, horário de Brasília).",
              "format": "date"
            },
            "example": "2026-09-30"
          }
        ],
        "responses": {
          "200": {
            "description": "Resumo do comercial no período.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "periodo": {
                      "type": "object",
                      "properties": {
                        "from": {
                          "type": "string",
                          "description": "Início."
                        },
                        "to": {
                          "type": "string",
                          "description": "Fim."
                        },
                        "dias": {
                          "type": "integer",
                          "description": "Dias no período."
                        }
                      },
                      "required": [
                        "from",
                        "to",
                        "dias"
                      ]
                    },
                    "pct_comissao": {
                      "type": "number",
                      "description": "Percentual da comissão sobre a base."
                    },
                    "totais": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "qtd, vendido, novas, recorrentes, base_comissao, comissao e ticket do período."
                    },
                    "por_fonte": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "Mesmo bloco por fonte: hotmart, pagarme, asaas."
                    },
                    "por_mes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "mes": {
                            "type": "string",
                            "description": "Mês YYYY-MM."
                          }
                        },
                        "required": [
                          "mes"
                        ],
                        "additionalProperties": true
                      },
                      "description": "Um bloco por mês do período, com o vendido por fonte."
                    },
                    "produtos": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "nome": {
                            "type": "string",
                            "description": "Produto."
                          },
                          "fonte": {
                            "type": "string",
                            "description": "Fonte."
                          }
                        },
                        "required": [
                          "nome",
                          "fonte"
                        ],
                        "additionalProperties": true
                      },
                      "description": "Produtos vendidos pelo comercial, do maior para o menor."
                    },
                    "fontes": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "Se cada fonte respondeu nesta consulta."
                    },
                    "avisos": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "description": "Aviso operacional."
                      },
                      "description": "Lacunas e fallbacks aplicados."
                    }
                  },
                  "required": [
                    "periodo",
                    "pct_comissao",
                    "totais",
                    "por_fonte",
                    "por_mes",
                    "produtos",
                    "avisos"
                  ]
                },
                "example": {
                  "periodo": {
                    "from": "string",
                    "to": "string",
                    "dias": 1
                  },
                  "pct_comissao": 1,
                  "totais": {},
                  "por_fonte": {},
                  "por_mes": [
                    {
                      "mes": "string"
                    }
                  ],
                  "produtos": [
                    {
                      "nome": "Exemplo Hermes",
                      "fonte": "string"
                    }
                  ],
                  "fontes": {},
                  "avisos": [
                    "string"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/vendas/comercial?from=2026-09-01&to=2026-09-30' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/orbum/resumo": {
      "get": {
        "operationId": "getOrbumSummary",
        "tags": [
          "Sales"
        ],
        "summary": "Consultar o painel da assinatura Orbum",
        "description": "Cruza o acesso no TheMembers com o pagamento (Hotmart, Pagar.me, Asaas) pessoa a pessoa. Assinante ativo é quem tem pagamento vigente; acesso sem pagamento, pagamento sem acesso e atraso vêm em `alertas`. Grava uma foto agregada por dia em `orbum_snapshots` e devolve o histórico. Só agregados. `atualizar=1` ignora o cache de 10 minutos.",
        "parameters": [
          {
            "name": "atualizar",
            "in": "query",
            "required": false,
            "description": "Força uma leitura nova das fontes.",
            "schema": {
              "type": "string",
              "description": "`1` para ignorar o cache.",
              "enum": [
                "1"
              ]
            },
            "example": "1"
          }
        ],
        "responses": {
          "200": {
            "description": "Painel do Orbum.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "kpis": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "pagantes, com_acesso, receita_recorrente_mensal, ticket_mensal, entradas_mes, saidas_mes, churn_mes, saida_anunciada, sem_renovacao_prevista."
                    },
                    "alertas": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "pagando_sem_acesso, acesso_sem_pagamento (pagou_antes, nunca_pagou), atraso_com_acesso, atraso_sem_acesso, sem_renovacao_prevista."
                    },
                    "por_plano": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "Pagantes por plano."
                    },
                    "por_renovacao": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "Pagantes por tipo de renovação: automatica, manual, cancelada."
                    },
                    "por_fonte": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "Pagantes por gateway."
                    },
                    "vencimentos": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "Fim do período pago em 30, 60 e 90 dias, por tipo de renovação."
                    },
                    "serie": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "mes": {
                            "type": "string",
                            "description": "Mês YYYY-MM."
                          }
                        },
                        "required": [
                          "mes"
                        ],
                        "additionalProperties": true
                      },
                      "description": "Últimos 12 meses pelo acesso: ativos no fim do mês, entradas, saídas e churn."
                    },
                    "receita": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "mes": {
                            "type": "string",
                            "description": "Mês YYYY-MM."
                          }
                        },
                        "required": [
                          "mes"
                        ],
                        "additionalProperties": true
                      },
                      "description": "Receita por mês: novas e renovações, em reais."
                    },
                    "historico": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "dia": {
                            "type": "string",
                            "description": "Dia YYYY-MM-DD."
                          }
                        },
                        "required": [
                          "dia"
                        ],
                        "additionalProperties": true
                      },
                      "description": "Foto diária gravada pelo painel: pagantes, com acesso e receita recorrente."
                    },
                    "atualizado_em": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "Último sync de cada fonte."
                    },
                    "avisos": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "description": "Aviso operacional."
                      },
                      "description": "Lacunas e fallbacks aplicados."
                    }
                  },
                  "required": [
                    "kpis",
                    "alertas",
                    "serie",
                    "receita",
                    "avisos"
                  ]
                },
                "example": {
                  "kpis": {},
                  "alertas": {},
                  "por_plano": {},
                  "por_renovacao": {},
                  "por_fonte": {},
                  "vencimentos": {},
                  "serie": [
                    {
                      "mes": "string"
                    }
                  ],
                  "receita": [
                    {
                      "mes": "string"
                    }
                  ],
                  "historico": [
                    {
                      "dia": "string"
                    }
                  ],
                  "atualizado_em": {},
                  "avisos": [
                    "string"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/orbum/resumo' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/orbum/saidas": {
      "get": {
        "operationId": "listOrbumExits",
        "tags": [
          "Sales"
        ],
        "summary": "Listar quem está saindo do Orbum",
        "description": "Pessoas que vão sair (acesso valendo sem cobrança futura), estão em atraso ou saíram nos últimos 60 dias, com e-mail mascarado e o motivo já registrado. `pessoa` é o hash do e-mail usado no registro do motivo.",
        "responses": {
          "200": {
            "description": "Saídas do Orbum.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "saidas": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "pessoa": {
                            "type": "string",
                            "description": "Hash do e-mail."
                          },
                          "grupo": {
                            "type": "string",
                            "description": "vai_sair, atraso ou saiu."
                          }
                        },
                        "required": [
                          "pessoa",
                          "grupo"
                        ],
                        "additionalProperties": true
                      },
                      "description": "Lista ordenada por grupo e data."
                    },
                    "motivos_registrados": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true,
                      "description": "Contagem por motivo."
                    },
                    "total_registros": {
                      "type": "integer",
                      "description": "Registros de motivo."
                    }
                  },
                  "required": [
                    "saidas"
                  ]
                },
                "example": {
                  "saidas": [
                    {
                      "pessoa": "string",
                      "grupo": "string"
                    }
                  ],
                  "motivos_registrados": {},
                  "total_registros": 1
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/orbum/saidas' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/orbum/cancelamentos": {
      "post": {
        "operationId": "createOrbumCancelReason",
        "tags": [
          "Sales"
        ],
        "summary": "Registrar o motivo de saída de um assinante do Orbum",
        "description": "Grava em `orbum_cancelamentos` o motivo, a oferta feita e o resultado (skill resgate-cancelamento-orbum). Não aceita dado pessoal: a pessoa é o hash vindo de /api/orbum/saidas.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "pessoa": {
                    "type": "string",
                    "description": "Hash do e-mail (24 hex)."
                  },
                  "motivo": {
                    "type": "string",
                    "description": "Motivo.",
                    "enum": [
                      "financeiro",
                      "tempo",
                      "ja_vi",
                      "insatisfacao",
                      "reembolso",
                      "tecnico",
                      "outro"
                    ]
                  },
                  "oferta": {
                    "anyOf": [
                      {
                        "type": "string",
                        "description": "Oferta feita.",
                        "enum": [
                          "nenhuma",
                          "desconto",
                          "congelamento",
                          "troca_plano",
                          "outra"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "resultado": {
                    "anyOf": [
                      {
                        "type": "string",
                        "description": "Resultado.",
                        "enum": [
                          "saiu",
                          "ficou",
                          "congelou",
                          "pendente"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "observacao": {
                    "anyOf": [
                      {
                        "type": "string",
                        "description": "Até 500 caracteres, sem dados pessoais."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "pessoa",
                  "motivo"
                ]
              },
              "example": {
                "pessoa": "string",
                "motivo": "financeiro",
                "oferta": "nenhuma",
                "resultado": "saiu",
                "observacao": "string"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "201": {
            "description": "Motivo registrado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Gravado."
                    },
                    "id": {
                      "type": "integer",
                      "description": "Id do registro."
                    },
                    "registrado_em": {
                      "type": "string",
                      "description": "Instante.",
                      "format": "date-time"
                    }
                  },
                  "required": [
                    "ok"
                  ]
                },
                "example": {
                  "ok": true,
                  "id": 1,
                  "registrado_em": "2026-08-22T15:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/orbum/cancelamentos' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"pessoa\":\"string\",\"motivo\":\"financeiro\",\"oferta\":\"nenhuma\",\"resultado\":\"saiu\",\"observacao\":\"string\"}'"
          }
        ]
      }
    },
    "/api/lancamentos": {
      "get": {
        "operationId": "listLaunches",
        "tags": [
          "Sales"
        ],
        "summary": "Listar os lançamentos com dashboard",
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string",
                      "description": "padrao ou config."
                    },
                    "avisos": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "description": "Aviso."
                      },
                      "description": "Configurações ignoradas."
                    },
                    "lancamentos": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {},
                        "additionalProperties": true
                      },
                      "description": "Lançamentos com o projeto do Studio."
                    }
                  },
                  "required": [
                    "fonte",
                    "lancamentos"
                  ]
                },
                "example": {
                  "fonte": "string",
                  "avisos": [
                    "string"
                  ],
                  "lancamentos": [
                    {}
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "description": "Lista os lançamentos com dashboard (configuração em hermes_config, chave `lancamentos`; sem ela, os quatro de fábrica) e o projeto do Studio de cada um. Exige a capability `vendas`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/lancamentos' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/lancamentos/{projetoId}/resumo": {
      "get": {
        "operationId": "getLaunchSummary",
        "tags": [
          "Sales"
        ],
        "summary": "Consultar o painel de um lançamento",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjetoId"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Início do período; padrão é o início do lançamento.",
            "schema": {
              "type": "string",
              "description": "Primeiro dia (YYYY-MM-DD, horário de Brasília).",
              "format": "date"
            },
            "example": "2026-09-01"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fim do período, no máximo amanhã.",
            "schema": {
              "type": "string",
              "description": "Último dia (YYYY-MM-DD, horário de Brasília).",
              "format": "date"
            },
            "example": "2026-09-23"
          },
          {
            "name": "aba",
            "in": "query",
            "required": false,
            "description": "Aba com datas e grupos próprios; padrão é a primeira.",
            "schema": {
              "type": "string",
              "description": "Chave da aba do lançamento (ex.: `prevenda_livro`)."
            },
            "example": "lancamento"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "lancamento": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true
                    },
                    "periodo": {
                      "type": "object",
                      "properties": {
                        "from": {
                          "type": "string",
                          "description": "Início."
                        },
                        "to": {
                          "type": "string",
                          "description": "Fim."
                        },
                        "dias": {
                          "type": "integer",
                          "description": "Dias."
                        }
                      },
                      "required": [
                        "from",
                        "to",
                        "dias"
                      ]
                    },
                    "fontes": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": {
                        "type": "string",
                        "description": "ok, erro ou nao_configurado."
                      }
                    },
                    "totais": {
                      "anyOf": [
                        {
                          "type": "object",
                          "properties": {},
                          "additionalProperties": true,
                          "description": "Vendas, bruto por moeda, iniciados, falhos, pendentes, aprovação e conversão."
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "grupos": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "chave": {
                            "type": "string",
                            "description": "Grupo."
                          }
                        },
                        "required": [
                          "chave"
                        ],
                        "additionalProperties": true
                      },
                      "description": "Números por grupo de produto."
                    },
                    "serie": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "dia": {
                            "type": "string",
                            "description": "Dia."
                          }
                        },
                        "required": [
                          "dia"
                        ],
                        "additionalProperties": true
                      },
                      "description": "Série diária."
                    },
                    "pendencias": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {},
                        "additionalProperties": true
                      },
                      "description": "Métricas sem fonte ligada."
                    },
                    "avisos": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "description": "Aviso."
                      },
                      "description": "Lacunas e regras aplicadas."
                    }
                  },
                  "required": [
                    "lancamento",
                    "periodo",
                    "fontes",
                    "grupos",
                    "serie",
                    "avisos"
                  ]
                },
                "example": {
                  "lancamento": {},
                  "periodo": {
                    "from": "string",
                    "to": "string",
                    "dias": 1
                  },
                  "fontes": {},
                  "totais": {},
                  "grupos": [
                    {
                      "chave": "string"
                    }
                  ],
                  "serie": [
                    {
                      "dia": "string"
                    }
                  ],
                  "pendencias": [
                    {}
                  ],
                  "avisos": [
                    "string"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "description": "Painel de um lançamento: vendas por grupo de produto, pagamentos falhos, pendentes e quantos iniciaram o pagamento, lidos ao vivo da Pagar.me e da Stripe por `commerce_product` e `launch_id`. Sem from/to usa a janela do lançamento ou da aba pedida (30 dias no perpétuo), no máximo 400 dias. Abas separam períodos, como pré-venda e lançamento, sem misturar números. Valores desconhecidos vêm como `null`, moedas nunca são somadas e a resposta nunca inclui dados pessoais. Cache de cinco minutos no servidor.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/lancamentos/projetoid-exemplo/resumo' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/lancamentos/{projetoId}/disparos": {
      "get": {
        "operationId": "getLaunchBroadcasts",
        "tags": [
          "Sales"
        ],
        "summary": "Consultar os disparos de WhatsApp de um lançamento",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjetoId"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Início do período.",
            "schema": {
              "type": "string",
              "description": "Primeiro dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-21"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fim do período.",
            "schema": {
              "type": "string",
              "description": "Último dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-23"
          },
          {
            "name": "aba",
            "in": "query",
            "required": false,
            "description": "Aba do lançamento.",
            "schema": {
              "type": "string",
              "description": "Chave da aba."
            },
            "example": "lancamento"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "ok, sem_config ou nao_configurado."
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "status": "processing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "description": "Aba Disparos do lançamento: cada template de WhatsApp cujo nome casa com `disparos.templates` da configuração, com enviadas, entregues, lidas, taxa de leitura e custo (USD da Meta e BRL pela PTAX), prévia da mensagem e vendas atribuídas pelo `utm_content` do botão. Cache de 30 minutos; templates que a Meta não respondeu aparecem em `incompletos`. Exige a capability `vendas`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/lancamentos/projetoid-exemplo/disparos' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/lancamentos/{projetoId}/origem": {
      "get": {
        "operationId": "getLaunchOrigin",
        "tags": [
          "Sales"
        ],
        "summary": "Consultar a origem das vendas de um lançamento",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjetoId"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Início do período.",
            "schema": {
              "type": "string",
              "description": "Primeiro dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-21"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fim do período.",
            "schema": {
              "type": "string",
              "description": "Último dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-23"
          },
          {
            "name": "aba",
            "in": "query",
            "required": false,
            "description": "Aba do lançamento.",
            "schema": {
              "type": "string",
              "description": "Chave da aba."
            },
            "example": "lancamento"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "ok."
                    },
                    "vendas": {
                      "type": "integer",
                      "description": "Vendas pagas consideradas."
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "status": "processing",
                  "vendas": 1
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "description": "Aba Origem do lançamento: vendas pagas agrupadas por canal (derivado do utm_source), campanha (utm_campaign), conteúdo (utm_content) e origem_venda, com receita por moeda. Último clique, pelas marcações que o checkout grava no pedido; vendas da loja Shopify ficam de fora. Exige a capability `vendas`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/lancamentos/projetoid-exemplo/origem' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/lancamentos/{projetoId}/funil": {
      "get": {
        "operationId": "getLaunchCrmFunnel",
        "tags": [
          "Sales"
        ],
        "summary": "Consultar o funil do CRM de um lançamento",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjetoId"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Início do período.",
            "schema": {
              "type": "string",
              "description": "Primeiro dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-21"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fim do período.",
            "schema": {
              "type": "string",
              "description": "Último dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-23"
          },
          {
            "name": "aba",
            "in": "query",
            "required": false,
            "description": "Aba do lançamento.",
            "schema": {
              "type": "string",
              "description": "Chave da aba."
            },
            "example": "lancamento"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "ok, sem_config ou nao_configurado."
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "status": "processing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "description": "Aba Check-in e presença: quantos cards estão em cada etapa do funil do lançamento no SiteUP CRM (config `funil`) e quantos entraram em cada etapa por dia no período. Cache de 5 minutos; exige a capability `vendas`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/lancamentos/projetoid-exemplo/funil' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/lancamentos/{projetoId}/compradores": {
      "get": {
        "operationId": "getLaunchBuyers",
        "tags": [
          "Sales"
        ],
        "summary": "Listar os compradores de um lançamento",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjetoId"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Início do período.",
            "schema": {
              "type": "string",
              "description": "Primeiro dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-21"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fim do período.",
            "schema": {
              "type": "string",
              "description": "Último dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-23"
          },
          {
            "name": "aba",
            "in": "query",
            "required": false,
            "description": "Aba do lançamento.",
            "schema": {
              "type": "string",
              "description": "Chave da aba."
            },
            "example": "lancamento"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "ok, sem_config ou nao_configurado."
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "status": "processing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "description": "Aba Compradores: pedidos pagos do lançamento no período com nome, e-mail, telefone, produto, valor, método e canal, mais recentes primeiro (até 2000). Contém dados pessoais: exige a capability `vendas` (permissão Financeiro) e a resposta nunca é cacheada.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/lancamentos/projetoid-exemplo/compradores' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/lancamentos/{projetoId}/saude": {
      "get": {
        "operationId": "getLaunchHealth",
        "tags": [
          "Sales"
        ],
        "summary": "Consultar a saúde de um lançamento",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjetoId"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Início do período.",
            "schema": {
              "type": "string",
              "description": "Primeiro dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-21"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fim do período.",
            "schema": {
              "type": "string",
              "description": "Último dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-23"
          },
          {
            "name": "aba",
            "in": "query",
            "required": false,
            "description": "Aba do lançamento.",
            "schema": {
              "type": "string",
              "description": "Chave da aba."
            },
            "example": "lancamento"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "ok, sem_config ou nao_configurado."
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "status": "processing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "description": "Aba Saúde: última venda, vendas e receita de hoje e o estado de cada fonte e rotina (leituras de pagamento, sincronização da linha do tempo, última recuperação enviada, último aviso do checkout e dados de anúncio). Exige a capability `vendas`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/lancamentos/projetoid-exemplo/saude' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/lancamentos/{projetoId}/midia": {
      "get": {
        "operationId": "getLaunchMedia",
        "tags": [
          "Sales"
        ],
        "summary": "Consultar a mídia paga de um lançamento",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjetoId"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Início do período.",
            "schema": {
              "type": "string",
              "description": "Primeiro dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-21"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fim do período.",
            "schema": {
              "type": "string",
              "description": "Último dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-23"
          },
          {
            "name": "aba",
            "in": "query",
            "required": false,
            "description": "Aba do lançamento.",
            "schema": {
              "type": "string",
              "description": "Chave da aba."
            },
            "example": "lancamento"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "ok, sem_config ou nao_configurado."
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "status": "processing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "description": "Aba Mídia do lançamento: gasto em anúncios do Meta e do Google das campanhas cujo nome casa com `midia.campanhas` da configuração, com impressões, cliques, CTR, CPC e CPM por plataforma, por grupo de produto (`midia.produtos`), por campanha (até 50), por anúncio (até 20) e por dia. Fonte: tabelas sincronizadas a cada ~5 h. Valores em reais; exige a capability `vendas`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/lancamentos/projetoid-exemplo/midia' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/jornada/ses": {
      "post": {
        "operationId": "ingestSesEvent",
        "tags": [
          "Sales"
        ],
        "summary": "Receber eventos de e-mail do SES (SNS)",
        "security": [
          {
            "sesToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "text/plain": {
              "schema": {
                "type": "string",
                "description": "Envelope JSON do SNS."
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Recebido."
                    },
                    "status": {
                      "type": "string",
                      "description": "evento, assinatura_confirmada, ignorado, topico_errado ou invalido."
                    }
                  },
                  "required": [
                    "ok"
                  ]
                },
                "example": {
                  "ok": true,
                  "status": "processing"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "description": "Entrada dos eventos de e-mail do SES (entregue, aberto, clicado, devolvido, reclamação) publicados pelo SNS do configuration set `jve-rastreio`. Autentica pelo `token` na query (JORNADA_SES_TOKEN) e confere o tópico (JORNADA_SES_TOPIC_ARN); confirma a assinatura do SNS só em URL da própria AWS. Grava na linha do tempo por pessoa (hash do e-mail).",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/jornada/ses' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/octet-stream' \\\n  --data-binary '@arquivo.bin'"
          }
        ]
      }
    },
    "/api/jornada/eventos": {
      "post": {
        "operationId": "ingestJourneyEvents",
        "tags": [
          "Sales"
        ],
        "summary": "Receber eventos do checkout (servidor a servidor)",
        "security": [
          {
            "jornadaToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "eventos": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "evento": {
                          "type": "string",
                          "description": "abriu_checkout, etapa_checkout, identificou, respondeu_enquete ou visitou_pagina.",
                          "enum": [
                            "abriu_checkout",
                            "etapa_checkout",
                            "identificou",
                            "respondeu_enquete",
                            "visitou_pagina"
                          ]
                        },
                        "sessao": {
                          "type": "string",
                          "description": "Id da sessão do navegador."
                        },
                        "id": {
                          "type": "string",
                          "description": "Id único do evento na sessão."
                        },
                        "email": {
                          "type": "string",
                          "description": "Obrigatório em identificou e respondeu_enquete; vira hash."
                        },
                        "produto": {
                          "type": "string",
                          "description": "commerce_product."
                        },
                        "lancamento": {
                          "type": "string",
                          "description": "launch_id."
                        },
                        "ocorreu_em": {
                          "type": "string",
                          "description": "Instante (até 1 dia de diferença).",
                          "format": "date-time"
                        },
                        "detalhe": {
                          "type": "object",
                          "properties": {},
                          "additionalProperties": {
                            "type": "string",
                            "description": "Chaves permitidas: etapa, pagina, origem, lote, utm_*, votacao, opcao, peso, titulo, site, referencia, gclid e fbclid."
                          }
                        }
                      },
                      "required": [
                        "evento",
                        "sessao",
                        "id"
                      ]
                    },
                    "description": "De 1 a 50 eventos."
                  }
                },
                "required": [
                  "eventos"
                ]
              },
              "example": {
                "eventos": [
                  {
                    "evento": "abriu_checkout",
                    "sessao": "sess-123456",
                    "id": "ev-000001",
                    "produto": "curso_kardec"
                  }
                ]
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "recebidos": {
                      "type": "integer",
                      "description": "Eventos recebidos."
                    },
                    "gravados": {
                      "type": "integer",
                      "description": "Eventos novos gravados."
                    },
                    "recusados": {
                      "type": "integer",
                      "description": "Eventos inválidos ignorados."
                    }
                  },
                  "required": [
                    "ok",
                    "gravados"
                  ]
                },
                "example": {
                  "ok": true,
                  "recebidos": 1,
                  "gravados": 1,
                  "recusados": 1
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "description": "Entrada servidor a servidor da linha do tempo: o checkout do Xamanismo avisa quando alguém abre o checkout, muda de etapa ou se identifica. Autentica pelo cabeçalho `x-jornada-token` (segredo compartilhado), não por sessão. Aceita de 1 a 50 eventos; e-mail vira hash e nunca é gravado em claro; eventos repetidos (mesma sessão e id) são ignorados.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/jornada/eventos' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"eventos\":[{\"evento\":\"abriu_checkout\",\"sessao\":\"sess-123456\",\"id\":\"ev-000001\",\"produto\":\"curso_kardec\"}]}'"
          }
        ]
      }
    },
    "/api/jornada/sincronizar": {
      "post": {
        "operationId": "syncJourney",
        "tags": [
          "Sales"
        ],
        "summary": "Sincronizar a linha do tempo",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "dias": {
                    "type": "integer",
                    "description": "Dias para trás (1 a 120, padrão 3; até 3650 quando fontes é só shopify)."
                  },
                  "fontes": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "description": "pagarme, stripe, shopify ou crm"
                    },
                    "description": "Limita as fontes lidas; sem ele lê todas. Use [\"shopify\"] para trazer o histórico da loja antiga."
                  }
                }
              },
              "example": {
                "dias": 30
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "dias": {
                      "type": "integer",
                      "description": "Dias lidos."
                    },
                    "gravados": {
                      "type": "integer",
                      "description": "Eventos novos."
                    }
                  },
                  "required": [
                    "ok"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "ok": true,
                  "dias": 1,
                  "gravados": 1
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "config",
        "description": "Relê as fontes da linha do tempo (pedidos da Pagar.me e da Stripe em todos os status e envios de recuperação do SiteUP CRM) dos últimos `dias` (1 a 120). A mesma sincronização roda sozinha a cada 15 minutos quando `JORNADA_SYNC=on`. Exige a capability `config`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/jornada/sincronizar' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"dias\":30}'"
          }
        ]
      }
    },
    "/api/lancamentos/{projetoId}/jornada": {
      "get": {
        "operationId": "getLaunchJourney",
        "tags": [
          "Sales"
        ],
        "summary": "Consultar o funil da linha do tempo de um lançamento",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjetoId"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Início do período.",
            "schema": {
              "type": "string",
              "description": "Primeiro dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-21"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fim do período.",
            "schema": {
              "type": "string",
              "description": "Último dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-23"
          },
          {
            "name": "aba",
            "in": "query",
            "required": false,
            "description": "Aba do lançamento.",
            "schema": {
              "type": "string",
              "description": "Chave da aba."
            },
            "example": "lancamento"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "pessoas": {
                      "type": "integer",
                      "description": "Pessoas distintas."
                    },
                    "passos": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": {
                        "type": "integer",
                        "description": "Pessoas que chegaram ao passo."
                      }
                    }
                  },
                  "required": [
                    "pessoas",
                    "passos"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "pessoas": 1,
                  "passos": {}
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "description": "Funil agregado do lançamento a partir da linha do tempo: pessoas que abriram o checkout, se identificaram, geraram pagamento e compraram, onde cada uma parou, pagamentos recusados e expirados, recuperações enviadas e quem voltou em até 7 dias. Sessões anônimas contam como a pessoa que se identificou nelas. Só números agregados; exige a capability `vendas`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/lancamentos/projetoid-exemplo/jornada' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/lancamentos/{projetoId}/decisao": {
      "get": {
        "operationId": "getLaunchDecision",
        "tags": [
          "Sales"
        ],
        "summary": "Consultar o painel de decisão de um lançamento",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjetoId"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Início do período.",
            "schema": {
              "type": "string",
              "description": "Primeiro dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-21"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Fim do período.",
            "schema": {
              "type": "string",
              "description": "Último dia (YYYY-MM-DD).",
              "format": "date"
            },
            "example": "2026-09-23"
          },
          {
            "name": "aba",
            "in": "query",
            "required": false,
            "description": "Aba do lançamento.",
            "schema": {
              "type": "string",
              "description": "Chave da aba."
            },
            "example": "lancamento"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "periodo": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true
                    },
                    "metas": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true
                    },
                    "comparacao": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true
                    },
                    "custo": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true
                    }
                  },
                  "required": [
                    "periodo",
                    "metas"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "periodo": {},
                  "metas": {},
                  "comparacao": {},
                  "custo": {}
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "description": "Painel de decisão do lançamento: metas escritas no projeto do Studio contra o realizado, ritmo dos últimos dias (sem o dia da abertura) e projeção até o fim; comparação com o lançamento anterior no mesmo dia do ciclo (ingressos, receita, Orbum); custo de mídia (anúncio + WhatsApp) e resultado; quem já era cliente; ingressos que viraram Orbum e por qual caminho; vendas por lote com a hora da virada; e o efeito de cada onda de WhatsApp (recebeu, leu, comprou em 24 h, custo). Só números agregados; exige a capability `vendas`. Cada bloco traz `status` próprio e um erro num bloco não derruba os outros.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/lancamentos/projetoid-exemplo/decisao' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/lancamentos/{projetoId}/perfis": {
      "get": {
        "operationId": "getLaunchProfiles",
        "tags": [
          "Sales"
        ],
        "summary": "Consultar os perfis agregados de quem mexeu num lançamento",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjetoId"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "ok."
                    },
                    "pessoas": {
                      "type": "integer",
                      "description": "Pessoas que mexeram no lançamento."
                    },
                    "segmentos": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "chave": {
                            "type": "string",
                            "description": "Segmento."
                          },
                          "rotulo": {
                            "type": "string",
                            "description": "Rótulo."
                          },
                          "pessoas": {
                            "type": "integer",
                            "description": "Pessoas."
                          }
                        },
                        "required": [
                          "chave",
                          "pessoas"
                        ]
                      },
                      "description": "Pessoas por segmento."
                    },
                    "proximo_evento": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {},
                        "additionalProperties": true
                      },
                      "description": "Sugestão de próximo evento, agregada."
                    }
                  },
                  "required": [
                    "status",
                    "pessoas",
                    "segmentos"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "status": "processing",
                  "pessoas": 1,
                  "segmentos": [
                    {
                      "chave": "string",
                      "rotulo": "string",
                      "pessoas": 1
                    }
                  ],
                  "proximo_evento": [
                    {}
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "description": "Perfis agregados de quem mexeu no lançamento (Fase 4): pessoas por segmento (recorrente, comprador, quase comprou, interessado, só mensagem), canal que mais responde, hora em que mais age (Brasília), assinantes do Orbum, quem comprou em outro lançamento, temas votados e a sugestão de próximo evento com a regra usada. As chaves `funeral` e `funeral-2026-10` contam como o mesmo lançamento. Só contagens, nenhuma pessoa; exige a capability `vendas`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/lancamentos/projetoid-exemplo/perfis' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/jornada/perfil": {
      "post": {
        "operationId": "getPersonProfile",
        "tags": [
          "Sales"
        ],
        "summary": "Consultar o perfil de uma pessoa pelo e-mail (dado pessoal, só Financeiro)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "description": "E-mail da pessoa. Vira hash e não é guardado.",
                    "format": "email"
                  }
                },
                "required": [
                  "email"
                ]
              },
              "example": {
                "email": "contato@siteup.com.br"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "encontrado": {
                      "type": "boolean",
                      "description": "Se há eventos dessa pessoa."
                    },
                    "segmento": {
                      "type": "string",
                      "description": "Segmento."
                    },
                    "proximo": {
                      "anyOf": [
                        {
                          "type": "object",
                          "properties": {},
                          "additionalProperties": true
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "encontrado"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "encontrado": true,
                  "segmento": "string",
                  "proximo": {}
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "vendas",
        "description": "Perfil de uma pessoa pelo e-mail, enviado no corpo (nunca na URL): segmento, compras, lançamentos em que mexeu, canal e hora preferidos, temas e a sugestão de próximo evento com o motivo. O e-mail só vira hash para a busca e não é guardado. Dado pessoal: exige a capability `vendas` (Financeiro) e a resposta não é cacheada.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/jornada/perfil' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"email\":\"contato@siteup.com.br\"}'"
          }
        ]
      }
    },
    "/api/jornada/lead": {
      "post": {
        "operationId": "getLeadContext",
        "tags": [
          "Sales"
        ],
        "summary": "Resumo de um lead para o SiteUP CRM (compras, origem e páginas)",
        "security": [
          {
            "jornadaLeadToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "description": "E-mail do contato. Vira hash e não é guardado.",
                    "format": "email"
                  }
                },
                "required": [
                  "email"
                ]
              },
              "example": {
                "email": "contato@siteup.com.br"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "encontrado": {
                      "type": "boolean",
                      "description": "Se há eventos dessa pessoa."
                    },
                    "compras": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {},
                        "additionalProperties": true
                      },
                      "description": "Um item por pedido, do mais novo para o mais antigo: produto, rotulo, valor_centavos, moeda, status (pago, recusado, pendente, vencido, estornado), metodo, parcelas, ocorreu_em, loja (xamanismo, loja-nova ou loja-antiga, que é a Shopify até a virada) e site."
                    },
                    "total_pago": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true
                    },
                    "origem": {
                      "anyOf": [
                        {
                          "type": "object",
                          "properties": {},
                          "additionalProperties": true
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "paginas": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {},
                        "additionalProperties": true
                      },
                      "description": "Últimas cinco páginas visitadas."
                    },
                    "paginas_total": {
                      "type": "integer",
                      "description": "Visitas registradas."
                    },
                    "paginas_dias": {
                      "type": "integer",
                      "description": "Dias com visita."
                    }
                  },
                  "required": [
                    "encontrado"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "encontrado": true,
                  "compras": [
                    {}
                  ],
                  "total_pago": {},
                  "origem": {},
                  "paginas": [
                    {}
                  ],
                  "paginas_total": 1,
                  "paginas_dias": 1
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "description": "Consulta servidor a servidor da aba Contexto do lead do SiteUP CRM: compras de todas as lojas (checkout do Xamanismo e loja nova), primeiro e último toque (canal, UTMs, página de entrada) e as últimas cinco páginas visitadas. Visita anônima só aparece depois que a pessoa se identificou na mesma sessão. O e-mail vai no corpo, vira hash e não é guardado; nenhum dado de cartão ou documento sai. Token só de leitura (JORNADA_LEAD_TOKEN) no cabeçalho `x-jornada-token`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/jornada/lead' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"email\":\"contato@siteup.com.br\"}'"
          }
        ]
      }
    },
    "/api/lancamentos/{projetoId}": {
      "put": {
        "operationId": "putLaunch",
        "tags": [
          "Sales"
        ],
        "summary": "Cadastrar ou editar o dashboard de um projeto",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjetoId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "projeto_id": {
                    "type": "string",
                    "description": "ID do projeto."
                  },
                  "nome": {
                    "type": "string",
                    "description": "Nome do lançamento."
                  },
                  "tipo": {
                    "type": "string",
                    "description": "Tipo.",
                    "enum": [
                      "lancamento",
                      "perpetuo"
                    ]
                  },
                  "inicio": {
                    "anyOf": [
                      {
                        "type": "string",
                        "description": "Primeiro dia (YYYY-MM-DD)."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "fim": {
                    "anyOf": [
                      {
                        "type": "string",
                        "description": "Último dia (YYYY-MM-DD)."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "grupos": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "chave": {
                          "type": "string",
                          "description": "Chave do grupo (a-z, 0-9, _)."
                        },
                        "rotulo": {
                          "type": "string",
                          "description": "Rótulo exibido."
                        },
                        "produtos": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "description": "Código commerce_product."
                          },
                          "description": "Códigos do grupo."
                        },
                        "launch_ids": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "description": "launch_id aceito."
                          },
                          "description": "Vazio: conta pela janela de datas."
                        }
                      },
                      "required": [
                        "chave",
                        "produtos"
                      ]
                    },
                    "description": "Grupos de produto."
                  }
                },
                "required": [
                  "projeto_id",
                  "nome",
                  "grupos"
                ]
              },
              "example": {
                "projeto_id": "ca185d1f-b631-4699-9bbc-4cd81169b6a9",
                "nome": "O Funeral da Evidência",
                "tipo": "lancamento",
                "inicio": "2026-09-01",
                "fim": null,
                "grupos": [
                  {
                    "chave": "ingressos",
                    "rotulo": "Ingressos",
                    "produtos": [
                      "o_funeral_da_evidencia_ingresso"
                    ],
                    "launch_ids": [
                      "funeral-2026-10"
                    ]
                  }
                ]
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "version": {
                      "type": "integer",
                      "description": "Versão gravada."
                    },
                    "lancamento": {
                      "type": "object",
                      "properties": {},
                      "additionalProperties": true
                    }
                  },
                  "required": [
                    "ok",
                    "version"
                  ]
                },
                "example": {
                  "ok": true,
                  "version": 1,
                  "lancamento": {}
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "config",
        "description": "Cadastra ou edita o dashboard de um projeto (grupos de produto, códigos `commerce_product`, `launch_id` opcionais e janela). Grava a lista inteira em hermes_config com nova versão e histórico. Exige a capability `config`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request PUT \\\n  --url 'https://socialmedia.janvalellam.com.br/api/lancamentos/projetoid-exemplo' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"projeto_id\":\"ca185d1f-b631-4699-9bbc-4cd81169b6a9\",\"nome\":\"O Funeral da Evidência\",\"tipo\":\"lancamento\",\"inicio\":\"2026-09-01\",\"fim\":null,\"grupos\":[{\"chave\":\"ingressos\",\"rotulo\":\"Ingressos\",\"produtos\":[\"o_funeral_da_evidencia_ingresso\"],\"launch_ids\":[\"funeral-2026-10\"]}]}'"
          }
        ]
      }
    },
    "/api/insights/horarios": {
      "get": {
        "operationId": "getPublishingTimes",
        "tags": [
          "Intelligence"
        ],
        "summary": "Consultar melhores horários de publicação",
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string",
                      "description": "Origem do cálculo."
                    }
                  },
                  "required": [
                    "fonte"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "fonte": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "analytics",
        "description": "Retorna horários e sinais disponíveis para orientar o planejamento editorial. A origem do cálculo aparece no campo `fonte`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/insights/horarios' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/art": {
      "post": {
        "operationId": "generateArt",
        "tags": [
          "Creative"
        ],
        "summary": "Gerar e armazenar uma arte",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "prompt": {
                    "type": "string",
                    "description": "Prompt visual."
                  },
                  "event_id": {
                    "type": "string",
                    "description": "Evento opcional."
                  },
                  "size": {
                    "type": "string",
                    "description": "Tamanho aceito pelo modelo.",
                    "default": "1024x1536"
                  },
                  "slide_index": {
                    "type": "integer",
                    "description": "Ordem no evento.",
                    "default": 0
                  },
                  "quality": {
                    "type": "string",
                    "description": "Qualidade.",
                    "default": "medium"
                  },
                  "kind": {
                    "type": "string",
                    "description": "Tipo lógico.",
                    "default": "imagem"
                  },
                  "style": {
                    "type": "string",
                    "description": "Estilo.",
                    "default": "epico"
                  },
                  "format": {
                    "type": "string",
                    "description": "Proporção.",
                    "default": "2:3"
                  }
                },
                "required": [
                  "prompt"
                ]
              },
              "example": {
                "prompt": "Céu estrelado em verde profundo",
                "event_id": "event-id"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StoredMedia"
                },
                "example": {
                  "id": "id-exemplo",
                  "url": "https://socialmedia.janvalellam.com.br/media/media-id?exp=1790000000&sig=assinatura",
                  "storage_path": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "art",
        "description": "Gera uma imagem, armazena o resultado e opcionalmente a anexa a um evento acessível. Use `Idempotency-Key` para repetir com segurança após timeout.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/art' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Idempotency-Key: docs-20260822-001' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"prompt\":\"Céu estrelado em verde profundo\",\"event_id\":\"event-id\"}'"
          }
        ],
        "x-idempotency": {
          "header": "Idempotency-Key",
          "required": false,
          "replay_requires_same_payload": true
        }
      }
    },
    "/api/carousel": {
      "post": {
        "operationId": "generateCarousel",
        "tags": [
          "Creative"
        ],
        "summary": "Gerar carrossel com até dez cards",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "event_id": {
                    "type": "string",
                    "description": "Evento opcional."
                  },
                  "cards": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "text": {
                          "type": "string",
                          "description": "Texto do card."
                        },
                        "prompt": {
                          "type": "string",
                          "description": "Prompt de fundo opcional."
                        }
                      },
                      "required": [
                        "text"
                      ]
                    },
                    "description": "Entre 1 e 10 cards.",
                    "minItems": 1,
                    "maxItems": 10
                  }
                },
                "required": [
                  "cards"
                ]
              },
              "example": {
                "event_id": "event-id",
                "cards": [
                  {
                    "text": "Primeiro insight",
                    "prompt": "Cosmos verde escuro"
                  }
                ]
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "cards": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MediaReference"
                      }
                    }
                  },
                  "required": [
                    "cards"
                  ]
                },
                "example": {
                  "cards": [
                    {
                      "id": "id-exemplo",
                      "url": "https://socialmedia.janvalellam.com.br/media/media-id?exp=1790000000&sig=assinatura",
                      "slide_index": 1,
                      "kind": "string"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "carousel",
        "description": "Gera de um a dez cards e os persiste como um conjunto ordenado. Se houver `event_id`, o vínculo de todas as mídias é atômico.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/carousel' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Idempotency-Key: docs-20260822-001' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"event_id\":\"event-id\",\"cards\":[{\"text\":\"Primeiro insight\",\"prompt\":\"Cosmos verde escuro\"}]}'"
          }
        ],
        "x-idempotency": {
          "header": "Idempotency-Key",
          "required": false,
          "replay_requires_same_payload": true
        }
      }
    },
    "/api/reels": {
      "post": {
        "operationId": "generateReel",
        "tags": [
          "Creative"
        ],
        "summary": "Iniciar geração assíncrona de vídeo",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "event_id": {
                    "type": "string",
                    "description": "Evento opcional."
                  },
                  "prompt": {
                    "type": "string",
                    "description": "Cena base."
                  },
                  "motion": {
                    "type": "string",
                    "description": "Movimento desejado."
                  },
                  "duration": {
                    "type": "string",
                    "description": "Duração em segundos.",
                    "default": "6"
                  },
                  "resolution": {
                    "type": "string",
                    "description": "Resolução.",
                    "default": "720p"
                  }
                },
                "required": [
                  "prompt"
                ]
              },
              "example": {
                "prompt": "Luzes sutis na floresta",
                "duration": "6",
                "resolution": "720p"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReelJobAccepted"
                },
                "example": {
                  "job_id": "job-id-exemplo",
                  "state": "processing",
                  "aviso": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "video",
        "description": "Cria um job assíncrono de vídeo e retorna imediatamente o identificador para polling. Somente o criador do job ou líderes podem consultar o resultado.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/reels' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Idempotency-Key: docs-20260822-001' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"prompt\":\"Luzes sutis na floresta\",\"duration\":\"6\",\"resolution\":\"720p\"}'"
          }
        ],
        "x-idempotency": {
          "header": "Idempotency-Key",
          "required": false,
          "replay_requires_same_payload": true
        }
      }
    },
    "/api/reels/{id}": {
      "get": {
        "operationId": "getReelJob",
        "tags": [
          "Creative"
        ],
        "summary": "Consultar uma geração de vídeo",
        "parameters": [
          {
            "$ref": "#/components/parameters/ReelJobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReelJob"
                },
                "example": {
                  "state": "processing",
                  "error": "string",
                  "url": "https://socialmedia.janvalellam.com.br/media/media-id?exp=1790000000&sig=assinatura"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "reels_view",
        "description": "Consulta o estado de um job de vídeo. Faça polling moderado até `completed` ou `failed`; a URL só está disponível após conclusão.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/reels/id-exemplo' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/upload": {
      "post": {
        "operationId": "uploadMedia",
        "tags": [
          "Creative"
        ],
        "summary": "Enviar arquivo pronto",
        "description": "Corpo binário, limite de 300 MB. Metadados seguem na query string.\n\nRecebe bytes diretamente no corpo e armazena o arquivo. Metadados ficam na query string; use `Idempotency-Key` para evitar duplicatas em repetições.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "name": "event_id",
            "in": "query",
            "required": false,
            "description": "Evento opcional.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "Tipo lógico.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "Proporção/formato.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "slide_index",
            "in": "query",
            "required": false,
            "description": "Ordem.",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "filename",
            "in": "query",
            "required": false,
            "description": "Nome usado também para detectar vídeo.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "contentMediaType": "application/octet-stream"
              }
            },
            "image/*": {
              "schema": {
                "type": "string",
                "contentMediaType": "image/*"
              }
            },
            "video/*": {
              "schema": {
                "type": "string",
                "contentMediaType": "video/*"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadedMedia"
                },
                "example": {
                  "id": "id-exemplo",
                  "url": "https://socialmedia.janvalellam.com.br/media/media-id?exp=1790000000&sig=assinatura",
                  "kind": "string",
                  "bytes": 1
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "art",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/upload' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Idempotency-Key: docs-20260822-001' \\\n  --header 'Content-Type: application/octet-stream' \\\n  --data-binary '@arquivo.bin'"
          }
        ],
        "x-idempotency": {
          "header": "Idempotency-Key",
          "required": false,
          "replay_requires_same_payload": true
        }
      }
    },
    "/api/draft": {
      "post": {
        "operationId": "saveDraft",
        "tags": [
          "Workflow"
        ],
        "summary": "Salvar rascunho editorial",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "event_id": {
                    "type": "string",
                    "description": "Evento."
                  },
                  "expected_revision": {
                    "type": "integer",
                    "description": "api_revision obtida na leitura mais recente.",
                    "minimum": 0
                  },
                  "caption": {
                    "type": "string",
                    "description": "Legenda opcional."
                  },
                  "status": {
                    "type": "string",
                    "description": "Status.",
                    "default": "em progresso"
                  }
                },
                "required": [
                  "event_id",
                  "expected_revision"
                ]
              },
              "example": {
                "event_id": "event-id",
                "expected_revision": 4,
                "caption": "Nova legenda"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "status": {
                      "type": "string",
                      "description": "Status persistido."
                    },
                    "api_revision": {
                      "type": "integer",
                      "description": "Nova revisão CAS.",
                      "minimum": 0
                    }
                  },
                  "required": [
                    "ok",
                    "status",
                    "api_revision"
                  ]
                },
                "example": {
                  "ok": true,
                  "status": "processing",
                  "api_revision": 0
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "draft_save",
        "description": "Atualiza legenda e estado editorial usando CAS. Leia o evento imediatamente antes e envie o `api_revision` obtido como `expected_revision`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/draft' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"event_id\":\"event-id\",\"expected_revision\":4,\"caption\":\"Nova legenda\"}'"
          }
        ]
      }
    },
    "/api/demanda": {
      "post": {
        "operationId": "createDemand",
        "tags": [
          "Workflow"
        ],
        "summary": "Criar demanda editorial",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "Título."
                  },
                  "channel": {
                    "type": "string",
                    "description": "Canal.",
                    "default": "instagram"
                  },
                  "assignee_id": {
                    "type": "string",
                    "description": "Membro ativo opcional."
                  },
                  "day": {
                    "type": "integer",
                    "description": "Dia no horário de Brasília.",
                    "minimum": 1,
                    "maximum": 31
                  },
                  "month": {
                    "type": "integer",
                    "description": "Mês no horário de Brasília.",
                    "minimum": 1,
                    "maximum": 12
                  },
                  "year": {
                    "type": "integer",
                    "description": "Ano com quatro dígitos.",
                    "minimum": 2000
                  },
                  "hour": {
                    "type": "string",
                    "description": "Horário local HH:mm. O padrão do backend é 12:00.",
                    "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
                  },
                  "description": {
                    "type": "string",
                    "description": "Descrição."
                  },
                  "tipo": {
                    "type": "string",
                    "description": "Tag editorial."
                  }
                },
                "required": [
                  "title"
                ]
              },
              "example": {
                "title": "Novo corte",
                "channel": "instagram",
                "assignee_id": "member-id",
                "day": 2,
                "month": 9,
                "year": 2026,
                "hour": "12:00"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "event_id": {
                      "type": "string",
                      "description": "Evento criado."
                    },
                    "clickup_id": {
                      "type": "string",
                      "description": "ID externo."
                    },
                    "due_at": {
                      "anyOf": [
                        {
                          "type": "string",
                          "description": "Data ISO.",
                          "format": "date-time"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "event": {
                      "$ref": "#/components/schemas/Event"
                    }
                  },
                  "required": [
                    "ok",
                    "event_id",
                    "clickup_id",
                    "event"
                  ]
                },
                "example": {
                  "ok": true,
                  "event_id": "event-id-exemplo",
                  "clickup_id": "clickup-id-exemplo",
                  "due_at": "2026-08-22T15:00:00.000Z",
                  "event": {
                    "id": "id-exemplo",
                    "api_revision": 0,
                    "clickup_id": "clickup-id-exemplo",
                    "title": "Conteúdo editorial",
                    "channel": "instagram",
                    "status": "processing",
                    "description": "Conteúdo de exemplo",
                    "day": 1,
                    "month": 1,
                    "year": 1,
                    "due_at": "2026-08-22T15:00:00.000Z",
                    "editorial_tag": "string",
                    "assignee_member_ids": [
                      "assignee-member-id-exemplo"
                    ],
                    "assignees_names": [
                      "Exemplo Hermes"
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "tasks_assign",
        "description": "Cria uma demanda no calendário e, quando informado, atribui somente um membro ativo. Datas são interpretadas no horário de Brasília.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/demanda' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"title\":\"Novo corte\",\"channel\":\"instagram\",\"assignee_id\":\"member-id\",\"day\":2,\"month\":9,\"year\":2026,\"hour\":\"12:00\"}'"
          }
        ]
      }
    },
    "/api/tarefas": {
      "get": {
        "operationId": "listMyTasks",
        "tags": [
          "Workflow"
        ],
        "summary": "Listar tarefas ativas do membro",
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tarefas": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    }
                  },
                  "required": [
                    "tarefas"
                  ]
                },
                "example": {
                  "tarefas": [
                    {
                      "id": "id-exemplo",
                      "api_revision": 0,
                      "clickup_id": "clickup-id-exemplo",
                      "title": "Conteúdo editorial",
                      "channel": "instagram",
                      "status": "processing",
                      "description": "Conteúdo de exemplo",
                      "day": 1,
                      "month": 1,
                      "year": 1,
                      "due_at": "2026-08-22T15:00:00.000Z",
                      "editorial_tag": "string",
                      "assignee_member_ids": [
                        "assignee-member-id-exemplo"
                      ],
                      "assignees_names": [
                        "Exemplo Hermes"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "tasks_view",
        "description": "Lista tarefas ativas visíveis ao membro autenticado. Cada evento inclui `api_revision`, que deve ser reutilizado em mutações protegidas por CAS.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/tarefas' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/anexaveis": {
      "get": {
        "operationId": "listAttachableEvents",
        "tags": [
          "Workflow"
        ],
        "summary": "Listar eventos que aceitam mídia do membro",
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "eventos": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "Identificador do evento."
                          },
                          "api_revision": {
                            "type": "integer",
                            "description": "Token CAS da API; releia o evento antes de toda mutação.",
                            "minimum": 0
                          },
                          "clickup_id": {
                            "anyOf": [
                              {
                                "type": "string",
                                "description": "Identificador externo/legado."
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "title": {
                            "type": "string",
                            "description": "Título editorial."
                          },
                          "channel": {
                            "type": "string",
                            "description": "Canal de publicação."
                          },
                          "status": {
                            "type": "string",
                            "description": "Estado do fluxo editorial."
                          },
                          "description": {
                            "anyOf": [
                              {
                                "type": "string",
                                "description": "Legenda ou descrição."
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "day": {
                            "anyOf": [
                              {
                                "type": "integer",
                                "description": "Dia no horário de Brasília.",
                                "minimum": 1,
                                "maximum": 31
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "month": {
                            "anyOf": [
                              {
                                "type": "integer",
                                "description": "Mês no horário de Brasília.",
                                "minimum": 1,
                                "maximum": 12
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "year": {
                            "anyOf": [
                              {
                                "type": "integer",
                                "description": "Ano no horário de Brasília."
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "due_at": {
                            "anyOf": [
                              {
                                "type": "string",
                                "description": "Data/hora ISO 8601 persistida.",
                                "format": "date-time"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "editorial_tag": {
                            "anyOf": [
                              {
                                "type": "string",
                                "description": "Tipo/tag editorial."
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "assignee_member_ids": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "description": "ID de membro."
                            },
                            "description": "Responsáveis por ID."
                          },
                          "assignees_names": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "description": "Nome de membro."
                            },
                            "description": "Nomes dos responsáveis."
                          },
                          "media": {
                            "type": "array",
                            "items": {
                              "$ref": "#/components/schemas/MediaReference"
                            }
                          }
                        },
                        "additionalProperties": true
                      }
                    }
                  },
                  "required": [
                    "eventos"
                  ]
                },
                "example": {
                  "eventos": [
                    {
                      "id": "id-exemplo",
                      "api_revision": 0,
                      "clickup_id": "clickup-id-exemplo",
                      "title": "Conteúdo editorial",
                      "channel": "instagram",
                      "status": "processing",
                      "description": "Conteúdo de exemplo",
                      "day": 1,
                      "month": 1,
                      "year": 1,
                      "due_at": "2026-08-22T15:00:00.000Z",
                      "editorial_tag": "string",
                      "assignee_member_ids": [
                        "assignee-member-id-exemplo"
                      ],
                      "assignees_names": [
                        "Exemplo Hermes"
                      ],
                      "media": [
                        {
                          "id": "id-exemplo",
                          "url": "https://socialmedia.janvalellam.com.br/media/media-id?exp=1790000000&sig=assinatura",
                          "slide_index": 1,
                          "kind": "string"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "art",
        "description": "Lista eventos nos quais o membro pode anexar mídia, já acompanhados das referências atualmente persistidas.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/anexaveis' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/enviar": {
      "post": {
        "operationId": "submitForApproval",
        "tags": [
          "Workflow"
        ],
        "summary": "Enviar conteúdo para aprovação",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "event_id": {
                    "type": "string",
                    "description": "Evento."
                  },
                  "expected_revision": {
                    "type": "integer",
                    "description": "api_revision obtida na leitura mais recente.",
                    "minimum": 0
                  },
                  "day": {
                    "type": "integer",
                    "description": "Dia no horário de Brasília.",
                    "minimum": 1,
                    "maximum": 31
                  },
                  "month": {
                    "type": "integer",
                    "description": "Mês no horário de Brasília.",
                    "minimum": 1,
                    "maximum": 12
                  },
                  "year": {
                    "type": "integer",
                    "description": "Ano com quatro dígitos.",
                    "minimum": 2000
                  },
                  "hour": {
                    "type": "string",
                    "description": "Horário local HH:mm. O padrão do backend é 12:00.",
                    "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
                  },
                  "caption": {
                    "type": "string",
                    "description": "Legenda."
                  },
                  "tipo": {
                    "type": "string",
                    "description": "Tag editorial."
                  }
                },
                "required": [
                  "event_id",
                  "expected_revision"
                ]
              },
              "example": {
                "event_id": "event-id",
                "expected_revision": 4,
                "day": 2,
                "month": 9,
                "year": 2026,
                "hour": "15:30"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "status": {
                      "type": "string",
                      "description": "Sempre para agendar."
                    },
                    "api_revision": {
                      "type": "integer",
                      "description": "Nova revisão CAS.",
                      "minimum": 0
                    },
                    "due_at": {
                      "anyOf": [
                        {
                          "type": "string",
                          "description": "Data ISO.",
                          "format": "date-time"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "proposto": {
                      "anyOf": [
                        {
                          "type": "string",
                          "description": "Alias de due_at.",
                          "format": "date-time"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "status",
                    "api_revision"
                  ]
                },
                "example": {
                  "ok": true,
                  "status": "processing",
                  "api_revision": 0,
                  "due_at": "2026-08-22T15:00:00.000Z",
                  "proposto": "2026-08-22T15:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "enviar",
        "description": "Move um conteúdo editável para o fluxo de aprovação e pode atualizar a data proposta. Exige o `api_revision` mais recente e aceita repetição segura com `Idempotency-Key`.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/enviar' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Idempotency-Key: docs-20260822-001' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"event_id\":\"event-id\",\"expected_revision\":4,\"day\":2,\"month\":9,\"year\":2026,\"hour\":\"15:30\"}'"
          }
        ],
        "x-idempotency": {
          "header": "Idempotency-Key",
          "required": false,
          "replay_requires_same_payload": true
        }
      }
    },
    "/api/aprovacoes": {
      "get": {
        "operationId": "listApprovals",
        "tags": [
          "Workflow"
        ],
        "summary": "Listar conteúdos aguardando aprovação",
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "pendentes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "Identificador do evento."
                          },
                          "api_revision": {
                            "type": "integer",
                            "description": "Token CAS da API; releia o evento antes de toda mutação.",
                            "minimum": 0
                          },
                          "clickup_id": {
                            "anyOf": [
                              {
                                "type": "string",
                                "description": "Identificador externo/legado."
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "title": {
                            "type": "string",
                            "description": "Título editorial."
                          },
                          "channel": {
                            "type": "string",
                            "description": "Canal de publicação."
                          },
                          "status": {
                            "type": "string",
                            "description": "Estado do fluxo editorial."
                          },
                          "description": {
                            "anyOf": [
                              {
                                "type": "string",
                                "description": "Legenda ou descrição."
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "day": {
                            "anyOf": [
                              {
                                "type": "integer",
                                "description": "Dia no horário de Brasília.",
                                "minimum": 1,
                                "maximum": 31
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "month": {
                            "anyOf": [
                              {
                                "type": "integer",
                                "description": "Mês no horário de Brasília.",
                                "minimum": 1,
                                "maximum": 12
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "year": {
                            "anyOf": [
                              {
                                "type": "integer",
                                "description": "Ano no horário de Brasília."
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "due_at": {
                            "anyOf": [
                              {
                                "type": "string",
                                "description": "Data/hora ISO 8601 persistida.",
                                "format": "date-time"
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "editorial_tag": {
                            "anyOf": [
                              {
                                "type": "string",
                                "description": "Tipo/tag editorial."
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "assignee_member_ids": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "description": "ID de membro."
                            },
                            "description": "Responsáveis por ID."
                          },
                          "assignees_names": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "description": "Nome de membro."
                            },
                            "description": "Nomes dos responsáveis."
                          },
                          "media": {
                            "type": "array",
                            "items": {
                              "$ref": "#/components/schemas/MediaReference"
                            }
                          }
                        },
                        "additionalProperties": true
                      }
                    }
                  },
                  "required": [
                    "pendentes"
                  ]
                },
                "example": {
                  "pendentes": [
                    {
                      "id": "id-exemplo",
                      "api_revision": 0,
                      "clickup_id": "clickup-id-exemplo",
                      "title": "Conteúdo editorial",
                      "channel": "instagram",
                      "status": "processing",
                      "description": "Conteúdo de exemplo",
                      "day": 1,
                      "month": 1,
                      "year": 1,
                      "due_at": "2026-08-22T15:00:00.000Z",
                      "editorial_tag": "string",
                      "assignee_member_ids": [
                        "assignee-member-id-exemplo"
                      ],
                      "assignees_names": [
                        "Exemplo Hermes"
                      ],
                      "media": [
                        {
                          "id": "id-exemplo",
                          "url": "https://socialmedia.janvalellam.com.br/media/media-id?exp=1790000000&sig=assinatura",
                          "slide_index": 1,
                          "kind": "string"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "approve",
        "description": "Lista conteúdos aguardando decisão para membros com capability `approve`, incluindo mídias e revisão atual do evento.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/aprovacoes' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/aprovar": {
      "post": {
        "operationId": "decideApproval",
        "tags": [
          "Workflow"
        ],
        "summary": "Aprovar ou recusar conteúdo",
        "description": "A aprovação é atômica e idempotente no banco; a recusa preserva o conteúdo e muda o status.\n\nAprova ou recusa o conteúdo sem apagar o histórico. Ao recusar, informe um motivo útil; ao aprovar, a data final pode ser ajustada.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "event_id": {
                    "type": "string",
                    "description": "Evento."
                  },
                  "action": {
                    "type": "string",
                    "description": "Decisão.",
                    "enum": [
                      "aprovar",
                      "recusar"
                    ]
                  },
                  "motivo": {
                    "type": "string",
                    "description": "Motivo da recusa."
                  },
                  "day": {
                    "type": "integer",
                    "description": "Dia no horário de Brasília.",
                    "minimum": 1,
                    "maximum": 31
                  },
                  "month": {
                    "type": "integer",
                    "description": "Mês no horário de Brasília.",
                    "minimum": 1,
                    "maximum": 12
                  },
                  "year": {
                    "type": "integer",
                    "description": "Ano com quatro dígitos.",
                    "minimum": 2000
                  },
                  "hour": {
                    "type": "string",
                    "description": "Horário local HH:mm. O padrão do backend é 12:00.",
                    "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
                  },
                  "caption": {
                    "type": "string",
                    "description": "Legenda final opcional."
                  }
                },
                "required": [
                  "event_id",
                  "action"
                ]
              },
              "example": {
                "event_id": "event-id",
                "action": "aprovar",
                "day": 2,
                "month": 9,
                "year": 2026,
                "hour": "19:00"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "status": {
                      "type": "string",
                      "description": "Estado resultante."
                    }
                  },
                  "required": [
                    "ok",
                    "status"
                  ],
                  "additionalProperties": true
                },
                "example": {
                  "ok": true,
                  "status": "processing"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "approve",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/aprovar' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"event_id\":\"event-id\",\"action\":\"aprovar\",\"day\":2,\"month\":9,\"year\":2026,\"hour\":\"19:00\"}'"
          }
        ]
      }
    },
    "/api/projects": {
      "get": {
        "operationId": "listProjects",
        "tags": [
          "Projects"
        ],
        "summary": "Listar projetos colaborativos",
        "description": "Paginação determinística por created_at. Use created_after com o último timestamp recebido.\n\nLista projetos em ordem determinística de criação. Para paginação, use o `created_at` do último item como cursor exclusivo em `created_after`.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Máximo de projetos.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            }
          },
          {
            "name": "created_after",
            "in": "query",
            "required": false,
            "description": "Cursor exclusivo de criação.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "projects": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Project"
                      }
                    }
                  },
                  "required": [
                    "projects"
                  ]
                },
                "example": {
                  "projects": [
                    {
                      "id": "id-exemplo",
                      "name": "Exemplo Hermes",
                      "payload": {},
                      "api_revision": 0,
                      "revision": 0,
                      "created_at": "2026-08-22T15:00:00.000Z",
                      "updated_at": "2026-08-22T15:00:00.000Z",
                      "created_by": "string",
                      "updated_by": "string"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "projects_view",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/projects' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      },
      "post": {
        "operationId": "createProject",
        "tags": [
          "Projects"
        ],
        "summary": "Criar projeto colaborativo vazio",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Nome do projeto.",
                    "minLength": 1,
                    "maxLength": 200
                  }
                },
                "required": [
                  "name"
                ]
              },
              "example": {
                "name": "Lançamento Xamanismo"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "201": {
            "description": "Projeto criado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    }
                  },
                  "required": [
                    "ok",
                    "project"
                  ]
                },
                "example": {
                  "ok": true,
                  "project": {
                    "id": "id-exemplo",
                    "name": "Exemplo Hermes",
                    "payload": {},
                    "api_revision": 0,
                    "revision": 0,
                    "created_at": "2026-08-22T15:00:00.000Z",
                    "updated_at": "2026-08-22T15:00:00.000Z",
                    "created_by": "string",
                    "updated_by": "string"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "projects_manage",
        "description": "Cria um documento de projeto vazio no formato atual. Forneça uma chave de idempotência para tornar retries de rede seguros.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/projects' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Idempotency-Key: docs-20260822-001' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"name\":\"Lançamento Xamanismo\"}'"
          }
        ],
        "x-idempotency": {
          "header": "Idempotency-Key",
          "required": false,
          "replay_requires_same_payload": true
        }
      }
    },
    "/api/projects/{projectId}": {
      "get": {
        "operationId": "getProject",
        "tags": [
          "Projects"
        ],
        "summary": "Consultar um projeto e seu token CAS",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    }
                  },
                  "required": [
                    "project"
                  ]
                },
                "example": {
                  "project": {
                    "id": "id-exemplo",
                    "name": "Exemplo Hermes",
                    "payload": {},
                    "api_revision": 0,
                    "revision": 0,
                    "created_at": "2026-08-22T15:00:00.000Z",
                    "updated_at": "2026-08-22T15:00:00.000Z",
                    "created_by": "string",
                    "updated_by": "string"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "projects_view",
        "description": "Retorna o projeto completo e os tokens `api_revision`/`revision`. Sempre leia esta rota antes de aplicar uma alteração semântica.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/projects/projectid-exemplo' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/projects/{projectId}/operations": {
      "get": {
        "operationId": "listProjectOperations",
        "tags": [
          "Projects"
        ],
        "summary": "Listar histórico de operações do projeto",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Máximo de operações.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "operations": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ProjectOperationLog"
                      }
                    },
                    "revision": {
                      "type": "integer",
                      "description": "api_revision atual.",
                      "minimum": 0
                    }
                  },
                  "required": [
                    "operations",
                    "revision"
                  ]
                },
                "example": {
                  "operations": [
                    {
                      "id": "id-exemplo",
                      "payload_revision": 0,
                      "operation_type": "string",
                      "operation": {},
                      "actor_member_id": "actor-member-id-exemplo",
                      "actor_user_id": "actor-user-id-exemplo",
                      "created_at": "2026-08-22T15:00:00.000Z"
                    }
                  ],
                  "revision": 0
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "projects_audit_view",
        "description": "Exibe o histórico imutável de operações semânticas, da revisão mais recente para a mais antiga, para auditoria e reconstrução de mudanças.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/projects/projectid-exemplo/operations' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      },
      "post": {
        "operationId": "applyProjectOperation",
        "tags": [
          "Projects"
        ],
        "summary": "Aplicar uma operação semântica com CAS",
        "description": "Nunca envie um snapshot inteiro. Leia o projeto, use revision/api_revision como expected_revision e aplique uma operação. Em 409, releia antes de decidir um novo payload. O servidor exige `projects_manage` para estrutura, ordem e responsáveis. Com somente `projects_edit`, task.update exige atribuição na tarefa e subtask.update exige atribuição na subtarefa ou tarefa-pai; comentários próprios continuam permitidos.\n\nAplica uma única mudança semântica ao projeto. Criadores só atualizam tarefas atribuídas à própria conta; líderes e admins podem gerenciar a equipe. Nunca envie um snapshot inteiro e, em conflito `409`, releia o projeto.",
        "x-capability-dispatch": {
          "default": "projects_edit",
          "projects_manage": [
            "meta.update",
            "goal.add",
            "goal.update",
            "goal.remove",
            "goal.reorder",
            "task.add",
            "task.remove",
            "task.reorder",
            "task.assignees.set",
            "subtask.add",
            "subtask.remove",
            "subtask.reorder",
            "subtask.assignees.set"
          ]
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProjectOperationRequest"
              },
              "example": {
                "expected_revision": 4,
                "expected_updated_at": "2026-08-21T12:00:00.000Z",
                "operation": {
                  "type": "task.add",
                  "title": "Revisar copy",
                  "status": "pending"
                }
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    }
                  },
                  "required": [
                    "ok",
                    "project"
                  ]
                },
                "example": {
                  "ok": true,
                  "project": {
                    "id": "id-exemplo",
                    "name": "Exemplo Hermes",
                    "payload": {},
                    "api_revision": 0,
                    "revision": 0,
                    "created_at": "2026-08-22T15:00:00.000Z",
                    "updated_at": "2026-08-22T15:00:00.000Z",
                    "created_by": "string",
                    "updated_by": "string"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "projects_edit",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/projects/projectid-exemplo/operations' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Idempotency-Key: docs-20260822-001' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"expected_revision\":4,\"expected_updated_at\":\"2026-08-21T12:00:00.000Z\",\"operation\":{\"type\":\"task.add\",\"title\":\"Revisar copy\",\"status\":\"pending\"}}'"
          }
        ],
        "x-idempotency": {
          "header": "Idempotency-Key",
          "required": false,
          "replay_requires_same_payload": true
        }
      }
    },
    "/api/email-drafts": {
      "get": {
        "operationId": "listEmailDrafts",
        "tags": [
          "Email Drafts"
        ],
        "summary": "Listar metadados de rascunhos de e-mail",
        "description": "A listagem não inclui HTML. Consulte o template individual quando precisar editar.\n\nLista apenas metadados, sem transferir HTML potencialmente grande. Abra individualmente somente o template que será consultado ou editado.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Máximo de rascunhos.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "drafts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EmailDraftSummary"
                      }
                    }
                  },
                  "required": [
                    "drafts"
                  ]
                },
                "example": {
                  "drafts": [
                    {
                      "template_id": "xamanismo-boas-vindas",
                      "metadata": {},
                      "updated_at": "2026-08-22T15:00:00.000Z",
                      "updated_by": "string"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "email_drafts_view",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/email-drafts' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/email-drafts/{templateId}": {
      "get": {
        "operationId": "getEmailDraft",
        "tags": [
          "Email Drafts"
        ],
        "summary": "Consultar um rascunho de e-mail",
        "parameters": [
          {
            "$ref": "#/components/parameters/TemplateId"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "draft": {
                      "$ref": "#/components/schemas/EmailDraft"
                    }
                  },
                  "required": [
                    "draft"
                  ]
                },
                "example": {
                  "draft": {
                    "template_id": "xamanismo-boas-vindas",
                    "html": "string",
                    "metadata": {},
                    "updated_at": "2026-08-22T15:00:00.000Z",
                    "updated_by": "string"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "email_drafts_view",
        "description": "Retorna o HTML completo, metadados e `updated_at`, que funciona como token CAS para a próxima edição ou exclusão.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/email-drafts/xamanismo-boas-vindas' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      },
      "put": {
        "operationId": "putEmailDraft",
        "tags": [
          "Email Drafts"
        ],
        "summary": "Criar ou atualizar um rascunho com CAS",
        "description": "Use expected_updated_at null somente para criar. Para editar, use exatamente o updated_at da leitura mais recente.\n\nCria ou atualiza um template com CAS. Use `expected_updated_at: null` somente na criação e o timestamp exato da leitura mais recente nas edições.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TemplateId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "html": {
                    "type": "string",
                    "description": "HTML do e-mail, até 2 MB.",
                    "maxLength": 2000000
                  },
                  "metadata": {
                    "type": "object",
                    "properties": {},
                    "additionalProperties": true
                  },
                  "expected_updated_at": {
                    "anyOf": [
                      {
                        "type": "string",
                        "description": "Token CAS da leitura mais recente.",
                        "format": "date-time"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "html",
                  "expected_updated_at"
                ]
              },
              "example": {
                "html": "<!doctype html><html><body>...</body></html>",
                "metadata": {
                  "campaign": "xamanismo"
                },
                "expected_updated_at": null
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "draft": {
                      "$ref": "#/components/schemas/EmailDraft"
                    }
                  },
                  "required": [
                    "ok",
                    "draft"
                  ]
                },
                "example": {
                  "ok": true,
                  "draft": {
                    "template_id": "xamanismo-boas-vindas",
                    "html": "string",
                    "metadata": {},
                    "updated_at": "2026-08-22T15:00:00.000Z",
                    "updated_by": "string"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "description": "HTML excede 2 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "html excede 2 MB",
                  "code": "EMAIL_HTML_TOO_LARGE"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "email_drafts_edit",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request PUT \\\n  --url 'https://socialmedia.janvalellam.com.br/api/email-drafts/xamanismo-boas-vindas' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>' \\\n  --header 'Idempotency-Key: docs-20260822-001' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"html\":\"<!doctype html><html><body>...</body></html>\",\"metadata\":{\"campaign\":\"xamanismo\"},\"expected_updated_at\":null}'"
          }
        ],
        "x-idempotency": {
          "header": "Idempotency-Key",
          "required": false,
          "replay_requires_same_payload": true
        }
      },
      "delete": {
        "operationId": "deleteEmailDraft",
        "tags": [
          "Email Drafts"
        ],
        "summary": "Excluir exatamente um rascunho com CAS",
        "description": "A exclusão é destrutiva e exige o updated_at atual. Leia o rascunho e confirme o template exato antes de chamar.\n\nExclusão destrutiva de um único template. Confirme o identificador e envie o `expected_updated_at` atual; conflitos nunca são sobrescritos.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TemplateId"
          },
          {
            "name": "expected_updated_at",
            "in": "query",
            "required": true,
            "description": "Token CAS da leitura mais recente.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "template_id": {
                      "type": "string",
                      "description": "Template excluído."
                    }
                  },
                  "required": [
                    "ok",
                    "template_id"
                  ]
                },
                "example": {
                  "ok": true,
                  "template_id": "xamanismo-boas-vindas"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          },
          {
            "personalApiToken": []
          }
        ],
        "x-required-capability": "delete",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request DELETE \\\n  --url 'https://socialmedia.janvalellam.com.br/api/email-drafts/xamanismo-boas-vindas?expected_updated_at=2026-08-22T15%3A00%3A00.000Z' \\\n  --header 'Authorization: Bearer <supabase_session_or_hms_live_token>'"
          }
        ]
      }
    },
    "/api/membros": {
      "get": {
        "operationId": "listMembers",
        "tags": [
          "Members"
        ],
        "summary": "Listar membros ativos",
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "membros": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Member"
                      }
                    }
                  },
                  "required": [
                    "membros"
                  ]
                },
                "example": {
                  "membros": [
                    {
                      "id": "id-exemplo",
                      "name": "Exemplo Hermes",
                      "email": "membro@example.com",
                      "role": "string",
                      "access_level": "criador",
                      "api_access_level": "nenhum",
                      "is_admin": true,
                      "financeiro": true
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "members",
        "x-session-only": true,
        "description": "Lista membros ativos que podem receber atribuições, sem retornar credenciais ou registros já desativados.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/membros' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>'"
          }
        ]
      },
      "post": {
        "operationId": "createMember",
        "tags": [
          "Members"
        ],
        "summary": "Convidar um novo membro",
        "description": "O Supabase envia um link de convite para o e-mail informado. O usuário define a própria senha no fluxo de onboarding; a API nunca cria nem retorna senha provisória.\n\nEnvia um convite seguro por e-mail e cria o vínculo ativo na equipe. Nenhuma senha provisória é criada ou devolvida pela API.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Nome."
                  },
                  "email": {
                    "type": "string",
                    "description": "E-mail.",
                    "format": "email"
                  },
                  "access_level": {
                    "type": "string",
                    "description": "Nível.",
                    "enum": [
                      "criador",
                      "lider",
                      "admin"
                    ]
                  },
                  "role": {
                    "type": "string",
                    "description": "Função livre."
                  }
                },
                "required": [
                  "name",
                  "email",
                  "access_level"
                ]
              },
              "example": {
                "name": "Novo membro",
                "email": "membro@example.com",
                "access_level": "criador"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "201": {
            "description": "Convite enviado e membro criado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "member": {
                      "$ref": "#/components/schemas/Member"
                    },
                    "invitation": {
                      "type": "object",
                      "properties": {
                        "sent": {
                          "type": "boolean",
                          "description": "Confirma o envio do convite."
                        },
                        "email": {
                          "type": "string",
                          "description": "Destino normalizado.",
                          "format": "email"
                        }
                      },
                      "required": [
                        "sent",
                        "email"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "member",
                    "invitation"
                  ]
                },
                "example": {
                  "ok": true,
                  "member": {
                    "id": "member-id",
                    "name": "Novo membro",
                    "email": "membro@example.com",
                    "access_level": "criador"
                  },
                  "invitation": {
                    "sent": true,
                    "email": "membro@example.com"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "members",
        "x-session-only": true,
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/membros' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"name\":\"Novo membro\",\"email\":\"membro@example.com\",\"access_level\":\"criador\"}'"
          }
        ]
      },
      "patch": {
        "operationId": "updateMemberAccess",
        "tags": [
          "Members"
        ],
        "summary": "Alterar nível de acesso ou permissão financeira",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "member_id": {
                    "type": "string",
                    "description": "Membro."
                  },
                  "access_level": {
                    "type": "string",
                    "description": "Nível.",
                    "enum": [
                      "criador",
                      "lider",
                      "admin"
                    ]
                  },
                  "financeiro": {
                    "type": "boolean",
                    "description": "Liga ou desliga o acesso ao painel de Vendas."
                  }
                },
                "required": [
                  "member_id"
                ]
              },
              "example": {
                "member_id": "member-id",
                "access_level": "lider",
                "financeiro": false
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "member_id": {
                      "type": "string",
                      "description": "Membro."
                    },
                    "access_level": {
                      "type": "string",
                      "description": "Nível resultante."
                    },
                    "financeiro": {
                      "type": "boolean",
                      "description": "Permissão financeira resultante."
                    }
                  },
                  "required": [
                    "ok",
                    "member_id",
                    "access_level",
                    "financeiro"
                  ]
                },
                "example": {
                  "ok": true,
                  "member_id": "member-id-exemplo",
                  "access_level": "string",
                  "financeiro": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "members",
        "x-session-only": true,
        "description": "Altera o nível de acesso (criador, líder, admin) e/ou a permissão por pessoa `financeiro`, que libera o painel de Vendas. Informe ao menos um dos dois; as capabilities efetivas são recalculadas na próxima requisição. Evite elevar privilégios sem necessidade operacional.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request PATCH \\\n  --url 'https://socialmedia.janvalellam.com.br/api/membros' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"member_id\":\"member-id\",\"access_level\":\"lider\",\"financeiro\":false}'"
          }
        ]
      }
    },
    "/api/membros/{memberId}": {
      "delete": {
        "operationId": "deactivateMember",
        "tags": [
          "Members"
        ],
        "summary": "Revogar acesso e limpar atribuições atuais",
        "description": "Não exclui tarefas, conteúdos nem histórico. Preserva o usuário e o membro como âncoras de autoria/FKs; pode retornar 207 quando o acesso foi revogado, mas alguma limpeza precisa ser repetida.\n\nRevoga o login e remove apenas atribuições atuais. Conteúdos, tarefas e histórico permanecem preservados como registros de autoria.",
        "parameters": [
          {
            "$ref": "#/components/parameters/MemberId"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemberOffboardingResult"
                },
                "example": {
                  "ok": true,
                  "accessRevoked": true,
                  "alreadyInactive": true,
                  "retryable": true,
                  "member": {
                    "id": "id-exemplo",
                    "name": "Exemplo Hermes",
                    "email": "membro@example.com"
                  },
                  "summary": {
                    "events": 1,
                    "tasks": 1,
                    "comments": 1,
                    "platforms": 1,
                    "projects": 1,
                    "authBan": {}
                  },
                  "errors": [
                    {
                      "scope": "string",
                      "error": "string"
                    }
                  ]
                }
              }
            }
          },
          "207": {
            "description": "Acesso revogado; uma ou mais limpezas falharam e são repetíveis.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemberOffboardingResult"
                },
                "example": {
                  "ok": true,
                  "accessRevoked": true,
                  "alreadyInactive": true,
                  "retryable": true,
                  "member": {
                    "id": "id-exemplo",
                    "name": "Exemplo Hermes",
                    "email": "membro@example.com"
                  },
                  "summary": {
                    "events": 1,
                    "tasks": 1,
                    "comments": 1,
                    "platforms": 1,
                    "projects": 1,
                    "authBan": {}
                  },
                  "errors": [
                    {
                      "scope": "string",
                      "error": "string"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "members",
        "x-session-only": true,
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request DELETE \\\n  --url 'https://socialmedia.janvalellam.com.br/api/membros/memberid-exemplo' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>'"
          }
        ]
      }
    },
    "/api/membros/{memberId}/senha": {
      "post": {
        "operationId": "setMemberPassword",
        "tags": [
          "Members"
        ],
        "summary": "Definir senha nova para um membro",
        "description": "Para quem perdeu a senha e não consegue usar o e-mail de recuperação. A senha é escolhida pelo administrador, aplicada pelo Auth Admin e nunca é armazenada, logada ou devolvida. Não se aplica à própria conta (409).",
        "parameters": [
          {
            "$ref": "#/components/parameters/MemberId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "password": {
                    "type": "string",
                    "description": "Senha nova (8 a 72 caracteres).",
                    "minLength": 8,
                    "maxLength": 72,
                    "format": "password"
                  }
                },
                "required": [
                  "password"
                ]
              },
              "example": {
                "password": "********"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "member": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "ID do membro."
                        },
                        "name": {
                          "type": "string",
                          "description": "Nome."
                        },
                        "email": {
                          "anyOf": [
                            {
                              "type": "string",
                              "description": "E-mail.",
                              "format": "email"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        }
                      },
                      "required": [
                        "id",
                        "name"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "member"
                  ]
                },
                "example": {
                  "ok": true,
                  "member": {
                    "id": "id-exemplo",
                    "name": "Exemplo Hermes",
                    "email": "membro@example.com"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "members",
        "x-session-only": true,
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://socialmedia.janvalellam.com.br/api/membros/memberid-exemplo/senha' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"password\":\"********\"}'"
          }
        ]
      }
    },
    "/api/plataformas/{platformId}/senha": {
      "get": {
        "operationId": "getPlatformPassword",
        "tags": [
          "Platforms"
        ],
        "summary": "Ler a senha de uma plataforma",
        "x-cache-policy": "no-store",
        "parameters": [
          {
            "$ref": "#/components/parameters/PlatformId"
          }
        ],
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "senha": {
                      "anyOf": [
                        {
                          "type": "string",
                          "description": "Senha decifrada; null quando não há senha salva.",
                          "format": "password"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "senha"
                  ]
                },
                "example": {
                  "senha": "********"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "team_admin",
        "x-session-only": true,
        "description": "Exige sessão Supabase de administrador da equipe e nunca aceita token pessoal nem MCP. Decifra e devolve a senha de uma única plataforma de Gastos de Aplicativos; o banco guarda só a cifra. A auditoria da API registra quem pediu, qual plataforma e quando, sem o valor.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://socialmedia.janvalellam.com.br/api/plataformas/platformid-exemplo/senha' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>'"
          }
        ]
      },
      "put": {
        "operationId": "setPlatformPassword",
        "tags": [
          "Platforms"
        ],
        "summary": "Gravar ou apagar a senha de uma plataforma",
        "x-cache-policy": "no-store",
        "parameters": [
          {
            "$ref": "#/components/parameters/PlatformId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "senha": {
                    "anyOf": [
                      {
                        "type": "string",
                        "description": "Senha nova (até 500 caracteres); null ou vazio apaga a senha salva.",
                        "maxLength": 500,
                        "format": "password"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "senha"
                ]
              },
              "example": {
                "senha": "********"
              }
            }
          },
          "description": "Payload da operação. Envie somente os campos documentados e preserve os tipos indicados pelo schema."
        },
        "responses": {
          "200": {
            "description": "Operação concluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sucesso."
                    },
                    "has_password": {
                      "type": "boolean",
                      "description": "Se a plataforma ficou com senha salva."
                    }
                  },
                  "required": [
                    "ok",
                    "has_password"
                  ]
                },
                "example": {
                  "ok": true,
                  "has_password": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-required-capability": "team_admin",
        "x-session-only": true,
        "description": "Exige sessão Supabase de administrador da equipe. Cifra e grava a senha de uma plataforma (AES-256-GCM no servidor) ou apaga a senha salva com `senha: null`. A resposta nunca devolve o valor.",
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "cURL",
            "source": "curl --request PUT \\\n  --url 'https://socialmedia.janvalellam.com.br/api/plataformas/platformid-exemplo/senha' \\\n  --header 'Authorization: Bearer <supabase_session_access_token>' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\"senha\":\"********\"}'"
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Supabase JWT",
        "description": "Access token da sessão Supabase do colaborador ativo. Suas capabilities vêm exclusivamente do cargo `access_level` do Studio e não são limitadas por `api_access_level`. É o único método aceito por operações com `x-session-only: true`."
      },
      "sesToken": {
        "type": "apiKey",
        "in": "query",
        "name": "token",
        "description": "Segredo na URL da assinatura do SNS (JORNADA_SES_TOKEN), só para POST /api/jornada/ses. O SNS não envia cabeçalho próprio."
      },
      "jornadaToken": {
        "type": "apiKey",
        "in": "header",
        "name": "x-jornada-token",
        "description": "Segredo compartilhado entre os sites e a API, só para POST /api/jornada/eventos: checkout e páginas do Xamanismo (JORNADA_INGEST_TOKEN) e loja nova (JORNADA_INGEST_TOKEN_LOJA)."
      },
      "jornadaLeadToken": {
        "type": "apiKey",
        "in": "header",
        "name": "x-jornada-token",
        "description": "Token só de leitura do SiteUP CRM (JORNADA_LEAD_TOKEN), só para POST /api/jornada/lead."
      },
      "personalApiToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Hermes personal token (hms_live_)",
        "description": "Token pessoal de alta entropia com prefixo `hms_live_`. O servidor armazena somente SHA-256 e aplica a interseção entre scopes, `api_access_level` individual e cargo `access_level` atual do Studio. Essa configuração não afeta sessões Supabase."
      }
    },
    "parameters": {
      "Provider": {
        "name": "provider",
        "in": "path",
        "required": true,
        "description": "Provedor social potencialmente disponível no ambiente.",
        "schema": {
          "type": "string",
          "enum": [
            "meta",
            "pinterest",
            "tiktok",
            "youtube"
          ]
        }
      },
      "MediaId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "ID de media_assets.",
        "schema": {
          "type": "string"
        }
      },
      "ReelJobId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "ID da geração de Reel.",
        "schema": {
          "type": "string"
        }
      },
      "ProjetoId": {
        "name": "projetoId",
        "in": "path",
        "required": true,
        "description": "ID do projeto em hermes_projects.",
        "schema": {
          "type": "string"
        }
      },
      "MemberId": {
        "name": "memberId",
        "in": "path",
        "required": true,
        "description": "ID de team_members.",
        "schema": {
          "type": "string"
        }
      },
      "PlatformId": {
        "name": "platformId",
        "in": "path",
        "required": true,
        "description": "ID (UUID) da plataforma em Gastos de Aplicativos.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "ApiTokenId": {
        "name": "tokenId",
        "in": "path",
        "required": true,
        "description": "ID público de metadados do token pessoal; nunca é o segredo `hms_live_` nem seu hash.",
        "schema": {
          "type": "string"
        }
      },
      "ProjectId": {
        "name": "projectId",
        "in": "path",
        "required": true,
        "description": "ID de hermes_projects.",
        "schema": {
          "type": "string"
        }
      },
      "TemplateId": {
        "name": "templateId",
        "in": "path",
        "required": true,
        "description": "ID lógico seguro do template.",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9._:~-]+$",
          "maxLength": 200
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Chave opcional de 8 a 128 caracteres seguros. Repita a mesma chave somente com o mesmo payload; reutilização com conteúdo diferente retorna 409.",
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 128,
          "pattern": "^[A-Za-z0-9._:~-]+$"
        },
        "example": "docs-20260822-001"
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Entrada inválida.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "detalhe da validação"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Token ausente, inválido ou falha de autenticação.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "não autenticado"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Usuário fora da equipe ativa ou sem a capability necessária.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "sem permissão para: capability"
            }
          }
        }
      },
      "NotFound": {
        "description": "Recurso não encontrado.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "recurso não encontrado"
            }
          }
        }
      },
      "Conflict": {
        "description": "Operação conflita com o estado atual.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "conflito"
            }
          }
        }
      },
      "ServerError": {
        "description": "Falha interna ou de integração.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "detalhe da falha"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "Recurso não configurado neste servidor.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "painel de vendas não configurado neste servidor",
              "code": "VENDAS_NOT_CONFIGURED"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Mensagem segura para diagnóstico."
          },
          "code": {
            "type": "string",
            "description": "Código estável opcional."
          },
          "details": {
            "type": "object",
            "properties": {},
            "additionalProperties": true
          }
        },
        "required": [
          "error"
        ],
        "description": "Formato padrão de erro JSON. `code` e `details` aparecem quando existe um diagnóstico estável e acionável."
      },
      "OkResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Sucesso."
          }
        },
        "required": [
          "ok"
        ],
        "description": "Confirmação mínima de uma operação concluída."
      },
      "ApiAccessLevel": {
        "type": "string",
        "description": "Nível individual configurável somente para tokens pessoais da API; não limita sessões do Studio.",
        "enum": [
          "nenhum",
          "leitor",
          "criador",
          "lider",
          "admin"
        ]
      },
      "AuthContext": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "description": "Método que autenticou a chamada.",
            "enum": [
              "session",
              "api_token"
            ]
          },
          "token_id": {
            "anyOf": [
              {
                "type": "string",
                "description": "ID do token pessoal quando kind é api_token."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "kind",
          "token_id"
        ],
        "description": "Método efetivamente usado para autenticar a requisição atual."
      },
      "MemberIdentity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID do membro."
          },
          "user_id": {
            "type": "string",
            "description": "ID do usuário Supabase vinculado."
          },
          "name": {
            "type": "string",
            "description": "Nome."
          },
          "email": {
            "anyOf": [
              {
                "type": "string",
                "description": "E-mail do membro.",
                "format": "email"
              },
              {
                "type": "null"
              }
            ]
          },
          "access_level": {
            "$ref": "#/components/schemas/ApiAccessLevel",
            "description": "Nível desta credencial: cargo do Studio para session; nível PAT efetivo para api_token."
          },
          "team_access_level": {
            "type": "string",
            "description": "Cargo atual no Studio; governa a sessão e serve de teto somente para PAT.",
            "enum": [
              "criador",
              "lider",
              "admin"
            ]
          },
          "api_access_level": {
            "$ref": "#/components/schemas/ApiAccessLevel",
            "description": "Configuração de PAT na sessão; nível PAT efetivo quando auth.kind é api_token."
          }
        },
        "required": [
          "id",
          "name",
          "access_level",
          "team_access_level",
          "api_access_level"
        ],
        "description": "Identidade e autorização da credencial atual: cargo do Studio para sessão ou nível efetivo para PAT."
      },
      "Member": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID."
          },
          "name": {
            "type": "string",
            "description": "Nome."
          },
          "email": {
            "type": "string",
            "description": "E-mail.",
            "format": "email"
          },
          "role": {
            "anyOf": [
              {
                "type": "string",
                "description": "Função."
              },
              {
                "type": "null"
              }
            ]
          },
          "access_level": {
            "type": "string",
            "description": "Cargo no Studio.",
            "enum": [
              "criador",
              "lider",
              "admin"
            ]
          },
          "api_access_level": {
            "$ref": "#/components/schemas/ApiAccessLevel"
          },
          "is_admin": {
            "type": "boolean",
            "description": "Compatibilidade com legado."
          },
          "financeiro": {
            "type": "boolean",
            "description": "Permissão por pessoa: vê o painel de Vendas (capability `vendas`)."
          }
        },
        "required": [
          "id",
          "name",
          "email",
          "access_level"
        ],
        "description": "Membro ativo que pode receber atribuições e capabilities."
      },
      "ApiAccessSelfMember": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID do membro."
          },
          "name": {
            "type": "string",
            "description": "Nome."
          },
          "email": {
            "anyOf": [
              {
                "type": "string",
                "description": "E-mail.",
                "format": "email"
              },
              {
                "type": "null"
              }
            ]
          },
          "access_level": {
            "type": "string",
            "description": "Cargo atual no Studio; governa a sessão e funciona como teto do PAT.",
            "enum": [
              "criador",
              "lider",
              "admin"
            ]
          },
          "financeiro": {
            "type": "boolean",
            "description": "Permissão por pessoa: vê o painel de Vendas."
          },
          "api_access_level": {
            "$ref": "#/components/schemas/ApiAccessLevel"
          },
          "effective_api_access_level": {
            "$ref": "#/components/schemas/ApiAccessLevel"
          }
        },
        "required": [
          "id",
          "name",
          "access_level",
          "api_access_level",
          "effective_api_access_level"
        ],
        "description": "Resumo da configuração de tokens pessoais do membro; não limita a sessão atual do Studio."
      },
      "PersonalApiTokenMetadata": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID público usado para revogação."
          },
          "label": {
            "type": "string",
            "description": "Nome legível definido pelo usuário."
          },
          "prefix": {
            "type": "string",
            "description": "Prefixo identificável sem a parte secreta.",
            "pattern": "^hms_live_[A-Za-z0-9_-]{16}$"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Capability concedida ao token."
            },
            "description": "Scopes persistidos em ordem determinística."
          },
          "created_at": {
            "type": "string",
            "description": "Criação ISO.",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "description": "Expiração ISO.",
            "format": "date-time"
          },
          "last_used_at": {
            "anyOf": [
              {
                "type": "string",
                "description": "Último uso observado, atualizado de forma best effort.",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "revoked_at": {
            "anyOf": [
              {
                "type": "string",
                "description": "Revogação ISO, quando aplicável.",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "type": "string",
            "description": "Estado derivado no momento da leitura.",
            "enum": [
              "active",
              "expired",
              "revoked"
            ]
          }
        },
        "required": [
          "id",
          "label",
          "prefix",
          "scopes",
          "created_at",
          "expires_at",
          "last_used_at",
          "revoked_at",
          "status"
        ],
        "description": "Metadados revogáveis de um token pessoal sem segredo nem hash."
      },
      "ApiAccessMember": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID do membro."
          },
          "name": {
            "type": "string",
            "description": "Nome."
          },
          "email": {
            "anyOf": [
              {
                "type": "string",
                "description": "E-mail.",
                "format": "email"
              },
              {
                "type": "null"
              }
            ]
          },
          "access_level": {
            "type": "string",
            "description": "Cargo atual no Studio; governa sessões e funciona como teto do PAT.",
            "enum": [
              "criador",
              "lider",
              "admin"
            ]
          },
          "api_access_level": {
            "$ref": "#/components/schemas/ApiAccessLevel"
          },
          "effective_api_access_level": {
            "$ref": "#/components/schemas/ApiAccessLevel"
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Capability efetiva disponível para tokens pessoais; não descreve nem limita a sessão do Studio."
            }
          },
          "token_count": {
            "type": "integer",
            "description": "Quantidade de tokens ativos.",
            "minimum": 0,
            "maximum": 10
          },
          "tokens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PersonalApiTokenMetadata"
            }
          }
        },
        "required": [
          "id",
          "name",
          "access_level",
          "api_access_level",
          "effective_api_access_level",
          "capabilities",
          "token_count",
          "tokens"
        ],
        "description": "Visão administrativa do cargo do Studio e da camada separada de tokens pessoais de um membro ativo."
      },
      "ApiAuditEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID do evento de auditoria."
          },
          "occurred_at": {
            "type": "string",
            "description": "Data/hora do evento.",
            "format": "date-time"
          },
          "request_id": {
            "anyOf": [
              {
                "type": "string",
                "description": "Correlação segura da requisição."
              },
              {
                "type": "null"
              }
            ]
          },
          "actor_member_id": {
            "anyOf": [
              {
                "type": "string",
                "description": "Membro autor."
              },
              {
                "type": "null"
              }
            ]
          },
          "actor_user_id": {
            "anyOf": [
              {
                "type": "string",
                "description": "Usuário Supabase autor."
              },
              {
                "type": "null"
              }
            ]
          },
          "token_id": {
            "anyOf": [
              {
                "type": "string",
                "description": "ID de metadados do token pessoal, nunca o segredo ou hash."
              },
              {
                "type": "null"
              }
            ]
          },
          "auth_method": {
            "type": "string",
            "description": "Método de autenticação observado.",
            "enum": [
              "session",
              "personal_token",
              "system",
              "anonymous"
            ]
          },
          "capability": {
            "anyOf": [
              {
                "type": "string",
                "description": "Capability avaliada."
              },
              {
                "type": "null"
              }
            ]
          },
          "action": {
            "type": "string",
            "description": "Ação normalizada."
          },
          "resource_type": {
            "anyOf": [
              {
                "type": "string",
                "description": "Tipo lógico do recurso."
              },
              {
                "type": "null"
              }
            ]
          },
          "resource_id": {
            "anyOf": [
              {
                "type": "string",
                "description": "ID lógico do recurso."
              },
              {
                "type": "null"
              }
            ]
          },
          "outcome": {
            "type": "string",
            "description": "Resultado normalizado.",
            "enum": [
              "allowed",
              "denied",
              "succeeded",
              "failed"
            ]
          },
          "status_code": {
            "anyOf": [
              {
                "type": "integer",
                "description": "Status HTTP relacionado.",
                "minimum": 100,
                "maximum": 599
              },
              {
                "type": "null"
              }
            ]
          },
          "metadata": {
            "type": "object",
            "properties": {},
            "additionalProperties": true
          }
        },
        "required": [
          "id",
          "occurred_at",
          "auth_method",
          "action",
          "outcome",
          "metadata"
        ],
        "description": "Evento sanitizado da trilha de autorização e gestão de acesso à API."
      },
      "ConfigEntry": {
        "type": "object",
        "properties": {
          "value": {},
          "version": {
            "type": "integer",
            "description": "Versão."
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string",
                "description": "Atualização ISO.",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "value",
          "version"
        ],
        "description": "Versão mais recente de uma configuração."
      },
      "Skill": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Nome."
          },
          "content": {
            "type": "string",
            "description": "Conteúdo."
          },
          "version": {
            "type": "integer",
            "description": "Versão."
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string",
                "description": "Atualização ISO.",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "name",
          "content",
          "version"
        ],
        "description": "Conteúdo versionado de uma skill publicada no backend."
      },
      "RagResponse": {
        "type": "object",
        "properties": {
          "contexto": {
            "type": "string",
            "description": "Contexto consolidado."
          },
          "fontes": {
            "anyOf": [
              {},
              {
                "type": "null"
              }
            ]
          },
          "resultados": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "titulo": {
                  "anyOf": [
                    {
                      "type": "string",
                      "description": "Título."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "fonte": {
                  "anyOf": [
                    {
                      "type": "string",
                      "description": "Fonte."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "texto": {
                  "type": "string",
                  "description": "Trecho."
                },
                "citacao": {
                  "type": "object",
                  "properties": {
                    "pagina": {
                      "type": "integer",
                      "description": "Página detectada."
                    }
                  },
                  "additionalProperties": false
                }
              },
              "required": [
                "texto",
                "citacao"
              ]
            }
          }
        },
        "required": [
          "contexto",
          "resultados"
        ],
        "description": "Contexto e evidências retornados pela pesquisa no Cérebro."
      },
      "MediaReference": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID."
          },
          "url": {
            "type": "string",
            "description": "URL pública no Hermes.",
            "format": "uri"
          },
          "slide_index": {
            "type": "integer",
            "description": "Ordem."
          },
          "kind": {
            "type": "string",
            "description": "Tipo lógico."
          }
        },
        "required": [
          "id",
          "url"
        ],
        "additionalProperties": true,
        "description": "Referência pública e ordenável de uma mídia persistida."
      },
      "StoredMedia": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID."
          },
          "url": {
            "type": "string",
            "description": "URL pública.",
            "format": "uri"
          },
          "storage_path": {
            "type": "string",
            "description": "Caminho interno sem credenciais."
          }
        },
        "required": [
          "id",
          "url",
          "storage_path"
        ],
        "description": "Resultado de mídia gerada e armazenada pelo Hermes."
      },
      "UploadedMedia": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID."
          },
          "url": {
            "type": "string",
            "description": "URL pública.",
            "format": "uri"
          },
          "kind": {
            "type": "string",
            "description": "Tipo lógico."
          },
          "bytes": {
            "type": "integer",
            "description": "Tamanho recebido.",
            "minimum": 1
          }
        },
        "required": [
          "id",
          "url",
          "kind",
          "bytes"
        ],
        "description": "Resultado de um upload binário concluído."
      },
      "ReelJobAccepted": {
        "type": "object",
        "properties": {
          "job_id": {
            "type": "string",
            "description": "ID do job."
          },
          "state": {
            "type": "string",
            "description": "Estado.",
            "const": "processing"
          },
          "aviso": {
            "type": "string",
            "description": "Orientação de polling."
          }
        },
        "required": [
          "job_id",
          "state",
          "aviso"
        ],
        "description": "Confirmação de que a geração assíncrona de vídeo entrou na fila."
      },
      "ReelJob": {
        "type": "object",
        "properties": {
          "state": {
            "type": "string",
            "description": "Estado."
          },
          "error": {
            "anyOf": [
              {
                "type": "string",
                "description": "Erro do worker."
              },
              {
                "type": "null"
              }
            ]
          },
          "url": {
            "type": "string",
            "description": "URL quando concluído.",
            "format": "uri"
          }
        },
        "required": [
          "state"
        ],
        "description": "Estado observável de uma geração de vídeo."
      },
      "Event": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador do evento."
          },
          "api_revision": {
            "type": "integer",
            "description": "Token CAS da API; releia o evento antes de toda mutação.",
            "minimum": 0
          },
          "clickup_id": {
            "anyOf": [
              {
                "type": "string",
                "description": "Identificador externo/legado."
              },
              {
                "type": "null"
              }
            ]
          },
          "title": {
            "type": "string",
            "description": "Título editorial."
          },
          "channel": {
            "type": "string",
            "description": "Canal de publicação."
          },
          "status": {
            "type": "string",
            "description": "Estado do fluxo editorial."
          },
          "description": {
            "anyOf": [
              {
                "type": "string",
                "description": "Legenda ou descrição."
              },
              {
                "type": "null"
              }
            ]
          },
          "day": {
            "anyOf": [
              {
                "type": "integer",
                "description": "Dia no horário de Brasília.",
                "minimum": 1,
                "maximum": 31
              },
              {
                "type": "null"
              }
            ]
          },
          "month": {
            "anyOf": [
              {
                "type": "integer",
                "description": "Mês no horário de Brasília.",
                "minimum": 1,
                "maximum": 12
              },
              {
                "type": "null"
              }
            ]
          },
          "year": {
            "anyOf": [
              {
                "type": "integer",
                "description": "Ano no horário de Brasília."
              },
              {
                "type": "null"
              }
            ]
          },
          "due_at": {
            "anyOf": [
              {
                "type": "string",
                "description": "Data/hora ISO 8601 persistida.",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "editorial_tag": {
            "anyOf": [
              {
                "type": "string",
                "description": "Tipo/tag editorial."
              },
              {
                "type": "null"
              }
            ]
          },
          "assignee_member_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "ID de membro."
            },
            "description": "Responsáveis por ID."
          },
          "assignees_names": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Nome de membro."
            },
            "description": "Nomes dos responsáveis."
          }
        },
        "required": [
          "id",
          "title",
          "channel",
          "status"
        ],
        "additionalProperties": true,
        "description": "Evento editorial do calendário com token de revisão CAS."
      },
      "Project": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID do projeto."
          },
          "name": {
            "type": "string",
            "description": "Nome."
          },
          "payload": {
            "type": "object",
            "properties": {},
            "additionalProperties": true
          },
          "api_revision": {
            "type": "integer",
            "description": "Token CAS canônico.",
            "minimum": 0
          },
          "revision": {
            "type": "integer",
            "description": "Alias de api_revision.",
            "minimum": 0
          },
          "created_at": {
            "type": "string",
            "description": "Criação ISO.",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "description": "Atualização ISO.",
            "format": "date-time"
          },
          "created_by": {
            "type": "string",
            "description": "Usuário criador."
          },
          "updated_by": {
            "type": "string",
            "description": "Último usuário editor."
          }
        },
        "required": [
          "id",
          "name",
          "payload",
          "api_revision",
          "revision",
          "created_at",
          "updated_at",
          "created_by",
          "updated_by"
        ],
        "description": "Documento colaborativo de projeto e seus tokens de concorrência."
      },
      "ProjectOperationRequest": {
        "type": "object",
        "properties": {
          "expected_revision": {
            "type": "integer",
            "description": "api_revision da leitura mais recente.",
            "minimum": 0
          },
          "expected_updated_at": {
            "type": "string",
            "description": "Token timestamp adicional opcional.",
            "format": "date-time"
          },
          "operation": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "description": "Tipo semântico da operação.",
                "enum": [
                  "meta.update",
                  "goal.add",
                  "goal.update",
                  "goal.remove",
                  "goal.reorder",
                  "task.add",
                  "task.update",
                  "task.remove",
                  "task.reorder",
                  "task.assignees.set",
                  "subtask.add",
                  "subtask.update",
                  "subtask.remove",
                  "subtask.reorder",
                  "subtask.assignees.set",
                  "comment.add",
                  "comment.update",
                  "comment.remove"
                ]
              }
            },
            "required": [
              "type"
            ],
            "additionalProperties": true
          }
        },
        "required": [
          "expected_revision",
          "operation"
        ],
        "description": "Envelope de uma alteração semântica e atômica de projeto."
      },
      "ProjectOperationLog": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID da operação."
          },
          "payload_revision": {
            "type": "integer",
            "description": "Revisão produzida.",
            "minimum": 0
          },
          "operation_type": {
            "type": "string",
            "description": "Tipo."
          },
          "operation": {
            "type": "object",
            "properties": {},
            "additionalProperties": true
          },
          "actor_member_id": {
            "type": "string",
            "description": "Membro autor."
          },
          "actor_user_id": {
            "type": "string",
            "description": "Usuário autor."
          },
          "created_at": {
            "type": "string",
            "description": "Data ISO.",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "payload_revision",
          "operation_type",
          "operation",
          "created_at"
        ],
        "description": "Registro imutável de uma operação já aplicada ao projeto."
      },
      "EmailDraftSummary": {
        "type": "object",
        "properties": {
          "template_id": {
            "type": "string",
            "description": "ID lógico do template."
          },
          "metadata": {
            "type": "object",
            "properties": {},
            "additionalProperties": true
          },
          "updated_at": {
            "type": "string",
            "description": "Token CAS.",
            "format": "date-time"
          },
          "updated_by": {
            "type": "string",
            "description": "Usuário editor."
          }
        },
        "required": [
          "template_id",
          "metadata",
          "updated_at",
          "updated_by"
        ],
        "description": "Metadados leves de um rascunho, sem o HTML completo."
      },
      "EmailDraft": {
        "type": "object",
        "properties": {
          "template_id": {
            "type": "string",
            "description": "ID lógico do template."
          },
          "html": {
            "type": "string",
            "description": "HTML completo."
          },
          "metadata": {
            "type": "object",
            "properties": {},
            "additionalProperties": true
          },
          "updated_at": {
            "type": "string",
            "description": "Token CAS.",
            "format": "date-time"
          },
          "updated_by": {
            "type": "string",
            "description": "Usuário editor."
          }
        },
        "required": [
          "template_id",
          "html",
          "metadata",
          "updated_at",
          "updated_by"
        ],
        "description": "Template de e-mail completo com token CAS baseado em timestamp."
      },
      "AiManifest": {
        "type": "object",
        "properties": {
          "schema_version": {
            "type": "integer",
            "description": "Versão do formato.",
            "const": 1
          },
          "release": {
            "type": "object",
            "properties": {
              "version": {
                "type": "string",
                "description": "Versão da camada de IA."
              },
              "date": {
                "type": "string",
                "description": "Data ISO.",
                "format": "date"
              }
            },
            "required": [
              "version",
              "date"
            ]
          },
          "artifacts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "ID estável."
                },
                "path": {
                  "type": "string",
                  "description": "Caminho no repositório."
                },
                "url": {
                  "type": "string",
                  "description": "URL pública.",
                  "format": "uri"
                },
                "media_type": {
                  "type": "string",
                  "description": "MIME."
                },
                "bytes": {
                  "type": "integer",
                  "description": "Tamanho.",
                  "minimum": 1
                },
                "sha256": {
                  "type": "string",
                  "description": "SHA-256 hexadecimal.",
                  "pattern": "^[a-f0-9]{64}$"
                }
              },
              "required": [
                "id",
                "path",
                "url",
                "media_type",
                "bytes",
                "sha256"
              ]
            }
          },
          "skills": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Nome da skill."
                },
                "version": {
                  "type": "string",
                  "description": "Versão."
                },
                "artifact_id": {
                  "type": "string",
                  "description": "ID do ZIP."
                },
                "sha256": {
                  "type": "string",
                  "description": "SHA-256 do ZIP."
                }
              },
              "required": [
                "name",
                "version",
                "artifact_id",
                "sha256"
              ]
            }
          }
        },
        "required": [
          "schema_version",
          "release",
          "artifacts",
          "skills"
        ],
        "description": "Catálogo verificável dos artefatos públicos da camada de IA."
      },
      "MemberOffboardingResult": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Todas as limpezas terminaram."
          },
          "accessRevoked": {
            "type": "boolean",
            "description": "Acesso revogado."
          },
          "alreadyInactive": {
            "type": "boolean",
            "description": "Já estava inativo."
          },
          "retryable": {
            "type": "boolean",
            "description": "Uma repetição é segura."
          },
          "member": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "ID."
              },
              "name": {
                "type": "string",
                "description": "Nome."
              },
              "email": {
                "type": "string",
                "description": "E-mail.",
                "format": "email"
              }
            },
            "required": [
              "id",
              "name",
              "email"
            ]
          },
          "summary": {
            "type": "object",
            "properties": {
              "events": {
                "type": "integer",
                "description": "Eventos alterados."
              },
              "tasks": {
                "type": "integer",
                "description": "Tarefas desatribuídas."
              },
              "comments": {
                "type": "integer",
                "description": "Comentários alterados."
              },
              "platforms": {
                "type": "integer",
                "description": "Plataformas alteradas."
              },
              "projects": {
                "type": "integer",
                "description": "Projetos alterados."
              },
              "authBan": {
                "type": "object",
                "properties": {},
                "additionalProperties": true
              }
            },
            "required": [
              "events",
              "tasks",
              "comments",
              "platforms",
              "projects",
              "authBan"
            ]
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "scope": {
                  "type": "string",
                  "description": "Escopo."
                },
                "error": {
                  "type": "string",
                  "description": "Erro."
                }
              },
              "required": [
                "scope",
                "error"
              ]
            }
          }
        },
        "required": [
          "ok",
          "accessRevoked",
          "alreadyInactive",
          "retryable",
          "member",
          "summary",
          "errors"
        ],
        "description": "Relatório do desligamento seguro e das limpezas de atribuição."
      }
    }
  }
}
