openapi: 3.0.3
info:
  title: KnotAPI CPF
  version: 1.1.0
  description: API de consulta por CPF com quota, rate limit e chaves restritas por IP ou origem.
servers:
  - url: https://knotapi.online
paths:
  /api:
    get:
      operationId: consultarCpf
      summary: Consulta um CPF
      security: [{ ApiKey: [] }]
      parameters:
        - in: query
          name: modulo
          required: true
          schema: { type: string, enum: [cpf] }
        - in: query
          name: consulta
          required: true
          schema: { type: string, pattern: '^\\d{11}$', example: '12345678909' }
      responses:
        '200':
          description: Consulta processada
          headers:
            X-Quota-Remaining: { schema: { type: integer } }
            X-Quota-Reset: { schema: { type: string, format: date-time } }
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Success' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '403': { $ref: '#/components/responses/Forbidden' }
        '404': { $ref: '#/components/responses/NotFound' }
        '429': { $ref: '#/components/responses/TooManyRequests' }
  /plans:
    get:
      operationId: listarPlanos
      summary: Lista planos comerciais ativos
      responses:
        '200':
          description: Planos
          content:
            application/json:
              schema: { type: array, items: { $ref: '#/components/schemas/Plan' } }
  /me/keys/{id}/test:
    post:
      operationId: testarChaveNoPortal
      summary: Executa consulta real usando uma chave da conta autenticada
      description: Teste gratuito que não consome franquia e não exige novo 2FA. Não valida IP/domínio porque parte do portal; valide restrições também no ambiente final.
      security: [{ CookieSession: [] }]
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [cpf]
              properties:
                cpf: { type: string, pattern: '^\\d{11}$' }
      responses:
        '200': { description: Teste concluído, content: { application/json: { schema: { $ref: '#/components/schemas/Success' } } } }
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '404': { $ref: '#/components/responses/NotFound' }
        '403': { $ref: '#/components/responses/Forbidden' }
  /mcp:
    post:
      operationId: mcpJsonRpc
      summary: Servidor MCP Streamable HTTP stateless
      description: Aceita initialize, ping, tools/list, tools/call e notifications/initialized. A ferramenta consultar_cpf consome quota normalmente.
      security: [{ BearerApiKey: [] }, { ApiKey: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { type: object, description: Mensagem JSON-RPC 2.0 }
      responses:
        '200': { description: Resposta JSON-RPC }
        '202': { description: Notificação aceita }
        '401': { $ref: '#/components/responses/Unauthorized' }
  /health.json:
    get:
      operationId: health
      summary: Saúde dos bancos e da aplicação
      responses:
        '200':
          description: Sistema saudável
          content:
            application/json:
              schema:
                type: object
                required: [status, auth_db, data_db, timestamp]
                properties:
                  status: { type: string, enum: [ok] }
                  auth_db: { type: string, enum: [ok] }
                  data_db: { type: string, enum: [ok] }
                  transactional_email: { type: string, enum: [configured, disabled] }
                  pix_gateway: { type: string, enum: [allowpay, mock, disabled] }
                  timestamp: { type: string, format: date-time }
components:
  securitySchemes:
    ApiKey:
      type: apiKey
      in: header
      name: x-api-key
    CookieSession:
      type: apiKey
      in: cookie
      name: knot_session
    BearerApiKey:
      type: http
      scheme: bearer
  schemas:
    Success:
      type: object
      required: [sucesso, dados, meta]
      properties:
        sucesso: { type: boolean, enum: [true] }
        dados:
          type: object
          required: [CPF, NOME, NASCIMENTO, MAE]
          properties:
            CPF: { type: string, pattern: '^\\d{11}$' }
            NOME: { type: string, nullable: true }
            NASCIMENTO: { type: string, pattern: '^\\d{2}-\\d{2}-\\d{4}$' }
            MAE: { type: string, nullable: true }
        meta:
          type: object
          required: [quota_remaining, quota_reset, quota_reset_iso, timezone]
          properties:
            quota_remaining: { type: integer, minimum: 0 }
            quota_reset: { type: string, pattern: '^\\d{2}-\\d{2}-\\d{4} \\d{2}:\\d{2}:\\d{2}$' }
            quota_reset_iso: { type: string, format: date-time }
            timezone: { type: string, enum: [America/Sao_Paulo] }
    Plan:
      type: object
      properties:
        codigo: { type: string }
        nome: { type: string }
        request_limit: { type: integer }
        validade_dias: { type: integer }
        preco_centavos: { type: integer }
    Error:
      type: object
      required: [erro]
      properties:
        erro: { type: string }
        codigo: { type: string }
  responses:
    BadRequest: { description: Parâmetro inválido, content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
    Unauthorized: { description: Chave ausente ou inválida, content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
    Forbidden: { description: Plano inativo, conta suspensa, IP ou origem não autorizado, content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
    NotFound: { description: CPF sem registro, content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
    TooManyRequests: { description: Limite de requisições, content: { application/json: { schema: { $ref: '#/components/schemas/Error' } } } }
