{
  "openapi": "3.1.0",
  "info": {
    "title": "RAGJur API",
    "version": "1.2.0",
    "summary": "Busca jurisprudencial e jurimetria sobre ~62 milhões de julgados de ~35 tribunais brasileiros.",
    "description": "API REST da RAGJur (Beans Tech Inova Simples (I.S.), CNPJ 64.160.205/0001-17).\n\n- **Busca**: BM25 sobre ementas/inteiro teor com analisador jurídico pt-BR; modo híbrido com kNN (`multilingual-e5-large-instruct`, 1024d) + rerank.\n- **Jurimetria**: taxa de provimento por tema/turma/relator, evolução, divergência (χ²), mudança de entendimento (CUSUM), predição multi-fator, intervalos de Wilson, decaimento temporal.\n- **IA**: verificação anti-alucinação de citações, chat com fontes e geração de peças fundamentadas em precedentes reais.\n\nTodas as rotas exigem `x-api-key` (exceto `/health` e `/openapi.json`). Também aceitamos tokens OAuth 2.1 emitidos pelo servidor MCP (`https://mcp.ragjur.ai`) para integrações Claude/ChatGPT/Copilot — ver `securitySchemes.OAuth2`.\n\nConvenções: `fonte` identifica a base (`GET /filtros`); sem `fonte`/`tribunal` os endpoints jurimétricos usam `tst_jurisprudencia`. Respostas em JSON UTF-8; percentuais em 0–100.",
    "termsOfService": "https://ragjur.ai/termos",
    "contact": {
      "name": "Suporte RAGJur",
      "email": "suporte@ragjur.ai",
      "url": "https://ragjur.ai/suporte"
    },
    "license": {
      "name": "Proprietária — ver Termos de Uso",
      "url": "https://ragjur.ai/termos"
    },
    "x-logo": {
      "url": "https://ragjur.ai/logo-512.png",
      "altText": "RAGJur"
    }
  },
  "externalDocs": {
    "description": "Documentação para desenvolvedores",
    "url": "https://docs.ragjur.ai"
  },
  "servers": [
    {
      "url": "https://api.ragjur.ai",
      "description": "Produção"
    },
    {
      "url": "https://api.ragjur.com.br",
      "description": "Legado (redireciona 301 para api.ragjur.ai)"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    },
    {
      "OAuth2": [
        "ragjur:read"
      ]
    }
  ],
  "tags": [
    {
      "name": "Busca",
      "description": "Busca textual, híbrida, similaridade e clusters"
    },
    {
      "name": "Jurimetria",
      "description": "Métricas estatísticas por tema, turma e relator (ver https://docs.ragjur.ai/jurimetria)"
    },
    {
      "name": "IA",
      "description": "Recursos generativos fundamentados no índice"
    },
    {
      "name": "Classificação",
      "description": "Classificação direcional em massa"
    },
    {
      "name": "Alertas",
      "description": "Alertas jurimétricos"
    },
    {
      "name": "DJEN",
      "description": "Monitoramento do Diário de Justiça Eletrônico Nacional"
    },
    {
      "name": "Sistema",
      "description": "Health e metadados"
    }
  ],
  "paths": {
    "/api/v1/health": {
      "get": {
        "tags": [
          "Sistema"
        ],
        "operationId": "getHealth",
        "summary": "Health check (público)",
        "description": "Estado do serviço e do Elasticsearch. Não exige credencial.",
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "ok",
                        "degraded",
                        "unhealthy"
                      ]
                    },
                    "service": {
                      "type": "string"
                    },
                    "version": {
                      "type": "string"
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "elastic": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "ok",
                            "degraded",
                            "unreachable",
                            "nao_configurado"
                          ]
                        },
                        "doc_count": {
                          "type": "integer"
                        },
                        "latency_ms": {
                          "type": "integer"
                        },
                        "erro": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "status": "ok",
                  "service": "ragjur-api",
                  "version": "1.0.0",
                  "timestamp": "2026-09-15T12:00:00.000Z",
                  "elastic": {
                    "status": "ok",
                    "doc_count": 62412318,
                    "latency_ms": 41
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/openapi.json": {
      "get": {
        "tags": [
          "Sistema"
        ],
        "operationId": "getOpenApi",
        "summary": "Esta especificação (público)",
        "security": [],
        "responses": {
          "200": {
            "description": "Documento OpenAPI 3.1",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/filtros": {
      "get": {
        "tags": [
          "Busca"
        ],
        "operationId": "listarFiltros",
        "summary": "Fontes, tribunais, turmas e relatores disponíveis",
        "description": "Sem `fonte`: lista todas as fontes e tribunais do índice. Com `fonte`: também as turmas e relatores dessa base (até 200 cada). Use para descobrir os códigos válidos de `fonte`.",
        "parameters": [
          {
            "name": "fonte",
            "in": "query",
            "description": "Restringe turmas/relatores a uma base.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          }
        ],
        "responses": {
          "200": {
            "description": "Listas com contagem",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fontes": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contagem"
                      }
                    },
                    "tribunais": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contagem"
                      }
                    },
                    "turmas": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contagem"
                      }
                    },
                    "relatores": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contagem"
                      }
                    }
                  }
                },
                "example": {
                  "fontes": [
                    {
                      "key": "tjsp_cjsg",
                      "count": 18240112
                    },
                    {
                      "key": "stj_integras",
                      "count": 2103455
                    }
                  ],
                  "tribunais": [
                    {
                      "key": "TJSP",
                      "count": 21004003
                    }
                  ],
                  "turmas": [],
                  "relatores": []
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/busca": {
      "get": {
        "tags": [
          "Busca"
        ],
        "operationId": "buscarJurisprudencia",
        "summary": "Busca textual (BM25) ou híbrida (BM25 + kNN e5 + rerank)",
        "description": "Busca em ~62M julgados. 50 resultados por página. Por padrão exclui decisões-stub (`word_count < 10`) e deduplica ementas quase idênticas.\n\n`modo=hibrido` funde BM25 com kNN sobre `embedding_e5` (RRF) e reordena o topo com cross-encoder; se o serviço de embeddings estiver indisponível, responde só BM25 com `embedding_fallback: \"bm25\"`.\n\nCorreção ortográfica automática: `sugestao` traz a query corrigida quando aplicável.\n\nSe `q` inteira for um número de processo — CNJ (`0703333-12.2026.8.07.0009`, com ou sem máscara) ou sigla de superior + número (`REsp 1842871`, `HC 773186`) — a busca vira filtro exato em `numero_processo` (`busca_processo: \"cnj\" | \"superior\"`); zero acertos recai na busca textual (número citado em ementa).",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Termos de busca (mín. 3 caracteres) ou número de processo (CNJ ou `REsp 123`).",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          },
          {
            "name": "relator",
            "in": "query",
            "description": "Nome (ou parte) do relator/juiz.",
            "schema": {
              "type": "string"
            },
            "example": "NANCY ANDRIGHI"
          },
          {
            "name": "classe",
            "in": "query",
            "description": "Classe processual (ex.: `REsp`, `AgInt`, `HC`).",
            "schema": {
              "type": "string"
            },
            "example": "REsp"
          },
          {
            "name": "dataInicio",
            "in": "query",
            "description": "Data inicial (YYYY-MM-DD) — julgamento ou publicação.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2023-01-01"
          },
          {
            "name": "dataFim",
            "in": "query",
            "description": "Data final (YYYY-MM-DD) — julgamento ou publicação.",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2025-12-31"
          },
          {
            "name": "data_julg_de",
            "in": "query",
            "description": "Data de julgamento inicial (YYYY-MM-DD) — range no campo `data_julg_dt` (futuro; até o backfill devolve 0 hits).",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2024-01-01"
          },
          {
            "name": "data_julg_ate",
            "in": "query",
            "description": "Data de julgamento final (YYYY-MM-DD) — range no campo `data_julg_dt` (futuro; até o backfill devolve 0 hits).",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2024-12-31"
          },
          {
            "name": "pagina",
            "in": "query",
            "description": "Página (1–200).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 1
            }
          },
          {
            "name": "modo",
            "in": "query",
            "description": "`hibrido` ativa kNN + rerank.",
            "schema": {
              "type": "string",
              "enum": [
                "hibrido"
              ]
            }
          },
          {
            "name": "dedup",
            "in": "query",
            "description": "`false` desliga a deduplicação semântica.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "true"
            }
          },
          {
            "name": "incluir_stubs",
            "in": "query",
            "description": "`true` inclui decisões-stub.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ],
              "default": "false"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de resultados",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "total",
                    "pagina",
                    "totalPaginas",
                    "resultados"
                  ],
                  "properties": {
                    "total": {
                      "type": "integer",
                      "description": "Total de documentos que casam (antes da paginação)"
                    },
                    "pagina": {
                      "type": "integer"
                    },
                    "totalPaginas": {
                      "type": "integer"
                    },
                    "resultados": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Julgado"
                      }
                    },
                    "relaxed": {
                      "type": "boolean",
                      "description": "Consulta relaxada (menos termos obrigatórios) por escassez de resultados"
                    },
                    "busca_processo": {
                      "type": "string",
                      "enum": [
                        "cnj",
                        "superior"
                      ],
                      "description": "`q` interpretada como número de processo — filtro exato em `numero_processo`"
                    },
                    "modo": {
                      "type": "string",
                      "enum": [
                        "hibrido"
                      ]
                    },
                    "rerank": {
                      "type": "boolean"
                    },
                    "embedding_fallback": {
                      "type": "string",
                      "enum": [
                        "bm25"
                      ]
                    },
                    "incluir_stubs": {
                      "type": "boolean"
                    },
                    "deduplicados": {
                      "type": "integer"
                    },
                    "sugestao": {
                      "type": "string",
                      "description": "Correção ortográfica sugerida/aplicada"
                    },
                    "turmas": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contagem"
                      }
                    },
                    "relatores": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contagem"
                      }
                    },
                    "tribunais": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contagem"
                      }
                    }
                  }
                },
                "example": {
                  "total": 18432,
                  "pagina": 1,
                  "totalPaginas": 200,
                  "resultados": [
                    {
                      "score": 42.17,
                      "fonte": "stj_integras",
                      "tribunal": "STJ",
                      "numero_processo": "REsp 1.987.654/SP",
                      "classe": "REsp",
                      "relator": "NANCY ANDRIGHI",
                      "orgao_julgador": "TERCEIRA TURMA",
                      "data_julgamento": "2024-05-14",
                      "ementa": "RECURSO ESPECIAL. RESPONSABILIDADE CIVIL. INSCRIÇÃO INDEVIDA EM CADASTRO DE INADIMPLENTES. DANO MORAL IN RE IPSA...",
                      "highlight": {
                        "ementa": [
                          "INSCRIÇÃO INDEVIDA ... <em>dano</em> <em>moral</em> in re ipsa"
                        ]
                      }
                    }
                  ],
                  "turmas": [
                    {
                      "key": "TERCEIRA TURMA",
                      "count": 6120
                    },
                    {
                      "key": "QUARTA TURMA",
                      "count": 5874
                    }
                  ],
                  "relatores": [
                    {
                      "key": "NANCY ANDRIGHI",
                      "count": 1402
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/similaridade": {
      "get": {
        "tags": [
          "Busca"
        ],
        "operationId": "similaridadeGet",
        "summary": "Decisões semanticamente similares (GET)",
        "description": "Atalho GET para `POST /similaridade` (mesmos parâmetros em query). `texto` mínimo 10 caracteres.",
        "parameters": [
          {
            "name": "texto",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 10
            },
            "example": "rescisão indireta por atraso reiterado de salários"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Base de referência (padrão `tst_jurisprudencia`).",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          },
          {
            "name": "limite",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 20,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Similares",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimilaridadeResposta"
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Busca"
        ],
        "operationId": "similaridade",
        "summary": "Decisões semanticamente similares (embeddings e5)",
        "description": "Gera o embedding do texto (multilingual-e5-large-instruct, 1024d) e compara por cosseno com candidatos BM25 da base. Latência típica 3–10 s. Sem o serviço de embeddings → 500.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "texto"
                ],
                "properties": {
                  "texto": {
                    "type": "string",
                    "minLength": 5,
                    "description": "Ementa, tese ou resumo dos fatos"
                  },
                  "fonte": {
                    "type": "string",
                    "default": "tst_jurisprudencia"
                  },
                  "turma": {
                    "type": "string"
                  },
                  "limite": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 20,
                    "default": 10
                  }
                }
              },
              "example": {
                "texto": "rescisão indireta por atraso reiterado de salários",
                "fonte": "tst_jurisprudencia",
                "limite": 5
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Similares",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimilaridadeResposta"
                },
                "example": {
                  "similares": [
                    {
                      "numero_processo": "RR-1000123-45.2021.5.02.0001",
                      "relator": "MAURICIO GODINHO DELGADO",
                      "orgao_julgador": "3ª Turma",
                      "data_publicacao": "2024-03-08",
                      "ementa": "RESCISÃO INDIRETA. ATRASO REITERADO NO PAGAMENTO DE SALÁRIOS...",
                      "similaridade": 91.37,
                      "classificacao": "favoravel"
                    }
                  ],
                  "total_candidatos": 200,
                  "modelo_embedding": "intfloat/multilingual-e5-large-instruct",
                  "provedor_embedding": "e5"
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/clusters": {
      "get": {
        "tags": [
          "Busca"
        ],
        "operationId": "clustersTematicos",
        "summary": "Clusters temáticos (k-means sobre embeddings)",
        "description": "Agrupa uma amostra de decisões do tema em sub-temas. Latência 10–60 s. Requer serviço de embeddings.",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": true,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          },
          {
            "name": "clusters",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 2,
              "maximum": 10,
              "default": 5
            }
          },
          {
            "name": "amostra",
            "in": "query",
            "description": "Documentos amostrados (≤ 50).",
            "schema": {
              "type": "integer",
              "minimum": 5,
              "maximum": 50,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Clusters",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string"
                    },
                    "busca": {
                      "type": "string"
                    },
                    "total_documentos": {
                      "type": "integer"
                    },
                    "total_base": {
                      "type": "integer"
                    },
                    "num_clusters": {
                      "type": "integer"
                    },
                    "clusters": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "label": {
                            "type": "string"
                          },
                          "tamanho": {
                            "type": "integer"
                          },
                          "documentos": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "numero_processo": {
                                  "type": "string"
                                },
                                "relator": {
                                  "type": "string"
                                },
                                "orgao_julgador": {
                                  "type": "string"
                                },
                                "ementa_resumo": {
                                  "type": "string"
                                },
                                "classificacao": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "distribuicao_direcional": {
                            "type": "object",
                            "properties": {
                              "favoravel": {
                                "type": "integer"
                              },
                              "desfavoravel": {
                                "type": "integer"
                              },
                              "incidental": {
                                "type": "integer"
                              }
                            }
                          }
                        }
                      }
                    },
                    "modelo_embedding": {
                      "type": "string"
                    },
                    "provedor_embedding": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/panorama": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "panorama",
        "summary": "Panorama do tema: taxa de provimento por turma, relator e ano",
        "description": "Classifica as decisões do tema em categorias de resultado (favorável/desfavorável/parcial…) e agrega por turma (top 10), relator (top 10) e ano. `merito=true` indica que a taxa considera só decisões de mérito classificadas.",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": false,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          }
        ],
        "responses": {
          "200": {
            "description": "Panorama",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string"
                    },
                    "tribunal": {
                      "type": "string"
                    },
                    "turma": {
                      "type": "string"
                    },
                    "busca": {
                      "type": "string"
                    },
                    "merito": {
                      "type": "boolean"
                    },
                    "categorias": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string"
                          },
                          "cor": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "labelFavoravel": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "classificados": {
                      "type": "integer"
                    },
                    "favoravel": {
                      "type": "integer"
                    },
                    "desfavoravel": {
                      "type": "integer"
                    },
                    "taxa_geral": {
                      "type": "number",
                      "description": "% favorável (0–100)"
                    },
                    "turmas": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "turma": {
                            "type": "string",
                            "description": "Órgão julgador"
                          },
                          "total": {
                            "type": "integer"
                          },
                          "classificados": {
                            "type": "integer"
                          },
                          "favoravel": {
                            "type": "integer"
                          },
                          "desfavoravel": {
                            "type": "integer"
                          },
                          "taxa_favoravel": {
                            "type": "number",
                            "description": "Percentual (0–100)"
                          }
                        }
                      }
                    },
                    "relatores": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "relator": {
                            "type": "string",
                            "description": "Relator"
                          },
                          "total": {
                            "type": "integer"
                          },
                          "classificados": {
                            "type": "integer"
                          },
                          "favoravel": {
                            "type": "integer"
                          },
                          "desfavoravel": {
                            "type": "integer"
                          },
                          "taxa_favoravel": {
                            "type": "number",
                            "description": "Percentual (0–100)"
                          }
                        }
                      }
                    },
                    "anos": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "ano": {
                            "type": "string"
                          },
                          "total": {
                            "type": "integer"
                          },
                          "classificados": {
                            "type": "integer"
                          },
                          "favoravel": {
                            "type": "integer"
                          },
                          "desfavoravel": {
                            "type": "integer"
                          },
                          "taxa": {
                            "type": "number"
                          }
                        }
                      }
                    },
                    "_meta": {
                      "type": "object",
                      "description": "Qualidade da amostra: n ≥ 100 alta, ≥ 30 média, ≥ 10 baixa, < 10 insuficiente.",
                      "properties": {
                        "n": {
                          "type": "integer"
                        },
                        "confianca": {
                          "type": "string",
                          "enum": [
                            "alta",
                            "media",
                            "baixa",
                            "insuficiente"
                          ]
                        },
                        "nota": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "fonte": "stj_integras",
                  "tribunal": "",
                  "turma": "",
                  "busca": "dano moral negativação indevida",
                  "merito": true,
                  "categorias": [
                    {
                      "key": "provido",
                      "label": "Provido",
                      "cor": "#16a34a"
                    },
                    {
                      "key": "desprovido",
                      "label": "Desprovido",
                      "cor": "#dc2626"
                    }
                  ],
                  "labelFavoravel": "Provido",
                  "total": 18432,
                  "classificados": 11205,
                  "favoravel": 6318,
                  "desfavoravel": 4887,
                  "taxa_geral": 56.4,
                  "turmas": [
                    {
                      "turma": "TERCEIRA TURMA",
                      "total": 6120,
                      "classificados": 3900,
                      "favoravel": 2340,
                      "desfavoravel": 1560,
                      "taxa_favoravel": 60
                    }
                  ],
                  "relatores": [
                    {
                      "relator": "NANCY ANDRIGHI",
                      "total": 1402,
                      "classificados": 910,
                      "favoravel": 601,
                      "desfavoravel": 309,
                      "taxa_favoravel": 66
                    }
                  ],
                  "anos": [
                    {
                      "ano": "2024",
                      "total": 2310,
                      "classificados": 1500,
                      "favoravel": 870,
                      "desfavoravel": 630,
                      "taxa": 58
                    }
                  ],
                  "_meta": {
                    "n": 11205,
                    "confianca": "alta",
                    "nota": "Amostra robusta"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/relator": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "perfilRelator",
        "summary": "Ranking de relatores no tema (top 30) com taxa favorável",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": false,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          }
        ],
        "responses": {
          "200": {
            "description": "Relatores",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string"
                    },
                    "tribunal": {
                      "type": "string"
                    },
                    "turma": {
                      "type": "string"
                    },
                    "busca": {
                      "type": "string"
                    },
                    "merito": {
                      "type": "boolean"
                    },
                    "categorias": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string"
                          },
                          "cor": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "labelFavoravel": {
                      "type": "string"
                    },
                    "labelRelator": {
                      "type": "string",
                      "enum": [
                        "Juiz(a)",
                        "Relator(a)"
                      ]
                    },
                    "relatores": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "relator": {
                            "type": "string"
                          },
                          "total": {
                            "type": "integer"
                          },
                          "classificados": {
                            "type": "integer"
                          },
                          "taxa_favoravel": {
                            "type": "number"
                          }
                        },
                        "additionalProperties": {
                          "type": "integer",
                          "description": "Contagem por categoria (chave = `categorias[].key`)"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/divergencia": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "divergenciaTurmas",
        "summary": "Divergência entre turmas (teste qui-quadrado)",
        "description": "Compara a taxa favorável entre órgãos julgadores do tribunal e testa se a diferença é estatisticamente significativa (χ², p < 0,05).",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": false,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          }
        ],
        "responses": {
          "200": {
            "description": "Divergência",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string"
                    },
                    "busca": {
                      "type": "string"
                    },
                    "merito": {
                      "type": "boolean"
                    },
                    "categorias": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string"
                          },
                          "cor": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "labelFavoravel": {
                      "type": "string"
                    },
                    "turmas": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "turma": {
                            "type": "string",
                            "description": "Órgão julgador"
                          },
                          "total": {
                            "type": "integer"
                          },
                          "classificados": {
                            "type": "integer"
                          },
                          "favoravel": {
                            "type": "integer"
                          },
                          "desfavoravel": {
                            "type": "integer"
                          },
                          "taxa_favoravel": {
                            "type": "number",
                            "description": "Percentual (0–100)"
                          }
                        }
                      }
                    },
                    "teste_divergencia": {
                      "type": "object",
                      "properties": {
                        "metodo": {
                          "type": "string",
                          "const": "chi-quadrado"
                        },
                        "chi2": {
                          "type": "number"
                        },
                        "graus_liberdade": {
                          "type": "integer"
                        },
                        "p_value": {
                          "type": "number"
                        },
                        "significativo": {
                          "type": "boolean"
                        },
                        "interpretacao": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "fonte": "stj_integras",
                  "busca": "dano moral negativação indevida",
                  "merito": true,
                  "labelFavoravel": "Provido",
                  "categorias": [
                    {
                      "key": "provido",
                      "label": "Provido",
                      "cor": "#16a34a"
                    }
                  ],
                  "turmas": [
                    {
                      "turma": "TERCEIRA TURMA",
                      "total": 6120,
                      "classificados": 3900,
                      "favoravel": 2340,
                      "desfavoravel": 1560,
                      "taxa_favoravel": 60
                    },
                    {
                      "turma": "QUARTA TURMA",
                      "total": 5874,
                      "classificados": 3700,
                      "favoravel": 1961,
                      "desfavoravel": 1739,
                      "taxa_favoravel": 53
                    }
                  ],
                  "teste_divergencia": {
                    "metodo": "chi-quadrado",
                    "chi2": 37.9,
                    "graus_liberdade": 1,
                    "p_value": 0.0001,
                    "significativo": true,
                    "interpretacao": "Há divergência estatisticamente significativa entre as turmas (p=0.0001)"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/evolucao": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "evolucaoJurisprudencial",
        "summary": "Evolução trimestral da taxa favorável (com média móvel de 4 trimestres)",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": false,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          }
        ],
        "responses": {
          "200": {
            "description": "Série trimestral",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string"
                    },
                    "tribunal": {
                      "type": "string"
                    },
                    "turma": {
                      "type": "string"
                    },
                    "busca": {
                      "type": "string"
                    },
                    "campoData": {
                      "type": "string",
                      "description": "Campo de data usado (julgamento ou publicação, o de maior cobertura)"
                    },
                    "merito": {
                      "type": "boolean"
                    },
                    "labelFavoravel": {
                      "type": "string"
                    },
                    "periodos": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PeriodoTaxa"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Classificação direcional não disponível para este tema",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/mudanca": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "mudancaEntendimento",
        "summary": "Detecção de mudança de entendimento (CUSUM + Welch t-test)",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": false,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          }
        ],
        "responses": {
          "200": {
            "description": "Mudanças detectadas",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string"
                    },
                    "turma": {
                      "type": "string"
                    },
                    "busca": {
                      "type": "string"
                    },
                    "merito": {
                      "type": "boolean"
                    },
                    "labelFavoravel": {
                      "type": "string"
                    },
                    "metodo": {
                      "type": "string",
                      "const": "CUSUM + Welch t-test"
                    },
                    "periodos": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PeriodoTaxa"
                      }
                    },
                    "mudancas": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "periodo": {
                            "type": "string"
                          },
                          "p_value": {
                            "type": "number"
                          },
                          "significativo": {
                            "type": "boolean"
                          }
                        }
                      }
                    },
                    "resumo": {
                      "type": "object",
                      "properties": {
                        "total_periodos": {
                          "type": "integer"
                        },
                        "mudancas_detectadas": {
                          "type": "integer"
                        },
                        "mudancas_significativas": {
                          "type": "integer"
                        },
                        "maior_variacao": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "additionalProperties": true
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/breakpoints": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "breakpoints",
        "summary": "Pontos de ruptura na série temporal (CUSUM ou bayesiano)",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": true,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          },
          {
            "name": "metodo",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "cusum",
                "bayesian"
              ],
              "default": "cusum"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Breakpoints",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string"
                    },
                    "busca": {
                      "type": "string"
                    },
                    "metodo": {
                      "type": "string"
                    },
                    "periodos": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PeriodoTaxa"
                      }
                    },
                    "breakpoints": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "tendencia_atual": {
                      "type": "object",
                      "properties": {
                        "direcao": {
                          "type": "string",
                          "enum": [
                            "alta",
                            "queda",
                            "estavel"
                          ]
                        },
                        "taxa_media_recente": {
                          "type": "number"
                        },
                        "variacao_12m": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/previsao": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "previsao",
        "summary": "Taxa favorável com intervalo de confiança de Wilson (95%)",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": true,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          },
          {
            "name": "relator",
            "in": "query",
            "description": "Nome (ou parte) do relator/juiz.",
            "schema": {
              "type": "string"
            },
            "example": "NANCY ANDRIGHI"
          }
        ],
        "responses": {
          "200": {
            "description": "Previsão",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string"
                    },
                    "tribunal": {
                      "type": "string"
                    },
                    "turma": {
                      "type": "string"
                    },
                    "relator": {
                      "type": "string"
                    },
                    "busca": {
                      "type": "string"
                    },
                    "merito": {
                      "type": "boolean"
                    },
                    "labelFavoravel": {
                      "type": "string"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "classificados": {
                      "type": "integer"
                    },
                    "favoravel": {
                      "type": "integer"
                    },
                    "desfavoravel": {
                      "type": "integer"
                    },
                    "taxa": {
                      "type": "number"
                    },
                    "intervalo_confianca": {
                      "$ref": "#/components/schemas/Intervalo"
                    },
                    "n": {
                      "type": "integer"
                    },
                    "relatores": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "_meta": {
                      "type": "object",
                      "description": "Qualidade da amostra: n ≥ 100 alta, ≥ 30 média, ≥ 10 baixa, < 10 insuficiente.",
                      "properties": {
                        "n": {
                          "type": "integer"
                        },
                        "confianca": {
                          "type": "string",
                          "enum": [
                            "alta",
                            "media",
                            "baixa",
                            "insuficiente"
                          ]
                        },
                        "nota": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/previsao-temporal": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "previsaoTemporal",
        "summary": "Previsão ponderada por recência (decaimento exponencial + Wilson)",
        "description": "Cada decisão recebe peso 2^(-idade/meia-vida). A meia-vida depende da área (`area`) ou é inferida do tema.",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": true,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          },
          {
            "name": "relator",
            "in": "query",
            "description": "Nome (ou parte) do relator/juiz.",
            "schema": {
              "type": "string"
            },
            "example": "NANCY ANDRIGHI"
          },
          {
            "name": "area",
            "in": "query",
            "description": "Área do direito para calibrar a meia-vida (ex.: `trabalhista`, `consumidor`, `tributario`).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Previsão temporal",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total_decisoes": {
                      "type": "integer"
                    },
                    "cobertura": {
                      "type": "object",
                      "properties": {
                        "docs_no_periodo": {
                          "type": "integer"
                        },
                        "classificados": {
                          "type": "integer"
                        },
                        "pct": {
                          "type": "number"
                        }
                      }
                    },
                    "previsao_temporal": {
                      "type": "object",
                      "properties": {
                        "taxa_ponderada": {
                          "type": "number"
                        },
                        "intervalo_confianca": {
                          "$ref": "#/components/schemas/Intervalo"
                        },
                        "n_efetivo": {
                          "type": "number"
                        },
                        "p_hat_ponderado": {
                          "type": "number"
                        }
                      }
                    },
                    "tendencia": {
                      "type": "object",
                      "properties": {
                        "direcao": {
                          "type": "string"
                        },
                        "variacao_percentual": {
                          "type": "number"
                        },
                        "serie": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "additionalProperties": true
                          }
                        }
                      }
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/predicao": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "predicaoResultado",
        "summary": "Predição multi-fator do resultado (base + turma + relator + tendência)",
        "description": "Combina a taxa-base do tema com desvios da turma e do relator e a tendência recente; devolve probabilidade, intervalo e texto interpretativo.",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": true,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          },
          {
            "name": "relator",
            "in": "query",
            "description": "Nome (ou parte) do relator/juiz.",
            "schema": {
              "type": "string"
            },
            "example": "NANCY ANDRIGHI"
          }
        ],
        "responses": {
          "200": {
            "description": "Predição",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "predicao": {
                      "type": "object",
                      "properties": {
                        "probabilidade": {
                          "type": "number"
                        },
                        "intervalo": {
                          "$ref": "#/components/schemas/Intervalo"
                        },
                        "confianca": {
                          "type": "string"
                        },
                        "n_decisoes": {
                          "type": "integer"
                        }
                      }
                    },
                    "fatores": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "interpretacao": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "predicao": {
                    "probabilidade": 61.2,
                    "intervalo": {
                      "lower": 58.9,
                      "upper": 63.4
                    },
                    "confianca": "alta",
                    "n_decisoes": 3900
                  },
                  "fatores": {
                    "base": {
                      "taxa": 56.4,
                      "n": 11205,
                      "contribuicao": "+0.0"
                    },
                    "turma": {
                      "nome": "TERCEIRA TURMA",
                      "taxa": 60,
                      "n": 3900,
                      "desvio": "+3.6",
                      "contribuicao": "+2.9"
                    },
                    "tendencia": {
                      "direcao": "alta",
                      "variacao_recente": "+4.1",
                      "contribuicao": "+1.9"
                    }
                  },
                  "interpretacao": "Probabilidade de resultado favorável de 61% (IC 95%: 59–63%). A Terceira Turma é 3,6 pp mais favorável que a média do tribunal e a tendência recente é de alta."
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "404": {
            "description": "Nenhum resultado / recurso não encontrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Nenhum resultado encontrado para esta busca/fonte"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          },
          "502": {
            "description": "Erro no Elasticsearch ou no modelo de IA",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Modelo de IA indisponível"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/argumentos": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "argumentosDiferenciais",
        "summary": "Termos que diferenciam decisões favoráveis das desfavoráveis (log-odds)",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": true,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          },
          {
            "name": "tamanho",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 30,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Argumentos",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "favoraveis": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TermoScore"
                      }
                    },
                    "desfavoraveis": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TermoScore"
                      }
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/dna": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "dnaTurma",
        "summary": "Termos estatisticamente significativos (significant_text) de turma/tema",
        "description": "Timeout de 12 s no Elasticsearch: em caso de timeout devolve 200 com `termos: []` e `error` explicativo.",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": false,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          }
        ],
        "responses": {
          "200": {
            "description": "Termos",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string"
                    },
                    "tribunal": {
                      "type": "string"
                    },
                    "turma": {
                      "type": "string"
                    },
                    "busca": {
                      "type": "string"
                    },
                    "termos": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "termo": {
                            "type": "string"
                          },
                          "ocorrencias": {
                            "type": "integer"
                          },
                          "score": {
                            "type": "number"
                          },
                          "bg_count": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          },
          "502": {
            "description": "Erro no Elasticsearch ou no modelo de IA",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Modelo de IA indisponível"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/rigor": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "indiceRigor",
        "summary": "Índice de rigor por julgador (desvio da média do tribunal)",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": true,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          },
          {
            "name": "relator",
            "in": "query",
            "description": "Destaca este julgador em `relator_consultado`.",
            "schema": {
              "type": "string"
            },
            "example": "NANCY ANDRIGHI"
          },
          {
            "name": "min_casos",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ranking de rigor",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string"
                    },
                    "tribunal": {
                      "type": "string"
                    },
                    "turma": {
                      "type": "string"
                    },
                    "busca": {
                      "type": "string"
                    },
                    "total_decisoes": {
                      "type": "integer"
                    },
                    "media_geral_favoravel": {
                      "type": "number"
                    },
                    "n_juizes": {
                      "type": "integer"
                    },
                    "relator_consultado": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "additionalProperties": true
                    },
                    "ranking": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "juiz": {
                            "type": "string"
                          },
                          "total": {
                            "type": "integer"
                          },
                          "taxa_favoravel": {
                            "type": "number"
                          },
                          "indice_rigor": {
                            "type": "number"
                          }
                        },
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/radar": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "radarIdeologico",
        "summary": "Radar ideológico do relator (eixos temáticos vs. média do tribunal)",
        "parameters": [
          {
            "name": "relator",
            "in": "query",
            "description": "Obrigatório (mín. 3 caracteres).",
            "schema": {
              "type": "string"
            },
            "example": "NANCY ANDRIGHI"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          }
        ],
        "responses": {
          "200": {
            "description": "Radar",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string"
                    },
                    "tribunal": {
                      "type": "string"
                    },
                    "relator": {
                      "type": "string"
                    },
                    "total_decisoes_analisadas": {
                      "type": "integer"
                    },
                    "n_eixos": {
                      "type": "integer"
                    },
                    "radar": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "eixo": {
                            "type": "string"
                          },
                          "valor": {
                            "type": "number"
                          }
                        },
                        "additionalProperties": true
                      }
                    },
                    "eixos_insuficientes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/taxa-reforma": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "taxaReforma",
        "summary": "Taxa de reforma/manutenção em 2ª instância (e comparativo com 1ª)",
        "description": "Exige `fonte_2g` (ou `fonte`, ou `tribunal` ∈ TJSP, TRF4, TRF3, TRF2, TRF1, TJMG, TJRS, TJPR, TJBA, TJDFT…). `fonte_1g` é inferida quando existe base de 1º grau relacionada; a leitura de alinhamento usa sobreposição de ICs de Wilson 95%.",
        "parameters": [
          {
            "name": "fonte_2g",
            "in": "query",
            "description": "Base de 2ª instância (ex.: `tjsp_cjsg`, `trf4_jur`).",
            "schema": {
              "type": "string"
            },
            "example": "tjsp_cjsg"
          },
          {
            "name": "fonte_1g",
            "in": "query",
            "description": "Base de 1ª instância para comparativo.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "busca",
            "in": "query",
            "required": false,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          },
          {
            "name": "juiz",
            "in": "query",
            "description": "Relator de 2º grau (alias `relator`).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Taxa de reforma",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total_2g": {
                      "type": "integer"
                    },
                    "taxa_reforma": {
                      "type": "number"
                    },
                    "taxa_manutencao": {
                      "type": "number"
                    },
                    "taxa_parcial": {
                      "type": "number"
                    },
                    "comparativo_instancias": {
                      "type": "object",
                      "properties": {
                        "fonte_1g": {
                          "type": "string"
                        },
                        "total_1g": {
                          "type": "integer"
                        },
                        "classificados_1g": {
                          "type": "integer"
                        },
                        "taxa_favoravel_1g": {
                          "type": "number"
                        },
                        "taxa_favoravel_2g": {
                          "type": "number"
                        },
                        "diferenca": {
                          "type": "number"
                        },
                        "interpretacao": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`fonte_2g` ausente ou de 1ª instância",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "tribunais_suportados": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tempo-tramitacao": {
      "get": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "tempoTramitacao",
        "summary": "Tempo entre julgamento e publicação: média, mediana, percentis, por turma e ano",
        "parameters": [
          {
            "name": "busca",
            "in": "query",
            "required": false,
            "description": "Tema ou palavras-chave. Aliases aceitos: `tema`, `q`. Mínimo 3 caracteres.",
            "schema": {
              "type": "string",
              "minLength": 3
            },
            "example": "dano moral negativação indevida"
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tribunal",
            "in": "query",
            "description": "Sigla do tribunal (ex.: `STJ`, `TST`, `TJSP`). Alternativa a `fonte`; abrange todas as bases do tribunal.",
            "schema": {
              "type": "string"
            },
            "example": "STJ"
          },
          {
            "name": "turma",
            "in": "query",
            "description": "Órgão julgador / turma / câmara.",
            "schema": {
              "type": "string"
            },
            "example": "TERCEIRA TURMA"
          },
          {
            "name": "relator",
            "in": "query",
            "description": "Nome (ou parte) do relator/juiz.",
            "schema": {
              "type": "string"
            },
            "example": "NANCY ANDRIGHI"
          }
        ],
        "responses": {
          "200": {
            "description": "Estatísticas de tempo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fonte": {
                      "type": "string"
                    },
                    "tribunal": {
                      "type": "string"
                    },
                    "turma": {
                      "type": "string"
                    },
                    "busca": {
                      "type": "string"
                    },
                    "relator": {
                      "type": "string"
                    },
                    "total_com_datas": {
                      "type": "integer"
                    },
                    "estatisticas": {
                      "type": "object",
                      "properties": {
                        "media_dias": {
                          "type": "integer"
                        },
                        "mediana_dias": {
                          "type": "integer"
                        },
                        "p10": {
                          "type": "integer"
                        },
                        "p25": {
                          "type": "integer"
                        },
                        "p75": {
                          "type": "integer"
                        },
                        "p90": {
                          "type": "integer"
                        },
                        "p95": {
                          "type": "integer"
                        }
                      }
                    },
                    "por_turma": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "por_ano": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "histograma": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "faixa_dias": {
                            "type": "integer"
                          },
                          "label": {
                            "type": "string"
                          },
                          "total": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/estrategia-juiz": {
      "post": {
        "tags": [
          "Jurimetria"
        ],
        "operationId": "estrategiaJuiz",
        "summary": "Análise estratégica completa de um julgador para um tema",
        "description": "Executa em paralelo perfil, DNA, argumentos, evolução e rigor (12 s cada) e devolve também um `prompt_estrategia` pronto para um LLM. Latência típica 5–15 s.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "relator",
                  "tema",
                  "fonte"
                ],
                "properties": {
                  "relator": {
                    "type": "string"
                  },
                  "tema": {
                    "type": "string"
                  },
                  "fonte": {
                    "type": "string"
                  },
                  "turma": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "relator": "NANCY ANDRIGHI",
                "tema": "dano moral negativação indevida",
                "fonte": "stj_integras"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Estratégia",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "perfil": {
                      "type": "object",
                      "properties": {
                        "total_decisoes": {
                          "type": "integer"
                        },
                        "taxa_favoravel": {
                          "type": "number"
                        },
                        "intervalo_confianca": {
                          "$ref": "#/components/schemas/Intervalo"
                        },
                        "confiabilidade": {
                          "type": "string"
                        }
                      }
                    },
                    "previsao_temporal": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "dna_termos": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "argumentos_favoraveis": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TermoScore"
                      }
                    },
                    "argumentos_desfavoraveis": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TermoScore"
                      }
                    },
                    "tendencia_recente": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "indice_rigor": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "additionalProperties": true
                    },
                    "prompt_estrategia": {
                      "type": "string"
                    },
                    "took_ms": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          },
          "502": {
            "description": "Erro no Elasticsearch ou no modelo de IA",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Modelo de IA indisponível"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/verificar-citacao": {
      "post": {
        "tags": [
          "IA"
        ],
        "operationId": "verificarCitacao",
        "summary": "Anti-alucinação: verifica citações jurisprudenciais de um texto",
        "description": "Extrai citações (REsp, AgInt, RR, HC, súmulas…) e confere no índice. `rapido` usa só Elasticsearch; `google` e `deep` acrescentam busca web (mais lentos). Texto truncado em 50.000 caracteres.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "content",
                  "mode"
                ],
                "properties": {
                  "content": {
                    "type": "string",
                    "minLength": 20
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "rapido",
                      "google",
                      "deep"
                    ]
                  }
                }
              },
              "example": {
                "content": "Conforme decidiu o STJ no REsp 1.987.654/SP, rel. Min. Nancy Andrighi, o dano moral por negativação indevida é in re ipsa.",
                "mode": "rapido"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Citações verificadas",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "citations": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "text": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "confirmado",
                              "suspeito",
                              "nao_encontrado"
                            ]
                          },
                          "details": {
                            "type": "string"
                          },
                          "source_url": {
                            "type": "string"
                          }
                        },
                        "additionalProperties": true
                      }
                    },
                    "summary": {
                      "type": "object",
                      "properties": {
                        "confirmados": {
                          "type": "integer"
                        },
                        "suspeitos": {
                          "type": "integer"
                        },
                        "naoEncontrados": {
                          "type": "integer"
                        },
                        "total": {
                          "type": "integer"
                        }
                      }
                    },
                    "mode": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "citations": [
                    {
                      "text": "REsp 1.987.654/SP",
                      "status": "confirmado",
                      "details": "Encontrado em stj_integras (Terceira Turma, 2024-05-14)"
                    }
                  ],
                  "summary": {
                    "confirmados": 1,
                    "suspeitos": 0,
                    "naoEncontrados": 0,
                    "total": 1
                  },
                  "mode": "rapido"
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/chat": {
      "post": {
        "tags": [
          "IA"
        ],
        "operationId": "chatJuridico",
        "summary": "Chat jurídico com resposta fundamentada em decisões reais (RAG)",
        "description": "Recupera decisões do tema na `fonte` e responde em prosa citando-as. `historico` mantém o contexto da conversa. Alias: `POST /api/v1/chat-estrategia`.",
        "requestBody": {
          "$ref": "#/components/requestBodies/ChatRequest"
        },
        "responses": {
          "200": {
            "description": "Resposta",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "resposta": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          },
          "502": {
            "description": "Erro no Elasticsearch ou no modelo de IA",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Modelo de IA indisponível"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/chat-estrategia": {
      "post": {
        "tags": [
          "IA"
        ],
        "operationId": "chatEstrategia",
        "summary": "Alias de `/chat`",
        "requestBody": {
          "$ref": "#/components/requestBodies/ChatRequest"
        },
        "responses": {
          "200": {
            "description": "Resposta",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "resposta": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          },
          "502": {
            "description": "Erro no Elasticsearch ou no modelo de IA",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Modelo de IA indisponível"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/gerar-peca": {
      "post": {
        "tags": [
          "IA"
        ],
        "operationId": "gerarPeca",
        "summary": "Minuta de peça processual fundamentada em precedentes reais",
        "description": "Busca jurimetria e precedentes do tema/lado e gera a minuta com LLM (somente precedentes do índice). Latência 20–90 s.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "tipo",
                  "tema",
                  "fonte",
                  "fatos",
                  "lado"
                ],
                "properties": {
                  "tipo": {
                    "type": "string",
                    "enum": [
                      "peticao_inicial",
                      "contestacao",
                      "recurso",
                      "parecer"
                    ]
                  },
                  "tema": {
                    "type": "string"
                  },
                  "fonte": {
                    "type": "string"
                  },
                  "turma": {
                    "type": "string"
                  },
                  "fatos": {
                    "type": "string",
                    "description": "Resumo dos fatos do caso"
                  },
                  "lado": {
                    "type": "string",
                    "enum": [
                      "autor",
                      "reu"
                    ]
                  },
                  "incluir_jurimetria": {
                    "type": "boolean",
                    "default": true
                  }
                }
              },
              "example": {
                "tipo": "peticao_inicial",
                "tema": "dano moral negativação indevida",
                "fonte": "tjsp_cjsg",
                "fatos": "Cliente teve o nome inscrito no SPC por dívida já quitada; contestou administrativamente sem resposta.",
                "lado": "autor"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Peça gerada",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "peca": {
                      "type": "string",
                      "description": "Texto da minuta (Markdown)"
                    },
                    "metadados": {
                      "type": "object",
                      "properties": {
                        "tipo": {
                          "type": "string"
                        },
                        "tema": {
                          "type": "string"
                        },
                        "dados_jurimetricos": {
                          "type": "object",
                          "properties": {
                            "total_decisoes": {
                              "type": "integer"
                            },
                            "taxa_favoravel": {
                              "type": "number"
                            },
                            "tendencia": {
                              "type": "string"
                            }
                          }
                        },
                        "precedentes_utilizados": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "numero": {
                                "type": "string"
                              },
                              "relator": {
                                "type": "string"
                              },
                              "data": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "argumentos_priorizados": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          },
          "502": {
            "description": "Erro no Elasticsearch ou no modelo de IA",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Modelo de IA indisponível"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/batch-classify": {
      "post": {
        "tags": [
          "Classificação"
        ],
        "operationId": "batchClassify",
        "summary": "Classificação direcional em massa (padrões + LLM)",
        "description": "Lotes ≤ 20 executam de forma síncrona; acima disso responde 202 com `job_id` e processa em background. Consulte o progresso em `GET /batch-classify/status?job_id=`. Restrito à chave interna.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "fonte",
                  "tema"
                ],
                "properties": {
                  "fonte": {
                    "type": "string"
                  },
                  "tema": {
                    "type": "string",
                    "description": "Chave de tema direcional (ex.: `dano_moral`)"
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 20000,
                    "default": 1000
                  }
                }
              },
              "example": {
                "fonte": "tst_jurisprudencia",
                "tema": "dano_moral",
                "limit": 100
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lote síncrono concluído",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "202": {
            "description": "Job em background",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "job_id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "status_url": {
                      "type": "string"
                    },
                    "fonte": {
                      "type": "string"
                    },
                    "tema": {
                      "type": "string"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "chunk_size": {
                      "type": "integer"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/batch-classify/status": {
      "get": {
        "tags": [
          "Classificação"
        ],
        "operationId": "batchClassifyStatus",
        "summary": "Progresso de job ou cobertura de classificação por tema",
        "parameters": [
          {
            "name": "job_id",
            "in": "query",
            "description": "Se informado, devolve o progresso do job.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fonte",
            "in": "query",
            "description": "Código da base/tribunal (ver `GET /filtros`). Ex.: `stj_integras`, `tst_jurisprudencia`, `tjsp_cjsg`. Se omitido junto com `tribunal`, usa `tst_jurisprudencia`.",
            "schema": {
              "type": "string"
            },
            "example": "stj_integras"
          },
          {
            "name": "tema",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "404": {
            "description": "Nenhum resultado / recurso não encontrado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Nenhum resultado encontrado para esta busca/fonte"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/alertas": {
      "get": {
        "tags": [
          "Alertas"
        ],
        "operationId": "listarAlertas",
        "summary": "Lista alertas jurimétricos (até 200)",
        "responses": {
          "200": {
            "description": "Alertas",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": {
                      "type": "integer"
                    },
                    "alertas": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Alerta"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Alertas"
        ],
        "operationId": "criarAlerta",
        "summary": "Cria alerta (webhook HTTPS ou e-mail)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AlertaInput"
              },
              "example": {
                "tipo": "taxa_queda",
                "fonte": "stj_integras",
                "busca": "dano moral negativação indevida",
                "threshold": 5,
                "webhook_url": "https://exemplo.com/hooks/ragjur"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Criado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Alerta"
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Alertas"
        ],
        "operationId": "removerAlerta",
        "summary": "Remove alerta",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Removido",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/alertas/check": {
      "post": {
        "tags": [
          "Alertas"
        ],
        "operationId": "checarAlertas",
        "summary": "Executa a checagem de todos os alertas (cron)",
        "responses": {
          "200": {
            "description": "Resultado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/djen": {
      "get": {
        "tags": [
          "DJEN"
        ],
        "operationId": "listarMonitoresDjen",
        "summary": "Lista monitores do DJEN (Diário de Justiça Eletrônico Nacional)",
        "parameters": [
          {
            "name": "cliente_id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Monitores",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "DJEN"
        ],
        "operationId": "criarMonitorDjen",
        "summary": "Cria monitor por processo, OAB ou nome de parte",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MonitorDjenInput"
              },
              "example": {
                "cliente_id": "cli_123",
                "estrategia": "oab",
                "numero_oab": "123456",
                "uf_oab": "SP",
                "webhook_url": "https://exemplo.com/hooks/djen"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Criado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "DJEN"
        ],
        "operationId": "removerMonitorDjen",
        "summary": "Remove monitor",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Removido",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/djen/publicacoes": {
      "get": {
        "tags": [
          "DJEN"
        ],
        "operationId": "listarPublicacoesDjen",
        "summary": "Publicações capturadas para um cliente",
        "parameters": [
          {
            "name": "cliente_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "severidade",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "desde",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Publicações",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": {
                      "type": "integer"
                    },
                    "por_severidade": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "integer"
                      }
                    },
                    "publicacoes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Parâmetro obrigatório ausente ou inválido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Busca deve ter ao menos 3 caracteres"
                }
              }
            }
          },
          "401": {
            "description": "Sem `x-api-key` ou chave inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Missing x-api-key header"
                }
              }
            }
          },
          "403": {
            "description": "Chave desativada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "API key is deactivated. Contact support."
                }
              }
            }
          },
          "429": {
            "description": "Rate limit excedido (janela deslizante por chave). Ver `Retry-After`, `X-RateLimit-Limit`, `X-RateLimit-Remaining`.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos até a próxima janela"
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Rate limit exceeded"
                }
              }
            }
          },
          "500": {
            "description": "Erro interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                },
                "example": {
                  "error": "Erro interno"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Chave `rj_…` criada no painel (https://app.ragjur.ai/painel/chaves). Nunca exponha em front-end."
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "OAuth 2.1 (PKCE S256, DCR RFC 7591, metadata RFC 8414/9728) do servidor MCP. Escopo único `ragjur:read`.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://mcp.ragjur.ai/oauth/authorize",
            "tokenUrl": "https://mcp.ragjur.ai/oauth/token",
            "refreshUrl": "https://mcp.ragjur.ai/oauth/token",
            "scopes": {
              "ragjur:read": "Busca jurisprudencial e jurimetria (somente leitura)"
            }
          }
        }
      }
    },
    "requestBodies": {
      "ChatRequest": {
        "required": true,
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "pergunta",
                "fonte"
              ],
              "properties": {
                "pergunta": {
                  "type": "string"
                },
                "fonte": {
                  "type": "string"
                },
                "turma": {
                  "type": "string"
                },
                "historico": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "role": {
                        "type": "string",
                        "enum": [
                          "user",
                          "assistant"
                        ]
                      },
                      "content": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            },
            "example": {
              "pergunta": "Qual a tendência do STJ sobre dano moral por negativação indevida?",
              "fonte": "stj_integras"
            }
          }
        }
      }
    },
    "schemas": {
      "Erro": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "Contagem": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          }
        }
      },
      "Intervalo": {
        "type": "object",
        "description": "Intervalo de confiança 95% (Wilson), em pontos percentuais",
        "properties": {
          "lower": {
            "type": "number"
          },
          "upper": {
            "type": "number"
          }
        }
      },
      "TermoScore": {
        "type": "object",
        "properties": {
          "termo": {
            "type": "string"
          },
          "frequencia": {
            "type": "integer"
          },
          "score": {
            "type": "number",
            "description": "log2 odds ratio"
          }
        }
      },
      "PeriodoTaxa": {
        "type": "object",
        "properties": {
          "periodo": {
            "type": "string",
            "description": "Início do trimestre (YYYY-MM-DD)"
          },
          "total": {
            "type": "integer"
          },
          "classificados": {
            "type": "integer"
          },
          "favoravel": {
            "type": "integer"
          },
          "desfavoravel": {
            "type": "integer"
          },
          "taxa": {
            "type": "number"
          },
          "media_movel": {
            "type": [
              "number",
              "null"
            ]
          }
        }
      },
      "Julgado": {
        "type": "object",
        "description": "Documento do índice (campos variam por fonte). Vetores de embedding são sempre removidos.",
        "properties": {
          "score": {
            "type": "number"
          },
          "rrf_score": {
            "type": "number",
            "description": "Só em `modo=hibrido`"
          },
          "rerank_score": {
            "type": "number",
            "description": "Só em `modo=hibrido` com rerank ativo"
          },
          "vector_similarity": {
            "type": "number",
            "description": "Só em `modo=hibrido` (0–100)"
          },
          "fonte": {
            "type": "string"
          },
          "tribunal": {
            "type": "string"
          },
          "numero_processo": {
            "type": "string"
          },
          "classe": {
            "type": "string"
          },
          "relator": {
            "type": "string"
          },
          "orgao_julgador": {
            "type": "string"
          },
          "data_julgamento": {
            "type": "string",
            "format": "date"
          },
          "data_publicacao": {
            "type": "string",
            "format": "date"
          },
          "titulo": {
            "type": "string"
          },
          "ementa": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "highlight": {
            "type": "object",
            "properties": {
              "ementa": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        },
        "additionalProperties": true
      },
      "SimilaridadeResposta": {
        "type": "object",
        "properties": {
          "similares": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "numero_processo": {
                  "type": "string"
                },
                "relator": {
                  "type": "string"
                },
                "orgao_julgador": {
                  "type": "string"
                },
                "data_publicacao": {
                  "type": "string"
                },
                "ementa": {
                  "type": "string",
                  "description": "Até 500 caracteres"
                },
                "similaridade": {
                  "type": "number",
                  "description": "Cosseno × 100"
                },
                "classificacao": {
                  "type": "string"
                }
              }
            }
          },
          "total_candidatos": {
            "type": "integer"
          },
          "modelo_embedding": {
            "type": "string"
          },
          "provedor_embedding": {
            "type": "string"
          }
        }
      },
      "AlertaInput": {
        "type": "object",
        "required": [
          "tipo",
          "fonte"
        ],
        "properties": {
          "tipo": {
            "type": "string",
            "enum": [
              "taxa_queda",
              "taxa_alta",
              "nova_decisao",
              "mudanca_entendimento"
            ]
          },
          "fonte": {
            "type": "string"
          },
          "busca": {
            "type": "string"
          },
          "turma": {
            "type": "string"
          },
          "threshold": {
            "type": "number",
            "description": "Obrigatório para `taxa_queda`/`taxa_alta` (pontos percentuais)"
          },
          "webhook_url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS público (hosts privados rejeitados)"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "descricao": {
            "type": "string"
          }
        }
      },
      "Alerta": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AlertaInput"
          },
          {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "criado_em": {
                "type": "string",
                "format": "date-time"
              },
              "ativo": {
                "type": "boolean"
              }
            },
            "additionalProperties": true
          }
        ]
      },
      "MonitorDjenInput": {
        "type": "object",
        "required": [
          "cliente_id",
          "estrategia"
        ],
        "properties": {
          "cliente_id": {
            "type": "string"
          },
          "estrategia": {
            "type": "string",
            "enum": [
              "processo",
              "oab",
              "nomeParte"
            ]
          },
          "numero_processo": {
            "type": "string"
          },
          "numero_oab": {
            "type": "string"
          },
          "uf_oab": {
            "type": "string"
          },
          "nome_parte": {
            "type": "string"
          },
          "sigla_tribunal": {
            "type": "string"
          },
          "descricao": {
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "format": "uri"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "ativo": {
            "type": "boolean",
            "default": true
          }
        }
      }
    }
  }
}
