{
  "openapi": "3.1.0",
  "info": {
    "title": "SmartDoctor Integration API",
    "version": "1.0.0",
    "description": "API REST de integração do SmartDoctor. Permite que sistemas externos, n8n e agentes de IA consultem horários, pacientes e valores, e criem, reagendem ou cancelem consultas. Autenticação por API Key (header X-Api-Key), com escopo automático por clínica.",
    "contact": { "name": "SmartDoctor", "url": "https://www.smartdoctor.com.br" }
  },
  "servers": [
    { "url": "https://api.smartdoctor.com.br", "description": "Produção" }
  ],
  "security": [ { "ApiKeyAuth": [] } ],
  "tags": [
    { "name": "Agendas", "description": "Criar, reagendar, cancelar e consultar consultas" },
    { "name": "Disponibilidade", "description": "Horários livres por especialidade" },
    { "name": "Pacientes", "description": "Consulta de pacientes por CPF" },
    { "name": "Valores", "description": "Tabela de valores de consulta" }
  ],
  "paths": {
    "/integracao/agendas": {
      "post": {
        "tags": ["Agendas"],
        "summary": "Criar agenda",
        "description": "Agenda uma nova consulta. A clínica é derivada da API Key. A especialidade é resolvida pelo nome com convênio PARTICULAR; o valor é preenchido automaticamente.",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/NovaAgenda" } } }
        },
        "responses": {
          "201": { "description": "Agenda criada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Agenda" } } } },
          "400": { "$ref": "#/components/responses/Erro" },
          "401": { "$ref": "#/components/responses/NaoAutorizado" }
        }
      },
      "put": {
        "tags": ["Agendas"],
        "summary": "Reagendar ou cancelar agenda",
        "description": "Atualiza uma agenda existente. Envie situacaoAgenda=CANCELADO para cancelar, ou dtAgenda+hora para reagendar.",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AtualizaAgenda" } } }
        },
        "responses": {
          "200": { "description": "Agenda atualizada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Agenda" } } } },
          "400": { "$ref": "#/components/responses/Erro" },
          "401": { "$ref": "#/components/responses/NaoAutorizado" }
        }
      }
    },
    "/integracao/agendas/{id}": {
      "get": {
        "tags": ["Agendas"],
        "summary": "Buscar agenda por ID",
        "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } } ],
        "responses": {
          "200": { "description": "Agenda", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Agenda" } } } },
          "401": { "$ref": "#/components/responses/NaoAutorizado" },
          "404": { "$ref": "#/components/responses/NaoEncontrado" }
        }
      }
    },
    "/integracao/agendas/listar": {
      "get": {
        "tags": ["Agendas"],
        "summary": "Listar agendas",
        "description": "Lista agendas a partir de uma data (padrão: hoje), com filtros opcionais.",
        "parameters": [
          { "name": "pacienteCpf", "in": "query", "required": false, "schema": { "type": "string" } },
          { "name": "dataInicio", "in": "query", "required": false, "schema": { "type": "string", "format": "date" } },
          { "name": "situacaoAgenda", "in": "query", "required": false, "schema": { "$ref": "#/components/schemas/SituacaoAgenda" } }
        ],
        "responses": {
          "200": { "description": "Lista de agendas", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Agenda" } } } } },
          "401": { "$ref": "#/components/responses/NaoAutorizado" }
        }
      }
    },
    "/integracao/agendas/verificar": {
      "get": {
        "tags": ["Agendas"],
        "summary": "Verificar conflito de agenda",
        "description": "Retorna as agendas do paciente na data/especialidade (array vazio se não houver conflito).",
        "parameters": [
          { "name": "pacienteCpf", "in": "query", "required": true, "schema": { "type": "string" } },
          { "name": "dataConsulta", "in": "query", "required": true, "schema": { "type": "string", "format": "date" } },
          { "name": "especialidadeNome", "in": "query", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Agendas encontradas", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Agenda" } } } } },
          "401": { "$ref": "#/components/responses/NaoAutorizado" }
        }
      }
    },
    "/integracao/controle-agendas/horarios-disponiveis": {
      "post": {
        "tags": ["Disponibilidade"],
        "summary": "Horários livres por especialidade",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": {
            "type": "object",
            "properties": { "especialidade": { "type": "string", "example": "CARDIOLOGIA" } },
            "required": ["especialidade"]
          } } }
        },
        "responses": {
          "200": { "description": "Slots disponíveis", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/SlotDisponivel" } } } } },
          "401": { "$ref": "#/components/responses/NaoAutorizado" }
        }
      }
    },
    "/integracao/pacientes/cpf": {
      "get": {
        "tags": ["Pacientes"],
        "summary": "Buscar paciente por CPF",
        "description": "Retorna o paciente se tiver vínculo (agenda) com a clínica da chave.",
        "parameters": [ { "name": "cpf", "in": "query", "required": true, "schema": { "type": "string" } } ],
        "responses": {
          "200": { "description": "Resultado da busca", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PacienteLookup" } } } },
          "401": { "$ref": "#/components/responses/NaoAutorizado" }
        }
      }
    },
    "/integracao/consultas-valor": {
      "get": {
        "tags": ["Valores"],
        "summary": "Listar valores de consulta",
        "parameters": [ { "name": "especialidadeNome", "in": "query", "required": false, "schema": { "type": "string" } } ],
        "responses": {
          "200": { "description": "Valores ativos", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ConsultaValor" } } } } },
          "401": { "$ref": "#/components/responses/NaoAutorizado" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": { "type": "apiKey", "in": "header", "name": "X-Api-Key", "description": "Chave gerada em Perfil › Configurações › Integrações. Vinculada a uma clínica." }
    },
    "responses": {
      "Erro": { "description": "Erro de validação de negócio", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Erro" }, "example": { "erro": "Nome da especialidade é obrigatório" } } } },
      "NaoAutorizado": { "description": "API Key ausente, inválida ou revogada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Erro" }, "example": { "erro": "API Key inválida ou ausente" } } } },
      "NaoEncontrado": { "description": "Recurso não encontrado ou de outra clínica", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Erro" }, "example": { "erro": "Agenda não encontrada" } } } }
    },
    "schemas": {
      "SituacaoAgenda": { "type": "string", "enum": ["AGENDADO", "AUSENTE", "CANCELADO", "EM_ATENDIMENTO", "FINALIZADO", "SALA_ESPERA"] },
      "PacienteInput": {
        "type": "object",
        "required": ["cpf"],
        "properties": {
          "nome": { "type": "string", "description": "Obrigatório se o paciente ainda não existe (será criado)." },
          "cpf": { "type": "string", "description": "Com ou sem máscara. Identifica/reaproveita o paciente." },
          "celular": { "type": "string" },
          "dtnascimento": { "type": "string", "format": "date" }
        }
      },
      "NovaAgenda": {
        "type": "object",
        "required": ["dtAgenda", "consultaValor", "paciente"],
        "description": "A especialidade precisa ter preço no convênio PARTICULAR e grade de agenda na data; precisa existir ao menos um tipo de atendimento na clínica.",
        "properties": {
          "dtAgenda": { "type": "string", "format": "date", "example": "2026-07-15" },
          "hora": { "type": "string", "example": "09:00", "description": "Opcional. Se omitido, o sistema escolhe o primeiro horário livre da data." },
          "consultaValor": {
            "type": "object",
            "properties": { "especialidade": { "type": "object", "properties": { "nome": { "type": "string", "example": "CARDIOLOGIA" } } } }
          },
          "medico": { "type": "object", "properties": { "id": { "type": "string" } }, "description": "Opcional. Omita para qualquer médico." },
          "paciente": { "$ref": "#/components/schemas/PacienteInput" },
          "observacao": { "type": "string" },
          "operador": { "type": "string", "readOnly": true, "description": "Ignorado no envio. O sistema registra como AGENTE AUTOMÁTICO." }
        }
      },
      "AtualizaAgenda": {
        "type": "object",
        "required": ["id"],
        "properties": {
          "id": { "type": "string" },
          "situacaoAgenda": { "$ref": "#/components/schemas/SituacaoAgenda" },
          "dtAgenda": { "type": "string", "format": "date" },
          "hora": { "type": "string" },
          "cpf": { "type": "string" },
          "operador": { "type": "string" }
        }
      },
      "Agenda": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "dtAgenda": { "type": "string", "format": "date" },
          "hora": { "type": "string" },
          "situacaoAgenda": { "$ref": "#/components/schemas/SituacaoAgenda" },
          "observacao": { "type": "string" },
          "operador": { "type": "string" },
          "especialidade": { "type": "string" },
          "medico": { "type": "string" },
          "medicoId": { "type": "string" },
          "endereco": { "type": "string" },
          "valorConsulta": { "type": "number" },
          "paciente": {
            "type": "object",
            "properties": {
              "id": { "type": "string" },
              "nome": { "type": "string" },
              "cpf": { "type": "string" },
              "celular": { "type": "string" },
              "dtnascimento": { "type": "string", "format": "date" }
            }
          }
        }
      },
      "SlotDisponivel": {
        "type": "object",
        "properties": {
          "especialidade": { "type": "string" },
          "medico": { "type": "string" },
          "medicoId": { "type": "string" },
          "data": { "type": "string", "format": "date" },
          "horariosDisponiveis": { "type": "array", "items": { "type": "string" } },
          "totalPossivel": { "type": "integer" },
          "totalOcupado": { "type": "integer" },
          "totalDisponivel": { "type": "integer" },
          "horaInicio": { "type": "string" },
          "horaFim": { "type": "string" },
          "tempoAtendimento": { "type": "integer" }
        }
      },
      "PacienteLookup": {
        "type": "object",
        "properties": {
          "encontrado": { "type": "boolean" },
          "id": { "type": "string" },
          "nome": { "type": "string" },
          "cpf": { "type": "string" },
          "celular": { "type": "string" },
          "dtnascimento": { "type": "string", "format": "date" },
          "mensagem": { "type": "string" }
        }
      },
      "ConsultaValor": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "especialidade": { "type": "string" },
          "convenio": { "type": "string" },
          "valor": { "type": "number" }
        }
      },
      "Erro": { "type": "object", "properties": { "erro": { "type": "string" } } }
    }
  }
}
