{
  "openapi": "3.1.0",
  "info": {
    "title": "Perpetuus API",
    "version": "1.0",
    "summary": "API REST oficial do Perpetuus CRM",
    "description": "A **Perpetuus API** dá acesso programático a tudo que você vê no CRM: boards,\ncards, contatos, segmentos, campanhas, tarefas, orçamentos e mais.\n\n## Base URL\n\n```\nhttps://api.perpetuus.com.br/api\n```\n\n## Leve para a IDE\n\nBaixe o contrato OpenAPI, a documentação completa e o JSON do MCP em\n[Leve para a IDE](/docs/api/para-ide).\n\n## Autenticação\n\nToda requisição (exceto login e formulários públicos) exige **dois headers**:\n\n| Header | Valor | Descrição |\n|--------|-------|-----------|\n| `Authorization` | `Bearer SEU_TOKEN` | Token de API ou JWT de sessão |\n| `x-tenant-id` | `slug-da-organizacao` | Identifica a sua organização (ex.: `acme`) |\n\nSem `x-tenant-id` a API responde `400`; sem token válido, `401`; sem permissão, `403`.\n\n## Identificadores\n\nUse sempre o **documentId** (string) dos recursos nas URLs — nunca o `id` numérico interno.\n\n## Envelopes de resposta\n\n- **Listas paginadas** (cards, contatos, boards): `{ \"data\": [...], \"meta\": { \"pagination\": {...} } }`\n- **Objeto único** (get/create/update de board, card e contato): o objeto **direto**, sem envelope\n- **Relatórios**: objeto flat próprio (ver `GET /boards/{boardId}/report`)\n",
    "contact": {
      "name": "Suporte Perpetuus",
      "url": "https://perpetuus.com.br",
      "email": "luis.santos@perpetuus.com.br"
    },
    "x-logo": {
      "url": "/logo.svg"
    }
  },
  "servers": [
    {
      "url": "https://api.perpetuus.com.br/api",
      "description": "Produção"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Autenticação",
      "description": "Login e geração de tokens de API."
    },
    {
      "name": "Boards",
      "description": "Funis/quadros do CRM. Um board tem fases, campos, tags e cards."
    },
    {
      "name": "Membros do board",
      "description": "Gestão de quem vê e edita cada board."
    },
    {
      "name": "Cards",
      "description": "Oportunidades/negócios dentro de um board. Sempre acessados via rota nested `/boards/{boardId}/cards`."
    },
    {
      "name": "Cards vinculados",
      "description": "Vínculos entre cards de boards diferentes (ex. venda → onboarding)."
    },
    {
      "name": "Fases",
      "description": "Colunas do board. A Fase 0 é o formulário de entrada."
    },
    {
      "name": "Campos",
      "description": "Campos dinâmicos configuráveis por fase (texto, e-mail, moeda, select…)."
    },
    {
      "name": "Condições de campo",
      "description": "Regras que exibem/ocultam campos conforme valores de outros campos."
    },
    {
      "name": "Tags",
      "description": "Etiquetas de card, escopadas por board."
    },
    {
      "name": "Relatórios",
      "description": "Analytics agregados do funil (conversão, ganhos/perdas, breakdown por fase)."
    },
    {
      "name": "Formulário público",
      "description": "Endpoints públicos (sem autenticação) para captura de leads via formulário da Fase 0."
    },
    {
      "name": "Contatos",
      "description": "Pessoas e empresas. Suporta campos customizados e operações em massa."
    },
    {
      "name": "Atividades de contato",
      "description": "Timeline de eventos do contato (notas, cards criados, e-mails enviados…)."
    },
    {
      "name": "Segmentos",
      "description": "Audiências dinâmicas de contatos definidas por regras de filtro."
    },
    {
      "name": "Campanhas",
      "description": "Disparos em massa (WhatsApp/e-mail) para segmentos, com estatísticas de entrega."
    },
    {
      "name": "Tarefas",
      "description": "Lembretes e follow-ups vinculados a cards e boards."
    },
    {
      "name": "Comentários",
      "description": "Comentários em cards, com suporte a menções."
    },
    {
      "name": "Orçamentos",
      "description": "Propostas comerciais (quotes) com itens, produtos e geração de PDF."
    },
    {
      "name": "Produtos",
      "description": "Catálogo de produtos e categorias."
    },
    {
      "name": "Times",
      "description": "Times comerciais para roteamento e escopo de carteira."
    },
    {
      "name": "Modelos de PDF",
      "description": "Templates de PDF usados em orçamentos e documentos."
    },
    {
      "name": "Automações",
      "description": "**BETA.** Workflows do CRM (triggers, ações, publish, runs). Contratos podem mudar;\npublish/test têm efeitos colaterais.\n"
    },
    {
      "name": "Canais",
      "description": "**BETA.** Canais de mensagem (WhatsApp, e-mail, etc.), templates e vínculo com boards.\nOperações de template alteram o provedor externo.\n"
    },
    {
      "name": "Meta Lead Ads",
      "description": "**BETA.** Integrações Lead Ads, OAuth e roteamento de formulários para boards.\nTokens e webhooks são sensíveis.\n"
    },
    {
      "name": "E-mail marketing",
      "description": "**BETA.** Templates e assets de e-mail. `send-test` envia mensagem real.\n"
    },
    {
      "name": "Distribuição",
      "description": "**BETA.** Filas de distribuição automática de cards entre membros.\n"
    },
    {
      "name": "Filtros salvos",
      "description": "**BETA.** Filtros salvos de board (pessoais ou compartilhados).\n"
    },
    {
      "name": "Conversões",
      "description": "**BETA.** Pixels / CAPI (Meta, GA4). Create/verify chamam APIs externas.\n"
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Token de API (recomendado para integrações) ou JWT de sessão.\nGere o seu em **Configurações → Organização → aba API** ou via\n`POST /users/generate-token`.\n"
      }
    },
    "parameters": {
      "TenantHeader": {
        "name": "x-tenant-id",
        "in": "header",
        "required": true,
        "description": "Slug da sua organização (ex.:`acme`). Visível na URL do app e em Configurações.",
        "schema": {
          "type": "string",
          "example": "acme"
        }
      },
      "PaginationPage": {
        "name": "pagination[page]",
        "in": "query",
        "description": "Página (começa em 1).",
        "schema": {
          "type": "integer",
          "default": 1,
          "minimum": 1
        }
      },
      "PaginationPageSize": {
        "name": "pagination[pageSize]",
        "in": "query",
        "description": "Itens por página. Máximo **100**.",
        "schema": {
          "type": "integer",
          "default": 25,
          "minimum": 1,
          "maximum": 100
        }
      },
      "Sort": {
        "name": "sort",
        "in": "query",
        "description": "Ordenação no formato `campo:asc|desc` (ex.: `updatedAt:desc`).",
        "schema": {
          "type": "string",
          "example": "updatedAt:desc"
        }
      },
      "Populate": {
        "name": "populate",
        "in": "query",
        "description": "Relações a incluir na resposta. Aceita notação de array:\n`populate[0]=assignees&populate[1]=tags`.\n",
        "schema": {
          "type": "string"
        },
        "style": "form",
        "explode": true
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Envelope padrão de erro.",
        "properties": {
          "data": {
            "type": "null"
          },
          "error": {
            "type": "object",
            "properties": {
              "status": {
                "type": "integer",
                "example": 400
              },
              "name": {
                "type": "string",
                "example": "BadRequestError"
              },
              "message": {
                "type": "string",
                "example": "Header x-tenant-id é obrigatório"
              },
              "details": {
                "type": "object",
                "description": "Detalhes adicionais (ex. erros de validação por campo)."
              }
            }
          }
        }
      },
      "Pagination": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "example": 1
          },
          "pageSize": {
            "type": "integer",
            "example": 25
          },
          "pageCount": {
            "type": "integer",
            "example": 4
          },
          "total": {
            "type": "integer",
            "example": 87
          }
        }
      },
      "CardStats": {
        "type": "object",
        "description": "Estatísticas agregadas da listagem de cards (presente por padrão; desligue com `stats=false`).",
        "properties": {
          "overdueCount": {
            "type": "integer",
            "description": "Cards com `dueDate` anterior ao início do dia (UTC, ou `statsTodayStart` se enviado).",
            "example": 3
          },
          "valueSum": {
            "type": "number",
            "description": "Soma de `value` de todos os cards que casam com o filtro (não só a página atual).",
            "example": 125000.5
          },
          "phaseSlaBreachedCount": {
            "type": "integer",
            "description": "Cards que estouraram o SLA da fase. Só é calculado quando o filtro fixa uma `currentPhase` com SLA configurado; caso contrário é `0`.",
            "example": 1
          }
        }
      },
      "UserRef": {
        "type": "object",
        "properties": {
          "username": {
            "type": "string",
            "example": "luis"
          },
          "email": {
            "type": "string",
            "example": "luis@acme.com"
          },
          "blocked": {
            "type": "boolean",
            "example": false
          }
        }
      },
      "MembershipRef": {
        "type": "object",
        "description": "Membro da organização (membership). Use o `documentId` em `assignees`, `owner` etc.",
        "properties": {
          "documentId": {
            "type": "string",
            "example": "mb1a2b3c"
          },
          "user": {
            "$ref": "#/components/schemas/UserRef"
          }
        }
      },
      "Tag": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string",
            "example": "tg1a2b3c"
          },
          "name": {
            "type": "string",
            "example": "VIP"
          },
          "slug": {
            "type": "string",
            "example": "vip"
          },
          "color": {
            "type": "string",
            "description": "Cor em hex (`#RGB` ou `#RRGGBB`).",
            "example": "#3b82f6"
          }
        }
      },
      "FieldDefinition": {
        "type": "object",
        "description": "Definição de um campo dinâmico de fase.",
        "properties": {
          "documentId": {
            "type": "string",
            "example": "fl1a2b3c"
          },
          "label": {
            "type": "string",
            "example": "E-mail"
          },
          "slug": {
            "type": "string",
            "description": "Identificador usado como chave em `fields` na escrita/leitura de cards.",
            "example": "email"
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "textarea",
              "richtext",
              "email",
              "number",
              "date",
              "datetime",
              "select",
              "multiselect",
              "radio",
              "switch",
              "file",
              "url",
              "phone",
              "card_link",
              "hidden",
              "statement",
              "time",
              "currency",
              "document",
              "checkbox"
            ],
            "example": "email"
          },
          "order": {
            "type": "integer",
            "example": 1
          },
          "required": {
            "type": "boolean",
            "example": true
          },
          "placeholder": {
            "type": "string"
          },
          "helpText": {
            "type": "string"
          },
          "defaultValue": {
            "type": "string"
          },
          "options": {
            "description": "Opções para `select`, `multiselect` e `radio`. Array de strings ou de `{ value, label }`.",
            "type": "array",
            "items": {}
          }
        }
      },
      "AllowedTransition": {
        "type": "object",
        "description": "Transição permitida entre fases (aplicada na interface Kanban).",
        "properties": {
          "phase": {
            "type": "object",
            "properties": {
              "documentId": {
                "type": "string"
              }
            }
          },
          "allowed": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "Phase": {
        "type": "object",
        "description": "Fase (coluna) de um board. A fase de `order` 0 é o formulário de entrada.",
        "properties": {
          "documentId": {
            "type": "string",
            "example": "ph1a2b3c"
          },
          "name": {
            "type": "string",
            "example": "Qualificação"
          },
          "slug": {
            "type": "string",
            "example": "qualificacao"
          },
          "order": {
            "type": "integer",
            "minimum": 0,
            "example": 2
          },
          "isPublic": {
            "type": "boolean",
            "description": "Fases `order` 0 são sempre públicas (formulário)."
          },
          "description": {
            "type": "string"
          },
          "maxTimeInPhaseHours": {
            "type": [
              "integer",
              "null"
            ],
            "description": "SLA da fase em horas (1–8760). `null` = sem SLA.",
            "example": 48
          },
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FieldDefinition"
            }
          },
          "allowedTransitions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AllowedTransition"
            }
          }
        }
      },
      "BoardSettings": {
        "type": "object",
        "description": "Configurações do board.",
        "properties": {
          "showValue": {
            "type": "boolean",
            "description": "Exibe/calcula valores monetários dos cards."
          },
          "currency": {
            "type": "string",
            "example": "BRL"
          },
          "wonPhase": {
            "type": [
              "string",
              "null"
            ],
            "description": "documentId ou slug da fase de \"ganho\"."
          },
          "lostPhase": {
            "type": [
              "string",
              "null"
            ],
            "description": "documentId ou slug da fase de \"perda\"."
          },
          "restrictEditToAssignees": {
            "type": "boolean"
          },
          "restrictViewToAssignees": {
            "type": "boolean"
          },
          "enableProducts": {
            "type": "boolean"
          },
          "autoUpdateCardValue": {
            "type": "boolean"
          },
          "autoUpdateDueDateFromPhase": {
            "type": "boolean"
          }
        }
      },
      "Board": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string",
            "example": "bd1a2b3c"
          },
          "name": {
            "type": "string",
            "example": "Funil de Vendas"
          },
          "slug": {
            "type": "string",
            "example": "funil-de-vendas"
          },
          "active": {
            "type": "boolean"
          },
          "boardType": {
            "type": "string",
            "enum": [
              "kanban",
              "chat",
              "hybrid"
            ],
            "default": "kanban"
          },
          "icon": {
            "type": "string",
            "example": "layout-grid"
          },
          "color": {
            "type": "string"
          },
          "template": {
            "type": "string",
            "example": "minimal-workflow"
          },
          "taskStatuses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "pending",
              "in-progress",
              "completed"
            ]
          },
          "boardSettings": {
            "$ref": "#/components/schemas/BoardSettings"
          },
          "phases": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Phase"
            }
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Tag"
            }
          },
          "owner": {
            "$ref": "#/components/schemas/MembershipRef"
          },
          "members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MembershipRef"
            }
          },
          "editors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MembershipRef"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ContactRef": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string",
            "example": "ct1a2b3c"
          },
          "name": {
            "type": "string",
            "example": "João Silva"
          },
          "email": {
            "type": "string",
            "example": "joao@cliente.com"
          },
          "phone": {
            "type": "string",
            "example": "+5511999999999"
          }
        }
      },
      "FieldDataItem": {
        "type": "object",
        "description": "Item cru de `fieldData[]` — detalhe avançado por fase. O storage interno de\nvalores escalares usa `{ \"val\": <valor> }`. Para a maioria dos casos, prefira\no mapa achatado `fields`.\n",
        "properties": {
          "documentId": {
            "type": "string"
          },
          "value": {
            "description": "Valor armazenado. Escalares vêm embrulhados: `{ \"val\": \"joao@x.com\" }`.",
            "type": "object"
          },
          "field": {
            "$ref": "#/components/schemas/FieldDefinition"
          },
          "phase": {
            "type": "object",
            "properties": {
              "documentId": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          }
        }
      },
      "Card": {
        "type": "object",
        "description": "Card (oportunidade/negócio). Nas respostas, além de `fieldData[]` (cru), o\ncard traz **`fields`** — um mapa `slug → valor` já desembrulhado, ideal para\nintegrações e BI.\n",
        "properties": {
          "documentId": {
            "type": "string",
            "example": "cd1a2b3c"
          },
          "title": {
            "type": "string",
            "example": "João Silva"
          },
          "description": {
            "type": "string",
            "description": "Texto rico (HTML)."
          },
          "value": {
            "type": "number",
            "example": 15000.5
          },
          "dueDate": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "dueDateSource": {
            "type": "string",
            "enum": [
              "manual",
              "phase",
              "automation"
            ]
          },
          "currentPhase": {
            "$ref": "#/components/schemas/Phase"
          },
          "currentPhaseEnteredAt": {
            "type": "string",
            "format": "date-time"
          },
          "assignees": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MembershipRef"
            }
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Tag"
            }
          },
          "contact": {
            "$ref": "#/components/schemas/ContactRef"
          },
          "fields": {
            "type": "object",
            "description": "Mapa `slug → valor` com todos os campos dinâmicos preenchidos (leitura preferida).",
            "additionalProperties": true,
            "example": {
              "name": "João Silva",
              "email": "joao@cliente.com",
              "valor_orcamento": 25000
            }
          },
          "fieldData": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FieldDataItem"
            }
          },
          "creationSource": {
            "type": "string",
            "enum": [
              "manual",
              "form",
              "meta_lead",
              "automation",
              "chatwoot_inbound",
              "import",
              "api"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Contact": {
        "type": "object",
        "description": "Contato (pessoa ou empresa). `customFields` é um objeto `chave → valor`.",
        "properties": {
          "documentId": {
            "type": "string",
            "example": "ct1a2b3c"
          },
          "name": {
            "type": "string",
            "example": "João Silva"
          },
          "email": {
            "type": [
              "string",
              "null"
            ],
            "example": "joao@cliente.com"
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "example": "+5511999999999"
          },
          "contact_type": {
            "type": "string",
            "enum": [
              "pessoa",
              "empresa"
            ],
            "default": "pessoa"
          },
          "cpf": {
            "type": [
              "string",
              "null"
            ],
            "description": "Validado e armazenado sem máscara. Único por organização."
          },
          "cnpj": {
            "type": [
              "string",
              "null"
            ],
            "description": "Validado e armazenado sem máscara. Único por organização."
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "state": {
            "type": [
              "string",
              "null"
            ]
          },
          "country": {
            "type": [
              "string",
              "null"
            ]
          },
          "postal_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "birthdate": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "first_buy_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "owner": {
            "$ref": "#/components/schemas/MembershipRef"
          },
          "ownedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "customFields": {
            "type": "object",
            "additionalProperties": true,
            "example": {
              "origem": "Indicação",
              "nps": 9
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ContactActivity": {
        "type": "object",
        "description": "Evento na timeline de um contato.",
        "properties": {
          "documentId": {
            "type": "string"
          },
          "activityType": {
            "type": "string",
            "enum": [
              "contact_created",
              "contact_updated",
              "owner_assigned",
              "owner_changed",
              "team_assigned",
              "team_changed",
              "card_created",
              "card_won",
              "card_lost",
              "email_sent",
              "whatsapp_sent",
              "note_added",
              "call_completed",
              "call_attempted"
            ]
          },
          "description": {
            "type": "string",
            "example": "Cliente pediu retorno na sexta."
          },
          "performedAt": {
            "type": "string",
            "format": "date-time"
          },
          "contact": {
            "$ref": "#/components/schemas/ContactRef"
          },
          "actor": {
            "$ref": "#/components/schemas/MembershipRef"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "SegmentFilters": {
        "type": "object",
        "description": "Regras de um segmento.",
        "required": [
          "logic",
          "conditions"
        ],
        "properties": {
          "logic": {
            "type": "string",
            "enum": [
              "AND",
              "OR"
            ]
          },
          "conditions": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "description": "Condição de filtro. Campos string: `phone, email, name, address, city, state,\ncountry, postal_code, cpf, cnpj, contact_type`. Operadores: `contains, eq,\nstartsWith, endsWith, empty, notEmpty`. Relações usam `kind: \"relation\"`\n(field `owner|team` + `documentId`); campos customizados usam `kind: \"custom\"`\n(`slug` + `op` + `value`).\n",
              "properties": {
                "field": {
                  "type": "string",
                  "example": "city"
                },
                "op": {
                  "type": "string",
                  "example": "eq"
                },
                "value": {
                  "example": "São Paulo"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "relation",
                    "custom"
                  ]
                },
                "slug": {
                  "type": "string"
                },
                "documentId": {
                  "type": "string"
                }
              }
            }
          }
        },
        "example": {
          "logic": "AND",
          "conditions": [
            {
              "field": "city",
              "op": "eq",
              "value": "São Paulo"
            },
            {
              "field": "email",
              "op": "notEmpty"
            }
          ]
        }
      },
      "Segment": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string",
            "example": "sg1a2b3c"
          },
          "name": {
            "type": "string",
            "example": "Leads SP com e-mail"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "active": {
            "type": "boolean"
          },
          "filters": {
            "$ref": "#/components/schemas/SegmentFilters"
          },
          "contactCount": {
            "type": "integer",
            "description": "Contagem de contatos que casam com as regras.",
            "example": 231
          }
        }
      },
      "CampaignStats": {
        "type": "object",
        "description": "Contadores agregados da campanha. Engajamento de e-mail (`delivered/opened/clicked/bounced`) vem da ingestão de eventos do provedor.",
        "properties": {
          "total": {
            "type": "integer",
            "example": 500
          },
          "pending": {
            "type": "integer",
            "example": 120
          },
          "sent": {
            "type": "integer",
            "example": 350
          },
          "failed": {
            "type": "integer",
            "example": 20
          },
          "skipped": {
            "type": "integer",
            "example": 10
          },
          "delivered": {
            "type": "integer",
            "example": 300
          },
          "opened": {
            "type": "integer",
            "example": 180
          },
          "clicked": {
            "type": "integer",
            "example": 45
          },
          "bounced": {
            "type": "integer",
            "example": 5
          }
        }
      },
      "Task": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string",
            "example": "tk1a2b3c"
          },
          "name": {
            "type": "string",
            "maxLength": 255,
            "example": "Ligar para o cliente"
          },
          "description": {
            "type": "string",
            "description": "Texto rico (HTML)."
          },
          "dueDate": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "type": {
            "type": "string",
            "enum": [
              "reminder",
              "follow-up",
              "action",
              "other"
            ],
            "default": "reminder"
          },
          "taskStatus": {
            "type": "string",
            "description": "Um dos status configurados no board (`taskStatuses`).",
            "example": "pending"
          },
          "completedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "card": {
            "type": "object",
            "properties": {
              "documentId": {
                "type": "string"
              },
              "title": {
                "type": "string"
              }
            }
          },
          "assignees": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MembershipRef"
            }
          }
        }
      },
      "BoardReport": {
        "type": "object",
        "description": "Relatório agregado do board (envelope flat, sem `{ data, meta }`).",
        "properties": {
          "boardId": {
            "type": "string",
            "example": "bd1a2b3c"
          },
          "boardName": {
            "type": "string",
            "example": "Funil de Vendas"
          },
          "showValue": {
            "type": "boolean"
          },
          "currency": {
            "type": "string",
            "example": "BRL"
          },
          "dateRange": {
            "type": "object",
            "properties": {
              "from": {
                "type": "string",
                "format": "date-time"
              },
              "to": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "summary": {
            "type": "object",
            "properties": {
              "totalCards": {
                "type": "integer",
                "example": 42
              },
              "totalValue": {
                "type": "number",
                "example": 128000
              },
              "wonCount": {
                "type": "integer",
                "example": 8
              },
              "lostCount": {
                "type": "integer",
                "example": 5
              },
              "wonValue": {
                "type": "number",
                "example": 64000
              },
              "opportunityValue": {
                "type": "number",
                "example": 40000
              },
              "unassignedCount": {
                "type": "integer",
                "example": 3
              },
              "untaggedCount": {
                "type": "integer",
                "example": 10
              }
            }
          },
          "phases": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "phaseId": {
                  "type": "string",
                  "description": "documentId da fase, ou `\"__no_phase__\"` para cards sem fase."
                },
                "name": {
                  "type": "string"
                },
                "slug": {
                  "type": "string"
                },
                "order": {
                  "type": "integer"
                },
                "count": {
                  "type": "integer"
                },
                "value": {
                  "type": "number"
                },
                "isWon": {
                  "type": "boolean"
                },
                "isLost": {
                  "type": "boolean"
                }
              }
            }
          },
          "assignees": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "membershipId": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "`null` para a linha \"Sem responsável\"."
                },
                "displayName": {
                  "type": "string"
                },
                "count": {
                  "type": "integer"
                },
                "value": {
                  "type": "number"
                }
              }
            }
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "tagId": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "color": {
                  "type": "string"
                },
                "count": {
                  "type": "integer"
                }
              }
            }
          },
          "createdByDay": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date",
                  "example": "2026-07-01"
                },
                "count": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "FieldCondition": {
        "type": "object",
        "description": "Regra de exibição condicional de campos.",
        "properties": {
          "documentId": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "example": "Mostrar CNPJ para empresas"
          },
          "scope": {
            "type": "string",
            "enum": [
              "phase",
              "board"
            ]
          },
          "order": {
            "type": "integer"
          },
          "enabled": {
            "type": "boolean"
          },
          "criteria": {
            "type": "array",
            "description": "Grupos `{ operator: \"AND\", expressions: [{ fieldSlug, operator, value }] }`.",
            "items": {
              "type": "object"
            }
          },
          "actionsWhenTrue": {
            "type": "array",
            "description": "Ações `{ type: \"show\"|\"hide\", targetFieldSlugs: [...] }`.",
            "items": {
              "type": "object"
            }
          },
          "actionsWhenFalse": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "phase": {
            "type": "object",
            "properties": {
              "documentId": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          }
        }
      },
      "Campaign": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string",
            "example": "cp1a2b3c"
          },
          "name": {
            "type": "string",
            "example": "Reativação julho"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "channel": {
            "type": "string",
            "enum": [
              "whatsapp",
              "email",
              "sms"
            ]
          },
          "campaignStatus": {
            "type": "string",
            "enum": [
              "draft",
              "scheduled",
              "processing",
              "paused",
              "completed",
              "failed",
              "cancelled"
            ]
          },
          "segment": {
            "$ref": "#/components/schemas/Segment"
          },
          "messageConfig": {
            "type": "object",
            "additionalProperties": true
          },
          "stats": {
            "$ref": "#/components/schemas/CampaignStats"
          },
          "scheduledAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "startedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "completedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "Comment": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string"
          },
          "content": {
            "type": "string",
            "example": "Cliente confirmou reunião para sexta."
          },
          "contentFormat": {
            "type": "string",
            "enum": [
              "plain",
              "html"
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "user",
              "system"
            ],
            "description": "Comentários `system` registram atividades automáticas do card."
          },
          "activityType": {
            "type": [
              "string",
              "null"
            ],
            "description": "Preenchido em comentários `system` (ex. `phase_changed`, `assignee_added`)."
          },
          "mentions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "documentIds dos memberships mencionados."
          },
          "metadata": {
            "type": "object",
            "description": "Metadados (ex. `links` detectados no conteúdo)."
          },
          "author": {
            "$ref": "#/components/schemas/UserRef"
          },
          "card": {
            "type": "object",
            "properties": {
              "documentId": {
                "type": "string"
              }
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Team": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "example": "Time SP"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "color": {
            "type": "string",
            "example": "#3B82F6"
          },
          "active": {
            "type": "boolean"
          },
          "leader": {
            "$ref": "#/components/schemas/MembershipRef"
          },
          "members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MembershipRef"
            }
          }
        }
      },
      "QuoteItemInput": {
        "type": "object",
        "description": "Item de orçamento. `subtotal` e `total` são calculados no servidor.",
        "required": [
          "name"
        ],
        "properties": {
          "product": {
            "type": "string",
            "description": "documentId do produto (opcional — itens livres são permitidos)."
          },
          "name": {
            "type": "string",
            "example": "Consultoria estratégica"
          },
          "sku": {
            "type": "string"
          },
          "quantity": {
            "type": "integer",
            "minimum": 1,
            "default": 1
          },
          "periods": {
            "type": "integer",
            "default": 1,
            "description": "Nº de períodos (para produtos recorrentes)."
          },
          "unitPrice": {
            "type": "number"
          },
          "discountPercent": {
            "type": "number",
            "default": 0
          },
          "notes": {
            "type": "string"
          }
        }
      },
      "Quote": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string",
            "example": "qt1a2b3c"
          },
          "number": {
            "type": "string",
            "description": "Gerado no servidor (formato `YYYY-00001`).",
            "example": "2026-00042"
          },
          "quoteStatus": {
            "type": "string",
            "enum": [
              "draft",
              "active",
              "won",
              "lost"
            ]
          },
          "documentType": {
            "type": "string",
            "enum": [
              "quote",
              "contract",
              "report",
              "other"
            ]
          },
          "items": {
            "type": "array",
            "items": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/QuoteItemInput"
                },
                {
                  "type": "object",
                  "properties": {
                    "subtotal": {
                      "type": "number"
                    },
                    "total": {
                      "type": "number"
                    }
                  }
                }
              ]
            }
          },
          "subtotal": {
            "type": "number",
            "example": 26880
          },
          "discountType": {
            "type": "string",
            "enum": [
              "percentage",
              "fixed"
            ]
          },
          "discountValue": {
            "type": "number"
          },
          "discountTotal": {
            "type": "number"
          },
          "total": {
            "type": "number",
            "example": 24192
          },
          "currency": {
            "type": "string",
            "example": "BRL"
          },
          "validUntil": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "version": {
            "type": "integer"
          },
          "card": {
            "type": "object",
            "properties": {
              "documentId": {
                "type": "string"
              },
              "title": {
                "type": "string"
              }
            }
          },
          "contact": {
            "$ref": "#/components/schemas/ContactRef"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Product": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string",
            "example": "pr9x8y7z"
          },
          "name": {
            "type": "string",
            "example": "Plano Pro"
          },
          "slug": {
            "type": "string"
          },
          "sku": {
            "type": "string",
            "example": "PLANO-PRO"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "shortDescription": {
            "type": [
              "string",
              "null"
            ]
          },
          "productType": {
            "type": "string",
            "enum": [
              "physical",
              "digital",
              "service"
            ]
          },
          "billingType": {
            "type": "string",
            "enum": [
              "one_time",
              "recurring"
            ]
          },
          "price": {
            "type": "number",
            "example": 990
          },
          "salePrice": {
            "type": [
              "number",
              "null"
            ]
          },
          "minPrice": {
            "type": [
              "number",
              "null"
            ]
          },
          "currency": {
            "type": "string",
            "example": "BRL"
          },
          "active": {
            "type": "boolean"
          },
          "categories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProductCategory"
            }
          }
        }
      },
      "ProductCategory": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "example": "Serviços"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "color": {
            "type": "string",
            "example": "#3b82f6"
          },
          "parent": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "documentId": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          }
        }
      },
      "PdfTemplate": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "example": "Proposta padrão"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "templateType": {
            "type": "string",
            "enum": [
              "quote",
              "invoice",
              "contract",
              "report"
            ]
          },
          "layout": {
            "type": "object",
            "description": "Estrutura de página com blocos de cabeçalho, corpo e rodapé."
          },
          "styles": {
            "type": "object",
            "description": "Cores e tipografia do documento."
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Requisição inválida (validação, header `x-tenant-id` ausente, payload malformado).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Token ausente, inválido ou expirado.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "data": null,
              "error": {
                "status": 401,
                "name": "UnauthorizedError",
                "message": "Autenticação obrigatória"
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "Sem permissão para esta ação (papel/board) ou organização inativa.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Recurso não encontrado nesta organização.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  },
  "paths": {
    "/auth/local": {
      "post": {
        "operationId": "login",
        "tags": [
          "Autenticação"
        ],
        "summary": "Login (JWT de sessão)",
        "security": [],
        "description": "Autentica com e-mail e senha e retorna um **JWT de sessão** de curta duração.\n\nPara integrações, prefira um **token de API de longa duração**: gere pela\ninterface (Configurações → Organização → aba API) ou via\n[`POST /users/generate-token`](#tag/autenticacao/post/users/generate-token).\n\n> Este endpoint **não** exige `x-tenant-id`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "identifier",
                  "password"
                ],
                "properties": {
                  "identifier": {
                    "type": "string",
                    "description": "E-mail do usuário.",
                    "example": "voce@empresa.com"
                  },
                  "password": {
                    "type": "string",
                    "format": "password",
                    "example": "SuaSenha123!"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Autenticado com sucesso.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "jwt": {
                      "type": "string",
                      "description": "JWT de sessão (expira em poucas horas)."
                    },
                    "user": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer"
                        },
                        "username": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
                  "user": {
                    "id": 42,
                    "username": "luis",
                    "email": "voce@empresa.com"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Credenciais inválidas.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl -X POST \"https://api.perpetuus.com.br/api/auth/local\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"identifier\": \"voce@empresa.com\", \"password\": \"SuaSenha123!\"}'\n"
          }
        ]
      }
    },
    "/users/generate-token": {
      "post": {
        "operationId": "generateToken",
        "tags": [
          "Autenticação"
        ],
        "summary": "Gerar token de API",
        "description": "Gera um **token de API de longa duração** para integrações (BI, Zapier, Make,\nscripts). Requer um JWT de sessão válido no header `Authorization`.\n\nExpirações aceitas: `1d`, `30d`, `365d` e `36500d` (≈ 100 anos).\n\n> Este endpoint **não** exige `x-tenant-id` e tem **rate limit** reforçado.\n\n**Guarde o token com segurança** — trate-o como uma senha e use variáveis de\nambiente. Ele não pode ser recuperado depois.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "expiration"
                ],
                "properties": {
                  "expiration": {
                    "type": "string",
                    "enum": [
                      "1d",
                      "30d",
                      "365d",
                      "36500d"
                    ],
                    "example": "365d"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token gerado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string",
                      "description": "Token de API (JWT). Use como `Authorization: Bearer <token>`."
                    },
                    "expiration": {
                      "type": "string",
                      "example": "365d"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Expiração inválida (`Invalid expiration time. Allowed: 1d, 30d, 365d, 36500d`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl -X POST \"https://api.perpetuus.com.br/api/users/generate-token\" \\\n  -H \"Authorization: Bearer SEU_JWT_DO_LOGIN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"expiration\": \"365d\"}'\n"
          }
        ]
      }
    },
    "/boards": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listBoards",
        "tags": [
          "Boards"
        ],
        "summary": "Listar boards",
        "description": "Lista os boards da organização. Usuários que não são **ADMIN** veem apenas\nos boards dos quais são membros.\n\nA resposta inclui, por padrão, `phases` (com `fields` e `allowedTransitions`),\n`tags`, `owner`, `members` e `editors`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/PaginationPage"
          },
          {
            "$ref": "#/components/parameters/PaginationPageSize"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Populate"
          }
        ],
        "responses": {
          "200": {
            "description": "Lista paginada de boards.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Board"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "pagination": {
                          "$ref": "#/components/schemas/Pagination"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl \"https://api.perpetuus.com.br/api/boards\" \\\n  -H \"Authorization: Bearer SEU_TOKEN\" \\\n  -H \"x-tenant-id: acme\"\n"
          }
        ]
      },
      "post": {
        "operationId": "createBoard",
        "tags": [
          "Boards"
        ],
        "summary": "Criar board",
        "description": "Cria um novo board. Sujeito ao limite de boards do seu plano.\nUse `template` para partir de um modelo pronto (padrão: `minimal-workflow`).\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "example": "Funil de Vendas"
                      },
                      "boardType": {
                        "type": "string",
                        "enum": [
                          "kanban",
                          "chat",
                          "hybrid"
                        ]
                      },
                      "icon": {
                        "type": "string",
                        "example": "layout-grid"
                      },
                      "color": {
                        "type": "string"
                      },
                      "template": {
                        "type": "string",
                        "example": "minimal-workflow"
                      },
                      "boardSettings": {
                        "$ref": "#/components/schemas/BoardSettings"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Board criado (objeto flat, sem envelope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Board"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/boards/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "documentId do board.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getBoard",
        "tags": [
          "Boards"
        ],
        "summary": "Buscar board",
        "description": "Retorna um board pelo **documentId**, com fases, campos, tags e membros.\n\n💡 Use este endpoint para descobrir os `documentId` das fases (para mover\ncards) e os `slug` dos campos (para preencher `fields`).\n",
        "responses": {
          "200": {
            "description": "O board (objeto flat, sem envelope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Board"
                },
                "example": {
                  "documentId": "bd1a2b3c",
                  "name": "Funil de Vendas",
                  "slug": "funil-de-vendas",
                  "active": true,
                  "boardType": "kanban",
                  "boardSettings": {
                    "showValue": true,
                    "currency": "BRL",
                    "wonPhase": "ph_won",
                    "lostPhase": null
                  },
                  "phases": [
                    {
                      "documentId": "ph0aaa",
                      "name": "Formulário",
                      "order": 0,
                      "isPublic": true,
                      "fields": [
                        {
                          "documentId": "fl1bbb",
                          "label": "Nome",
                          "slug": "name",
                          "type": "text",
                          "required": true
                        }
                      ]
                    },
                    {
                      "documentId": "ph1ccc",
                      "name": "Novo lead",
                      "order": 1,
                      "maxTimeInPhaseHours": 48
                    }
                  ],
                  "tags": [
                    {
                      "documentId": "tg1ddd",
                      "name": "VIP",
                      "slug": "vip",
                      "color": "#3b82f6"
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateBoard",
        "tags": [
          "Boards"
        ],
        "summary": "Atualizar board",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object",
                    "description": "Campos a alterar (parciais).",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "active": {
                        "type": "boolean"
                      },
                      "icon": {
                        "type": "string"
                      },
                      "color": {
                        "type": "string"
                      },
                      "boardSettings": {
                        "$ref": "#/components/schemas/BoardSettings"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Board atualizado (objeto flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Board"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteBoard",
        "tags": [
          "Boards"
        ],
        "summary": "Excluir board",
        "description": "⚠️ Ação destrutiva — remove o board e seus cards.",
        "responses": {
          "200": {
            "description": "Board excluído."
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{id}/members": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "documentId do board.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listBoardMembers",
        "tags": [
          "Membros do board"
        ],
        "summary": "Listar membros",
        "description": "Lista membros, editores e owner do board.",
        "responses": {
          "200": {
            "description": "Membros do board.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "members": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MembershipRef"
                      }
                    },
                    "editors": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MembershipRef"
                      }
                    },
                    "owner": {
                      "$ref": "#/components/schemas/MembershipRef"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "operationId": "addBoardMember",
        "tags": [
          "Membros do board"
        ],
        "summary": "Adicionar membro",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "membershipId"
                ],
                "properties": {
                  "membershipId": {
                    "type": "string",
                    "description": "documentId do membership da organização."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Board atualizado, com `members` e `editors` populados.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Board"
                }
              }
            }
          },
          "400": {
            "description": "Membership inválido ou usuário já é membro do board.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{id}/members/{membershipId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "membershipId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "delete": {
        "operationId": "removeBoardMember",
        "tags": [
          "Membros do board"
        ],
        "summary": "Remover membro",
        "description": "Remove o membership de `members` **e** `editors`. O owner do board não pode ser removido.",
        "responses": {
          "200": {
            "description": "Board atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Board"
                }
              }
            }
          },
          "400": {
            "description": "Membership inválido ou tentativa de remover o owner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{id}/members/bulk": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "put": {
        "operationId": "bulkUpdateBoardMembers",
        "tags": [
          "Membros do board"
        ],
        "summary": "Substituir membros em lote",
        "description": "Define de uma vez as listas completas de membros e editores do board.\n\n> ⚠️ Este endpoint usa **IDs numéricos** dos memberships (exceção à regra do\n> documentId). O owner é sempre mantido; editores precisam estar em `members`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "members": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    },
                    "description": "IDs numéricos dos memberships."
                  },
                  "editors": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    },
                    "description": "IDs numéricos (subconjunto de `members`)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Board atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Board"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{id}/editors": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "addBoardEditor",
        "tags": [
          "Membros do board"
        ],
        "summary": "Adicionar editor",
        "description": "Editores podem alterar a estrutura do board (fases, campos, tags).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "membershipId"
                ],
                "properties": {
                  "membershipId": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Editor adicionado."
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/boards/{id}/editors/{membershipId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "membershipId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "delete": {
        "operationId": "removeBoardEditor",
        "tags": [
          "Membros do board"
        ],
        "summary": "Remover editor",
        "responses": {
          "200": {
            "description": "Editor removido."
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/boards/{boardId}/report": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "description": "documentId do board.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getBoardReport",
        "tags": [
          "Relatórios"
        ],
        "summary": "Relatório do board",
        "description": "Métricas agregadas do funil: totais, ganhos/perdas, breakdown por fase,\nresponsável e tag, e criação por dia.\n\n- Sem `from`/`to`, o período padrão é **os últimos 15 dias**.\n- Valores monetários só são preenchidos quando `boardSettings.showValue = true`.\n- Ganho/perda derivam de `boardSettings.wonPhase` / `lostPhase`.\n\n**BI/ETL:** use este endpoint para dashboards agregados; para dados linha a\nlinha, use `GET /boards/{boardId}/cards`.\n",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "description": "Início do período (ISO 8601).",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2026-06-01"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Fim do período (ISO 8601).",
            "schema": {
              "type": "string",
              "format": "date",
              "example": "2026-06-30"
            }
          },
          {
            "name": "assignee",
            "in": "query",
            "description": "Filtrar por responsável (documentId do membership).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tag",
            "in": "query",
            "description": "Filtrar por tag (documentId).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Relatório (objeto flat — **não** usa envelope `{ data, meta }`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BoardReport"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl -G \"https://api.perpetuus.com.br/api/boards/BOARD_ID/report\" \\\n  -H \"Authorization: Bearer SEU_TOKEN\" \\\n  -H \"x-tenant-id: acme\" \\\n  --data-urlencode \"from=2026-06-01\" \\\n  --data-urlencode \"to=2026-06-30\"\n"
          }
        ]
      }
    },
    "/boards/{boardId}/public-form": {
      "parameters": [
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "description": "documentId do board.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getPublicForm",
        "tags": [
          "Formulário público"
        ],
        "summary": "Estrutura do formulário público",
        "security": [],
        "description": "Retorna a definição do formulário de entrada do board (Fase 0): título,\ncampos, cores e textos. **Não requer autenticação** — ideal para renderizar\nformulários de captura no seu site.\n",
        "responses": {
          "200": {
            "description": "Definição do formulário (campos da Fase 0)."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "operationId": "submitPublicForm",
        "tags": [
          "Formulário público"
        ],
        "summary": "Enviar formulário público",
        "security": [],
        "description": "Cria um card a partir do formulário público da Fase 0. **Não requer\nautenticação.** Os campos enviados devem corresponder aos slugs do formulário.\n\nCampos de rastreamento opcionais (`fbclid`, `gclid`, UTMs) são aceitos e\nanexados ao card.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "fields"
                ],
                "properties": {
                  "fields": {
                    "type": "object",
                    "additionalProperties": true,
                    "example": {
                      "name": "João Silva",
                      "email": "joao@cliente.com",
                      "phone": "+5511999999999"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lead registrado."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{boardId}/public-upload": {
      "parameters": [
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "publicUpload",
        "tags": [
          "Formulário público"
        ],
        "summary": "Upload de arquivo no formulário público",
        "security": [],
        "description": "Upload de anexos para campos do tipo `file` do formulário público.",
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "files": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Arquivo recebido."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/boards/{boardId}/cards": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "description": "documentId do board.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listCards",
        "tags": [
          "Cards"
        ],
        "summary": "Listar cards",
        "description": "Lista os cards do board, com paginação, filtros, ordenação e estatísticas.\n\nA resposta inclui por padrão `currentPhase`, `assignees`, `tags`, `contact`,\n`fieldData` e o mapa achatado **`fields`** (`slug → valor`, já desembrulhado).\n\n### Filtros comuns\n\n| Filtro | Exemplo |\n|--------|---------|\n| Fase atual | `filters[currentPhase][documentId]=PHASE_ID` |\n| Título contém | `filters[title][$containsi]=joão` |\n| Tag | `filters[tags][documentId][$in][0]=TAG_ID` |\n| Campo dinâmico | `filters[fieldData][field][slug]=email&filters[fieldData][value][val]=lead@cliente.com` |\n| Vencimento | `filters[dueDate][$lt]=2026-08-01` |\n\n### Estatísticas (`meta.stats`)\n\nPresentes por padrão; desligue com `stats=false`. Para alinhar a contagem de\natrasados ao fuso local, envie `statsTodayStart` (ISO da meia-noite local).\n\n> 💡 Board inexistente retorna lista **vazia** (não 404).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/PaginationPage"
          },
          {
            "$ref": "#/components/parameters/PaginationPageSize"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Populate"
          },
          {
            "name": "stats",
            "in": "query",
            "description": "`false` desliga o cálculo de `meta.stats`.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "statsTodayStart",
            "in": "query",
            "description": "ISO da meia-noite local, para contagem de atrasados no seu fuso.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lista paginada com estatísticas.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Card"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "pagination": {
                          "$ref": "#/components/schemas/Pagination"
                        },
                        "stats": {
                          "$ref": "#/components/schemas/CardStats"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "documentId": "cd1a2b3c",
                      "title": "João Silva",
                      "value": 15000.5,
                      "dueDate": "2026-07-20T00:00:00.000Z",
                      "currentPhase": {
                        "documentId": "ph1ccc",
                        "name": "Novo lead"
                      },
                      "assignees": [
                        {
                          "documentId": "mb1",
                          "user": {
                            "username": "luis"
                          }
                        }
                      ],
                      "tags": [
                        {
                          "documentId": "tg1ddd",
                          "name": "VIP",
                          "slug": "vip",
                          "color": "#3b82f6"
                        }
                      ],
                      "contact": {
                        "documentId": "ct1",
                        "name": "João Silva",
                        "email": "joao@cliente.com"
                      },
                      "fields": {
                        "name": "João Silva",
                        "email": "joao@cliente.com",
                        "valor_orcamento": 25000
                      }
                    }
                  ],
                  "meta": {
                    "pagination": {
                      "page": 1,
                      "pageSize": 25,
                      "pageCount": 4,
                      "total": 87
                    },
                    "stats": {
                      "overdueCount": 3,
                      "valueSum": 125000.5,
                      "phaseSlaBreachedCount": 0
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl -G \"https://api.perpetuus.com.br/api/boards/BOARD_ID/cards\" \\\n  -H \"Authorization: Bearer SEU_TOKEN\" \\\n  -H \"x-tenant-id: acme\" \\\n  --data-urlencode \"pagination[page]=1\" \\\n  --data-urlencode \"pagination[pageSize]=50\" \\\n  --data-urlencode \"sort=updatedAt:desc\"\n"
          },
          {
            "lang": "JavaScript",
            "label": "JavaScript",
            "source": "const params = new URLSearchParams({\n  'pagination[page]': '1',\n  'pagination[pageSize]': '100',\n  sort: 'createdAt:asc',\n});\n\nconst res = await fetch(\n  `https://api.perpetuus.com.br/api/boards/${boardId}/cards?${params}`,\n  { headers: { Authorization: `Bearer ${token}`, 'x-tenant-id': 'acme' } }\n);\nconst { data, meta } = await res.json();\n"
          }
        ]
      },
      "post": {
        "operationId": "createCard",
        "tags": [
          "Cards"
        ],
        "summary": "Criar card",
        "description": "Cria um card no board. O objeto **`fields` é obrigatório** e deve conter ao\nmenos os campos obrigatórios da Fase 0 (formulário de entrada) — em geral, `name`.\n\nO card nasce na primeira fase de trabalho (order 1) com `title = fields.name`.\n\n- `tags` aceita **slug ou documentId** — tags inexistentes retornam `400`.\n- `dueDate` ausente pode ser derivado do SLA da fase inicial.\n\n💡 Descubra os slugs dos campos com `GET /boards/{boardId}` (fases → fields).\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "fields"
                    ],
                    "properties": {
                      "fields": {
                        "type": "object",
                        "description": "Mapa `slug → valor`. Deve incluir os obrigatórios da Fase 0.",
                        "additionalProperties": true
                      },
                      "assignees": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "documentIds de memberships."
                      },
                      "tags": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Slugs **ou** documentIds de tags do board."
                      },
                      "contact": {
                        "type": "string",
                        "description": "documentId de um contato."
                      },
                      "dueDate": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "description": {
                        "type": "string",
                        "description": "Texto rico (HTML)."
                      },
                      "value": {
                        "type": "number"
                      }
                    }
                  }
                }
              },
              "example": {
                "data": {
                  "fields": {
                    "name": "Lead do formulário web",
                    "email": "lead@cliente.com",
                    "phone": "+5511987654321"
                  },
                  "tags": [
                    "novo-lead"
                  ],
                  "description": "Originado via API"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Card criado (objeto flat, com `fields` e `fieldData`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "400": {
            "description": "Validação falhou. Possíveis mensagens:\n- `Campo \"fields\" é obrigatório e deve ser um objeto`\n- `Campo \"name\" é obrigatório`\n- `Validação de campos falhou` — com `details.fields: { slug: mensagem }`\n- Tags inexistentes — com a lista em `details.tags`\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl -X POST \"https://api.perpetuus.com.br/api/boards/BOARD_ID/cards\" \\\n  -H \"Authorization: Bearer SEU_TOKEN\" \\\n  -H \"x-tenant-id: acme\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"data\": {\n      \"fields\": {\n        \"name\": \"Lead do formulário web\",\n        \"email\": \"lead@cliente.com\",\n        \"phone\": \"+5511987654321\"\n      },\n      \"description\": \"Originado via API\"\n    }\n  }'\n"
          },
          {
            "lang": "JavaScript",
            "label": "JavaScript",
            "source": "const res = await fetch(`https://api.perpetuus.com.br/api/boards/${boardId}/cards`, {\n  method: 'POST',\n  headers: {\n    Authorization: `Bearer ${token}`,\n    'x-tenant-id': 'acme',\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    data: {\n      fields: { name: 'Nova oportunidade', email: 'cliente@email.com' },\n      tags: ['novo-lead'],\n    },\n  }),\n});\n\nif (!res.ok) {\n  const err = await res.json();\n  throw new Error(err.error?.message ?? 'Erro ao criar card');\n}\n\nconst card = await res.json();\nconsole.log('Card criado:', card.documentId);\n"
          }
        ]
      }
    },
    "/boards/{boardId}/cards/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "description": "documentId do board.",
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "documentId do card.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getCard",
        "tags": [
          "Cards"
        ],
        "summary": "Buscar card",
        "description": "Retorna um card com fase, responsáveis, tags, contato e campos dinâmicos.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Populate"
          }
        ],
        "responses": {
          "200": {
            "description": "O card (objeto flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "400": {
            "description": "Card não pertence a este board.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateCard",
        "tags": [
          "Cards"
        ],
        "summary": "Atualizar card (campos, fase, responsáveis)",
        "description": "Atualiza metadados, campos dinâmicos e/ou **move o card de fase** — envie\napenas o que deseja alterar.\n\n### Campos dinâmicos\n\n`fields` mapeia `slug → valor`; o backend descobre em qual fase cada campo\nestá e faz o upsert. Os demais campos permanecem intactos.\n\n### Mover de fase\n\nEnvie `currentPhase` com o documentId da fase destino. Regras:\n- a fase precisa pertencer ao board (400 caso contrário);\n- não é possível mover para a Fase 0 (formulário);\n- ao avançar, os campos obrigatórios da fase de origem precisam estar\n  preenchidos (`400 — Preencha os campos obrigatórios antes de avançar`).\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string"
                      },
                      "dueDate": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "value": {
                        "type": "number"
                      },
                      "assignees": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "tags": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Slugs ou documentIds."
                      },
                      "contact": {
                        "type": "string"
                      },
                      "currentPhase": {
                        "type": "string",
                        "description": "documentId da fase destino (dispara a transição)."
                      },
                      "reason": {
                        "type": "string",
                        "description": "Motivo da transição (registrado no histórico)."
                      },
                      "fields": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              },
              "examples": {
                "atualizar-campos": {
                  "summary": "Atualizar campos dinâmicos",
                  "value": {
                    "data": {
                      "fields": {
                        "valor_orcamento": 35000,
                        "prioridade": "URGENTE"
                      }
                    }
                  }
                },
                "mover-fase": {
                  "summary": "Mover de fase (com campos da fase destino)",
                  "value": {
                    "data": {
                      "currentPhase": "fase-ganho-doc-id",
                      "fields": {
                        "valor_fechado": 50000,
                        "data_fechamento": "2026-07-10"
                      }
                    }
                  }
                },
                "atualizar-metadados": {
                  "summary": "Atualizar título e valor",
                  "value": {
                    "data": {
                      "title": "Oportunidade — orçamento aprovado",
                      "value": 42000
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Card atualizado (objeto flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "400": {
            "description": "Validação falhou — card de outro board, fase inválida, campos obrigatórios\nfaltando (`details.errors`) ou tipos de campo inválidos (`details.fields`).\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl -X PUT \"https://api.perpetuus.com.br/api/boards/BOARD_ID/cards/CARD_ID\" \\\n  -H \"Authorization: Bearer SEU_TOKEN\" \\\n  -H \"x-tenant-id: acme\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"data\": {\n      \"currentPhase\": \"fase-ganho-doc-id\",\n      \"fields\": { \"valor_fechado\": 50000 }\n    }\n  }'\n"
          }
        ]
      },
      "delete": {
        "operationId": "deleteCard",
        "tags": [
          "Cards"
        ],
        "summary": "Excluir card",
        "responses": {
          "200": {
            "description": "Card excluído.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Card deletado com sucesso"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Card não pertence a este board.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{boardId}/cards/linked": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "createLinkedCard",
        "tags": [
          "Cards vinculados"
        ],
        "summary": "Criar card vinculado",
        "description": "Cria um card em **outro board** já vinculado ao card de origem, através de um\ncampo do tipo `card_link` — útil para fluxos encadeados (ex.: venda ganha →\ncard de onboarding).\n\nO campo (`sourceFieldId`) precisa ser do tipo `card_link` com board de destino\nconfigurado. Campos com automap copiam valores do card de origem; os\nobrigatórios da Fase 0 do board destino são validados.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "sourceCardId",
                  "sourceFieldId",
                  "linkedCardData"
                ],
                "properties": {
                  "sourceCardId": {
                    "type": "string",
                    "description": "documentId do card de origem (deste board)."
                  },
                  "sourceFieldId": {
                    "type": "string",
                    "description": "documentId do campo `card_link` que guarda o vínculo."
                  },
                  "linkedCardData": {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string"
                      },
                      "fields": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Card criado no board de destino e vinculado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Card"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "link": {
                          "type": "object",
                          "properties": {
                            "cardId": {
                              "type": "string"
                            },
                            "boardId": {
                              "type": "string"
                            },
                            "title": {
                              "type": "string"
                            },
                            "createdAt": {
                              "type": "string",
                              "format": "date-time"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parâmetros faltando, campo não é `card_link`, board destino não configurado, cardinalidade 1:1 já preenchida ou validação de campos falhou.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/boards/{boardId}/cards/link-existing": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "linkExistingCard",
        "tags": [
          "Cards vinculados"
        ],
        "summary": "Vincular card existente",
        "description": "Vincula um card já existente do board de destino ao campo `card_link` do card\nde origem. Operação **idempotente** — se o par já estiver vinculado, retorna\n`meta.added: false`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "sourceCardId",
                  "sourceFieldId",
                  "targetCardId"
                ],
                "properties": {
                  "sourceCardId": {
                    "type": "string",
                    "description": "documentId do card deste board."
                  },
                  "sourceFieldId": {
                    "type": "string",
                    "description": "documentId do campo `card_link`."
                  },
                  "targetCardId": {
                    "type": "string",
                    "description": "documentId do card do board de destino."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Vínculo criado (ou já existente).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "link": {
                          "type": "object",
                          "properties": {
                            "cardId": {
                              "type": "string"
                            },
                            "boardId": {
                              "type": "string"
                            },
                            "title": {
                              "type": "string"
                            },
                            "createdAt": {
                              "type": "string",
                              "format": "date-time"
                            }
                          }
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "added": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{boardId}/cards/search-for-link": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "searchCardsForLink",
        "tags": [
          "Cards vinculados"
        ],
        "summary": "Buscar cards para vincular",
        "description": "Busca cards no board de destino configurado no campo `card_link`.",
        "parameters": [
          {
            "name": "fieldId",
            "in": "query",
            "required": true,
            "description": "documentId do campo `card_link`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Termo de busca (título do card, case-insensitive).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 50
            }
          },
          {
            "name": "excludeCardId",
            "in": "query",
            "description": "documentId de card a excluir dos resultados.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cards encontrados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "documentId": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "currentPhase": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "properties": {
                              "documentId": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              }
                            }
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`fieldId` ausente ou campo em modo `create` (busca bloqueada).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/boards/{boardId}/cards/{cardId}/links/{targetCardId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "cardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "targetCardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "delete": {
        "operationId": "unlinkCard",
        "tags": [
          "Cards vinculados"
        ],
        "summary": "Remover vínculo entre cards",
        "parameters": [
          {
            "name": "fieldId",
            "in": "query",
            "required": true,
            "description": "documentId do campo `card_link` que guarda o vínculo.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Vínculo removido.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Vínculo removido com sucesso"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{boardId}/phases": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "description": "documentId do board.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listPhases",
        "tags": [
          "Fases"
        ],
        "summary": "Listar fases",
        "description": "Lista as fases do board em ordem (`order:asc`), com seus campos.\nA fase de `order` 0 é o **formulário de entrada** — cards não ficam nela.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array de fases (flat, sem envelope).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Phase"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl \"https://api.perpetuus.com.br/api/boards/BOARD_ID/phases\" \\\n  -H \"Authorization: Bearer SEU_TOKEN\" \\\n  -H \"x-tenant-id: acme\"\n"
          }
        ]
      },
      "post": {
        "operationId": "createPhase",
        "tags": [
          "Fases"
        ],
        "summary": "Criar fase",
        "description": "Cria uma fase no board. Se `order` for omitido, a fase entra no fim;\ninserções no meio reordenam as demais automaticamente.\n\n- Fases de `order` 0 são sempre públicas (formulário).\n- `fields` opcional cria os campos junto (slugs duplicados retornam 400).\n- `maxTimeInPhaseHours` define o SLA da fase (1–8760 horas; `null` remove).\n- As transições permitidas são sincronizadas automaticamente na criação.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "example": "Qualificação"
                      },
                      "slug": {
                        "type": "string"
                      },
                      "order": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "description": {
                        "type": "string"
                      },
                      "maxTimeInPhaseHours": {
                        "type": [
                          "integer",
                          "null"
                        ],
                        "minimum": 1,
                        "maximum": 8760
                      },
                      "fields": {
                        "type": "array",
                        "items": {
                          "$ref": "#/components/schemas/FieldDefinition"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fase criada (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Phase"
                }
              }
            }
          },
          "400": {
            "description": "Slugs de campo duplicados ou em conflito com campos existentes do board.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{boardId}/phases/{phaseId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "phaseId",
          "in": "path",
          "required": true,
          "description": "documentId da fase.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getPhase",
        "tags": [
          "Fases"
        ],
        "summary": "Buscar fase",
        "responses": {
          "200": {
            "description": "A fase (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Phase"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updatePhase",
        "tags": [
          "Fases"
        ],
        "summary": "Atualizar fase",
        "description": "Atualiza nome, ordem, SLA, transições permitidas e textos do formulário.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "order": {
                        "type": "integer"
                      },
                      "description": {
                        "type": "string"
                      },
                      "maxTimeInPhaseHours": {
                        "type": [
                          "integer",
                          "null"
                        ]
                      },
                      "allowedTransitions": {
                        "type": "array",
                        "items": {
                          "$ref": "#/components/schemas/AllowedTransition"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fase atualizada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Phase"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deletePhase",
        "tags": [
          "Fases"
        ],
        "summary": "Excluir fase",
        "responses": {
          "200": {
            "description": "Fase excluída."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{boardId}/fields": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listFields",
        "tags": [
          "Campos"
        ],
        "summary": "Listar campos do board",
        "description": "Lista os campos dinâmicos de **todas as fases** do board, com a fase de cada um.\n\n💡 Use este endpoint para descobrir os `slug` aceitos em `fields` ao criar ou\natualizar cards.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Sort"
          }
        ],
        "responses": {
          "200": {
            "description": "Array de campos (flat), ordenado por `order:asc`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/FieldDefinition"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "operationId": "createField",
        "tags": [
          "Campos"
        ],
        "summary": "Criar campo",
        "description": "Cria um campo dinâmico. Todo campo pertence a uma **fase** — envie `phase`\ncom o documentId da fase.\n\nTipos disponíveis: `text, textarea, richtext, email, number, date, datetime,\nselect, multiselect, radio, switch, file, url, phone, card_link, hidden,\nstatement, time, currency, document, checkbox`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "label",
                      "slug",
                      "type",
                      "phase"
                    ],
                    "properties": {
                      "label": {
                        "type": "string",
                        "example": "Valor do orçamento"
                      },
                      "slug": {
                        "type": "string",
                        "example": "valor_orcamento"
                      },
                      "type": {
                        "type": "string",
                        "example": "currency"
                      },
                      "phase": {
                        "type": "string",
                        "description": "documentId da fase."
                      },
                      "order": {
                        "type": "integer"
                      },
                      "required": {
                        "type": "boolean"
                      },
                      "placeholder": {
                        "type": "string"
                      },
                      "helpText": {
                        "type": "string"
                      },
                      "options": {
                        "type": "array",
                        "items": {}
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campo criado (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FieldDefinition"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{boardId}/fields/{fieldId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "fieldId",
          "in": "path",
          "required": true,
          "description": "documentId do campo.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getField",
        "tags": [
          "Campos"
        ],
        "summary": "Buscar campo",
        "responses": {
          "200": {
            "description": "O campo (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FieldDefinition"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateField",
        "tags": [
          "Campos"
        ],
        "summary": "Atualizar campo",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object",
                    "properties": {
                      "label": {
                        "type": "string"
                      },
                      "required": {
                        "type": "boolean"
                      },
                      "order": {
                        "type": "integer"
                      },
                      "placeholder": {
                        "type": "string"
                      },
                      "helpText": {
                        "type": "string"
                      },
                      "options": {
                        "type": "array",
                        "items": {}
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campo atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FieldDefinition"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteField",
        "tags": [
          "Campos"
        ],
        "summary": "Excluir campo",
        "description": "⚠️ Os valores preenchidos deste campo nos cards deixam de ser exibidos.",
        "responses": {
          "200": {
            "description": "Campo excluído."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{boardId}/field-conditions": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listFieldConditions",
        "tags": [
          "Condições de campo"
        ],
        "summary": "Listar condições",
        "description": "Lista as regras de exibição condicional de campos do board, ordenadas por fase e ordem.",
        "parameters": [
          {
            "name": "phaseId",
            "in": "query",
            "description": "Filtrar por fase.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array de condições (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/FieldCondition"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "operationId": "createFieldCondition",
        "tags": [
          "Condições de campo"
        ],
        "summary": "Criar condição",
        "description": "Cria uma regra do tipo \"quando *critérios*, então *mostrar/ocultar campos*\".\n\n- `criteria`: grupos de expressões `{ fieldSlug, operator, value }` combinadas com `AND`.\n- `actionsWhenTrue` / `actionsWhenFalse`: ações `{ type: \"show\"|\"hide\", targetFieldSlugs: [...] }`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "example": "Mostrar CNPJ para empresas"
                      },
                      "scope": {
                        "type": "string",
                        "enum": [
                          "phase",
                          "board"
                        ],
                        "default": "phase"
                      },
                      "phase": {
                        "type": "string",
                        "description": "documentId da fase (quando `scope = phase`)."
                      },
                      "criteria": {
                        "type": "array",
                        "items": {
                          "type": "object"
                        }
                      },
                      "actionsWhenTrue": {
                        "type": "array",
                        "items": {
                          "type": "object"
                        }
                      },
                      "actionsWhenFalse": {
                        "type": "array",
                        "items": {
                          "type": "object"
                        }
                      },
                      "enabled": {
                        "type": "boolean",
                        "default": true
                      }
                    }
                  }
                }
              },
              "example": {
                "data": {
                  "name": "Mostrar CNPJ para empresas",
                  "scope": "phase",
                  "phase": "ph1ccc",
                  "criteria": [
                    {
                      "operator": "AND",
                      "expressions": [
                        {
                          "fieldSlug": "tipo_cliente",
                          "operator": "eq",
                          "value": "empresa"
                        }
                      ]
                    }
                  ],
                  "actionsWhenTrue": [
                    {
                      "type": "show",
                      "targetFieldSlugs": [
                        "cnpj",
                        "razao_social"
                      ]
                    }
                  ],
                  "actionsWhenFalse": [
                    {
                      "type": "hide",
                      "targetFieldSlugs": [
                        "cnpj",
                        "razao_social"
                      ]
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Condição criada (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FieldCondition"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{boardId}/field-conditions/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "documentId da condição.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "put": {
        "operationId": "updateFieldCondition",
        "tags": [
          "Condições de campo"
        ],
        "summary": "Atualizar condição",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Condição atualizada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FieldCondition"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteFieldCondition",
        "tags": [
          "Condições de campo"
        ],
        "summary": "Excluir condição",
        "responses": {
          "200": {
            "description": "Condição excluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Condição deletada com sucesso"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{boardId}/field-conditions/reorder": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "patch": {
        "operationId": "reorderFieldConditions",
        "tags": [
          "Condições de campo"
        ],
        "summary": "Reordenar condições",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "items"
                ],
                "properties": {
                  "items": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "documentId",
                        "order"
                      ],
                      "properties": {
                        "documentId": {
                          "type": "string"
                        },
                        "order": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lista completa reordenada (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/FieldCondition"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/boards/{boardId}/field-conditions/evaluate": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "evaluateFieldConditions",
        "tags": [
          "Condições de campo"
        ],
        "summary": "Avaliar condições",
        "description": "Avalia as condições de uma fase contra um conjunto de valores e retorna quais\ncampos ficam visíveis/ocultos — útil para renderizar formulários externos com\na mesma lógica condicional do app.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "phaseId"
                ],
                "properties": {
                  "phaseId": {
                    "type": "string"
                  },
                  "values": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              },
              "example": {
                "phaseId": "ph1ccc",
                "values": {
                  "tipo_cliente": "empresa"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resultado da avaliação.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "phaseId": {
                      "type": "string"
                    },
                    "visibleSlugs": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "hiddenSlugs": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "requiredOverrides": {
                      "type": "object"
                    },
                    "evaluatedConditions": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{boardId}/tags": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listTags",
        "tags": [
          "Tags"
        ],
        "summary": "Listar tags",
        "description": "Lista as tags do board. Cada tag expõe `slug` e `documentId` — ambos aceitos ao taggear cards.",
        "responses": {
          "200": {
            "description": "Array de tags (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Tag"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "operationId": "createTag",
        "tags": [
          "Tags"
        ],
        "summary": "Criar tag",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "maxLength": 100,
                        "example": "VIP"
                      },
                      "slug": {
                        "type": "string"
                      },
                      "color": {
                        "type": "string",
                        "description": "Hex `#RGB` ou `#RRGGBB`.",
                        "default": "#3b82f6"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tag criada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tag"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/boards/{boardId}/tags/{tagId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "tagId",
          "in": "path",
          "required": true,
          "description": "documentId da tag.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "put": {
        "operationId": "updateTag",
        "tags": [
          "Tags"
        ],
        "summary": "Atualizar tag",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "color": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tag atualizada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tag"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteTag",
        "tags": [
          "Tags"
        ],
        "summary": "Excluir tag",
        "responses": {
          "200": {
            "description": "Tag excluída (removida de todos os cards)."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/contacts": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listContacts",
        "tags": [
          "Contatos"
        ],
        "summary": "Listar contatos",
        "description": "Lista os contatos da organização, com paginação e filtros.\n\n- `quickSearch` busca em nome, e-mail, telefone, CPF e CNPJ.\n- `segment` filtra pelas regras de um segmento (JSON ou base64url).\n- `quickSearch` e `segment` **não podem ser combinados** (400).\n\nCada contato retorna `customFields` como objeto `chave → valor`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/PaginationPage"
          },
          {
            "$ref": "#/components/parameters/PaginationPageSize"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "name": "quickSearch",
            "in": "query",
            "description": "Busca rápida em nome/e-mail/telefone/CPF/CNPJ.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "segment",
            "in": "query",
            "description": "Regras de segmento (JSON, objeto querystring ou base64url).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lista paginada de contatos.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contact"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "pagination": {
                          "$ref": "#/components/schemas/Pagination"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl -G \"https://api.perpetuus.com.br/api/contacts\" \\\n  -H \"Authorization: Bearer SEU_TOKEN\" \\\n  -H \"x-tenant-id: acme\" \\\n  --data-urlencode \"quickSearch=joao\" \\\n  --data-urlencode \"pagination[pageSize]=50\"\n"
          }
        ]
      },
      "post": {
        "operationId": "createContact",
        "tags": [
          "Contatos"
        ],
        "summary": "Criar contato",
        "description": "Cria um contato. Regras:\n- `name` é obrigatório; e-mail **ou** telefone é necessário.\n- E-mail, telefone, CPF e CNPJ são **únicos por organização** (400 se duplicado).\n- CPF/CNPJ são validados algoritmicamente e armazenados sem máscara.\n- `customFields` grava campos customizados definidos na organização.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "phone": {
                        "type": "string"
                      },
                      "contact_type": {
                        "type": "string",
                        "enum": [
                          "pessoa",
                          "empresa"
                        ]
                      },
                      "cpf": {
                        "type": "string"
                      },
                      "cnpj": {
                        "type": "string"
                      },
                      "address": {
                        "type": "string"
                      },
                      "city": {
                        "type": "string"
                      },
                      "state": {
                        "type": "string"
                      },
                      "country": {
                        "type": "string"
                      },
                      "postal_code": {
                        "type": "string"
                      },
                      "birthdate": {
                        "type": "string",
                        "format": "date"
                      },
                      "first_buy_date": {
                        "type": "string",
                        "format": "date"
                      },
                      "owner": {
                        "type": "string",
                        "description": "documentId do membership responsável (define também `team` e `ownedAt`)."
                      },
                      "customFields": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              },
              "example": {
                "data": {
                  "name": "João Silva",
                  "email": "joao@cliente.com",
                  "phone": "+5511999999999",
                  "contact_type": "pessoa",
                  "city": "São Paulo",
                  "customFields": {
                    "origem": "Indicação"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contato criado (objeto flat, com `customFields`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "description": "Validação — nome ausente, e-mail/telefone/CPF/CNPJ duplicados ou inválidos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/contacts/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "documentId do contato.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getContact",
        "tags": [
          "Contatos"
        ],
        "summary": "Buscar contato",
        "responses": {
          "200": {
            "description": "O contato (objeto flat, com `customFields`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateContact",
        "tags": [
          "Contatos"
        ],
        "summary": "Atualizar contato",
        "description": "Atualização parcial — envie apenas o que mudou. Não é possível deixar e-mail\n**e** telefone vazios ao mesmo tempo (400).\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      },
                      "phone": {
                        "type": "string"
                      },
                      "customFields": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contato atualizado (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteContact",
        "tags": [
          "Contatos"
        ],
        "summary": "Excluir contato",
        "description": "Contatos com cards vinculados **não podem ser excluídos** — a API retorna 400\ncom o código `CONTACT_HAS_LINKED_CARDS` e `linkedCardsCount` nos detalhes.\n",
        "responses": {
          "200": {
            "description": "Contato excluído."
          },
          "400": {
            "description": "Contato possui cards vinculados (`CONTACT_HAS_LINKED_CARDS`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/contacts/{id}/linked-cards": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getContactLinkedCards",
        "tags": [
          "Contatos"
        ],
        "summary": "Cards vinculados ao contato",
        "responses": {
          "200": {
            "description": "Cards do contato (resumidos).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/contacts/{id}/transfer-owner": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "put": {
        "operationId": "transferContactOwner",
        "tags": [
          "Contatos"
        ],
        "summary": "Transferir responsável",
        "description": "Transfere a carteira do contato para outro membership. Atualiza `owner`,\n`team` (herdado do novo responsável) e `ownedAt`, e registra a atividade\n`owner_changed` na timeline.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "newOwnerId"
                ],
                "properties": {
                  "newOwnerId": {
                    "type": "string",
                    "description": "documentId do membership do novo responsável."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contato atualizado (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/contacts/bulk": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "bulkImportContacts",
        "tags": [
          "Contatos"
        ],
        "summary": "Importar contatos em massa",
        "description": "Importa contatos em lote. Cada item precisa de `name` e de um e-mail **ou**\ntelefone válido (telefones são normalizados para E.164; linhas inválidas são\nignoradas e reportadas em `errors`).\n\nCampos customizados podem ser enviados diretamente por slug em cada item.\n\nA resposta inclui `bulkImportJobDocumentId` para acompanhar o processamento\nvia `GET /contacts/bulk-import-status/{documentId}`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "items"
                ],
                "properties": {
                  "items": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "name"
                      ],
                      "additionalProperties": true,
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        },
                        "phone": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "options": {
                    "type": "object",
                    "properties": {
                      "triggerAutomations": {
                        "type": "boolean"
                      },
                      "autoAssignOwner": {
                        "type": "boolean"
                      }
                    }
                  }
                }
              },
              "example": {
                "items": [
                  {
                    "name": "João Silva",
                    "email": "joao@cliente.com",
                    "phone": "+5511999999999",
                    "origem": "Planilha"
                  },
                  {
                    "name": "Maria Souza",
                    "email": "maria@cliente.com"
                  }
                ],
                "options": {
                  "autoAssignOwner": true
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resultado da importação.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "results": {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "integer"
                        },
                        "failed": {
                          "type": "integer"
                        },
                        "total": {
                          "type": "integer"
                        },
                        "errors": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "bulkImportJobDocumentId": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/contacts/bulk-import-status/{documentId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "documentId",
          "in": "path",
          "required": true,
          "description": "documentId do job de importação.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getBulkImportStatus",
        "tags": [
          "Contatos"
        ],
        "summary": "Status da importação em massa",
        "responses": {
          "200": {
            "description": "Status do job.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "documentId": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "contactsImported": {
                      "type": "integer"
                    },
                    "finishedAt": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/contacts/bulk-delete": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "bulkDeleteContacts",
        "tags": [
          "Contatos"
        ],
        "summary": "Excluir contatos em massa",
        "description": "Exclui vários contatos de uma vez. Contatos com cards vinculados são\nreportados em `failures` com o código `CONTACT_HAS_LINKED_CARDS`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "documentIds"
                ],
                "properties": {
                  "documentIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resultado da exclusão em massa.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "integer"
                    },
                    "failed": {
                      "type": "integer"
                    },
                    "notFound": {
                      "type": "integer"
                    },
                    "failures": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "documentId": {
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          },
                          "linkedCardsCount": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/contacts/bulk-update": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "bulkUpdateContacts",
        "tags": [
          "Contatos"
        ],
        "summary": "Atualizar contatos em massa",
        "description": "Aplica um `patch` a um conjunto de contatos definido por `scope`:\n\n| `scope.type` | Alvos |\n|--------------|-------|\n| `selected` | `scope.documentIds` |\n| `filter` | `scope.rules` (regras de filtro) |\n| `segment_filters` | `scope.filters.conditions` (regras de segmento) |\n| `quick_search` | `scope.q` (busca rápida) |\n\nO `patch` aceita `newOwnerDocumentId`, `fields` (campos nativos permitidos) e\n`customFields` — pelo menos um é obrigatório.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "scope",
                  "patch"
                ],
                "properties": {
                  "scope": {
                    "type": "object",
                    "required": [
                      "type"
                    ],
                    "properties": {
                      "type": {
                        "type": "string",
                        "enum": [
                          "selected",
                          "filter",
                          "segment_filters",
                          "quick_search"
                        ]
                      },
                      "documentIds": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "rules": {
                        "type": "object"
                      },
                      "filters": {
                        "$ref": "#/components/schemas/SegmentFilters"
                      },
                      "q": {
                        "type": "string"
                      }
                    }
                  },
                  "patch": {
                    "type": "object",
                    "properties": {
                      "newOwnerDocumentId": {
                        "type": "string"
                      },
                      "fields": {
                        "type": "object",
                        "additionalProperties": true
                      },
                      "customFields": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              },
              "example": {
                "scope": {
                  "type": "selected",
                  "documentIds": [
                    "ct1a2b3c",
                    "ct4d5e6f"
                  ]
                },
                "patch": {
                  "newOwnerDocumentId": "mb9z8y7x"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resultado da atualização em massa.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "updated": {
                      "type": "integer"
                    },
                    "skippedOwner": {
                      "type": "integer"
                    },
                    "failed": {
                      "type": "integer"
                    },
                    "totalTargets": {
                      "type": "integer"
                    },
                    "failures": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/contacts/export": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "exportContacts",
        "tags": [
          "Contatos"
        ],
        "summary": "Exportar contatos (CSV)",
        "description": "Exporta contatos em **CSV** (`text/csv`). Aceita os mesmos filtros da\nlistagem (`filters`, `segment`, `quickSearch`, `sort`) — `segment` e\n`quickSearch` não podem ser combinados.\n\nO total exportado vem no header `X-Export-Total`. Colunas incluem dados do\ncontato, responsável, time e campos customizados.\n",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "filters": {
                    "type": "object"
                  },
                  "segment": {
                    "type": "object"
                  },
                  "quickSearch": {
                    "type": "string"
                  },
                  "sort": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Arquivo CSV.",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/contact-activities": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listContactActivities",
        "tags": [
          "Atividades de contato"
        ],
        "summary": "Listar atividades",
        "description": "Timeline de eventos dos contatos, ordenada por `performedAt:desc`.\nFiltre por contato com `contactId` (ou `filters[contact][documentId]`).\n",
        "parameters": [
          {
            "name": "contactId",
            "in": "query",
            "description": "documentId do contato.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Atividades.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ContactActivity"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/contact-activities/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getContactActivity",
        "tags": [
          "Atividades de contato"
        ],
        "summary": "Buscar atividade",
        "responses": {
          "200": {
            "description": "A atividade (objeto flat), com `contact` e `actor` populados.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactActivity"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/contact-activities/note": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "createContactNote",
        "tags": [
          "Atividades de contato"
        ],
        "summary": "Adicionar nota ao contato",
        "description": "Registra uma nota (`note_added`) na timeline do contato. A nota é atribuída\nao usuário autenticado e limitada a 5.000 caracteres.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "contactId",
                  "note"
                ],
                "properties": {
                  "contactId": {
                    "type": "string",
                    "description": "documentId do contato."
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 5000
                  }
                }
              },
              "example": {
                "contactId": "ct1a2b3c",
                "note": "Cliente pediu retorno na sexta-feira."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Nota criada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ContactActivity"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`contactId` ou `note` ausentes.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl -X POST \"https://api.perpetuus.com.br/api/contact-activities/note\" \\\n  -H \"Authorization: Bearer SEU_TOKEN\" \\\n  -H \"x-tenant-id: acme\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"contactId\": \"ct1a2b3c\", \"note\": \"Cliente pediu retorno na sexta.\"}'\n"
          }
        ]
      }
    },
    "/segments": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listSegments",
        "tags": [
          "Segmentos"
        ],
        "summary": "Listar segmentos",
        "description": "Lista os segmentos da organização. Com `pagination[page]`/`[pageSize]` retorna\n`{ data, meta.pagination }`; sem paginação, retorna `{ data }` com a lista completa.\n",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Busca em nome e descrição.",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/PaginationPage"
          },
          {
            "$ref": "#/components/parameters/PaginationPageSize"
          },
          {
            "$ref": "#/components/parameters/Sort"
          }
        ],
        "responses": {
          "200": {
            "description": "Segmentos.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Segment"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "pagination": {
                          "$ref": "#/components/schemas/Pagination"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "operationId": "createSegment",
        "tags": [
          "Segmentos"
        ],
        "summary": "Criar segmento",
        "description": "Cria um segmento dinâmico. `filters.conditions` não pode ser vazio.\nO `contactCount` é calculado na criação.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name",
                      "filters"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "example": "Leads SP com e-mail"
                      },
                      "description": {
                        "type": "string"
                      },
                      "filters": {
                        "$ref": "#/components/schemas/SegmentFilters"
                      },
                      "active": {
                        "type": "boolean"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Segmento criado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Segment"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`Filtros são obrigatórios` — `filters.conditions` vazio ou ausente.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/segments/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "documentId do segmento.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getSegment",
        "tags": [
          "Segmentos"
        ],
        "summary": "Buscar segmento",
        "responses": {
          "200": {
            "description": "O segmento.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Segment"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateSegment",
        "tags": [
          "Segmentos"
        ],
        "summary": "Atualizar segmento",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string"
                      },
                      "filters": {
                        "$ref": "#/components/schemas/SegmentFilters"
                      },
                      "active": {
                        "type": "boolean"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Segmento atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Segment"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteSegment",
        "tags": [
          "Segmentos"
        ],
        "summary": "Excluir segmento",
        "responses": {
          "200": {
            "description": "Segmento excluído."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/segments/preview": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "previewSegment",
        "tags": [
          "Segmentos"
        ],
        "summary": "Pré-visualizar audiência",
        "description": "Resolve um conjunto de regras **sem salvar o segmento** — ideal para testar\nfiltros antes de criar.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "filters"
                ],
                "properties": {
                  "filters": {
                    "$ref": "#/components/schemas/SegmentFilters"
                  },
                  "page": {
                    "type": "integer",
                    "default": 1
                  },
                  "pageSize": {
                    "type": "integer",
                    "default": 20
                  }
                }
              },
              "example": {
                "filters": {
                  "logic": "AND",
                  "conditions": [
                    {
                      "field": "city",
                      "op": "eq",
                      "value": "São Paulo"
                    },
                    {
                      "field": "email",
                      "op": "notEmpty"
                    }
                  ]
                },
                "page": 1,
                "pageSize": 20
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contatos que casam com as regras.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "contacts": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/ContactRef"
                          }
                        },
                        "total": {
                          "type": "integer"
                        },
                        "page": {
                          "type": "integer"
                        },
                        "pageSize": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/segments/{id}/resolve": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "resolveSegment",
        "tags": [
          "Segmentos"
        ],
        "summary": "Resolver segmento (listar contatos)",
        "description": "Retorna os contatos que casam com as regras do segmento salvo, paginados.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page": {
                    "type": "integer",
                    "default": 1
                  },
                  "pageSize": {
                    "type": "integer",
                    "default": 50
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contatos do segmento.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "contacts": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/ContactRef"
                          }
                        },
                        "total": {
                          "type": "integer"
                        },
                        "page": {
                          "type": "integer"
                        },
                        "pageSize": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/segments/{id}/count": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "countSegment",
        "tags": [
          "Segmentos"
        ],
        "summary": "Contar contatos do segmento",
        "responses": {
          "200": {
            "description": "Contagem atual.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "count": {
                          "type": "integer",
                          "example": 231
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/segments/filter-options": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "getSegmentFilterOptions",
        "tags": [
          "Segmentos"
        ],
        "summary": "Opções de filtro disponíveis",
        "description": "Campos, operadores e valores disponíveis para montar regras de segmento (inclui campos customizados da organização).",
        "responses": {
          "200": {
            "description": "Opções de filtro.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/campaigns": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listCampaigns",
        "tags": [
          "Campanhas"
        ],
        "summary": "Listar campanhas",
        "description": "Lista as campanhas da organização, com segmento e canal populados. Estatísticas de campanhas em andamento são recalculadas.",
        "responses": {
          "200": {
            "description": "Campanhas.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Campaign"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "operationId": "createCampaign",
        "tags": [
          "Campanhas"
        ],
        "summary": "Criar campanha",
        "description": "Cria uma campanha de disparo em massa para um segmento.\n\n- `channel`: `whatsapp`, `email` ou `sms`.\n- Para `email`, `messageConfig` exige `subject` e `html`.\n- Com `scheduledAt`, a campanha nasce `scheduled`; sem, nasce `draft`\n  (dispare com `POST /campaigns/{id}/trigger`).\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name",
                      "segment",
                      "channel",
                      "messageConfig"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "example": "Reativação julho"
                      },
                      "description": {
                        "type": "string"
                      },
                      "segment": {
                        "type": "string",
                        "description": "documentId do segmento alvo."
                      },
                      "channel": {
                        "type": "string",
                        "enum": [
                          "whatsapp",
                          "email",
                          "sms"
                        ]
                      },
                      "chatChannel": {
                        "type": "string",
                        "description": "documentId do canal de envio (obrigatório para WhatsApp)."
                      },
                      "messageConfig": {
                        "type": "object",
                        "description": "Conteúdo da mensagem. Para e-mail: `{ subject, html, text? }`.\nPara WhatsApp: template e variáveis conforme o canal.\n",
                        "additionalProperties": true
                      },
                      "scheduledAt": {
                        "type": "string",
                        "format": "date-time"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campanha criada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Campaign"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/campaigns/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "documentId da campanha.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getCampaign",
        "tags": [
          "Campanhas"
        ],
        "summary": "Buscar campanha",
        "responses": {
          "200": {
            "description": "A campanha.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Campaign"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateCampaign",
        "tags": [
          "Campanhas"
        ],
        "summary": "Atualizar campanha",
        "description": "Campanhas `processing` ou `completed` não podem ser editadas (400).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campanha atualizada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Campaign"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteCampaign",
        "tags": [
          "Campanhas"
        ],
        "summary": "Excluir campanha",
        "responses": {
          "200": {
            "description": "Excluída.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/campaigns/{id}/stats": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getCampaignStats",
        "tags": [
          "Campanhas"
        ],
        "summary": "Estatísticas da campanha",
        "description": "Contadores agregados de envio e engajamento. `total/pending/sent/failed/skipped`\nsão recalculados dos logs; `delivered/opened/clicked/bounced` vêm dos eventos\ndo provedor de e-mail.\n",
        "responses": {
          "200": {
            "description": "Estatísticas.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CampaignStats"
                    }
                  }
                },
                "example": {
                  "data": {
                    "total": 500,
                    "pending": 120,
                    "sent": 350,
                    "failed": 20,
                    "skipped": 10,
                    "delivered": 300,
                    "opened": 180,
                    "clicked": 45,
                    "bounced": 5
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl \"https://api.perpetuus.com.br/api/campaigns/CAMPAIGN_ID/stats\" \\\n  -H \"Authorization: Bearer SEU_TOKEN\" \\\n  -H \"x-tenant-id: acme\"\n"
          }
        ]
      }
    },
    "/campaigns/{id}/trigger": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "triggerCampaign",
        "tags": [
          "Campanhas"
        ],
        "summary": "Disparar campanha",
        "description": "Inicia o envio imediatamente. Sujeito a rate limit reforçado.",
        "responses": {
          "200": {
            "description": "Envio iniciado."
          },
          "400": {
            "description": "Transição de estado inválida (ex. campanha já em processamento).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/campaigns/{id}/pause": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "pauseCampaign",
        "tags": [
          "Campanhas"
        ],
        "summary": "Pausar campanha",
        "responses": {
          "200": {
            "description": "Campanha pausada."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/campaigns/{id}/resume": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "resumeCampaign",
        "tags": [
          "Campanhas"
        ],
        "summary": "Retomar campanha",
        "responses": {
          "200": {
            "description": "Campanha retomada."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/campaigns/{id}/cancel": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "cancelCampaign",
        "tags": [
          "Campanhas"
        ],
        "summary": "Cancelar campanha",
        "responses": {
          "200": {
            "description": "Campanha cancelada."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/campaigns/{id}/retry": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "retryCampaign",
        "tags": [
          "Campanhas"
        ],
        "summary": "Reenviar falhas",
        "description": "Recoloca na fila os envios com status `failed`.",
        "responses": {
          "200": {
            "description": "Reenvio iniciado."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/tasks": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listTasks",
        "tags": [
          "Tarefas"
        ],
        "summary": "Listar tarefas",
        "description": "Lista tarefas dos boards acessíveis ao usuário, ordenadas por `dueDate:asc`.\nFiltre por board com `filters[board][documentId]`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array de tarefas (flat), com `card` e `assignees` populados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Task"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "operationId": "createTask",
        "tags": [
          "Tarefas"
        ],
        "summary": "Criar tarefa",
        "description": "Cria uma tarefa. Se `assignees` for omitido, a tarefa é atribuída ao criador.\n`taskStatus` usa os status configurados no board (`taskStatuses`, padrão\n`pending`, `in-progress`, `completed`).\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "maxLength": 255,
                        "example": "Ligar para o cliente"
                      },
                      "description": {
                        "type": "string"
                      },
                      "dueDate": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "type": {
                        "type": "string",
                        "enum": [
                          "reminder",
                          "follow-up",
                          "action",
                          "other"
                        ]
                      },
                      "taskStatus": {
                        "type": "string"
                      },
                      "card": {
                        "type": "string",
                        "description": "documentId do card vinculado (opcional)."
                      },
                      "board": {
                        "type": "string",
                        "description": "documentId do board (opcional se `card` for enviado)."
                      },
                      "assignees": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "documentIds de memberships."
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tarefa criada (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/tasks/my-tasks": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "getMyTasks",
        "tags": [
          "Tarefas"
        ],
        "summary": "Minhas tarefas",
        "description": "Tarefas atribuídas ao usuário autenticado, em boards que ele acessa, ordenadas por vencimento.",
        "responses": {
          "200": {
            "description": "Array de tarefas (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Task"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/boards/{boardId}/tasks": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getBoardTasks",
        "tags": [
          "Tarefas"
        ],
        "summary": "Tarefas do board",
        "responses": {
          "200": {
            "description": "Array de tarefas do board (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Task"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/tasks/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "documentId da tarefa.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getTask",
        "tags": [
          "Tarefas"
        ],
        "summary": "Buscar tarefa",
        "responses": {
          "200": {
            "description": "A tarefa (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateTask",
        "tags": [
          "Tarefas"
        ],
        "summary": "Atualizar tarefa",
        "description": "Atualização parcial. Marcar um status de conclusão (ex. `completed`) preenche\n`completedAt` automaticamente. Operadores só editam tarefas onde são assignees.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "taskStatus": {
                        "type": "string",
                        "example": "completed"
                      },
                      "dueDate": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "assignees": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tarefa atualizada (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteTask",
        "tags": [
          "Tarefas"
        ],
        "summary": "Excluir tarefa",
        "responses": {
          "200": {
            "description": "Tarefa excluída."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/comments": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listComments",
        "tags": [
          "Comentários"
        ],
        "summary": "Listar comentários",
        "description": "Lista comentários dos cards acessíveis. Para os comentários de um card,\nuse `filters[card][documentId]=CARD_ID` (caminho otimizado).\n",
        "parameters": [
          {
            "name": "filters[card][documentId]",
            "in": "query",
            "description": "documentId do card.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Comentários (com `author` populado). Com filtro de card, envelope `{ data, meta.pagination }`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Comment"
                      }
                    },
                    "meta": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createComment",
        "tags": [
          "Comentários"
        ],
        "summary": "Comentar em um card",
        "description": "Cria um comentário. `card` é obrigatório.\n\n- **Menções**: envie `mentions` (documentIds de memberships) ou deixe que a\n  API as detecte no conteúdo; menções inválidas retornam 400.\n- Com `contentFormat: html`, o conteúdo é sanitizado.\n- Links no conteúdo são detectados e salvos em `metadata.links`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "card",
                      "content"
                    ],
                    "properties": {
                      "card": {
                        "type": "string",
                        "description": "documentId do card."
                      },
                      "content": {
                        "type": "string"
                      },
                      "contentFormat": {
                        "type": "string",
                        "enum": [
                          "plain",
                          "html"
                        ],
                        "default": "plain"
                      },
                      "mentions": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "data": {
                  "card": "cd1a2b3c",
                  "content": "Cliente confirmou reunião para sexta."
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Comentário criado (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Comment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/comments/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getComment",
        "tags": [
          "Comentários"
        ],
        "summary": "Buscar comentário",
        "responses": {
          "200": {
            "description": "O comentário (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Comment"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateComment",
        "tags": [
          "Comentários"
        ],
        "summary": "Editar comentário",
        "description": "Apenas o autor pode editar. Novas menções são notificadas.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object",
                    "properties": {
                      "content": {
                        "type": "string"
                      },
                      "contentFormat": {
                        "type": "string",
                        "enum": [
                          "plain",
                          "html"
                        ]
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Comentário atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Comment"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteComment",
        "tags": [
          "Comentários"
        ],
        "summary": "Excluir comentário",
        "description": "Apenas o autor pode excluir.",
        "responses": {
          "200": {
            "description": "Comentário excluído."
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/teams": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listTeams",
        "tags": [
          "Times"
        ],
        "summary": "Listar times",
        "description": "Lista os times da organização, com líder e membros populados. Requer o módulo de times habilitado no plano.",
        "responses": {
          "200": {
            "description": "Array de times (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Team"
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "operationId": "createTeam",
        "tags": [
          "Times"
        ],
        "summary": "Criar time",
        "description": "Apenas administradores. `leader` é obrigatório.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name",
                      "leader"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "example": "Time SP"
                      },
                      "description": {
                        "type": "string"
                      },
                      "leader": {
                        "type": "string",
                        "description": "documentId do membership líder."
                      },
                      "color": {
                        "type": "string",
                        "default": "#3B82F6"
                      },
                      "active": {
                        "type": "boolean"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Time criado (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Team"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/teams/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "documentId do time.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getTeam",
        "tags": [
          "Times"
        ],
        "summary": "Buscar time",
        "responses": {
          "200": {
            "description": "O time (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Team"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateTeam",
        "tags": [
          "Times"
        ],
        "summary": "Atualizar time",
        "description": "Permitido para administradores e para o líder do time.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Time atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Team"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteTeam",
        "tags": [
          "Times"
        ],
        "summary": "Excluir time",
        "description": "Apenas administradores. Times com contatos vinculados não podem ser excluídos (400).",
        "responses": {
          "200": {
            "description": "Time excluído."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/teams/{id}/members": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "addTeamMember",
        "tags": [
          "Times"
        ],
        "summary": "Adicionar membro ao time",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "membershipId"
                    ],
                    "properties": {
                      "membershipId": {
                        "type": "string",
                        "description": "documentId do membership."
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Membro adicionado."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/teams/{id}/members/{membershipId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "membershipId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "delete": {
        "operationId": "removeTeamMember",
        "tags": [
          "Times"
        ],
        "summary": "Remover membro do time",
        "responses": {
          "200": {
            "description": "Membro removido."
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/quotes": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listQuotes",
        "tags": [
          "Orçamentos"
        ],
        "summary": "Listar orçamentos",
        "description": "Lista orçamentos da organização. Filtre com `filters[quoteStatus]`,\n`filters[card]` ou `filters[contact]` (documentIds).\n",
        "parameters": [
          {
            "name": "filters[quoteStatus]",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "active",
                "won",
                "lost"
              ]
            }
          },
          {
            "name": "filters[card]",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filters[contact]",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array de orçamentos (flat), com card, contato e itens populados.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Quote"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createQuote",
        "tags": [
          "Orçamentos"
        ],
        "summary": "Criar orçamento",
        "description": "Cria um orçamento. `items` é obrigatório (mínimo 1).\n\n- `number`, `subtotal` e `total` são **calculados no servidor** — valores\n  enviados são ignorados.\n- `updateCardValue: true` atualiza o `value` do card com o total.\n- Itens abaixo do preço mínimo (`minPrice`) do produto exigem a permissão\n  de override de preço (400 caso contrário).\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "items"
                ],
                "properties": {
                  "items": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "$ref": "#/components/schemas/QuoteItemInput"
                    }
                  },
                  "card": {
                    "type": "string",
                    "description": "documentId do card."
                  },
                  "contact": {
                    "type": "string",
                    "description": "documentId do contato."
                  },
                  "quoteStatus": {
                    "type": "string",
                    "enum": [
                      "draft",
                      "active",
                      "won",
                      "lost"
                    ]
                  },
                  "discountType": {
                    "type": "string",
                    "enum": [
                      "percentage",
                      "fixed"
                    ]
                  },
                  "discountValue": {
                    "type": "number"
                  },
                  "currency": {
                    "type": "string",
                    "default": "BRL"
                  },
                  "validUntil": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "notes": {
                    "type": "string"
                  },
                  "pdfTemplate": {
                    "type": "string",
                    "description": "documentId do modelo de PDF."
                  },
                  "updateCardValue": {
                    "type": "boolean"
                  }
                }
              },
              "example": {
                "card": "cd1a2b3c",
                "items": [
                  {
                    "name": "Consultoria estratégica",
                    "quantity": 1,
                    "unitPrice": 15000
                  },
                  {
                    "product": "pr9x8y7z",
                    "name": "Plano anual",
                    "quantity": 1,
                    "periods": 12,
                    "unitPrice": 990
                  }
                ],
                "discountType": "percentage",
                "discountValue": 10,
                "updateCardValue": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Orçamento criado (flat), com número e totais calculados.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Quote"
                }
              }
            }
          },
          "400": {
            "description": "Sem itens (`At least one item is required`) ou preço abaixo do mínimo sem permissão.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/quotes/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "documentId do orçamento.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getQuote",
        "tags": [
          "Orçamentos"
        ],
        "summary": "Buscar orçamento",
        "responses": {
          "200": {
            "description": "O orçamento (flat), com itens e produtos.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Quote"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateQuote",
        "tags": [
          "Orçamentos"
        ],
        "summary": "Atualizar orçamento",
        "description": "Atualização parcial. Totais são recalculados quando itens/desconto mudam.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "items": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/QuoteItemInput"
                    }
                  },
                  "discountType": {
                    "type": "string",
                    "enum": [
                      "percentage",
                      "fixed"
                    ]
                  },
                  "discountValue": {
                    "type": "number"
                  },
                  "quoteStatus": {
                    "type": "string",
                    "enum": [
                      "draft",
                      "active",
                      "won",
                      "lost"
                    ]
                  },
                  "validUntil": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "notes": {
                    "type": "string"
                  },
                  "updateCardValue": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Orçamento atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Quote"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteQuote",
        "tags": [
          "Orçamentos"
        ],
        "summary": "Excluir orçamento",
        "responses": {
          "200": {
            "description": "Orçamento excluído."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/quotes/{id}/activate": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "activateQuote",
        "tags": [
          "Orçamentos"
        ],
        "summary": "Ativar orçamento",
        "description": "Marca o orçamento como `active` e rebaixa os demais orçamentos ativos do\nmesmo card para `draft`. Pode atualizar o valor do card conforme as\nconfigurações do board.\n",
        "responses": {
          "200": {
            "description": "Orçamento ativado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Quote"
                }
              }
            }
          },
          "400": {
            "description": "Orçamento já está ativo.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/quotes/{id}/duplicate": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "duplicateQuote",
        "tags": [
          "Orçamentos"
        ],
        "summary": "Duplicar orçamento",
        "description": "Cria uma cópia `draft` com novo número e versão incrementada.",
        "responses": {
          "200": {
            "description": "Cópia criada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Quote"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/quotes/{id}/pdf": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getQuotePdf",
        "tags": [
          "Orçamentos"
        ],
        "summary": "Gerar PDF do orçamento",
        "parameters": [
          {
            "name": "templateId",
            "in": "query",
            "description": "documentId de um modelo de PDF específico (opcional).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PDF do orçamento (download).",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL",
            "source": "curl \"https://api.perpetuus.com.br/api/quotes/QUOTE_ID/pdf\" \\\n  -H \"Authorization: Bearer SEU_TOKEN\" \\\n  -H \"x-tenant-id: acme\" \\\n  --output orcamento.pdf\n"
          }
        ]
      }
    },
    "/boards/{boardId}/cards/{cardId}/quotes": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "cardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listCardQuotes",
        "tags": [
          "Orçamentos"
        ],
        "summary": "Orçamentos de um card",
        "responses": {
          "200": {
            "description": "Array de orçamentos do card (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Quote"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Card não pertence a este board.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "operationId": "createCardQuote",
        "tags": [
          "Orçamentos"
        ],
        "summary": "Criar orçamento para um card",
        "description": "Mesmo corpo de `POST /quotes`, com `card` injetado automaticamente.\nO `contact` é herdado do card se não for enviado.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "items"
                ],
                "properties": {
                  "items": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "$ref": "#/components/schemas/QuoteItemInput"
                    }
                  },
                  "discountType": {
                    "type": "string"
                  },
                  "discountValue": {
                    "type": "number"
                  },
                  "updateCardValue": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Orçamento criado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Quote"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/products": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listProducts",
        "tags": [
          "Produtos"
        ],
        "summary": "Listar produtos",
        "description": "Lista o catálogo. `filters[name]` busca em nome **e** SKU.\n\nCom `pagination[page]`/`[pageSize]`, a resposta usa `{ data, meta.pagination }`;\nsem paginação, retorna array flat (até 100 itens).\n",
        "parameters": [
          {
            "name": "filters[productType]",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "physical",
                "digital",
                "service"
              ]
            }
          },
          {
            "name": "filters[billingType]",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "one_time",
                "recurring"
              ]
            }
          },
          {
            "name": "filters[active]",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "filters[categories][documentId]",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "filters[name]",
            "in": "query",
            "description": "Busca em nome e SKU.",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/PaginationPage"
          },
          {
            "$ref": "#/components/parameters/PaginationPageSize"
          },
          {
            "$ref": "#/components/parameters/Sort"
          }
        ],
        "responses": {
          "200": {
            "description": "Produtos.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Product"
                      }
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "pagination": {
                          "$ref": "#/components/schemas/Pagination"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createProduct",
        "tags": [
          "Produtos"
        ],
        "summary": "Criar produto",
        "description": "`name`, `sku` e `price` são obrigatórios. O SKU é único por organização.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name",
                      "sku",
                      "price"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "example": "Plano Pro"
                      },
                      "sku": {
                        "type": "string",
                        "example": "PLANO-PRO"
                      },
                      "price": {
                        "type": "number",
                        "example": 990
                      },
                      "salePrice": {
                        "type": "number"
                      },
                      "minPrice": {
                        "type": "number",
                        "description": "Piso de venda — orçamentos abaixo exigem permissão de override."
                      },
                      "productType": {
                        "type": "string",
                        "enum": [
                          "physical",
                          "digital",
                          "service"
                        ]
                      },
                      "billingType": {
                        "type": "string",
                        "enum": [
                          "one_time",
                          "recurring"
                        ]
                      },
                      "description": {
                        "type": "string"
                      },
                      "shortDescription": {
                        "type": "string",
                        "maxLength": 500
                      },
                      "currency": {
                        "type": "string",
                        "default": "BRL"
                      },
                      "active": {
                        "type": "boolean"
                      },
                      "categories": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "documentIds de categorias."
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Produto criado (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          },
          "400": {
            "description": "Nome/SKU/preço ausentes ou SKU duplicado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/products/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "documentId do produto.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getProduct",
        "tags": [
          "Produtos"
        ],
        "summary": "Buscar produto",
        "responses": {
          "200": {
            "description": "O produto (flat), com imagem, galeria e categorias.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateProduct",
        "tags": [
          "Produtos"
        ],
        "summary": "Atualizar produto",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Produto atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Product"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteProduct",
        "tags": [
          "Produtos"
        ],
        "summary": "Excluir produto",
        "responses": {
          "200": {
            "description": "Produto excluído."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/product-categories": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listProductCategories",
        "tags": [
          "Produtos"
        ],
        "summary": "Listar categorias",
        "responses": {
          "200": {
            "description": "Array de categorias (flat), com categoria pai populada.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ProductCategory"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createProductCategory",
        "tags": [
          "Produtos"
        ],
        "summary": "Criar categoria",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "maxLength": 100
                      },
                      "description": {
                        "type": "string"
                      },
                      "color": {
                        "type": "string",
                        "default": "#3b82f6"
                      },
                      "parent": {
                        "type": "string",
                        "description": "documentId da categoria pai (para hierarquia)."
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Categoria criada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductCategory"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/product-categories/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getProductCategory",
        "tags": [
          "Produtos"
        ],
        "summary": "Buscar categoria",
        "responses": {
          "200": {
            "description": "A categoria (flat).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductCategory"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateProductCategory",
        "tags": [
          "Produtos"
        ],
        "summary": "Atualizar categoria",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Categoria atualizada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductCategory"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteProductCategory",
        "tags": [
          "Produtos"
        ],
        "summary": "Excluir categoria",
        "responses": {
          "200": {
            "description": "Categoria excluída."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/pdf-templates": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listPdfTemplates",
        "tags": [
          "Modelos de PDF"
        ],
        "summary": "Listar modelos de PDF",
        "responses": {
          "200": {
            "description": "Modelos da organização.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PdfTemplate"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createPdfTemplate",
        "tags": [
          "Modelos de PDF"
        ],
        "summary": "Criar modelo de PDF",
        "description": "Cria um modelo com layout em blocos (cabeçalho, corpo e rodapé) e estilos\ncustomizados. Usado na geração de PDFs de orçamentos.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "maxLength": 100
                      },
                      "description": {
                        "type": "string"
                      },
                      "templateType": {
                        "type": "string",
                        "enum": [
                          "quote",
                          "invoice",
                          "contract",
                          "report"
                        ],
                        "default": "quote"
                      },
                      "layout": {
                        "type": "object",
                        "description": "Estrutura `{ pageSize, orientation, margins, header, body, footer }` com blocos."
                      },
                      "styles": {
                        "type": "object",
                        "description": "Cores e fontes: `{ primaryColor, secondaryColor, fontFamily, fontSize }`."
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Modelo criado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PdfTemplate"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/pdf-templates/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getPdfTemplate",
        "tags": [
          "Modelos de PDF"
        ],
        "summary": "Buscar modelo",
        "responses": {
          "200": {
            "description": "O modelo.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PdfTemplate"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updatePdfTemplate",
        "tags": [
          "Modelos de PDF"
        ],
        "summary": "Atualizar modelo",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Modelo atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PdfTemplate"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deletePdfTemplate",
        "tags": [
          "Modelos de PDF"
        ],
        "summary": "Excluir modelo",
        "responses": {
          "200": {
            "description": "Modelo excluído."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/pdf-templates/{id}/duplicate": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "duplicatePdfTemplate",
        "tags": [
          "Modelos de PDF"
        ],
        "summary": "Duplicar modelo",
        "responses": {
          "200": {
            "description": "Cópia criada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PdfTemplate"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/pdf-templates/preview": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "previewPdfTemplate",
        "tags": [
          "Modelos de PDF"
        ],
        "summary": "Pré-visualizar modelo",
        "description": "Gera um PDF de amostra a partir de um layout, sem salvar.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "layout"
                ],
                "properties": {
                  "layout": {
                    "type": "object"
                  },
                  "styles": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PDF de pré-visualização (inline).",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/automations": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listAutomations",
        "tags": [
          "Automações"
        ],
        "summary": "Listar automações",
        "description": "**BETA — API avançada (risco de breaking change).**\n\nLista automações da organização. Filtre por board com `filters[board][documentId]`.\n",
        "responses": {
          "200": {
            "description": "Lista de automações (envelope Strapi ou array, conforme query)."
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "operationId": "createAutomation",
        "tags": [
          "Automações"
        ],
        "summary": "Criar automação",
        "description": "**BETA.** Cria rascunho. `active: true` é rejeitado no create — publique antes de ativar.\n\nObrigatórios: `name`, `trigger` (`{ type, filters? }`), `actions[]` (≥1 com `type` + `order`).\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name",
                      "trigger",
                      "actions"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "example": "Lead novo → atribuir e notificar"
                      },
                      "description": {
                        "type": "string"
                      },
                      "board": {
                        "type": "string",
                        "description": "documentId do board (opcional)."
                      },
                      "trigger": {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "example": "card.created"
                          }
                        }
                      },
                      "actions": {
                        "type": "array",
                        "minItems": 1,
                        "items": {
                          "type": "object"
                        }
                      },
                      "active": {
                        "type": "boolean",
                        "default": false
                      }
                    }
                  }
                }
              },
              "example": {
                "data": {
                  "name": "Lead novo → tarefa",
                  "trigger": {
                    "type": "card.created"
                  },
                  "actions": [
                    {
                      "type": "task.create",
                      "order": 0
                    }
                  ],
                  "active": false
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Automação criada (inactive)."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/automations/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getAutomation",
        "tags": [
          "Automações"
        ],
        "summary": "Buscar automação",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Automação."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateAutomation",
        "tags": [
          "Automações"
        ],
        "summary": "Atualizar automação",
        "description": "**BETA.** Atualização parcial. `active: true` só é aceito se já existir versão publicada.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Automação atualizada."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      },
      "delete": {
        "operationId": "deleteAutomation",
        "tags": [
          "Automações"
        ],
        "summary": "Excluir automação",
        "description": "**BETA.** Remove a automação e versões associadas.",
        "responses": {
          "200": {
            "description": "Excluída."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/automations/{id}/toggle": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "toggleAutomation",
        "tags": [
          "Automações"
        ],
        "summary": "Ativar / desativar",
        "description": "**BETA.** Alterna `active`. Ativar exige publish prévio.\n",
        "responses": {
          "200": {
            "description": "Estado atualizado."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/automations/{id}/duplicate": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "duplicateAutomation",
        "tags": [
          "Automações"
        ],
        "summary": "Duplicar automação",
        "description": "**BETA.** Cria cópia inactive.",
        "responses": {
          "200": {
            "description": "Cópia criada."
          }
        }
      }
    },
    "/automations/{id}/validate-graph": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "validateAutomationGraph",
        "tags": [
          "Automações"
        ],
        "summary": "Validar grafo",
        "description": "**BETA.** Valida `nodes`/`edges` (ou `canvasData`) sem publicar. Sem side-effect.\n",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "nodes": {
                    "type": "array"
                  },
                  "edges": {
                    "type": "array"
                  },
                  "canvasData": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resultado da validação."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/automations/{id}/publish": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "publishAutomation",
        "tags": [
          "Automações"
        ],
        "summary": "Publicar versão",
        "description": "**BETA — efeito colateral.** Cria `automation-version` publicada, arquiva versões\nanteriores e no primeiro publish pode ativar a automação.\n",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Grafo opcional; se omitido, usa o canvas atual."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Versão publicada."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "source": "curl -X POST \"https://api.perpetuus.com.br/api/automations/AUTO_ID/publish\" \\\n  -H \"Authorization: Bearer SEU_TOKEN\" \\\n  -H \"x-tenant-id: acme\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'\n"
          }
        ]
      }
    },
    "/automations/{id}/test": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "testAutomation",
        "tags": [
          "Automações"
        ],
        "summary": "Testar automação",
        "description": "**BETA — perigoso.** `dryRun` default `true`. Com `dryRun: false` as ações\nexecutam de verdade (mensagens, HTTP, tarefas…). Rate limit reforçado.\n",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "dryRun": {
                    "type": "boolean",
                    "default": true
                  },
                  "event": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string"
                      },
                      "payload": {
                        "type": "object"
                      },
                      "boardId": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "example": {
                "dryRun": true,
                "event": {
                  "type": "card.created",
                  "boardId": "bd1a2b3c"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resultado do teste."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/automations/{id}/runs": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listAutomationRuns",
        "tags": [
          "Automações"
        ],
        "summary": "Listar execuções",
        "description": "**BETA.** Histórico de runs da automação.",
        "responses": {
          "200": {
            "description": "Lista de runs."
          }
        }
      }
    },
    "/automations/{id}/runs/{runId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "runId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getAutomationRun",
        "tags": [
          "Automações"
        ],
        "summary": "Detalhe de execução",
        "description": "**BETA.** Inclui step runs quando disponíveis.",
        "responses": {
          "200": {
            "description": "Run detalhado."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/automation-logs": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listAutomationLogs",
        "tags": [
          "Automações"
        ],
        "summary": "Listar logs",
        "description": "**BETA.** Logs agregados de automações.",
        "responses": {
          "200": {
            "description": "Logs."
          }
        }
      }
    },
    "/automation-logs/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getAutomationLog",
        "tags": [
          "Automações"
        ],
        "summary": "Buscar log",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Log."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/automations/{automationId}/logs/stats": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "automationId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getAutomationLogStats",
        "tags": [
          "Automações"
        ],
        "summary": "Estatísticas de logs",
        "description": "**BETA.** Contagens agregadas por status/período.",
        "responses": {
          "200": {
            "description": "Stats."
          }
        }
      }
    },
    "/chat-channels": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listChatChannels",
        "tags": [
          "Canais"
        ],
        "summary": "Listar canais",
        "description": "**BETA — API avançada (risco de breaking change).**\n\nLista canais da organização (`whatsapp`, `instagram`, `telegram`, `email`, `web`, `api`).\n",
        "responses": {
          "200": {
            "description": "Canais (credenciais sensíveis mascaradas)."
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "operationId": "createChatChannel",
        "tags": [
          "Canais"
        ],
        "summary": "Criar canal",
        "description": "**BETA — efeito colateral.** Cria o canal e provisiona a inbox associada.\nSujeito a limite de canais do plano. Obrigatórios: `name`, `channelType`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name",
                      "channelType"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "example": "WhatsApp Comercial"
                      },
                      "channelType": {
                        "type": "string",
                        "enum": [
                          "whatsapp",
                          "instagram",
                          "telegram",
                          "email",
                          "web",
                          "api"
                        ]
                      },
                      "credentials": {
                        "type": "object",
                        "description": "Credenciais do provedor (nunca retornadas completas)."
                      }
                    }
                  }
                }
              },
              "example": {
                "data": {
                  "name": "WhatsApp Comercial",
                  "channelType": "whatsapp",
                  "credentials": {
                    "accessToken": "EAAB...",
                    "phoneNumberId": "123456",
                    "businessAccountId": "789"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Canal criado."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/chat-channels/whatsapp-embedded-signup": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "createWhatsAppFromEmbeddedSignup",
        "tags": [
          "Canais"
        ],
        "summary": "Criar WhatsApp via Embedded Signup",
        "description": "**BETA.** Finaliza o fluxo Embedded Signup da Meta. Obrigatórios: `code`, `wabaId`, `phoneNumberId`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "code",
                  "wabaId",
                  "phoneNumberId"
                ],
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "wabaId": {
                    "type": "string"
                  },
                  "phoneNumberId": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Canal WhatsApp criado."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/chat-channels/email-config": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "getEmailChannelConfig",
        "tags": [
          "Canais"
        ],
        "summary": "Configuração de e-mail",
        "description": "**BETA.** Config global de envio de e-mail da organização.",
        "responses": {
          "200": {
            "description": "Configuração."
          }
        }
      },
      "put": {
        "operationId": "saveEmailChannelConfig",
        "tags": [
          "Canais"
        ],
        "summary": "Salvar configuração de e-mail",
        "description": "**BETA.**",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Config salva."
          }
        }
      }
    },
    "/chat-channels/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getChatChannel",
        "tags": [
          "Canais"
        ],
        "summary": "Buscar canal",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Canal."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateChatChannel",
        "tags": [
          "Canais"
        ],
        "summary": "Atualizar canal",
        "description": "**BETA.**",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Canal atualizado."
          }
        }
      },
      "delete": {
        "operationId": "deleteChatChannel",
        "tags": [
          "Canais"
        ],
        "summary": "Excluir canal",
        "description": "**BETA — efeito colateral.** Remove o canal e recursos vinculados no provedor.",
        "responses": {
          "200": {
            "description": "Excluído."
          }
        }
      }
    },
    "/chat-channels/{id}/health": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getChatChannelHealth",
        "tags": [
          "Canais"
        ],
        "summary": "Saúde do canal",
        "description": "**BETA.** Status de conectividade/credenciais.",
        "responses": {
          "200": {
            "description": "Health check."
          }
        }
      }
    },
    "/chat-channels/{id}/preferences": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getChatChannelPreferences",
        "tags": [
          "Canais"
        ],
        "summary": "Preferências do canal",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Preferências."
          }
        }
      },
      "patch": {
        "operationId": "updateChatChannelPreferences",
        "tags": [
          "Canais"
        ],
        "summary": "Atualizar preferências",
        "description": "**BETA.**",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preferências atualizadas."
          }
        }
      }
    },
    "/chat-channels/{id}/test": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "testChatChannel",
        "tags": [
          "Canais"
        ],
        "summary": "Testar conexão",
        "description": "**BETA.** Valida credenciais junto ao provedor.",
        "responses": {
          "200": {
            "description": "Resultado do teste."
          }
        }
      }
    },
    "/chat-channels/{id}/templates": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listChannelTemplates",
        "tags": [
          "Canais"
        ],
        "summary": "Listar templates WhatsApp",
        "description": "**BETA.** Lista templates HSM do WABA (proxy da Graph API). Só canais `whatsapp`.\n",
        "responses": {
          "200": {
            "description": "Templates."
          }
        }
      },
      "post": {
        "operationId": "createChannelTemplate",
        "tags": [
          "Canais"
        ],
        "summary": "Criar template WhatsApp",
        "description": "**BETA — efeito colateral.** Cria template na Meta (`name`, `language`, `category`, `components`).\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "language",
                  "category"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "language": {
                    "type": "string",
                    "example": "pt_BR"
                  },
                  "category": {
                    "type": "string",
                    "example": "MARKETING"
                  },
                  "components": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Template criado/enviado para aprovação."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      },
      "delete": {
        "operationId": "deleteChannelTemplate",
        "tags": [
          "Canais"
        ],
        "summary": "Excluir template WhatsApp",
        "description": "**BETA — efeito colateral.** Remove na Meta. Query: `name` e/ou `hsm_id`.\n",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "hsm_id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Template excluído."
          }
        }
      }
    },
    "/chat-channels/{id}/templates/sync": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "syncChannelTemplates",
        "tags": [
          "Canais"
        ],
        "summary": "Sincronizar templates",
        "description": "**BETA — efeito colateral.** Sincroniza templates do provedor com o canal.",
        "responses": {
          "200": {
            "description": "Sync concluído."
          }
        }
      }
    },
    "/chat-channels/{id}/templates/upload-handle": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "uploadChannelTemplateMedia",
        "tags": [
          "Canais"
        ],
        "summary": "Upload de mídia para template",
        "description": "**BETA.** Multipart `file` → `media_handle` para componentes de template.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Handle de mídia."
          }
        }
      }
    },
    "/boards/{boardId}/chat-channels": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listBoardChatChannels",
        "tags": [
          "Canais"
        ],
        "summary": "Canais vinculados ao board",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Vínculos canal↔board."
          }
        }
      },
      "post": {
        "operationId": "linkBoardChatChannel",
        "tags": [
          "Canais"
        ],
        "summary": "Vincular canal ao board",
        "description": "**BETA.** Associa um canal existente ao board.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "chatChannel"
                    ],
                    "properties": {
                      "chatChannel": {
                        "type": "string",
                        "description": "documentId do canal."
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Vínculo criado."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/boards/{boardId}/chat-channels/{linkId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "boardId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "linkId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "put": {
        "operationId": "updateBoardChatChannelLink",
        "tags": [
          "Canais"
        ],
        "summary": "Atualizar vínculo",
        "description": "**BETA.**",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Vínculo atualizado."
          }
        }
      },
      "delete": {
        "operationId": "unlinkBoardChatChannel",
        "tags": [
          "Canais"
        ],
        "summary": "Desvincular canal",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Vínculo removido."
          }
        }
      }
    },
    "/meta-lead-integrations": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listMetaLeadIntegrations",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Listar integrações Lead Ads",
        "description": "**BETA — API avançada (risco de breaking change).**\n\nTokens de página/usuário são privados e mascarados nas respostas.\n",
        "responses": {
          "200": {
            "description": "Integrações."
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "operationId": "createMetaLeadIntegration",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Criar integração",
        "description": "**BETA — efeito colateral.** Valida o page token e **inscreve a página em webhooks leadgen**.\nObrigatórios: `name`, `facebookPageId`, `pageAccessToken`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name",
                      "facebookPageId",
                      "pageAccessToken"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "example": "Página Acme Ads"
                      },
                      "facebookPageId": {
                        "type": "string"
                      },
                      "pageAccessToken": {
                        "type": "string"
                      },
                      "webhookVerifyToken": {
                        "type": "string"
                      },
                      "active": {
                        "type": "boolean",
                        "default": true
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Integração criada e inscrita."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/meta-lead-integrations/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getMetaLeadIntegration",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Buscar integração",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Integração."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateMetaLeadIntegration",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Atualizar integração",
        "description": "**BETA.** Pode re-inscrever webhooks ao atualizar tokens.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualizada."
          }
        }
      },
      "delete": {
        "operationId": "deleteMetaLeadIntegration",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Excluir integração",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Excluída."
          }
        }
      }
    },
    "/meta-lead-integrations/{id}/leadgen-forms": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listMetaLeadgenForms",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Formulários Leadgen da página",
        "description": "**BETA.** Lista forms disponíveis na página conectada.",
        "responses": {
          "200": {
            "description": "Forms."
          }
        }
      }
    },
    "/meta-lead-integrations/{id}/leadgen-forms/{formId}/questions": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        },
        {
          "name": "formId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getMetaLeadgenFormQuestions",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Perguntas do formulário",
        "description": "**BETA.** Use para montar `fieldMapping` nas form routes.",
        "responses": {
          "200": {
            "description": "Questions."
          }
        }
      }
    },
    "/meta-lead-integrations/{id}/campaign-performance": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getMetaLeadCampaignPerformance",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Performance de campanhas",
        "description": "**BETA.** Métricas agregadas das campanhas vinculadas.",
        "responses": {
          "200": {
            "description": "Performance."
          }
        }
      }
    },
    "/meta-lead-integrations/{id}/user-token": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "connectMetaLeadUserToken",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Conectar user access token",
        "description": "**BETA — sensível.** Grava `userAccessToken`, valida Ads e atualiza credentials.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "userAccessToken"
                ],
                "properties": {
                  "userAccessToken": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token conectado."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/meta-lead-form-routes": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "createMetaLeadFormRoute",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Criar roteamento de formulário",
        "description": "**BETA.** Mapeia um form Leadgen → board + `fieldMapping`.\n\nObrigatórios: `metaLeadIntegrationDocumentId`, `targetBoardDocumentId`,\n`facebookFormId`, `fieldMapping.mappings[]` (≥1).\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "metaLeadIntegrationDocumentId",
                      "targetBoardDocumentId",
                      "facebookFormId",
                      "fieldMapping"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "metaLeadIntegrationDocumentId": {
                        "type": "string"
                      },
                      "targetBoardDocumentId": {
                        "type": "string"
                      },
                      "facebookFormId": {
                        "type": "string"
                      },
                      "priority": {
                        "type": "integer"
                      },
                      "active": {
                        "type": "boolean"
                      },
                      "fieldMapping": {
                        "type": "object",
                        "properties": {
                          "mappings": {
                            "type": "array",
                            "items": {
                              "type": "object"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "data": {
                  "name": "Form Contato → Funil",
                  "metaLeadIntegrationDocumentId": "mli1a2b3c",
                  "targetBoardDocumentId": "bd1a2b3c",
                  "facebookFormId": "120000",
                  "fieldMapping": {
                    "mappings": [
                      {
                        "source": "email",
                        "target": "email"
                      },
                      {
                        "source": "full_name",
                        "target": "name"
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Form route criada."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/meta-lead-form-routes/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getMetaLeadFormRoute",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Buscar form route",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Form route."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateMetaLeadFormRoute",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Atualizar form route",
        "description": "**BETA.**",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualizada."
          }
        }
      },
      "delete": {
        "operationId": "deleteMetaLeadFormRoute",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Excluir form route",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Excluída."
          }
        }
      }
    },
    "/meta-lead/facebook-oauth/start": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "startMetaLeadOAuth",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Iniciar OAuth Facebook",
        "description": "**BETA.** Retorna URL de autorização (`url`, `state`) para redirecionar o usuário.\nO callback do browser é interno (`/meta-lead/facebook-oauth/callback`) e não faz\nparte do contrato público.\n"
      }
    },
    "/meta-lead/facebook-oauth/complete": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "completeMetaLeadOAuth",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Completar OAuth",
        "description": "**BETA.** Finaliza o fluxo após o usuário autorizar.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OAuth concluído / integração pronta."
          }
        }
      }
    },
    "/meta-lead/facebook-oauth/pages": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listMetaLeadOAuthPages",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Páginas disponíveis (OAuth)",
        "description": "**BETA.** Páginas Facebook acessíveis com o token da sessão OAuth.",
        "responses": {
          "200": {
            "description": "Pages."
          }
        }
      }
    },
    "/meta-lead/facebook-oauth/leadgen-forms": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listMetaLeadOAuthForms",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Forms Leadgen (OAuth)",
        "description": "**BETA.**",
        "parameters": [
          {
            "name": "pageId",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Forms."
          }
        }
      }
    },
    "/meta-lead/facebook-oauth/leadgen-form-questions": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "getMetaLeadOAuthFormQuestions",
        "tags": [
          "Meta Lead Ads"
        ],
        "summary": "Questions (OAuth)",
        "description": "**BETA.**",
        "parameters": [
          {
            "name": "formId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Questions."
          }
        }
      }
    },
    "/email-templates": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listEmailTemplates",
        "tags": [
          "E-mail marketing"
        ],
        "summary": "Listar templates de e-mail",
        "description": "**BETA — API avançada (risco de breaking change).**\n",
        "responses": {
          "200": {
            "description": "Templates."
          }
        }
      },
      "post": {
        "operationId": "createEmailTemplate",
        "tags": [
          "E-mail marketing"
        ],
        "summary": "Criar template de e-mail",
        "description": "**BETA.** Obrigatórios: `name`, `subject`, `html` (ou `designJson.html`).\n`category`: `marketing` | `transactional` | `notification`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name",
                      "subject",
                      "html"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "subject": {
                        "type": "string"
                      },
                      "html": {
                        "type": "string"
                      },
                      "preheader": {
                        "type": "string"
                      },
                      "text": {
                        "type": "string"
                      },
                      "category": {
                        "type": "string",
                        "enum": [
                          "marketing",
                          "transactional",
                          "notification"
                        ]
                      },
                      "editorMode": {
                        "type": "string",
                        "enum": [
                          "visual",
                          "html"
                        ]
                      }
                    }
                  }
                }
              },
              "example": {
                "data": {
                  "name": "Boas-vindas",
                  "subject": "Bem-vindo à {{organization.name}}",
                  "html": "<h1>Olá {{contact.name}}</h1>",
                  "category": "marketing"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Template criado."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/email-templates/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getEmailTemplate",
        "tags": [
          "E-mail marketing"
        ],
        "summary": "Buscar template",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Template."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateEmailTemplate",
        "tags": [
          "E-mail marketing"
        ],
        "summary": "Atualizar template",
        "description": "**BETA.**",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualizado."
          }
        }
      },
      "delete": {
        "operationId": "deleteEmailTemplate",
        "tags": [
          "E-mail marketing"
        ],
        "summary": "Excluir template",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Excluído."
          }
        }
      }
    },
    "/email-templates/preview": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "previewEmailTemplate",
        "tags": [
          "E-mail marketing"
        ],
        "summary": "Pré-visualizar template",
        "description": "**BETA.** Renderiza HTML/subject sem enviar. Aceita corpo inline ou `templateId`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "templateId": {
                    "type": "string"
                  },
                  "subject": {
                    "type": "string"
                  },
                  "html": {
                    "type": "string"
                  },
                  "sampleContact": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preview renderizado."
          }
        }
      }
    },
    "/email-templates/send-test": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "sendTestEmailTemplate",
        "tags": [
          "E-mail marketing"
        ],
        "summary": "Enviar e-mail de teste",
        "description": "**BETA — efeito colateral.** Envia e-mail **real** para `to`. Rate limit reforçado.\nRequer feature de campanhas no plano.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "to"
                ],
                "properties": {
                  "to": {
                    "type": "string",
                    "format": "email"
                  },
                  "toName": {
                    "type": "string"
                  },
                  "templateId": {
                    "type": "string"
                  },
                  "subject": {
                    "type": "string"
                  },
                  "html": {
                    "type": "string"
                  },
                  "chatChannelId": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "to": "voce@empresa.com",
                "templateId": "et1a2b3c"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Enviado."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/email-assets": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listEmailAssets",
        "tags": [
          "E-mail marketing"
        ],
        "summary": "Listar assets de e-mail",
        "description": "**BETA.** Imagens/arquivos usados em templates.",
        "responses": {
          "200": {
            "description": "Assets."
          }
        }
      }
    },
    "/email-assets/upload": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "post": {
        "operationId": "uploadEmailAsset",
        "tags": [
          "E-mail marketing"
        ],
        "summary": "Upload de asset",
        "description": "**BETA.** Multipart upload.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "files": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Asset criado."
          }
        }
      }
    },
    "/email-assets/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getEmailAsset",
        "tags": [
          "E-mail marketing"
        ],
        "summary": "Buscar asset",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Asset."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteEmailAsset",
        "tags": [
          "E-mail marketing"
        ],
        "summary": "Excluir asset",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Excluído."
          }
        }
      }
    },
    "/distribution-queues": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listDistributionQueues",
        "tags": [
          "Distribuição"
        ],
        "summary": "Listar filas de distribuição",
        "description": "**BETA — API avançada.** Filas ativas atribuem cards automaticamente (round-robin).\n",
        "responses": {
          "200": {
            "description": "Filas."
          }
        }
      },
      "post": {
        "operationId": "createDistributionQueue",
        "tags": [
          "Distribuição"
        ],
        "summary": "Criar fila",
        "description": "**BETA.** Obrigatórios: `name`, `board` (documentId). Opcional: `members[]`, `rules`, `schedule`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name",
                      "board"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "example": "Fila SP"
                      },
                      "board": {
                        "type": "string"
                      },
                      "active": {
                        "type": "boolean"
                      },
                      "members": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "rules": {
                        "type": "object"
                      },
                      "schedule": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fila criada."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/distribution-queues/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getDistributionQueue",
        "tags": [
          "Distribuição"
        ],
        "summary": "Buscar fila",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Fila."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateDistributionQueue",
        "tags": [
          "Distribuição"
        ],
        "summary": "Atualizar fila",
        "description": "**BETA.**",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualizada."
          }
        }
      },
      "delete": {
        "operationId": "deleteDistributionQueue",
        "tags": [
          "Distribuição"
        ],
        "summary": "Excluir fila",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Excluída."
          }
        }
      }
    },
    "/board-saved-filters": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listBoardSavedFilters",
        "tags": [
          "Filtros salvos"
        ],
        "summary": "Listar filtros salvos",
        "description": "**BETA.** Filtre por board com `filters[board][documentId]`.\n",
        "responses": {
          "200": {
            "description": "Filtros."
          }
        }
      },
      "post": {
        "operationId": "createBoardSavedFilter",
        "tags": [
          "Filtros salvos"
        ],
        "summary": "Criar filtro salvo",
        "description": "**BETA.** Obrigatórios: `name`, `board`, `payload` (com `version`).\n`scope`: `personal` (default) | `shared` (só admin/manager).\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name",
                      "board",
                      "payload"
                    ],
                    "properties": {
                      "name": {
                        "type": "string",
                        "maxLength": 120
                      },
                      "board": {
                        "type": "string"
                      },
                      "scope": {
                        "type": "string",
                        "enum": [
                          "personal",
                          "shared"
                        ]
                      },
                      "isDefault": {
                        "type": "boolean"
                      },
                      "payload": {
                        "type": "object",
                        "required": [
                          "version"
                        ],
                        "properties": {
                          "version": {
                            "type": "integer",
                            "example": 1
                          },
                          "quick": {
                            "type": "object"
                          },
                          "search": {
                            "type": "string"
                          },
                          "advanced": {
                            "type": "array",
                            "items": {
                              "type": "object"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "data": {
                  "name": "Meus atrasados",
                  "board": "bd1a2b3c",
                  "scope": "personal",
                  "payload": {
                    "version": 1,
                    "quick": {
                      "assignee": "me",
                      "dueTodayOnly": true
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Filtro criado."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/board-saved-filters/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getBoardSavedFilter",
        "tags": [
          "Filtros salvos"
        ],
        "summary": "Buscar filtro",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Filtro."
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateBoardSavedFilter",
        "tags": [
          "Filtros salvos"
        ],
        "summary": "Atualizar filtro",
        "description": "**BETA.**",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualizado."
          }
        }
      },
      "delete": {
        "operationId": "deleteBoardSavedFilter",
        "tags": [
          "Filtros salvos"
        ],
        "summary": "Excluir filtro",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Excluído."
          }
        }
      }
    },
    "/conversion-integrations": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        }
      ],
      "get": {
        "operationId": "listConversionIntegrations",
        "tags": [
          "Conversões"
        ],
        "summary": "Listar pixels / CAPI",
        "description": "**BETA — API avançada.** Credenciais mascaradas. Plataformas: `meta`, `google_ga4`.\n",
        "responses": {
          "200": {
            "description": "Integrações."
          }
        }
      },
      "post": {
        "operationId": "createConversionIntegration",
        "tags": [
          "Conversões"
        ],
        "summary": "Criar integração de conversão",
        "description": "**BETA — efeito colateral.** Create **verifica síncrono** nas APIs Meta/GA4;\nfalha = não cria.\n\n- Meta: `destinationId` = Pixel ID + `accessToken`\n- GA4: `destinationId` = Measurement ID + `apiSecret`\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object",
                    "required": [
                      "name",
                      "platform",
                      "destinationId"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "platform": {
                        "type": "string",
                        "enum": [
                          "meta",
                          "google_ga4"
                        ]
                      },
                      "destinationId": {
                        "type": "string"
                      },
                      "accessToken": {
                        "type": "string"
                      },
                      "apiSecret": {
                        "type": "string"
                      },
                      "testEventCode": {
                        "type": "string"
                      },
                      "active": {
                        "type": "boolean"
                      }
                    }
                  }
                }
              },
              "example": {
                "data": {
                  "name": "Pixel Site",
                  "platform": "meta",
                  "destinationId": "1234567890",
                  "accessToken": "EAAB..."
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Criada e verificada."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/conversion-integrations/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "put": {
        "operationId": "updateConversionIntegration",
        "tags": [
          "Conversões"
        ],
        "summary": "Atualizar integração",
        "description": "**BETA.**",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualizada."
          }
        }
      },
      "delete": {
        "operationId": "deleteConversionIntegration",
        "tags": [
          "Conversões"
        ],
        "summary": "Excluir integração",
        "description": "**BETA.**",
        "responses": {
          "200": {
            "description": "Excluída."
          }
        }
      }
    },
    "/conversion-integrations/{id}/verify": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TenantHeader"
        },
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "post": {
        "operationId": "verifyConversionIntegration",
        "tags": [
          "Conversões"
        ],
        "summary": "Revalidar credenciais",
        "description": "**BETA — efeito colateral.** Chama a API externa e atualiza `verificationStatus`\n(`verified` | `failed`).\n",
        "responses": {
          "200": {
            "description": "Resultado da verificação."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    }
  }
}
