{
  "openapi": "3.1.0",
  "info": {
    "title": "EditalMD",
    "version": "232bdf32"
  },
  "servers": [
    {
      "url": "https://staging.editalmd.com"
    }
  ],
  "components": {
    "schemas": {
      "DocumentosEmpresa": {
        "type": "object",
        "properties": {
          "itens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentoEmpresa"
            },
            "description": "Até 20 anexos da empresa nesta conta."
          },
          "revisao": {
            "type": "string",
            "description": "Hash do conjunto de documentos; alterações invalidam análises anteriores."
          },
          "limite": {
            "type": "integer",
            "description": "20 documentos."
          },
          "limite_bytes": {
            "type": "integer",
            "description": "8 MiB por PDF; 80 MiB no conjunto."
          },
          "limite_paginas": {
            "type": "integer",
            "description": "50 páginas somadas entre os anexos."
          }
        },
        "required": [
          "itens",
          "revisao",
          "limite",
          "limite_bytes",
          "limite_paginas"
        ]
      },
      "DocumentoEmpresa": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "SHA-256 do PDF privado."
          },
          "nome": {
            "type": "string",
            "description": "Nome informado pelo titular."
          },
          "tipo": {
            "type": "string",
            "description": "atestado, certidao, licenca, contrato_social ou outro."
          },
          "bytes": {
            "type": "integer",
            "description": "Tamanho do PDF."
          },
          "paginas": {
            "type": "integer",
            "description": "Páginas confirmadas no arquivo."
          },
          "enviado_em": {
            "type": "string",
            "description": "Instante do envio."
          }
        },
        "required": [
          "id",
          "nome",
          "tipo",
          "bytes",
          "paginas",
          "enviado_em"
        ]
      },
      "AnaliseParticipacao": {
        "type": "object",
        "properties": {
          "analise": {
            "type": "object",
            "description": "null quando nunca solicitada; id, status (queued/processing/retrying/paused/ready/failed/outdated/interrupted), atual, parcial, data_atual, etapa, processados, total, CNPJ, hashes, datas, erro, falha_etapa, problema (motivo/acao/automatico), historico e proxima_tentativa_em. atual permite consultar lotes validados; somente ready é cobertura concluída. data_atual=false exige conferir a data de referência. interrupted permite retomar pedido sem entrada de fila, inclusive legado.",
            "nullable": true
          },
          "itens": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Até 30 pares fact/analysis: fato do dossiê e avaliação com fact_id, status, reason, action, evidence (source_id/page/quote), edital_quote e edital_page."
          },
          "contagens": {
            "type": "object",
            "description": "Totais pendencias, atendidos e nao_aplicavel dos lotes já validados da análise atual, inclusive durante processamento ou pausa; parcial=true não representa cobertura completa."
          },
          "tipos": {
            "type": "object",
            "description": "Mesmas contagens separadas por requirement, attestation e obligation."
          },
          "next": {
            "type": "integer",
            "description": "Último ID desta página; use after até null.",
            "nullable": true
          }
        },
        "required": [
          "analise",
          "itens",
          "next"
        ]
      },
      "EmpresasConta": {
        "type": "object",
        "properties": {
          "itens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmpresaConta"
            },
            "description": "Até 20 vínculos, por CNPJ crescente; coleção completa."
          },
          "selecionada": {
            "type": "string",
            "description": "CNPJ selecionado na conta, ou null.",
            "nullable": true
          },
          "limite": {
            "type": "integer",
            "description": "20 empresas por conta."
          }
        },
        "required": [
          "itens",
          "selecionada",
          "limite"
        ]
      },
      "EmpresaConta": {
        "type": "object",
        "properties": {
          "cnpj": {
            "type": "string",
            "description": "CNPJ completo, 14 dígitos com verificação válida."
          },
          "razao_social": {
            "type": "string",
            "description": "Razão social cadastrada.",
            "nullable": true
          },
          "nome_fantasia": {
            "type": "string",
            "description": "Nome comercial cadastrado.",
            "nullable": true
          },
          "situacao": {
            "type": "string",
            "description": "Situação cadastral.",
            "nullable": true
          },
          "situacao_desde": {
            "type": "string",
            "description": "Data da situação.",
            "nullable": true
          },
          "porte": {
            "type": "string",
            "description": "Porte cadastral.",
            "nullable": true
          },
          "natureza_juridica": {
            "type": "string",
            "description": "Natureza jurídica.",
            "nullable": true
          },
          "inicio_atividade": {
            "type": "string",
            "description": "Data inicial das atividades.",
            "nullable": true
          },
          "matriz_filial": {
            "type": "string",
            "description": "Matriz ou filial.",
            "nullable": true
          },
          "capital_social": {
            "type": "number",
            "description": "Capital social em reais.",
            "nullable": true
          },
          "municipio": {
            "type": "string",
            "description": "Município do estabelecimento.",
            "nullable": true
          },
          "uf": {
            "type": "string",
            "description": "Sigla da unidade da federação.",
            "nullable": true
          },
          "cnaes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AtividadeEmpresa"
            },
            "description": "Principal primeiro; secundários podem não ter descrição."
          },
          "fonte": {
            "type": "string",
            "description": "Crédito de procedência do cadastro."
          },
          "importado_em": {
            "type": "string",
            "description": "Instante da importação na conta; não é a data de atualização do cadastro."
          }
        },
        "required": [
          "cnpj",
          "razao_social",
          "nome_fantasia",
          "situacao",
          "situacao_desde",
          "porte",
          "natureza_juridica",
          "inicio_atividade",
          "matriz_filial",
          "capital_social",
          "municipio",
          "uf",
          "cnaes",
          "fonte",
          "importado_em"
        ],
        "description": "Projeção cadastral importada na conta, até 24 KiB e 100 CNAEs. Não comprova representação nem habilitação."
      },
      "AtividadeEmpresa": {
        "type": "object",
        "properties": {
          "codigo": {
            "type": "string",
            "description": "Código de 7 dígitos."
          },
          "descricao": {
            "type": "string",
            "description": "Descrição conhecida.",
            "nullable": true
          },
          "principal": {
            "type": "boolean",
            "description": "Atividade principal."
          }
        },
        "required": [
          "codigo",
          "descricao",
          "principal"
        ]
      },
      "SugestaoEmpresa": {
        "type": "object",
        "properties": {
          "cnpj": {
            "type": "string",
            "description": "CNPJ completo, 14 dígitos com verificação válida."
          },
          "nome": {
            "type": "string",
            "description": "Nome exibido pela base.",
            "nullable": true
          },
          "municipio": {
            "type": "string",
            "description": "Município.",
            "nullable": true
          },
          "uf": {
            "type": "string",
            "description": "Sigla da unidade da federação.",
            "nullable": true
          },
          "situacao": {
            "type": "string",
            "description": "Situação cadastral.",
            "nullable": true
          }
        },
        "required": [
          "cnpj",
          "nome",
          "municipio",
          "uf",
          "situacao"
        ]
      },
      "Saude": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "`true` quando a origem respondeu."
          },
          "build": {
            "type": "string",
            "description": "Commit publicado (`env.BUILD`), o mesmo do `/api/`."
          },
          "acervo": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Acervo"
              }
            ],
            "description": "Números do acervo."
          },
          "preco_markdown_usd": {
            "type": "string",
            "description": "Tarifa por página por comprador, com geração incluída."
          },
          "gratis_acima_de_dias": {
            "type": "integer",
            "description": "Legado, sempre zero; nenhuma faixa de data concede gratuidade."
          }
        },
        "required": [
          "ok",
          "build",
          "acervo",
          "preco_markdown_usd",
          "gratis_acima_de_dias"
        ],
        "description": "Saúde do Worker e da origem."
      },
      "Acervo": {
        "type": "object",
        "properties": {
          "compras": {
            "type": "integer",
            "description": "Compras públicas indexadas."
          },
          "documentos_lidos": {
            "type": "integer",
            "description": "Documentos com texto extraído e disponível."
          }
        },
        "required": [
          "compras",
          "documentos_lidos"
        ],
        "description": "Tamanho do acervo lido na origem."
      },
      "Busca": {
        "type": "object",
        "properties": {
          "itens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Compra"
            },
            "description": "Compras que casaram com o termo."
          },
          "preco_markdown_usd": {
            "type": "string",
            "description": "Tarifa por página por comprador, inclusive texto pronto."
          },
          "gratis_acima_de_dias": {
            "type": "integer",
            "description": "Legado, sempre zero; nenhuma faixa de data concede gratuidade."
          },
          "pago": {
            "type": "boolean",
            "description": "Sempre `false`: buscar não custa."
          }
        },
        "required": [
          "itens",
          "preco_markdown_usd",
          "gratis_acima_de_dias",
          "pago"
        ],
        "description": "Resultado da busca — sempre grátis."
      },
      "Compra": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Identificador interno da compra — é ele que abre a ficha."
          },
          "pncp": {
            "type": "string",
            "description": "Número de controle PNCP da compra.",
            "nullable": true
          },
          "objeto": {
            "type": "string",
            "description": "Objeto da compra, como publicado.",
            "nullable": true
          },
          "uf": {
            "type": "string",
            "description": "Sigla da unidade da federação do órgão.",
            "nullable": true
          },
          "modalidade": {
            "type": "string",
            "description": "Modalidade (pregão eletrônico, dispensa…).",
            "nullable": true
          },
          "situacao": {
            "type": "string",
            "description": "Situação da compra no PNCP.",
            "nullable": true
          },
          "orgao": {
            "type": "string",
            "description": "Razão social do órgão comprador.",
            "nullable": true
          },
          "unidade": {
            "type": "string",
            "description": "Unidade administrativa responsável.",
            "nullable": true
          },
          "valor_estimado": {
            "type": "number",
            "description": "Valor total estimado em reais.",
            "nullable": true
          },
          "publicado_em": {
            "type": "string",
            "description": "Data de publicação no PNCP.",
            "nullable": true
          },
          "informacao_complementar": {
            "type": "string",
            "description": "Informação complementar publicada.",
            "nullable": true
          },
          "processo": {
            "type": "string",
            "description": "Número do processo administrativo.",
            "nullable": true
          },
          "abertura_proposta": {
            "type": "string",
            "description": "Início do recebimento de propostas, hora de Brasília.",
            "nullable": true
          },
          "encerramento_proposta": {
            "type": "string",
            "description": "Fim do recebimento de propostas, que é a abertura da sessão — a base da impugnação.",
            "nullable": true
          },
          "amparo_legal": {
            "type": "string",
            "description": "Amparo legal declarado, ex.: `Lei 14.133/2021, Art. 28, I`.",
            "nullable": true
          },
          "amparo_legal_codigo": {
            "type": "integer",
            "description": "Código do amparo legal no PNCP.",
            "nullable": true
          },
          "modalidade_id": {
            "type": "integer",
            "description": "Código da modalidade no PNCP (6 = pregão eletrônico, 8 = dispensa…).",
            "nullable": true
          },
          "situacao_id": {
            "type": "integer",
            "description": "Código da situação: 1 divulgada, 2 revogada, 3 anulada, 4 suspensa.",
            "nullable": true
          },
          "municipio": {
            "type": "string",
            "description": "Município da unidade compradora.",
            "nullable": true
          },
          "municipio_ibge": {
            "type": "string",
            "description": "Código IBGE do município.",
            "nullable": true
          },
          "orgao_cnpj": {
            "type": "string",
            "description": "CNPJ do órgão, só dígitos.",
            "nullable": true
          },
          "ano_compra": {
            "type": "integer",
            "description": "Ano da compra na numeração do PNCP.",
            "nullable": true
          },
          "sequencial_compra": {
            "type": "integer",
            "description": "Sequencial da compra no órgão e ano.",
            "nullable": true
          },
          "atualizado_em": {
            "type": "string",
            "description": "Última atualização da compra vista pelo acervo.",
            "nullable": true
          },
          "prazos": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Prazos"
              }
            ],
            "description": "Proposta e impugnação, calculados pelo Worker."
          },
          "pncp_url": {
            "type": "string",
            "description": "Página humana da compra no PNCP.",
            "nullable": true
          },
          "markdown_url": {
            "type": "string",
            "description": "Atalho para o markdown do documento."
          },
          "compra_url": {
            "type": "string",
            "description": "Ficha completa da compra."
          }
        },
        "required": [
          "id",
          "pncp",
          "objeto",
          "uf",
          "modalidade",
          "situacao",
          "orgao",
          "unidade",
          "valor_estimado",
          "publicado_em",
          "informacao_complementar",
          "processo",
          "abertura_proposta",
          "encerramento_proposta",
          "amparo_legal",
          "amparo_legal_codigo",
          "modalidade_id",
          "situacao_id",
          "municipio",
          "municipio_ibge",
          "orgao_cnpj",
          "ano_compra",
          "sequencial_compra",
          "atualizado_em",
          "prazos",
          "pncp_url",
          "markdown_url",
          "compra_url"
        ],
        "description": "Uma compra pública disponível no acervo."
      },
      "Prazos": {
        "type": "object",
        "properties": {
          "proposta_inicio": {
            "type": "string",
            "description": "Início do recebimento de propostas.",
            "nullable": true
          },
          "proposta_ate": {
            "type": "string",
            "description": "Fim do recebimento de propostas (abertura da sessão).",
            "nullable": true
          },
          "proposta_aberta": {
            "type": "boolean",
            "description": "Se ainda dá para enviar proposta agora."
          },
          "impugnacao_ate": {
            "type": "string",
            "description": "Último dia (AAAA-MM-DD) para impugnar: 3 dias úteis antes da sessão, Lei 14.133 art. 164.",
            "nullable": true
          },
          "impugnacao_aberta": {
            "type": "boolean",
            "description": "Se hoje, em Brasília, ainda cabe impugnação."
          },
          "estimado": {
            "type": "boolean",
            "description": "Sempre `true`: feriado municipal não está em base nenhuma."
          },
          "base_legal": {
            "type": "string",
            "description": "Regra usada na impugnação.",
            "nullable": true
          },
          "feriados": {
            "type": "string",
            "description": "Calendário considerado: `nacionais`."
          },
          "motivo": {
            "type": "string",
            "description": "Por que não há impugnação: `sem_data_de_encerramento` ou `amparo_sem_regra`.",
            "nullable": true
          }
        },
        "required": [
          "proposta_inicio",
          "proposta_ate",
          "proposta_aberta",
          "impugnacao_ate",
          "impugnacao_aberta",
          "estimado",
          "base_legal",
          "feriados",
          "motivo"
        ],
        "description": "Os relógios da compra: proposta vem do PNCP; impugnação é estimada pela lei, com feriados nacionais."
      },
      "Cnae": {
        "type": "object",
        "properties": {
          "codigo": {
            "type": "string",
            "description": "7 dígitos."
          },
          "cnae": {
            "type": "string",
            "description": "Formatado, ex. `1412-6/01`."
          },
          "descricao": {
            "type": "string",
            "description": "Descrição oficial (IBGE/Concla).",
            "nullable": true
          },
          "familia": {
            "type": "string",
            "description": "Família de termos no dicionário; nulo se ainda não mapeado.",
            "nullable": true
          },
          "familia_nome": {
            "type": "string",
            "description": "Nome da família.",
            "nullable": true
          },
          "termos": {
            "type": "string",
            "description": "Termos que um alerta por CNPJ usaria para este CNAE.",
            "nullable": true
          },
          "fornecedores_sicaf": {
            "type": "integer",
            "description": "Fornecedores ativos com este CNAE no SICAF (dados abertos do compras.gov.br).",
            "nullable": true
          },
          "sicaf_medido_em": {
            "type": "string",
            "description": "Quando essa contagem foi medida.",
            "nullable": true
          },
          "ibge_atualizado_em": {
            "type": "string",
            "description": "Quando a descrição foi atualizada do IBGE.",
            "nullable": true
          }
        },
        "required": [
          "codigo",
          "cnae",
          "descricao",
          "familia",
          "familia_nome",
          "termos",
          "fornecedores_sicaf",
          "sicaf_medido_em",
          "ibge_atualizado_em"
        ],
        "description": "Um CNAE (subclasse) como o produto o vê: descrição oficial, dicionário e fornecedores no SICAF."
      },
      "FichaCompra": {
        "type": "object",
        "properties": {
          "compra": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Compra"
              }
            ],
            "description": "A compra."
          },
          "documentos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Documento"
            },
            "description": "Documentos com texto pronto ou binário disponível."
          },
          "regime": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Regime"
              }
            ],
            "description": "Acesso individual pago; somente exemplos explícitos gratuitos."
          },
          "prazos": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Prazos"
              }
            ],
            "description": "Proposta e impugnação da compra — o mesmo objeto de `compra.prazos`."
          }
        },
        "required": [
          "compra",
          "documentos",
          "regime",
          "prazos"
        ],
        "description": "Compra + documentos disponíveis + o regime que se aplica a eles."
      },
      "Documento": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Identificador do documento — é ele que se pede em markdown."
          },
          "titulo": {
            "type": "string",
            "description": "Título do documento no PNCP.",
            "nullable": true
          },
          "tipo": {
            "type": "string",
            "description": "Tipo declarado (edital, anexo, ata…).",
            "nullable": true
          },
          "sequencial": {
            "type": "integer",
            "description": "Sequencial do documento dentro da compra no PNCP.",
            "nullable": true
          },
          "publicado_em": {
            "type": "string",
            "description": "Publicação do documento no PNCP.",
            "nullable": true
          },
          "caracteres": {
            "type": "integer",
            "description": "Tamanho do texto extraído, em caracteres.",
            "nullable": true
          },
          "paginas": {
            "type": "integer",
            "description": "Páginas do documento original.",
            "nullable": true
          },
          "motor": {
            "type": "string",
            "description": "Identificador da extração usada nesta versão.",
            "nullable": true
          },
          "formato": {
            "type": "string",
            "description": "`markdown` quando a extração é estruturada; `plain` no resto."
          },
          "sha256": {
            "type": "string",
            "description": "Hash do texto extraído na origem.",
            "nullable": true
          },
          "extraido_em": {
            "type": "string",
            "description": "Quando a extração rodou.",
            "nullable": true
          },
          "gratuito": {
            "type": "boolean",
            "description": "True somente nos cinco exemplos gratuitos; demais documentos exigem compra individual."
          },
          "preco_usd": {
            "type": "string",
            "description": "Nulo até consultar a cotação em /geracao.",
            "nullable": true
          },
          "markdown_url": {
            "type": "string",
            "description": "Onde pedir o markdown deste documento."
          },
          "geracao_url": {
            "type": "string",
            "description": "GET acompanha e informa cotação; POST compra acesso individual, inclusive ao texto pronto."
          },
          "preco_pagina_usd": {
            "type": "string",
            "description": "US$ 0,02 por página no site e API; consulte /geracao para confirmar páginas e total."
          },
          "disponivel": {
            "type": "boolean",
            "description": "Há texto pronto ou arquivo disponível para geração autorizada."
          }
        },
        "required": [
          "id",
          "titulo",
          "tipo",
          "sequencial",
          "publicado_em",
          "caracteres",
          "paginas",
          "motor",
          "formato",
          "sha256",
          "extraido_em",
          "gratuito",
          "preco_usd",
          "markdown_url",
          "geracao_url",
          "preco_pagina_usd",
          "disponivel"
        ],
        "description": "Um documento da compra e os caminhos para leitura ou geração explícita."
      },
      "Regime": {
        "type": "object",
        "properties": {
          "gratuito": {
            "type": "boolean",
            "description": "False: a compra não libera documentos para todos; exemplos são marcados individualmente."
          },
          "motivo": {
            "type": "string",
            "description": "`acesso_individual`."
          },
          "idade_dias": {
            "type": "integer",
            "description": "Dias desde a publicação no PNCP.",
            "nullable": true
          }
        },
        "required": [
          "gratuito",
          "motivo",
          "idade_dias"
        ],
        "description": "Acesso individual pago, independentemente da data ou de o texto já estar pronto."
      },
      "Habilitacao": {
        "type": "object",
        "properties": {
          "documento_id": {
            "type": "integer",
            "description": "Documento lido."
          },
          "compra_id": {
            "type": "integer",
            "description": "Compra do documento.",
            "nullable": true
          },
          "sha256_texto": {
            "type": "string",
            "description": "Hash do texto fonte do dossiê."
          },
          "dossie_versao": {
            "type": "string",
            "description": "Hash da identidade da análise compartilhada."
          },
          "modelo": {
            "type": "string",
            "description": "Modelo que extraiu.",
            "nullable": true
          },
          "cache": {
            "type": "boolean",
            "description": "False: consulta a versão atual disponível."
          },
          "recibo": {
            "type": "string",
            "description": "Recibo da entrega paga; nulo no cache.",
            "nullable": true
          },
          "recibo_url": {
            "type": "string",
            "description": "Onde consultar o recibo.",
            "nullable": true
          },
          "aviso": {
            "type": "string",
            "description": "Lembrete de conferir no edital."
          },
          "habilitacao": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ListaHabilitacao"
              }
            ],
            "description": "As exigências por família e o que o edital diz de prazo."
          }
        },
        "required": [
          "documento_id",
          "compra_id",
          "sha256_texto",
          "dossie_versao",
          "modelo",
          "cache",
          "recibo",
          "recibo_url",
          "aviso",
          "habilitacao"
        ],
        "description": "A lista de habilitação extraída de um edital, por família, com procedência."
      },
      "ListaHabilitacao": {
        "type": "object",
        "properties": {
          "juridica": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Exigencia"
            },
            "description": "Habilitação jurídica: ato constitutivo, registro, procuração…"
          },
          "fiscal_social_trabalhista": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Exigencia"
            },
            "description": "Regularidade fiscal, social e trabalhista: CND federal, FGTS, CNDT…"
          },
          "economico_financeira": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Exigencia"
            },
            "description": "Qualificação econômico-financeira: balanço, certidão de falência, índices."
          },
          "tecnica": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Exigencia"
            },
            "description": "Qualificação técnica: atestados, registro em conselho, equipe."
          },
          "exclusivo_me_epp": {
            "type": "boolean",
            "description": "Nulo: participação condicionada por item/lote está nos fatos do dossiê.",
            "nullable": true
          },
          "impugnacao_texto": {
            "type": "string",
            "description": "Nulo nesta projeção: consulte os prazos e condições no dossiê.",
            "nullable": true
          },
          "proposta_texto": {
            "type": "string",
            "description": "Nulo nesta projeção: consulte os prazos e condições no dossiê.",
            "nullable": true
          },
          "total": {
            "type": "integer",
            "description": "Exigências aceitas, somando as quatro famílias."
          },
          "descartados": {
            "type": "integer",
            "description": "Zero nesta projeção; a validação ocorre durante a preparação do dossiê."
          }
        },
        "required": [
          "juridica",
          "fiscal_social_trabalhista",
          "economico_financeira",
          "tecnica",
          "exclusivo_me_epp",
          "impugnacao_texto",
          "proposta_texto",
          "total",
          "descartados"
        ],
        "description": "Exigências de habilitação por família, mais as marcações que o edital traz em texto."
      },
      "Exigencia": {
        "type": "object",
        "properties": {
          "exigencia": {
            "type": "string",
            "description": "Descrição curta, ex.: `Certidão negativa de débitos trabalhistas (CNDT)`."
          },
          "trecho": {
            "type": "string",
            "description": "Trecho literal conferido no Markdown, até 4000 caracteres."
          },
          "pagina": {
            "type": "integer",
            "description": "Página física da primeira evidência."
          },
          "fato_id": {
            "type": "integer",
            "description": "Identidade do fato no dossiê versionado."
          },
          "condicao": {
            "type": "string",
            "description": "Quando se aplica.",
            "nullable": true
          },
          "excecoes": {
            "type": "string",
            "description": "Ressalvas da fonte.",
            "nullable": true
          },
          "evidencias": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Todos os trechos com página e offsets UTF-16."
          }
        },
        "required": [
          "exigencia",
          "trecho",
          "pagina",
          "fato_id",
          "condicao",
          "excecoes",
          "evidencias"
        ],
        "description": "Um documento ou requisito de habilitação e a linha do edital que o exige."
      },
      "Dono": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "description": "`edm_…` emitido pela biblioteca de conta — guarde; não é mostrado de novo nem recuperável."
          },
          "aviso": {
            "type": "string",
            "description": "Lembrete de guardar o token e como usá-lo."
          },
          "webhook_segredo": {
            "type": "string",
            "description": "`whsec_…` — assina todo POST de webhook (Standard Webhooks). Releia em `GET /api/dono`; rotacione em `POST /api/dono/segredo`."
          },
          "webhook_assinatura": {
            "type": "string",
            "description": "Como conferir a assinatura, em uma linha."
          },
          "franquia": {
            "type": "object",
            "description": "`alertas_gratis` e `vigias_gratis` incluídos."
          }
        },
        "required": [
          "token",
          "aviso",
          "webhook_segredo",
          "webhook_assinatura",
          "franquia"
        ],
        "description": "O convidado (token de dono), mostrado uma única vez, o segredo que assina os webhooks e a franquia."
      },
      "Precos": {
        "type": "object",
        "properties": {
          "consulta": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PrecosConsulta"
              }
            ],
            "description": "O pedido como a origem o entendeu."
          },
          "estatisticas": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PrecosEstatisticas"
              }
            ],
            "description": "Sobre os valores unitários da amostra devolvida em `itens`."
          },
          "resumo": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PrecosResumo"
              }
            ],
            "description": "Sobre todos os candidatos do período (não só a amostra). Nulo quando nada casou.",
            "nullable": true
          },
          "por_uf": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PrecosPorUf"
            },
            "description": "Um por UF do órgão comprador, mais resultados primeiro."
          },
          "por_mes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PrecosPorMes"
            },
            "description": "Um por mês do período, do mais antigo ao mais recente; mês sem homologação vem com `n: 0`."
          },
          "vencedores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PrecoVencedor"
            },
            "description": "Até 10 fornecedores, por itens ganhos e depois por valor."
          },
          "compradores": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PrecoComprador"
            },
            "description": "Até 10 órgãos, por itens comprados e depois por valor."
          },
          "amostra": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PrecosAmostra"
              }
            ],
            "description": "Como os candidatos foram escolhidos e se bateram no teto.",
            "nullable": true
          },
          "itens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PrecoHomologado"
            },
            "description": "Resultados por relevância e homologação mais recente."
          },
          "base_legal": {
            "type": "string",
            "description": "A base legal da pesquisa de preços que este dado atende."
          },
          "pago": {
            "type": "boolean",
            "description": "Sempre `false`: consultar preços não custa."
          }
        },
        "required": [
          "consulta",
          "estatisticas",
          "resumo",
          "por_uf",
          "por_mes",
          "vencedores",
          "compradores",
          "amostra",
          "itens",
          "base_legal",
          "pago"
        ],
        "description": "Preços homologados para um item parecido: a amostra (`itens`) e, sobre todos os candidatos, o resumo, a distribuição por UF e por mês, quem vence e quem compra. Sempre grátis."
      },
      "PrecosConsulta": {
        "type": "object",
        "properties": {
          "q": {
            "type": "string",
            "description": "Termo pesquisado."
          },
          "expressao": {
            "type": "string",
            "description": "Expressão FULLTEXT executada, com os prefixos obrigatórios."
          },
          "uf": {
            "type": "string",
            "description": "UF filtrada.",
            "nullable": true
          },
          "catmat": {
            "type": "string",
            "description": "Código de catálogo filtrado.",
            "nullable": true
          },
          "meses": {
            "type": "integer",
            "description": "Janela de homologação, em meses."
          },
          "desde": {
            "type": "string",
            "description": "Primeira data de homologação considerada, `AAAA-MM-DD`."
          },
          "limite": {
            "type": "integer",
            "description": "Teto de itens pedido."
          }
        },
        "required": [
          "q",
          "expressao",
          "uf",
          "catmat",
          "meses",
          "desde",
          "limite"
        ]
      },
      "PrecosEstatisticas": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer",
            "description": "Quantos valores unitários entraram na conta."
          },
          "media": {
            "type": "number",
            "description": "Média dos valores unitários, em reais.",
            "nullable": true
          },
          "mediana": {
            "type": "number",
            "description": "Mediana dos valores unitários.",
            "nullable": true
          },
          "menor": {
            "type": "number",
            "description": "Menor valor unitário.",
            "nullable": true
          },
          "maior": {
            "type": "number",
            "description": "Maior valor unitário.",
            "nullable": true
          },
          "desvio_padrao": {
            "type": "number",
            "description": "Desvio padrão populacional.",
            "nullable": true
          }
        },
        "required": [
          "total",
          "media",
          "mediana",
          "menor",
          "maior",
          "desvio_padrao"
        ]
      },
      "PrecosResumo": {
        "type": "object",
        "properties": {
          "n": {
            "type": "integer",
            "description": "Resultados homologados válidos no período."
          },
          "mediana": {
            "type": "number",
            "description": "Mediana dos valores unitários, em reais.",
            "nullable": true
          },
          "p25": {
            "type": "number",
            "description": "Primeiro quartil (25 % dos resultados abaixo).",
            "nullable": true
          },
          "p75": {
            "type": "number",
            "description": "Terceiro quartil (75 % dos resultados abaixo).",
            "nullable": true
          },
          "menor": {
            "type": "number",
            "description": "Menor valor unitário.",
            "nullable": true
          },
          "maior": {
            "type": "number",
            "description": "Maior valor unitário.",
            "nullable": true
          },
          "media": {
            "type": "number",
            "description": "Média dos valores unitários.",
            "nullable": true
          },
          "desconto_mediano": {
            "type": "number",
            "description": "Mediana de `1 − homologado/estimado` nos itens com referência do órgão: `0.10` é 10 % abaixo do estimado.",
            "nullable": true
          },
          "com_referencia": {
            "type": "integer",
            "description": "Quantos resultados tinham valor unitário estimado pelo órgão."
          },
          "me_epp": {
            "type": "number",
            "description": "Fração dos resultados vencidos por ME ou EPP, de 0 a 1.",
            "nullable": true
          },
          "valor_total": {
            "type": "number",
            "description": "Soma dos valores totais homologados, em reais.",
            "nullable": true
          },
          "fornecedores": {
            "type": "integer",
            "description": "Fornecedores distintos — n alto com 1 fornecedor é uma compra só."
          },
          "compradores": {
            "type": "integer",
            "description": "Órgãos distintos."
          },
          "ultima_homologacao": {
            "type": "string",
            "description": "Data do resultado mais recente, `AAAA-MM-DD`.",
            "nullable": true
          }
        },
        "required": [
          "n",
          "mediana",
          "p25",
          "p75",
          "menor",
          "maior",
          "media",
          "desconto_mediano",
          "com_referencia",
          "me_epp",
          "valor_total",
          "fornecedores",
          "compradores",
          "ultima_homologacao"
        ],
        "description": "O preço que ganha: distribuição dos valores unitários homologados de todos os candidatos."
      },
      "PrecosPorUf": {
        "type": "object",
        "properties": {
          "uf": {
            "type": "string",
            "description": "Sigla da UF do órgão comprador."
          },
          "n": {
            "type": "integer",
            "description": "Resultados na UF."
          },
          "mediana": {
            "type": "number",
            "description": "Mediana dos valores unitários na UF.",
            "nullable": true
          },
          "menor": {
            "type": "number",
            "description": "Menor valor unitário na UF.",
            "nullable": true
          },
          "maior": {
            "type": "number",
            "description": "Maior valor unitário na UF.",
            "nullable": true
          },
          "fornecedores": {
            "type": "integer",
            "description": "Fornecedores distintos na UF."
          },
          "compradores": {
            "type": "integer",
            "description": "Órgãos distintos na UF."
          },
          "ultima_homologacao": {
            "type": "string",
            "description": "Resultado mais recente na UF, `AAAA-MM-DD`.",
            "nullable": true
          }
        },
        "required": [
          "uf",
          "n",
          "mediana",
          "menor",
          "maior",
          "fornecedores",
          "compradores",
          "ultima_homologacao"
        ]
      },
      "PrecosPorMes": {
        "type": "object",
        "properties": {
          "mes": {
            "type": "string",
            "description": "`AAAA-MM` da homologação."
          },
          "n": {
            "type": "integer",
            "description": "Resultados no mês; `0` quando não houve."
          },
          "mediana": {
            "type": "number",
            "description": "Mediana dos valores unitários no mês.",
            "nullable": true
          },
          "menor": {
            "type": "number",
            "description": "Menor valor unitário no mês.",
            "nullable": true
          },
          "maior": {
            "type": "number",
            "description": "Maior valor unitário no mês.",
            "nullable": true
          }
        },
        "required": [
          "mes",
          "n",
          "mediana",
          "menor",
          "maior"
        ]
      },
      "PrecoVencedor": {
        "type": "object",
        "properties": {
          "fornecedor_cnpj": {
            "type": "string",
            "description": "CNPJ, só dígitos; nulo para pessoa física (CPF não é publicado).",
            "nullable": true
          },
          "pessoa_fisica": {
            "type": "boolean",
            "description": "`true` quando o vencedor é pessoa física."
          },
          "fornecedor": {
            "type": "string",
            "description": "Razão social ou nome, como publicado.",
            "nullable": true
          },
          "porte": {
            "type": "string",
            "description": "Porte declarado (ME, EPP, Demais).",
            "nullable": true
          },
          "itens": {
            "type": "integer",
            "description": "Itens homologados para este fornecedor."
          },
          "valor_total": {
            "type": "number",
            "description": "Soma dos valores totais homologados, em reais.",
            "nullable": true
          },
          "menor": {
            "type": "number",
            "description": "Menor valor unitário que este fornecedor levou.",
            "nullable": true
          },
          "maior": {
            "type": "number",
            "description": "Maior valor unitário que este fornecedor levou.",
            "nullable": true
          },
          "compradores": {
            "type": "integer",
            "description": "Órgãos distintos que compraram dele."
          },
          "ultima_homologacao": {
            "type": "string",
            "description": "Última vitória, `AAAA-MM-DD`.",
            "nullable": true
          }
        },
        "required": [
          "fornecedor_cnpj",
          "pessoa_fisica",
          "fornecedor",
          "porte",
          "itens",
          "valor_total",
          "menor",
          "maior",
          "compradores",
          "ultima_homologacao"
        ],
        "description": "Quem ganha este item: um fornecedor, com o que venceu no período."
      },
      "PrecoComprador": {
        "type": "object",
        "properties": {
          "orgao_cnpj": {
            "type": "string",
            "description": "CNPJ do órgão, só dígitos.",
            "nullable": true
          },
          "orgao": {
            "type": "string",
            "description": "Órgão comprador.",
            "nullable": true
          },
          "uf": {
            "type": "string",
            "description": "UF do órgão.",
            "nullable": true
          },
          "itens": {
            "type": "integer",
            "description": "Itens homologados por este órgão."
          },
          "compras": {
            "type": "integer",
            "description": "Compras distintas (processos) em que o item foi homologado."
          },
          "valor_total": {
            "type": "number",
            "description": "Soma dos valores totais homologados, em reais.",
            "nullable": true
          },
          "fornecedores": {
            "type": "integer",
            "description": "Fornecedores distintos que venderam a ele."
          },
          "ultima_homologacao": {
            "type": "string",
            "description": "Última compra homologada, `AAAA-MM-DD`.",
            "nullable": true
          }
        },
        "required": [
          "orgao_cnpj",
          "orgao",
          "uf",
          "itens",
          "compras",
          "valor_total",
          "fornecedores",
          "ultima_homologacao"
        ],
        "description": "Quem compra este item: um órgão, com quantas vezes e quando comprou."
      },
      "PrecosAmostra": {
        "type": "object",
        "properties": {
          "candidatos": {
            "type": "integer",
            "description": "Itens que o FULLTEXT achou para o termo (antes do período, UF e catálogo)."
          },
          "limitada": {
            "type": "boolean",
            "description": "`true` quando os candidatos bateram no teto de 2.000: há mais itens parecidos do que o resumo viu."
          },
          "criterio": {
            "type": "string",
            "description": "Como os candidatos foram escolhidos."
          },
          "desde": {
            "type": "string",
            "description": "Primeira homologação considerada, `AAAA-MM-DD`."
          },
          "ate": {
            "type": "string",
            "description": "Última homologação encontrada, `AAAA-MM-DD`.",
            "nullable": true
          }
        },
        "required": [
          "candidatos",
          "limitada",
          "criterio",
          "desde",
          "ate"
        ]
      },
      "PrecoHomologado": {
        "type": "object",
        "properties": {
          "compra_id": {
            "type": "integer",
            "description": "Compra no acervo — abre a ficha em `compra_url`."
          },
          "item": {
            "type": "integer",
            "description": "Número do item dentro da compra."
          },
          "resultado": {
            "type": "integer",
            "description": "Sequencial do resultado (mais de um vencedor em registro de preços)."
          },
          "pncp": {
            "type": "string",
            "description": "Número de controle PNCP da compra.",
            "nullable": true
          },
          "referencia": {
            "type": "string",
            "description": "`PNCP <controle> · item <n>`, pronto para citar na memória de cálculo."
          },
          "descricao": {
            "type": "string",
            "description": "Descrição do item, como publicada.",
            "nullable": true
          },
          "unidade": {
            "type": "string",
            "description": "Unidade de medida do item.",
            "nullable": true
          },
          "catmat": {
            "type": "string",
            "description": "Código do item no catálogo do governo (CATMAT/CATSER).",
            "nullable": true
          },
          "material_ou_servico": {
            "type": "string",
            "description": "`M` material ou `S` serviço.",
            "nullable": true
          },
          "valor_unitario": {
            "type": "number",
            "description": "Valor unitário homologado, em reais."
          },
          "valor_unitario_estimado": {
            "type": "number",
            "description": "Valor unitário estimado pelo órgão antes da disputa.",
            "nullable": true
          },
          "quantidade_homologada": {
            "type": "number",
            "description": "Quantidade adjudicada ao fornecedor vencedor, na unidade do item.",
            "nullable": true
          },
          "fornecedor": {
            "type": "string",
            "description": "Razão social do fornecedor vencedor.",
            "nullable": true
          },
          "fornecedor_cnpj": {
            "type": "string",
            "description": "CNPJ do fornecedor, só dígitos; nulo para pessoa física (CPF não é publicado).",
            "nullable": true
          },
          "pessoa_fisica": {
            "type": "boolean",
            "description": "`true` quando o vencedor é pessoa física."
          },
          "fornecedor_porte": {
            "type": "string",
            "description": "Porte do fornecedor (ME, EPP, demais).",
            "nullable": true
          },
          "orgao": {
            "type": "string",
            "description": "Órgão comprador.",
            "nullable": true
          },
          "orgao_cnpj": {
            "type": "string",
            "description": "CNPJ do órgão, só dígitos.",
            "nullable": true
          },
          "municipio": {
            "type": "string",
            "description": "Município da unidade compradora.",
            "nullable": true
          },
          "uf": {
            "type": "string",
            "description": "UF do órgão.",
            "nullable": true
          },
          "modalidade": {
            "type": "string",
            "description": "Modalidade da compra.",
            "nullable": true
          },
          "homologado_em": {
            "type": "string",
            "description": "Data do resultado, `AAAA-MM-DD`.",
            "nullable": true
          },
          "publicado_em": {
            "type": "string",
            "description": "Data de publicação da compra no PNCP, `AAAA-MM-DD`.",
            "nullable": true
          },
          "compra_url": {
            "type": "string",
            "description": "Ficha pública da compra."
          }
        },
        "required": [
          "compra_id",
          "item",
          "resultado",
          "pncp",
          "referencia",
          "descricao",
          "unidade",
          "catmat",
          "material_ou_servico",
          "valor_unitario",
          "valor_unitario_estimado",
          "quantidade_homologada",
          "fornecedor",
          "fornecedor_cnpj",
          "pessoa_fisica",
          "fornecedor_porte",
          "orgao",
          "orgao_cnpj",
          "municipio",
          "uf",
          "modalidade",
          "homologado_em",
          "publicado_em",
          "compra_url"
        ],
        "description": "Um item homologado de uma compra pública: valor, fornecedor e órgão comprador."
      },
      "FiltrosInteresse": {
        "type": "object",
        "properties": {
          "modalidades": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Até 10 modalidades do PNCP, IDs 1 a 13."
          },
          "municipios": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Até 10 nomes exatos ou códigos IBGE; use UF para distinguir homônimos."
          },
          "excluir": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Até 10 expressões literais de 3 a 80 caracteres a excluir do objeto."
          },
          "valor_min": {
            "type": "number",
            "description": "Valor estimado mínimo em reais.",
            "nullable": true
          },
          "valor_max": {
            "type": "number",
            "description": "Valor estimado máximo em reais.",
            "nullable": true
          },
          "abertas": {
            "type": "boolean",
            "description": "Exige prazo de propostas ainda aberto ao coletar."
          }
        },
        "required": [
          "modalidades",
          "municipios",
          "excluir",
          "valor_min",
          "valor_max",
          "abertas"
        ],
        "description": "Filtros combinados por E. Listas vazias e valores nulos deixam o campo livre."
      },
      "CompraSalva": {
        "type": "object",
        "properties": {
          "compra_id": {
            "type": "integer",
            "description": "ID da compra."
          },
          "compra": {
            "type": "object",
            "description": "Retrato: id, objeto, UF, município, órgão, modalidade e valor estimado."
          },
          "salvo_em": {
            "type": "string",
            "description": "Data ISO de inclusão."
          },
          "url": {
            "type": "string",
            "description": "Ficha pública no acervo."
          }
        },
        "required": [
          "compra_id",
          "compra",
          "salvo_em",
          "url"
        ],
        "description": "Licitação da lista pessoal, acessível com o código de acesso do dono."
      },
      "Alerta": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador do alerta."
          },
          "termos": {
            "type": "string",
            "description": "Palavras do objeto que o alerta procura (`|` = qualquer uma do grupo)."
          },
          "origem": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OrigemCnae"
              }
            ],
            "description": "De onde veio um alerta criado por CNPJ; nulo no alerta por termos.",
            "nullable": true
          },
          "uf": {
            "type": "string",
            "description": "UF restrita, ou nulo para o Brasil.",
            "nullable": true
          },
          "filtros": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FiltrosInteresse"
              }
            ],
            "description": "Recorte adicional do interesse."
          },
          "canal": {
            "type": "string",
            "description": "`pull`, `webhook` ou `email`."
          },
          "destino": {
            "type": "string",
            "description": "URL do webhook; nulo no pull e no e-mail, que vai para o e-mail verificado da conta, lido nela a cada envio (alertas antigos mostram o endereço da época, mascarado).",
            "nullable": true
          },
          "ativo": {
            "type": "boolean",
            "description": "Se o cron ainda confere este alerta."
          },
          "pago_ate": {
            "type": "string",
            "description": "Fim da validade paga; nulo na franquia.",
            "nullable": true
          },
          "ultimo_check": {
            "type": "string",
            "description": "Última rodada; não significa que todo o backlog foi entregue.",
            "nullable": true
          },
          "falhas_seguidas": {
            "type": "integer",
            "description": "Entregas seguidas que falharam; em 10 o alerta pausa."
          },
          "criado_em": {
            "type": "string",
            "description": "Criação em ISO 8601."
          },
          "alerta_url": {
            "type": "string",
            "description": "URL deste alerta."
          },
          "compras_url": {
            "type": "string",
            "description": "Onde ler as compras casadas (pull)."
          }
        },
        "required": [
          "id",
          "termos",
          "origem",
          "uf",
          "filtros",
          "canal",
          "destino",
          "ativo",
          "pago_ate",
          "ultimo_check",
          "falhas_seguidas",
          "criado_em",
          "alerta_url",
          "compras_url"
        ],
        "description": "Um alerta de compra nova: termos, UF, filtros e canal de entrega."
      },
      "OrigemCnae": {
        "type": "object",
        "properties": {
          "cnpj": {
            "type": "string",
            "description": "CNPJ da empresa, 14 dígitos."
          },
          "familia": {
            "type": "string",
            "description": "Identificador da família de termos no dicionário."
          },
          "cnae": {
            "type": "string",
            "description": "O primeiro CNAE da empresa que acionou a família, 7 dígitos."
          },
          "descricao": {
            "type": "string",
            "description": "Descrição oficial (IBGE) desse CNAE.",
            "nullable": true
          },
          "cnaes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Todos os CNAEs da empresa que caem nesta família."
          }
        },
        "required": [
          "cnpj",
          "familia",
          "cnae",
          "descricao",
          "cnaes"
        ],
        "description": "A empresa e a atividade (CNAE) que geraram um alerta por CNPJ."
      },
      "Empresa": {
        "type": "object",
        "properties": {
          "cnpj": {
            "type": "string",
            "description": "14 dígitos."
          },
          "cnpj_formatado": {
            "type": "string",
            "description": "Com pontuação, para gente."
          },
          "razao_social": {
            "type": "string",
            "description": "Razão social na Receita.",
            "nullable": true
          },
          "nome_fantasia": {
            "type": "string",
            "description": "O nome comercial, quando difere da razão social.",
            "nullable": true
          },
          "situacao": {
            "type": "string",
            "description": "Situação cadastral (Ativa, Baixada…).",
            "nullable": true
          },
          "uf": {
            "type": "string",
            "description": "UF da sede.",
            "nullable": true
          },
          "municipio": {
            "type": "string",
            "description": "Município da sede.",
            "nullable": true
          },
          "cnaes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CnaeDaEmpresa"
            },
            "description": "Principal primeiro, depois os secundários."
          }
        },
        "required": [
          "cnpj",
          "cnpj_formatado",
          "razao_social",
          "nome_fantasia",
          "situacao",
          "uf",
          "municipio",
          "cnaes"
        ],
        "description": "A ficha resumida da empresa consultada pelo CNPJ, com a leitura do dicionário para cada CNAE."
      },
      "CnaeDaEmpresa": {
        "type": "object",
        "properties": {
          "codigo": {
            "type": "string",
            "description": "7 dígitos."
          },
          "cnae": {
            "type": "string",
            "description": "Formatado como o IBGE escreve, ex. `1412-6/01`."
          },
          "descricao": {
            "type": "string",
            "description": "Descrição oficial.",
            "nullable": true
          },
          "principal": {
            "type": "boolean",
            "description": "Se é o CNAE principal da empresa."
          },
          "familia": {
            "type": "string",
            "description": "Família de termos que este CNAE aciona; nulo fora do dicionário.",
            "nullable": true
          },
          "termos": {
            "type": "string",
            "description": "Os termos dessa família; nulo fora do dicionário.",
            "nullable": true
          }
        },
        "required": [
          "codigo",
          "cnae",
          "descricao",
          "principal",
          "familia",
          "termos"
        ],
        "description": "Um CNAE da empresa e o que o dicionário faz com ele."
      },
      "FamiliaNaoCriada": {
        "type": "object",
        "properties": {
          "familia": {
            "type": "string",
            "description": "Identificador da família."
          },
          "nome": {
            "type": "string",
            "description": "Nome da família."
          },
          "termos": {
            "type": "string",
            "description": "Os termos que o alerta teria."
          },
          "cnaes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "CNAEs da empresa que caem nela."
          },
          "motivo": {
            "type": "string",
            "description": "`acima_de_max_familias`."
          }
        },
        "required": [
          "familia",
          "nome",
          "termos",
          "cnaes",
          "motivo"
        ],
        "description": "Uma família da empresa que não virou alerta neste pedido."
      },
      "AlertaCompra": {
        "type": "object",
        "properties": {
          "compra_id": {
            "type": "integer",
            "description": "Identificador da compra no acervo."
          },
          "status": {
            "type": "string",
            "description": "`pull`, `webhook:ok`, `webhook:falhou`, `email:ok`, `email:falhou`, `email:recusado` (a SES recusou em definitivo; não é tentado de novo), `email:sem_conta` (convidado ou conta sem e-mail), `email:nao_confirmado` (anterior a 21/09/2026), `email:teto_do_dia` ou `pendente`."
          },
          "visto_em": {
            "type": "string",
            "description": "Quando o cron viu a compra."
          },
          "compra": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Compra"
              }
            ],
            "description": "A compra como estava quando casou, com prazos.",
            "nullable": true
          }
        },
        "required": [
          "compra_id",
          "status",
          "visto_em",
          "compra"
        ],
        "description": "Uma compra que casou com o alerta e o que aconteceu com a entrega."
      },
      "Vigia": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador da vigia."
          },
          "compra_id": {
            "type": "integer",
            "description": "Compra vigiada no acervo."
          },
          "canal": {
            "type": "string",
            "description": "`pull`, `webhook` ou `email`."
          },
          "destino": {
            "type": "string",
            "description": "URL do webhook; nulo no pull e no e-mail.",
            "nullable": true
          },
          "ativo": {
            "type": "boolean",
            "description": "Se o cron ainda reconfere; encerra 30 dias após o fim das propostas."
          },
          "pago_ate": {
            "type": "string",
            "description": "Fim da validade paga; nulo na franquia.",
            "nullable": true
          },
          "ultimo_check": {
            "type": "string",
            "description": "Última reconferência.",
            "nullable": true
          },
          "criado_em": {
            "type": "string",
            "description": "Criação em ISO 8601."
          },
          "vigia_url": {
            "type": "string",
            "description": "URL desta vigia."
          },
          "eventos_url": {
            "type": "string",
            "description": "Onde ler os eventos (pull)."
          },
          "compra_url": {
            "type": "string",
            "description": "Ficha da compra."
          }
        },
        "required": [
          "id",
          "compra_id",
          "canal",
          "destino",
          "ativo",
          "pago_ate",
          "ultimo_check",
          "criado_em",
          "vigia_url",
          "eventos_url",
          "compra_url"
        ],
        "description": "Uma compra vigiada: canal de aviso, validade e o cursor do cron."
      },
      "Snapshot": {
        "type": "object",
        "properties": {
          "situacao_id": {
            "type": "integer",
            "description": "Situação: 1 divulgada, 2 revogada, 3 anulada, 4 suspensa.",
            "nullable": true
          },
          "situacao": {
            "type": "string",
            "description": "Situação por extenso.",
            "nullable": true
          },
          "encerramento_proposta": {
            "type": "string",
            "description": "Fim das propostas visto na fotografia.",
            "nullable": true
          },
          "valor_estimado": {
            "type": "number",
            "description": "Valor estimado visto na fotografia.",
            "nullable": true
          },
          "atualizado_em": {
            "type": "string",
            "description": "Última atualização conhecida da compra.",
            "nullable": true
          },
          "documentos": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Documentos por sequencial do PNCP: `sequencial`, `id`, `titulo`, `tipo`."
          }
        },
        "required": [
          "situacao_id",
          "situacao",
          "encerramento_proposta",
          "valor_estimado",
          "atualizado_em",
          "documentos"
        ],
        "description": "A fotografia da compra que a vigia compara."
      },
      "Evento": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador do evento."
          },
          "tipo": {
            "type": "string",
            "description": "`situacao`, `prazo_adiado`, `valor`, `documento_novo`, `documento_removido`, `prazo_impugnacao` ou `prazo_proposta`."
          },
          "antes": {
            "type": "string",
            "description": "Valor anterior; nulo em documento novo e nos avisos de prazo.",
            "nullable": true
          },
          "depois": {
            "type": "string",
            "description": "Valor novo; nulo em documento removido.",
            "nullable": true
          },
          "visto_em": {
            "type": "string",
            "description": "Quando o cron viu."
          },
          "entregue_em": {
            "type": "string",
            "description": "Quando o aviso saiu por webhook ou e-mail; nulo no pull ou em falha.",
            "nullable": true
          }
        },
        "required": [
          "id",
          "tipo",
          "antes",
          "depois",
          "visto_em",
          "entregue_em"
        ],
        "description": "Uma mudança vista na compra vigiada, ou um aviso de prazo."
      },
      "Metricas": {
        "type": "object",
        "properties": {
          "app": {
            "type": "string",
            "description": "Nome do produto."
          },
          "today": {
            "type": "string",
            "description": "Dia de referência (UTC, AAAA-MM-DD)."
          },
          "today_visits": {
            "type": "integer",
            "description": "Visitas contadas hoje pela interface."
          },
          "today_contacts": {
            "type": "integer",
            "description": "Mensagens de contato hoje — este produto não tem formulário, fica em zero. Só com `METRICS_TOKEN`: contato não sai sem token."
          },
          "days": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Um registro por dia da janela, com as contagens de cada métrica."
          },
          "usage": {
            "type": "object",
            "description": "Uso por recurso: `markdown` (entregas), `alertas` e `vigias` criados, por dia."
          },
          "accounts": {
            "type": "object",
            "description": "Vazio: pessoas e convidados moram na conta global, não no produto."
          },
          "financeiro": {
            "type": "object",
            "description": "Agregado do dia: `hoje_usd`, `hoje_count`, `rede`. Só com `METRICS_TOKEN`: dinheiro não sai sem token; a série completa é `payments`."
          },
          "payments": {
            "type": "object",
            "description": "Resumo financeiro do x402; só com METRICS_TOKEN."
          }
        },
        "required": [
          "app",
          "today",
          "today_visits",
          "days",
          "usage",
          "accounts"
        ],
        "description": "Painel de 7 dias do operador. `payments` só aparece com o token e só em Base mainnet."
      },
      "Recibo": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador do recibo (32 hex)."
          },
          "recurso": {
            "type": "string",
            "description": "Recurso entregue, ex.: `documento/123/markdown`."
          },
          "documento_id": {
            "type": "integer",
            "description": "Documento entregue.",
            "nullable": true
          },
          "preco_usd": {
            "type": "string",
            "description": "Preço cobrado — `$0.00` em amostra."
          },
          "modo": {
            "type": "string",
            "description": "`gratuito`, `homolog` ou `onchain`."
          },
          "sha256_entregue": {
            "type": "string",
            "description": "SHA-256 do markdown entregue, ou `nao_entregue`."
          },
          "bytes": {
            "type": "integer",
            "description": "Tamanho do que foi entregue."
          },
          "criado_em": {
            "type": "string",
            "description": "Instante da entrega em ISO 8601."
          }
        },
        "required": [
          "id",
          "recurso",
          "documento_id",
          "preco_usd",
          "modo",
          "sha256_entregue",
          "bytes",
          "criado_em"
        ],
        "description": "Prova da entrega: o que foi pago, quanto, como e o hash do que saiu."
      },
      "ApiAccess": {
        "type": "object",
        "properties": {
          "offer": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ApiAccessOffer"
              }
            ],
            "description": "Current offer and payment instructions."
          },
          "enabled": {
            "type": "boolean",
            "description": "Present in public discovery; false means no purchases."
          },
          "id": {
            "type": "string",
            "description": "Purchase ID; not a credential."
          },
          "status": {
            "type": "string",
            "description": "paid, unpaid or pending."
          },
          "granted_credits": {
            "type": "integer",
            "description": "Original grant, not remaining usage."
          },
          "expires_at": {
            "type": "string",
            "description": "ISO expiry, 30 days after purchase.",
            "nullable": true
          },
          "receipt": {
            "type": "string",
            "description": "Confirmed payment receipt.",
            "nullable": true
          },
          "via": {
            "type": "string",
            "description": "x402, credito or gated homolog.",
            "nullable": true
          },
          "message": {
            "type": "string",
            "description": "Next action in the requested language."
          }
        },
        "required": [
          "offer"
        ]
      },
      "ApiAccessOffer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Package identifier."
          },
          "price_usd": {
            "type": "number",
            "description": "Price in USD."
          },
          "credits": {
            "type": "integer",
            "description": "Basic reads included."
          },
          "days": {
            "type": "integer",
            "description": "Validity after payment, in days."
          },
          "auto_renew": {
            "type": "boolean",
            "description": "False: the client explicitly buys another package."
          },
          "unit": {
            "type": "string",
            "description": "basic_data_read; one page of up to 20 metadata records."
          },
          "products": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Data indexes sharing the same package."
          },
          "purchase": {
            "type": "string",
            "description": "Absolute purchase URL."
          },
          "method": {
            "type": "string",
            "description": "HTTP method for the explicit package purchase: POST."
          },
          "status": {
            "type": "string",
            "description": "GET with X-API-Pass checks the private purchase status."
          },
          "header": {
            "type": "string",
            "description": "X-API-Pass."
          },
          "payment_methods": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "x402 or prepaid_credit."
          },
          "instructions": {
            "type": "string",
            "description": "Generate and retain the pass before payment."
          },
          "generate_pass": {
            "type": "string",
            "description": "JavaScript example using cryptographic randomness."
          },
          "client": {
            "type": "string",
            "description": "Auditable ES module client; orchestrates purchase and data retry with caller-owned wallet and durable state.",
            "nullable": true
          },
          "guide": {
            "type": "string",
            "description": "Client setup, explicit budget, recovery and data value.",
            "nullable": true
          },
          "workflow": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ApiAccessWorkflow"
              }
            ],
            "description": "Machine-readable purchase and recovery contract."
          },
          "evaluation": {
            "type": "object",
            "description": "Free evaluation: register URL, X-Agent-Pass header, 1,000 reads per product, 30 days, no renewal. Registration grants independent quotas on the three indexes; preserve the credential.",
            "nullable": true
          }
        },
        "required": [
          "id",
          "price_usd",
          "credits",
          "days",
          "auto_renew",
          "unit",
          "products",
          "purchase",
          "method",
          "status",
          "header",
          "payment_methods",
          "instructions",
          "generate_pass",
          "client",
          "guide",
          "workflow",
          "evaluation"
        ]
      },
      "ApiAccessWorkflow": {
        "type": "object",
        "properties": {
          "version": {
            "type": "integer",
            "description": "Workflow version."
          },
          "kind": {
            "type": "string",
            "description": "package_then_retry: buy at purchase, then retry the original data URL."
          },
          "purchase_requires_authority": {
            "type": "boolean",
            "description": "The client needs an explicit spending budget."
          },
          "retry_same_pass": {
            "type": "boolean",
            "description": "Persist the pass and original signed proof before submitting."
          },
          "on_unknown_payment": {
            "type": "string",
            "description": "Query the purchase or reconcile the original proof; never sign again automatically."
          }
        },
        "required": [
          "version",
          "kind",
          "purchase_requires_authority",
          "retry_same_pass",
          "on_unknown_payment"
        ]
      },
      "PaymentQuota": {
        "type": "object",
        "properties": {
          "free": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentFree"
            },
            "description": "Free allowances and their windows."
          },
          "paid": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentPrice"
            },
            "description": "List prices in USD. The operation's 402 is the payable quote."
          },
          "how_to_pay": {
            "type": "string",
            "description": "Payment instructions and availability restrictions."
          },
          "live": {
            "type": "string",
            "description": "Authoritative product quota endpoint.",
            "nullable": true
          },
          "free_now": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "SKUs temporarily free despite their list price."
          },
          "trial": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PaymentTrial"
              }
            ],
            "description": "Registration trial, when offered."
          }
        },
        "required": [
          "free",
          "paid",
          "how_to_pay",
          "live"
        ]
      },
      "PaymentFree": {
        "type": "object",
        "properties": {
          "o_que": {
            "type": "string",
            "description": "Operation or allowance."
          },
          "limite": {
            "type": "string",
            "description": "Allowance and eligibility."
          },
          "janela": {
            "type": "string",
            "description": "Reset window, when applicable.",
            "nullable": true
          }
        },
        "required": [
          "o_que",
          "limite",
          "janela"
        ]
      },
      "PaymentPrice": {
        "type": "object",
        "properties": {
          "o_que": {
            "type": "string",
            "description": "Operation and billing unit."
          },
          "price_usd": {
            "type": "number",
            "description": "Current list price in USD."
          }
        },
        "required": [
          "o_que",
          "price_usd"
        ]
      },
      "PaymentTrial": {
        "type": "object",
        "properties": {
          "days": {
            "type": "integer",
            "description": "Trial duration in days."
          },
          "how": {
            "type": "string",
            "description": "Eligibility and activation steps."
          }
        },
        "required": [
          "days",
          "how"
        ]
      },
      "PaymentX402": {
        "type": "object",
        "properties": {
          "provider": {
            "type": "string",
            "description": "Always `x402` — the only billing protocol accepted."
          },
          "mode": {
            "type": "string",
            "description": "Seller mode: `live` charges for real, `dev` lets calls through unpaid."
          },
          "network": {
            "type": "string",
            "description": "USDC network: `base` in production, `base-sepolia` in staging."
          },
          "chain_id": {
            "type": "integer",
            "description": "EVM chain ID of the network above, so the wallet signs on the right chain."
          },
          "pay_to": {
            "type": "string",
            "description": "Address that receives the payment.",
            "nullable": true
          },
          "homolog": {
            "type": "boolean",
            "description": "Staging seam on: the loop can be closed without spending USDC."
          },
          "dev": {
            "type": "boolean",
            "description": "Development mode: the 402 is simulated."
          },
          "dev_gate": {
            "type": "boolean",
            "description": "A homologation credential is configured; this grants no access."
          },
          "gratis": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Temporarily free SKUs."
          },
          "facilitator": {
            "type": "string",
            "description": "URL of the facilitator that verifies and settles the payment."
          },
          "asset": {
            "type": "string",
            "description": "Accepted currency — always `USDC`."
          },
          "asset_address": {
            "type": "string",
            "description": "USDC contract on the network above."
          },
          "faucet": {
            "type": "string",
            "description": "Test-USDC faucet; only on base-sepolia.",
            "nullable": true
          },
          "wallets": {
            "type": "object",
            "description": "Links to wallets that speak x402 (metamask, coinbase, base_app)."
          }
        },
        "required": [
          "provider",
          "mode",
          "network",
          "chain_id",
          "pay_to",
          "homolog",
          "dev",
          "dev_gate",
          "facilitator",
          "asset",
          "asset_address",
          "faucet",
          "wallets"
        ],
        "description": "x402 payment configuration in force. Comes from `planPublic` and is the same across the products."
      },
      "PaymentCredit": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "POST to purchase credit; GET with X-Credito to inspect its balance."
          },
          "header": {
            "type": "string",
            "description": "Header for a previously issued credit token: X-Credito."
          }
        },
        "required": [
          "url",
          "header"
        ]
      }
    },
    "securitySchemes": {
      "globalAccount": {
        "type": "apiKey",
        "in": "cookie",
        "name": "__Host-mm-auth",
        "description": "Global session in the product's HttpOnly cookie; writes require exact Origin and X-CSRF-Token."
      },
      "contaChaveApi": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "mmk_…",
        "description": "Account API key: `Authorization: Bearer mmk_…` or `X-Api-Key: mmk_…`. Created on the account page (API keys), valid only in the product where it was created; it acts as the account (or the organization that owns it)."
      }
    }
  },
  "paths": {
    "/api/avaliacao": {
      "get": {
        "operationId": "get_api_avaliacao",
        "summary": "Cotas documentais deste agente: um premium patrocinado e 100 leituras básicas.",
        "description": "Devolve: { expires_at, premium, basic }",
        "parameters": [
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual persistente obtida em POST https://api.editalmd.com/licitacoes/api/agente. Não é User-Agent."
          }
        ],
        "responses": {
          "200": {
            "description": "{ expires_at, premium, basic }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "expires_at": {
                      "type": "string",
                      "description": "Fim da concessão individual, limitado pelo piloto."
                    },
                    "premium": {
                      "type": "object",
                      "description": "granted:1, used, document_id e max_pages:50."
                    },
                    "basic": {
                      "type": "object",
                      "description": "granted:100, used, max_pages:50 e reviewed:false."
                    }
                  },
                  "required": [
                    "expires_at",
                    "premium",
                    "basic"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Campos ou consulta desconhecidos; POST aceita corpo ausente ou {}."
          },
          "401": {
            "description": "Credencial de agente ausente ou inválida."
          },
          "402": {
            "description": "Cota individual usada ou expirada; veja purchase_url para comprar."
          },
          "404": {
            "description": "Documento ou solicitação deste agente inexistente."
          },
          "409": {
            "description": "Fonte ou cotação indisponível/alterada; nenhuma cobrança."
          },
          "422": {
            "description": "Premium até 50 páginas; básico PDF até 50 páginas e 32 MiB."
          },
          "503": {
            "description": "Piloto encerrado, orçamento esgotado ou fila sem capacidade; preserve a credencial e tente depois."
          }
        }
      }
    },
    "/api/documento/{id}/avaliacao/premium": {
      "post": {
        "operationId": "post_api_documento_by_id_avaliacao_premium",
        "summary": "Concede um documento premium por agente; gera se necessário, sem cobrar o agente.",
        "description": "Franquia por credencial, até a menor data entre os 30 dias do agente e o fim do piloto. Repetição do mesmo documento não consome outra unidade. Não envie pagamento. Premium: guarde evaluation.access_code e use X-Editalmd-Avaliacao junto de X-Agent-Pass nas leituras e no GET /geracao. Básico não abre conteúdo premium. Piloto sujeito ao orçamento global; sem renovação automática.\nDevolve: { documento_id, status?, error?, retry_after_s?, evaluation, state_url?, result? }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID positivo do documento do acervo.",
            "example": "9927611"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual persistente obtida em POST https://api.editalmd.com/licitacoes/api/agente. Não é User-Agent."
          }
        ],
        "responses": {
          "200": {
            "description": "{ documento_id, status?, error?, retry_after_s?, evaluation, state_url?, result? }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "documento_id": {
                      "type": "integer",
                      "description": "Documento solicitado."
                    },
                    "status": {
                      "type": "string",
                      "description": "ready, pending, running ou failed; access_granted recupera a concessão premium, sem afirmar processamento concluído. Preparação premium também pode trazer error."
                    },
                    "error": {
                      "type": "string",
                      "description": "Causa da falha, quando houver.",
                      "nullable": true
                    },
                    "retry_after_s": {
                      "type": "integer",
                      "description": "Intervalo para o próximo GET."
                    },
                    "evaluation": {
                      "type": "object",
                      "description": "kind basic ou sponsored_premium. Premium inclui access_code privado, access_header e expires_at; cobrança zero."
                    },
                    "state_url": {
                      "type": "string",
                      "description": "GET de acompanhamento do premium, com os dois headers de avaliação."
                    },
                    "result": {
                      "type": "object",
                      "description": "Somente básico pronto: pages [{page,text}], page_count, ocr_page_count, source_sha256, reviewed:false, structured_tables:false e empty_pages."
                    }
                  },
                  "required": [
                    "documento_id",
                    "evaluation"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Campos ou consulta desconhecidos; POST aceita corpo ausente ou {}."
          },
          "401": {
            "description": "Credencial de agente ausente ou inválida."
          },
          "402": {
            "description": "Cota individual usada ou expirada; veja purchase_url para comprar."
          },
          "404": {
            "description": "Documento ou solicitação deste agente inexistente."
          },
          "409": {
            "description": "Fonte ou cotação indisponível/alterada; nenhuma cobrança."
          },
          "422": {
            "description": "Premium até 50 páginas; básico PDF até 50 páginas e 32 MiB."
          },
          "503": {
            "description": "Piloto encerrado, orçamento esgotado ou fila sem capacidade; preserve a credencial e tente depois."
          }
        }
      }
    },
    "/api/documento/{id}/avaliacao/basico": {
      "post": {
        "operationId": "post_api_documento_by_id_avaliacao_basico",
        "summary": "Enfileira uma leitura básica individual: texto nativo e OCR local, sem revisão.",
        "description": "Franquia por credencial, até a menor data entre os 30 dias do agente e o fim do piloto. Repetição do mesmo documento não consome outra unidade. Não envie pagamento. Premium: guarde evaluation.access_code e use X-Editalmd-Avaliacao junto de X-Agent-Pass nas leituras e no GET /geracao. Básico não abre conteúdo premium. Piloto sujeito ao orçamento global; sem renovação automática.\nDevolve: { documento_id, status?, error?, retry_after_s?, evaluation, state_url?, result? }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID positivo do documento do acervo.",
            "example": "9927611"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual persistente obtida em POST https://api.editalmd.com/licitacoes/api/agente. Não é User-Agent."
          }
        ],
        "responses": {
          "200": {
            "description": "{ documento_id, status?, error?, retry_after_s?, evaluation, state_url?, result? }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "documento_id": {
                      "type": "integer",
                      "description": "Documento solicitado."
                    },
                    "status": {
                      "type": "string",
                      "description": "ready, pending, running ou failed; access_granted recupera a concessão premium, sem afirmar processamento concluído. Preparação premium também pode trazer error."
                    },
                    "error": {
                      "type": "string",
                      "description": "Causa da falha, quando houver.",
                      "nullable": true
                    },
                    "retry_after_s": {
                      "type": "integer",
                      "description": "Intervalo para o próximo GET."
                    },
                    "evaluation": {
                      "type": "object",
                      "description": "kind basic ou sponsored_premium. Premium inclui access_code privado, access_header e expires_at; cobrança zero."
                    },
                    "state_url": {
                      "type": "string",
                      "description": "GET de acompanhamento do premium, com os dois headers de avaliação."
                    },
                    "result": {
                      "type": "object",
                      "description": "Somente básico pronto: pages [{page,text}], page_count, ocr_page_count, source_sha256, reviewed:false, structured_tables:false e empty_pages."
                    }
                  },
                  "required": [
                    "documento_id",
                    "evaluation"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Campos ou consulta desconhecidos; POST aceita corpo ausente ou {}."
          },
          "401": {
            "description": "Credencial de agente ausente ou inválida."
          },
          "402": {
            "description": "Cota individual usada ou expirada; veja purchase_url para comprar."
          },
          "404": {
            "description": "Documento ou solicitação deste agente inexistente."
          },
          "409": {
            "description": "Fonte ou cotação indisponível/alterada; nenhuma cobrança."
          },
          "422": {
            "description": "Premium até 50 páginas; básico PDF até 50 páginas e 32 MiB."
          },
          "503": {
            "description": "Piloto encerrado, orçamento esgotado ou fila sem capacidade; preserve a credencial e tente depois."
          }
        }
      },
      "get": {
        "operationId": "get_api_documento_by_id_avaliacao_basico",
        "summary": "Recupera estado e texto básico por página, somente para o agente que solicitou.",
        "description": "Franquia por credencial, até a menor data entre os 30 dias do agente e o fim do piloto. Repetição do mesmo documento não consome outra unidade. Não envie pagamento. Premium: guarde evaluation.access_code e use X-Editalmd-Avaliacao junto de X-Agent-Pass nas leituras e no GET /geracao. Básico não abre conteúdo premium. Piloto sujeito ao orçamento global; sem renovação automática.\nDevolve: { documento_id, status?, error?, retry_after_s?, evaluation, state_url?, result? }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID positivo do documento do acervo.",
            "example": "9927611"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual persistente obtida em POST https://api.editalmd.com/licitacoes/api/agente. Não é User-Agent."
          }
        ],
        "responses": {
          "200": {
            "description": "{ documento_id, status?, error?, retry_after_s?, evaluation, state_url?, result? }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "documento_id": {
                      "type": "integer",
                      "description": "Documento solicitado."
                    },
                    "status": {
                      "type": "string",
                      "description": "ready, pending, running ou failed; access_granted recupera a concessão premium, sem afirmar processamento concluído. Preparação premium também pode trazer error."
                    },
                    "error": {
                      "type": "string",
                      "description": "Causa da falha, quando houver.",
                      "nullable": true
                    },
                    "retry_after_s": {
                      "type": "integer",
                      "description": "Intervalo para o próximo GET."
                    },
                    "evaluation": {
                      "type": "object",
                      "description": "kind basic ou sponsored_premium. Premium inclui access_code privado, access_header e expires_at; cobrança zero."
                    },
                    "state_url": {
                      "type": "string",
                      "description": "GET de acompanhamento do premium, com os dois headers de avaliação."
                    },
                    "result": {
                      "type": "object",
                      "description": "Somente básico pronto: pages [{page,text}], page_count, ocr_page_count, source_sha256, reviewed:false, structured_tables:false e empty_pages."
                    }
                  },
                  "required": [
                    "documento_id",
                    "evaluation"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Campos ou consulta desconhecidos; POST aceita corpo ausente ou {}."
          },
          "401": {
            "description": "Credencial de agente ausente ou inválida."
          },
          "402": {
            "description": "Cota individual usada ou expirada; veja purchase_url para comprar."
          },
          "404": {
            "description": "Documento ou solicitação deste agente inexistente."
          },
          "409": {
            "description": "Fonte ou cotação indisponível/alterada; nenhuma cobrança."
          },
          "422": {
            "description": "Premium até 50 páginas; básico PDF até 50 páginas e 32 MiB."
          },
          "503": {
            "description": "Piloto encerrado, orçamento esgotado ou fila sem capacidade; preserve a credencial e tente depois."
          }
        }
      }
    },
    "/api/me/empresas/{cnpj}/documentos": {
      "get": {
        "operationId": "get_api_me_empresas_by_cnpj_documentos",
        "summary": "Lista os anexos privados da empresa; não inicia leitura ou análise.",
        "description": "Devolve: { itens[{id,nome,tipo,bytes,paginas,enviado_em}], revisao, limite, limite_bytes, limite_paginas }",
        "parameters": [
          {
            "name": "cnpj",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "CNPJ de 14 dígitos vinculado à conta.",
            "example": "00394460000141"
          }
        ],
        "responses": {
          "200": {
            "description": "{ itens[{id,nome,tipo,bytes,paginas,enviado_em}], revisao, limite, limite_bytes, limite_paginas }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentosEmpresa"
                }
              }
            }
          },
          "400": {
            "description": "Entrada inválida."
          },
          "401": {
            "description": "Sessão necessária."
          },
          "402": {
            "description": "Acesso ao edital necessário."
          },
          "403": {
            "description": "Origem recusada."
          },
          "404": {
            "description": "Empresa ou documento ausente na conta."
          },
          "409": {
            "description": "Fontes ou checkpoint indisponíveis."
          },
          "413": {
            "description": "Limite de documentos, páginas ou bytes."
          },
          "429": {
            "description": "Processamento em curso; tente depois."
          },
          "502": {
            "description": "Core indisponível."
          },
          "503": {
            "description": "Configuração ou orçamento de processamento indisponível."
          }
        }
      },
      "post": {
        "operationId": "post_api_me_empresas_by_cnpj_documentos",
        "summary": "Adiciona PDF de atestado, certidão ou outro comprovante à empresa.",
        "description": "201. JSON até 11.200.000 bytes; PDF até 8 MiB, 20 documentos/80 MiB/50 páginas por empresa. Arquivo idêntico é reaproveitado. A leitura automática acontece somente ao solicitar a análise.\nDevolve: { itens[{id,nome,tipo,bytes,paginas,enviado_em}], revisao, limite, limite_bytes, limite_paginas }",
        "parameters": [
          {
            "name": "cnpj",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "CNPJ de 14 dígitos vinculado à conta.",
            "example": "00394460000141"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "nome": {
                    "type": "string",
                    "description": "Nome até 160 caracteres."
                  },
                  "tipo": {
                    "type": "string",
                    "description": "atestado, certidao, licenca, contrato_social ou outro."
                  },
                  "arquivo_base64": {
                    "type": "string",
                    "description": "PDF em base64 canônico, sem prefixo data:. Prefira envio HTTP a partir do arquivo local."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ itens[{id,nome,tipo,bytes,paginas,enviado_em}], revisao, limite, limite_bytes, limite_paginas }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentosEmpresa"
                }
              }
            }
          },
          "400": {
            "description": "Entrada inválida."
          },
          "401": {
            "description": "Sessão necessária."
          },
          "402": {
            "description": "Acesso ao edital necessário."
          },
          "403": {
            "description": "Origem recusada."
          },
          "404": {
            "description": "Empresa ou documento ausente na conta."
          },
          "409": {
            "description": "Fontes ou checkpoint indisponíveis."
          },
          "413": {
            "description": "Limite de documentos, páginas ou bytes."
          },
          "429": {
            "description": "Processamento em curso; tente depois."
          },
          "502": {
            "description": "Core indisponível."
          },
          "503": {
            "description": "Configuração ou orçamento de processamento indisponível."
          }
        }
      }
    },
    "/api/me/empresas/{cnpj}/documentos/{arquivo}": {
      "get": {
        "operationId": "get_api_me_empresas_by_cnpj_documentos_by_arquivo",
        "summary": "Baixa o PDF privado, sem chamada de IA.",
        "description": "Devolve: PDF binário com Content-Disposition: attachment; use HTTP autenticado para baixar.",
        "parameters": [
          {
            "name": "cnpj",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "CNPJ de 14 dígitos vinculado à conta.",
            "example": "00394460000141"
          },
          {
            "name": "arquivo",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SHA-256 retornado no envio.",
            "example": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
          }
        ],
        "responses": {
          "200": {
            "description": "PDF binário com Content-Disposition: attachment; use HTTP autenticado para baixar."
          },
          "400": {
            "description": "Entrada inválida."
          },
          "401": {
            "description": "Sessão necessária."
          },
          "402": {
            "description": "Acesso ao edital necessário."
          },
          "403": {
            "description": "Origem recusada."
          },
          "404": {
            "description": "Empresa ou documento ausente na conta."
          },
          "409": {
            "description": "Fontes ou checkpoint indisponíveis."
          },
          "413": {
            "description": "Limite de documentos, páginas ou bytes."
          },
          "429": {
            "description": "Processamento em curso; tente depois."
          },
          "502": {
            "description": "Core indisponível."
          },
          "503": {
            "description": "Configuração ou orçamento de processamento indisponível."
          }
        }
      },
      "delete": {
        "operationId": "delete_api_me_empresas_by_cnpj_documentos_by_arquivo",
        "summary": "Remove o anexo desta empresa e invalida a análise que o utilizou.",
        "description": "Devolve: { itens[{id,nome,tipo,bytes,paginas,enviado_em}], revisao, limite, limite_bytes, limite_paginas }",
        "parameters": [
          {
            "name": "cnpj",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "CNPJ de 14 dígitos vinculado à conta.",
            "example": "00394460000141"
          },
          {
            "name": "arquivo",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SHA-256 do anexo.",
            "example": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
          }
        ],
        "responses": {
          "200": {
            "description": "{ itens[{id,nome,tipo,bytes,paginas,enviado_em}], revisao, limite, limite_bytes, limite_paginas }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentosEmpresa"
                }
              }
            }
          },
          "400": {
            "description": "Entrada inválida."
          },
          "401": {
            "description": "Sessão necessária."
          },
          "402": {
            "description": "Acesso ao edital necessário."
          },
          "403": {
            "description": "Origem recusada."
          },
          "404": {
            "description": "Empresa ou documento ausente na conta."
          },
          "409": {
            "description": "Fontes ou checkpoint indisponíveis."
          },
          "413": {
            "description": "Limite de documentos, páginas ou bytes."
          },
          "429": {
            "description": "Processamento em curso; tente depois."
          },
          "502": {
            "description": "Core indisponível."
          },
          "503": {
            "description": "Configuração ou orçamento de processamento indisponível."
          }
        }
      }
    },
    "/api/me/empresas/{cnpj}/analises/{id}": {
      "post": {
        "operationId": "post_api_me_empresas_by_cnpj_analises_by_id",
        "summary": "Inicia ou retoma comparação de requisitos, atestados e obrigações com a empresa.",
        "description": "202 após aceitar e preservar o pedido; 200 ao reaproveitar análise concluída. Usa perfil e anexos desta conta. Pedidos interrompidos podem ser retomados; falhas informam motivo e próxima ação. POST explícito retoma uma pausa. Até 2 mil fatos e 100 editais por empresa, sujeitos à capacidade e ao orçamento disponíveis. Não cobra nova compra nesta operação. Acompanhamento somente por GET. A análise oferece triagem com evidências, não decisão definitiva de habilitação nem consulta jurídica externa.\nDevolve: { analise }",
        "parameters": [
          {
            "name": "cnpj",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "CNPJ de 14 dígitos vinculado à conta.",
            "example": "00394460000141"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID do documento com dossiê pronto e acesso autorizado.",
            "example": 1993401
          },
          {
            "name": "v",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SHA-256 do Markdown aberto, 64 hex minúsculos."
          }
        ],
        "responses": {
          "200": {
            "description": "{ analise }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "analise": {
                      "type": "object",
                      "description": "Estado inicial: id, status, etapa, processados, total, CNPJ, hashes e datas."
                    }
                  },
                  "required": [
                    "analise"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Entrada inválida."
          },
          "401": {
            "description": "Sessão necessária."
          },
          "402": {
            "description": "Acesso ao edital necessário."
          },
          "403": {
            "description": "Origem recusada."
          },
          "404": {
            "description": "Empresa ou documento ausente na conta."
          },
          "409": {
            "description": "Fontes ou checkpoint indisponíveis."
          },
          "413": {
            "description": "Limite de documentos, páginas ou bytes."
          },
          "429": {
            "description": "Processamento em curso; tente depois."
          },
          "502": {
            "description": "Core indisponível."
          },
          "503": {
            "description": "Configuração ou orçamento de processamento indisponível."
          }
        }
      },
      "get": {
        "operationId": "get_api_me_empresas_by_cnpj_analises_by_id",
        "summary": "Consulta andamento ou resultados paginados; não inicia IA nem modifica a análise.",
        "description": "Pendências reúne precisa_comprovar (falta prova), divergente (evidência incompatível) e acompanhar (obrigação futura). Cadastro, anexos ou dossiê diferentes retornam outdated sem resultados atuais. A data de referência é conservada na retomada; dia anterior retorna data_atual=false. Os lotes validados continuam disponíveis durante falhas/processamento com parcial=true e processados/total; nunca representam conclusão das exigências ainda não comparadas. GET não executa a fila nem inicia IA.\nDevolve: { analise, itens, contagens?, tipos?, next }",
        "parameters": [
          {
            "name": "cnpj",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "CNPJ de 14 dígitos vinculado à conta.",
            "example": "00394460000141"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID do documento.",
            "example": 1993401
          },
          {
            "name": "v",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "SHA-256 do Markdown aberto, 64 hex minúsculos."
          },
          {
            "name": "grupo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "pendencias, atendidos ou nao_aplicavel; omitido retorna todos."
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "requirement, attestation ou obligation."
          },
          {
            "name": "after",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Último ID recebido; padrão 0."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "1 a 30; padrão 30."
          }
        ],
        "responses": {
          "200": {
            "description": "{ analise, itens, contagens?, tipos?, next }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnaliseParticipacao"
                }
              }
            }
          },
          "400": {
            "description": "Entrada inválida."
          },
          "401": {
            "description": "Sessão necessária."
          },
          "402": {
            "description": "Acesso ao edital necessário."
          },
          "403": {
            "description": "Origem recusada."
          },
          "404": {
            "description": "Empresa ou documento ausente na conta."
          },
          "409": {
            "description": "Fontes ou checkpoint indisponíveis."
          },
          "413": {
            "description": "Limite de documentos, páginas ou bytes."
          },
          "429": {
            "description": "Processamento em curso; tente depois."
          },
          "502": {
            "description": "Core indisponível."
          },
          "503": {
            "description": "Configuração ou orçamento de processamento indisponível."
          }
        }
      }
    },
    "/api/me/empresas": {
      "get": {
        "operationId": "get_api_me_empresas",
        "summary": "Lista as empresas importadas e a seleção privada da conta; GET não grava.",
        "description": "Devolve: { itens[{cnpj,razao_social,nome_fantasia,situacao,situacao_desde,porte,natureza_juridica,inicio_atividade,matriz_filial,capital_social,municipio,uf,cnaes,fonte,importado_em}], selecionada, limite }",
        "responses": {
          "200": {
            "description": "{ itens[{cnpj,razao_social,nome_fantasia,situacao,situacao_desde,porte,natureza_juridica,inicio_atividade,matriz_filial,capital_social,municipio,uf,cnaes,fonte,importado_em}], selecionada, limite }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmpresasConta"
                }
              }
            }
          },
          "400": {
            "description": "CNPJ ou busca inválida."
          },
          "401": {
            "description": "Sessão necessária."
          },
          "403": {
            "description": "Origem recusada."
          },
          "404": {
            "description": "Empresa ausente nesta conta ou na base."
          },
          "405": {
            "description": "Método não permitido."
          },
          "409": {
            "description": "Limite de 20 empresas."
          },
          "503": {
            "description": "Origem, conta ou orçamento indisponível."
          }
        }
      }
    },
    "/api/me/empresas/busca": {
      "get": {
        "operationId": "get_api_me_empresas_busca",
        "summary": "Busca até oito sugestões por razão social ou CNPJ completo; não cadastra.",
        "description": "Devolve: { itens[{cnpj,nome,municipio,uf,situacao}] }",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "CNPJ com ou sem pontuação ou razão social, de 3 a 120 caracteres."
          }
        ],
        "responses": {
          "200": {
            "description": "{ itens[{cnpj,nome,municipio,uf,situacao}] }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SugestaoEmpresa"
                      },
                      "description": "Até oito resultados; refine a busca quando necessário."
                    }
                  },
                  "required": [
                    "itens"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "CNPJ ou busca inválida."
          },
          "401": {
            "description": "Sessão necessária."
          },
          "403": {
            "description": "Origem recusada."
          },
          "404": {
            "description": "Empresa ausente nesta conta ou na base."
          },
          "405": {
            "description": "Método não permitido."
          },
          "409": {
            "description": "Limite de 20 empresas."
          },
          "503": {
            "description": "Origem, conta ou orçamento indisponível."
          }
        }
      }
    },
    "/api/me/empresas/{cnpj}": {
      "put": {
        "operationId": "put_api_me_empresas_by_cnpj",
        "summary": "Importa os dados cadastrais e vincula o CNPJ à conta.",
        "description": "201 ao criar, 200 na repetição sem nova consulta/escrita. Até 20 empresas. Importa os dados cadastrais disponíveis, sem sócios ou contatos; nenhuma análise é iniciada.\nDevolve: { itens[{cnpj,razao_social,nome_fantasia,situacao,situacao_desde,porte,natureza_juridica,inicio_atividade,matriz_filial,capital_social,municipio,uf,cnaes,fonte,importado_em}], selecionada, limite }",
        "parameters": [
          {
            "name": "cnpj",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "CNPJ completo, 14 dígitos com verificação válida.",
            "example": "00394460000141"
          }
        ],
        "responses": {
          "200": {
            "description": "{ itens[{cnpj,razao_social,nome_fantasia,situacao,situacao_desde,porte,natureza_juridica,inicio_atividade,matriz_filial,capital_social,municipio,uf,cnaes,fonte,importado_em}], selecionada, limite }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmpresasConta"
                }
              }
            }
          },
          "400": {
            "description": "CNPJ ou busca inválida."
          },
          "401": {
            "description": "Sessão necessária."
          },
          "403": {
            "description": "Origem recusada."
          },
          "404": {
            "description": "Empresa ausente nesta conta ou na base."
          },
          "405": {
            "description": "Método não permitido."
          },
          "409": {
            "description": "Limite de 20 empresas."
          },
          "503": {
            "description": "Origem, conta ou orçamento indisponível."
          }
        }
      },
      "delete": {
        "operationId": "delete_api_me_empresas_by_cnpj",
        "summary": "Remove somente o vínculo da própria conta e limpa a seleção se necessário.",
        "description": "Devolve: { itens[{cnpj,razao_social,nome_fantasia,situacao,situacao_desde,porte,natureza_juridica,inicio_atividade,matriz_filial,capital_social,municipio,uf,cnaes,fonte,importado_em}], selecionada, limite }",
        "parameters": [
          {
            "name": "cnpj",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "CNPJ completo, 14 dígitos com verificação válida.",
            "example": "00394460000141"
          }
        ],
        "responses": {
          "200": {
            "description": "{ itens[{cnpj,razao_social,nome_fantasia,situacao,situacao_desde,porte,natureza_juridica,inicio_atividade,matriz_filial,capital_social,municipio,uf,cnaes,fonte,importado_em}], selecionada, limite }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmpresasConta"
                }
              }
            }
          },
          "400": {
            "description": "CNPJ ou busca inválida."
          },
          "401": {
            "description": "Sessão necessária."
          },
          "403": {
            "description": "Origem recusada."
          },
          "404": {
            "description": "Empresa ausente nesta conta ou na base."
          },
          "405": {
            "description": "Método não permitido."
          },
          "409": {
            "description": "Limite de 20 empresas."
          },
          "503": {
            "description": "Origem, conta ou orçamento indisponível."
          }
        }
      }
    },
    "/api/me/empresas/{cnpj}/selecionar": {
      "put": {
        "operationId": "put_api_me_empresas_by_cnpj_selecionar",
        "summary": "Seleciona uma empresa já cadastrada para trabalhar no edital.",
        "description": "Seleção persistida na conta e recuperável em outros aparelhos. Não executa análise; repetir a seleção atual não grava.\nDevolve: { itens[{cnpj,razao_social,nome_fantasia,situacao,situacao_desde,porte,natureza_juridica,inicio_atividade,matriz_filial,capital_social,municipio,uf,cnaes,fonte,importado_em}], selecionada, limite }",
        "parameters": [
          {
            "name": "cnpj",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "CNPJ completo, 14 dígitos com verificação válida.",
            "example": "00394460000141"
          }
        ],
        "responses": {
          "200": {
            "description": "{ itens[{cnpj,razao_social,nome_fantasia,situacao,situacao_desde,porte,natureza_juridica,inicio_atividade,matriz_filial,capital_social,municipio,uf,cnaes,fonte,importado_em}], selecionada, limite }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmpresasConta"
                }
              }
            }
          },
          "400": {
            "description": "CNPJ ou busca inválida."
          },
          "401": {
            "description": "Sessão necessária."
          },
          "403": {
            "description": "Origem recusada."
          },
          "404": {
            "description": "Empresa ausente nesta conta ou na base."
          },
          "405": {
            "description": "Método não permitido."
          },
          "409": {
            "description": "Limite de 20 empresas."
          },
          "503": {
            "description": "Origem, conta ou orçamento indisponível."
          }
        }
      }
    },
    "/api/auth/bootstrap": {
      "get": {
        "operationId": "get_api_auth_bootstrap",
        "summary": "Prepara o navegador para entrar na conta global.",
        "description": "Define cookie HttpOnly restrito ao host. CSRF vinculado à sessão atual. Sem CORS.\nDevolve: { csrf, context }",
        "responses": {
          "200": {
            "description": "{ csrf, context }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "csrf": {
                      "type": "string",
                      "description": "X-CSRF-Token"
                    },
                    "context": {
                      "type": "string",
                      "description": "Opaque view context, also in X-MM-Context; not a credential / contexto opaco da vista, não é credencial."
                    }
                  },
                  "required": [
                    "csrf",
                    "context"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "invalid_request"
          },
          "403": {
            "description": "invalid_origin / invalid_csrf"
          },
          "503": {
            "description": "auth_unavailable: a sessão anterior é preservada / the previous session is preserved"
          }
        },
        "security": []
      }
    },
    "/api/account/profile": {
      "get": {
        "operationId": "get_api_account_profile",
        "summary": "Consulta seu perfil global.",
        "description": "Lê preferências atuais da conta. Altere-as na página da conta; produtos não mantêm perfil autoritativo separado.\nDevolve: {profile:{name,locale,timeZone,theme,revision}}",
        "responses": {
          "200": {
            "description": "{profile:{name,locale,timeZone,theme,revision}}"
          },
          "401": {
            "description": "invalid_session"
          },
          "503": {
            "description": "auth_unavailable"
          }
        },
        "security": [
          {
            "globalAccount": []
          }
        ]
      }
    },
    "/api/account/avatar": {
      "get": {
        "operationId": "get_api_account_avatar",
        "summary": "Consulta sua foto de perfil global.",
        "description": "WebP privado de até 64 KiB, sem cache. Altere-o na conta. Não aceita ID de usuário ou URL de objeto.\nDevolve: image/webp; Cache-Control: no-store",
        "responses": {
          "200": {
            "description": "image/webp; Cache-Control: no-store",
            "content": {
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "description": "invalid_session"
          },
          "404": {
            "description": "not_found: no photo / sem foto"
          },
          "503": {
            "description": "auth_unavailable"
          }
        },
        "security": [
          {
            "globalAccount": []
          }
        ]
      }
    },
    "/api/auth/logout": {
      "post": {
        "operationId": "post_api_auth_logout",
        "summary": "Revoga esta sessão do produto.",
        "description": "Exige bootstrap/CSRF deste navegador e sessão. As sessões de outros produtos permanecem ativas.\nDevolve: { ok }",
        "responses": {
          "200": {
            "description": "{ ok }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "true"
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "invalid_request"
          },
          "403": {
            "description": "invalid_origin / invalid_csrf"
          },
          "503": {
            "description": "auth_unavailable: a sessão anterior é preservada / the previous session is preserved"
          }
        },
        "security": [
          {
            "globalAccount": []
          }
        ]
      }
    },
    "/api/account/keys": {
      "get": {
        "operationId": "get_api_account_keys",
        "summary": "Lista suas chaves de API neste produto.",
        "description": "Nunca devolve a chave: nome, 4 últimos caracteres, organização, criação, último uso (por hora) e se ainda vale.\nDevolve: { keys }",
        "responses": {
          "200": {
            "description": "{ keys }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "keys": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "`id`, `name`, `organizationId`, `last4`, `createdAt`, `lastUsedAt`, `revokedAt`, `active` (false quando revogada ou parada por troca de senha / encerrar todos os acessos)."
                    }
                  },
                  "required": [
                    "keys"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "invalid_session"
          },
          "503": {
            "description": "auth_unavailable"
          }
        },
        "security": [
          {
            "globalAccount": []
          }
        ]
      }
    },
    "/api/account/keys/create": {
      "post": {
        "operationId": "post_api_account_keys_create",
        "summary": "Cria uma chave de API para agentes e scripts.",
        "description": "Exige entrada nos últimos 5 minutos; a de organização também exige segundo fator na sessão e o papel de dona/administradora com o produto ligado. No máximo 10 chaves vivas por conta e produto. A chave (`secret`) volta UMA vez.\nDevolve: { key, secret }",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Até 60 caracteres."
                  },
                  "organizationId": {
                    "type": "string",
                    "description": "`null` para chave da conta."
                  }
                },
                "required": [
                  "name",
                  "organizationId"
                ]
              },
              "example": {
                "name": "agent",
                "organizationId": null
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ key, secret }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "key": {
                      "type": "object",
                      "description": "`id`, `name`, `organizationId`, `last4`, `createdAt`."
                    },
                    "secret": {
                      "type": "string",
                      "description": "`mmk_…`, mostrada uma vez."
                    }
                  },
                  "required": [
                    "key",
                    "secret"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "invalid_key_name / invalid_organization"
          },
          "401": {
            "description": "invalid_session / reauth_required"
          },
          "403": {
            "description": "invalid_origin / invalid_csrf / organization_forbidden / organization_mfa_required"
          },
          "409": {
            "description": "key_limit_reached"
          },
          "503": {
            "description": "auth_unavailable"
          }
        },
        "security": [
          {
            "globalAccount": []
          }
        ]
      }
    },
    "/api/account/keys/revoke": {
      "post": {
        "operationId": "post_api_account_keys_revoke",
        "summary": "Revoga uma das suas chaves de API.",
        "description": "Para a chave na hora. Repetir não faz mal.\nDevolve: { ok }",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "O `id` da chave."
                  }
                },
                "required": [
                  "id"
                ]
              },
              "example": {
                "id": "…"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ ok }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "true"
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "invalid_key_id"
          },
          "401": {
            "description": "invalid_session"
          },
          "403": {
            "description": "invalid_origin / invalid_csrf"
          },
          "404": {
            "description": "key_not_found"
          },
          "503": {
            "description": "auth_unavailable"
          }
        },
        "security": [
          {
            "globalAccount": []
          }
        ]
      }
    },
    "/api/auth/claim": {
      "post": {
        "operationId": "post_api_auth_claim",
        "summary": "Passa para a conta o que o convidado criou: as Salvas, os Alertas e as Vigias que a conta ainda não tem (uma lista de cada por conta), o segredo do webhook se ela ainda não tem um, e as compras do convidado.",
        "description": "Exige bootstrap/CSRF deste navegador; a página faz isso logo depois de entrar. Só passa o que o convidado ainda tem, numa transação, e o que colide com o que a conta já tem fica com o convidado. O que o convidado comprou passa junto. Token antigo, sem assinatura, que não é dono de nada aqui é recusado. Repetir não faz mal (move zero).\nDevolve: { ok, claimed }",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "guest_token": {
                    "type": "string",
                    "description": "Convidado `edm_…` deste navegador."
                  }
                },
                "required": [
                  "guest_token"
                ]
              },
              "example": {
                "guest_token": "edm_…"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ ok, claimed }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Se o convidado foi reconhecido e passou."
                    },
                    "claimed": {
                      "type": "object",
                      "description": "`product.movidos` (linhas que mudaram de dono, por tabela), `product.apagados` (duplicatas do convidado descartadas) e `product.direitos` (compras que passaram)."
                    }
                  },
                  "required": [
                    "ok",
                    "claimed"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "invalid_product_claim / invalid_body"
          },
          "401": {
            "description": "invalid_session"
          },
          "403": {
            "description": "invalid_origin / invalid_csrf"
          },
          "409": {
            "description": "unknown_guest (em `claimed.reason` / in `claimed.reason`)"
          },
          "503": {
            "description": "product_claim_pending / auth_unavailable"
          }
        },
        "security": [
          {
            "globalAccount": []
          }
        ]
      }
    },
    "/api/me": {
      "get": {
        "operationId": "get_api_me",
        "summary": "Identifica sua conta, conta seus acessos e acompanhamentos e aponta biblioteca e histórico.",
        "description": "A conta global já é a pessoa no EditalMD: não há ativação por produto.\nDevolve: { user, documentos_url, compras_url, totais, acompanhamento_vinculado, locais_vinculados }",
        "parameters": [
          {
            "name": "locais",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Até 90 IDs positivos de documentos separados por vírgula, no máximo 1529 caracteres; omita se não houver acessos locais para conciliar."
          }
        ],
        "responses": {
          "200": {
            "description": "{ user, documentos_url, compras_url, totais, acompanhamento_vinculado, locais_vinculados }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "type": "object",
                      "description": "id (o id da conta global) e email da conta."
                    },
                    "documentos_url": {
                      "type": "string",
                      "description": "Biblioteca privada."
                    },
                    "compras_url": {
                      "type": "string",
                      "description": "Histórico privado."
                    },
                    "totais": {
                      "type": "object",
                      "description": "documentos (IDs distintos com direito comprado), salvas e alertas (incluindo pausados) da conta; zero quando vazio."
                    },
                    "acompanhamento_vinculado": {
                      "type": "boolean",
                      "description": "Sempre true: a conta é dona direto das listas dela."
                    },
                    "locais_vinculados": {
                      "type": "array",
                      "items": {
                        "type": "integer"
                      },
                      "description": "Dos IDs informados em locais, somente os que já pertencem à conta atual; evita duplicar o contador do navegador. Não concede acesso."
                    }
                  },
                  "required": [
                    "user",
                    "documentos_url",
                    "compras_url",
                    "totais",
                    "acompanhamento_vinculado",
                    "locais_vinculados"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Corpo/cursor inválido."
          },
          "401": {
            "description": "Sessão ausente, inválida ou encerrada (`session_ended`: entre de novo)."
          },
          "403": {
            "description": "Origem de mutação ou CSRF recusados."
          },
          "404": {
            "description": "Aquisição não encontrada para este cliente."
          },
          "405": {
            "description": "Método não permitido."
          },
          "503": {
            "description": "Conta ou limite global indisponível."
          }
        },
        "security": [
          {
            "globalAccount": []
          }
        ]
      }
    },
    "/api/me/documentos": {
      "get": {
        "operationId": "get_api_me_documentos",
        "summary": "Documentos comprados por esta conta; reabertura sem novo pagamento.",
        "description": "Devolve: { itens, proximo_antes }",
        "parameters": [
          {
            "name": "antes",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "proximo_antes da página anterior; hex, cursor exclusivo do cliente."
          }
        ],
        "responses": {
          "200": {
            "description": "{ itens, proximo_antes }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Direitos de documento da conta (direito global do pagamento): id, documento_id, via (x402, credito, deposito ou simulado), created_at, abrir_url, geracao_url, markdown_url."
                    },
                    "proximo_antes": {
                      "type": "string",
                      "description": "Sempre null: a coleção vem inteira, até 200.",
                      "nullable": true
                    }
                  },
                  "required": [
                    "itens",
                    "proximo_antes"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Corpo/cursor inválido."
          },
          "401": {
            "description": "Sessão ausente, inválida ou encerrada (`session_ended`: entre de novo)."
          },
          "403": {
            "description": "Origem de mutação ou CSRF recusados."
          },
          "404": {
            "description": "Aquisição não encontrada para este cliente."
          },
          "405": {
            "description": "Método não permitido."
          },
          "503": {
            "description": "Conta ou limite global indisponível."
          }
        }
      }
    },
    "/api/me/compras": {
      "get": {
        "operationId": "get_api_me_compras",
        "summary": "Histórico privado das aquisições, mais recentes primeiro.",
        "description": "Devolve: { itens, proximo_antes }",
        "parameters": [
          {
            "name": "antes",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "proximo_antes da página anterior; hex, cursor exclusivo do cliente."
          }
        ],
        "responses": {
          "200": {
            "description": "{ itens, proximo_antes }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Direitos de documento da conta (direito global do pagamento): id, documento_id, via (x402, credito, deposito ou simulado), created_at, abrir_url, geracao_url, markdown_url."
                    },
                    "proximo_antes": {
                      "type": "string",
                      "description": "Sempre null: a coleção vem inteira, até 200.",
                      "nullable": true
                    }
                  },
                  "required": [
                    "itens",
                    "proximo_antes"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Corpo/cursor inválido."
          },
          "401": {
            "description": "Sessão ausente, inválida ou encerrada (`session_ended`: entre de novo)."
          },
          "403": {
            "description": "Origem de mutação ou CSRF recusados."
          },
          "404": {
            "description": "Aquisição não encontrada para este cliente."
          },
          "405": {
            "description": "Método não permitido."
          },
          "503": {
            "description": "Conta ou limite global indisponível."
          }
        }
      }
    },
    "/api/documento/{id}/vincular": {
      "post": {
        "operationId": "post_api_documento_by_id_vincular",
        "summary": "Associa sua aquisição anônima à conta autenticada, sem nova cobrança.",
        "description": "Exige sessão e prova privada da aquisição. Grava o direito global da conta pelo recibo do pagamento: idempotente para o mesmo dono, e outro dono não pode reivindicar. O código continua abrindo o documento sozinho.\nDevolve: { vinculado, documento_id }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID positivo do documento comprado.",
            "example": "2110258"
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Capacidade privada recebida após pagamento. Cookie documental também aceito."
          }
        ],
        "responses": {
          "200": {
            "description": "{ vinculado, documento_id }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "vinculado": {
                      "type": "boolean",
                      "description": "Aquisição pertence à conta."
                    },
                    "documento_id": {
                      "type": "integer",
                      "description": "Documento."
                    }
                  },
                  "required": [
                    "vinculado",
                    "documento_id"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Corpo/cursor inválido."
          },
          "401": {
            "description": "Sessão ausente, inválida ou encerrada (`session_ended`: entre de novo)."
          },
          "403": {
            "description": "Origem de mutação ou CSRF recusados."
          },
          "404": {
            "description": "Aquisição não encontrada para este cliente."
          },
          "405": {
            "description": "Método não permitido."
          },
          "503": {
            "description": "Conta ou limite global indisponível."
          }
        }
      }
    },
    "/api/documento/{id}/acesso": {
      "get": {
        "operationId": "get_api_documento_by_id_acesso",
        "summary": "Confere vínculo e permite exportar o código da aquisição ainda anônima.",
        "description": "Devolve: { documento_id, vinculado, recuperacao }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID positivo do documento comprado.",
            "example": "2110258"
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código de acesso; sessão/cookie equivalente aceitos."
          }
        ],
        "responses": {
          "200": {
            "description": "{ documento_id, vinculado, recuperacao }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "documento_id": {
                      "type": "integer",
                      "description": "Documento."
                    },
                    "vinculado": {
                      "type": "boolean",
                      "description": "A conta atual possui este documento."
                    },
                    "recuperacao": {
                      "type": "string",
                      "description": "Código privado exportável somente enquanto não vinculado.",
                      "nullable": true
                    }
                  },
                  "required": [
                    "documento_id",
                    "vinculado",
                    "recuperacao"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Corpo/cursor inválido."
          },
          "401": {
            "description": "Sessão ausente, inválida ou encerrada (`session_ended`: entre de novo)."
          },
          "402": {
            "description": "Acesso não comprado."
          },
          "403": {
            "description": "Origem de mutação ou CSRF recusados."
          },
          "404": {
            "description": "Aquisição não encontrada para este cliente."
          },
          "405": {
            "description": "Método não permitido."
          },
          "503": {
            "description": "Conta ou limite global indisponível."
          }
        }
      }
    },
    "/api/me/acompanhamento": {
      "get": {
        "operationId": "get_api_me_acompanhamento",
        "summary": "Confere que Salvas/Alertas/Vigias são da conta da sessão.",
        "description": "As listas de um convidado edm_… passam para a conta em `POST /api/auth/claim`; o POST desta rota responde 410 com o caminho.\nDevolve: { vinculado }",
        "responses": {
          "200": {
            "description": "{ vinculado }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "vinculado": {
                      "type": "boolean",
                      "description": "Sempre true com sessão: a conta é dona direto das listas dela."
                    }
                  },
                  "required": [
                    "vinculado"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Corpo/cursor inválido."
          },
          "401": {
            "description": "Sessão ausente, inválida ou encerrada (`session_ended`: entre de novo)."
          },
          "403": {
            "description": "Origem de mutação ou CSRF recusados."
          },
          "404": {
            "description": "Aquisição não encontrada para este cliente."
          },
          "405": {
            "description": "Método não permitido."
          },
          "503": {
            "description": "Conta ou limite global indisponível."
          }
        }
      }
    },
    "/api/": {
      "get": {
        "operationId": "get_api",
        "summary": "Índice auto-descrito: rotas, regime de cobrança, preço e MCP.",
        "description": "Devolve: { name, description, build, base_url, docs, endpoints, mcp_tools, regime, gratis_acima_de_dias, pago, cota }",
        "responses": {
          "200": {
            "description": "{ name, description, build, base_url, docs, endpoints, mcp_tools, regime, gratis_acima_de_dias, pago, cota }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "Nome do produto."
                    },
                    "description": {
                      "type": "string",
                      "description": "O que o produto faz."
                    },
                    "build": {
                      "type": "string",
                      "description": "Commit publicado."
                    },
                    "base_url": {
                      "type": "string",
                      "description": "Origem em que esta API está servindo."
                    },
                    "docs": {
                      "type": "object",
                      "description": "Links para llms.txt, OpenAPI, MCP e a UI."
                    },
                    "endpoints": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Catálogo de endpoints."
                    },
                    "mcp_tools": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Tools do MCP."
                    },
                    "regime": {
                      "type": "string",
                      "description": "A regra de cobrança por recência, em uma frase."
                    },
                    "gratis_acima_de_dias": {
                      "type": "integer",
                      "description": "Idade de publicação a partir da qual o documento é amostra grátis."
                    },
                    "pago": {
                      "type": "object",
                      "description": "Rota paga e o preço por requisição."
                    },
                    "cota": {
                      "type": "object",
                      "description": "O que é grátis, o que é pago e como pagar."
                    }
                  },
                  "required": [
                    "name",
                    "description",
                    "build",
                    "base_url",
                    "docs",
                    "endpoints",
                    "mcp_tools",
                    "regime",
                    "gratis_acima_de_dias",
                    "pago",
                    "cota"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "operationId": "get_api_health",
        "summary": "Saúde da origem e tamanho do acervo.",
        "description": "Devolve: { ok, build, acervo{compras,documentos_lidos}, preco_markdown_usd, gratis_acima_de_dias }",
        "responses": {
          "200": {
            "description": "{ ok, build, acervo{compras,documentos_lidos}, preco_markdown_usd, gratis_acima_de_dias }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Saude"
                }
              }
            }
          },
          "503": {
            "description": "Origem indisponível."
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "operationId": "post_mcp",
        "summary": "MCP Streamable HTTP — as tools deste catálogo, despachadas neste mesmo Worker.",
        "description": "Devolve: JSON-RPC 2.0 (`initialize`, `tools/list`, `tools/call`).",
        "responses": {
          "200": {
            "description": "JSON-RPC 2.0 (`initialize`, `tools/list`, `tools/call`)."
          }
        }
      }
    },
    "/okf/{arquivo}": {
      "get": {
        "operationId": "get_okf_by_arquivo",
        "summary": "Bundle OKF (Open Knowledge Format v0.1): markdown com frontmatter para o agente ler o produto inteiro sem parsear HTML.",
        "description": "Devolve: `text/markdown`. Comece por `/okf/index.md`, que lista o bundle.",
        "parameters": [
          {
            "name": "arquivo",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "`index.md`, `sobre.md`, `api.md` ou `faq.md`.",
            "example": "index.md"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
          },
          {
            "name": "X-Editalmd-Avaliacao",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
          }
        ],
        "responses": {
          "200": {
            "description": "`text/markdown`. Comece por `/okf/index.md`, que lista o bundle."
          },
          "402": {
            "description": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; cinco exemplos são gratuitos."
          },
          "404": {
            "description": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente."
          }
        }
      }
    },
    "/.well-known/{arquivo}": {
      "get": {
        "operationId": "get_well_known_by_arquivo",
        "summary": "Descoberta de máquina antes da home: `api-catalog` (RFC 9727, linkset com a API e o MCP), `security.txt` (RFC 9116), `x402` (manifesto de pagamento: rede, carteira e rotas que cobram), `agent-card.json` (identidade do agente: ferramentas MCP e portas de descoberta; também em `/agent.json`) e `mcp-registry-auth` (chave do registro oficial de MCP).",
        "description": "Devolve: `application/linkset+json` no api-catalog; `application/json` no x402, no agent-card.json e no apis.json; `text/plain` nos outros dois.",
        "parameters": [
          {
            "name": "arquivo",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "`api-catalog`, `security.txt`, `x402`, `agent-card.json`, `mcp-registry-auth` ou `apis.json`.",
            "example": "api-catalog"
          }
        ],
        "responses": {
          "200": {
            "description": "`application/linkset+json` no api-catalog; `application/json` no x402, no agent-card.json e no apis.json; `text/plain` nos outros dois."
          },
          "404": {
            "description": "Nome fora dos seis publicados."
          }
        }
      }
    },
    "/apis.json": {
      "get": {
        "operationId": "get_apis_json",
        "summary": "APIs.json (apisjson.org, 0.19): o índice que o APIs.io colhe — a API, o MCP, OpenAPI, guia e bundle OKF num arquivo só. Também em `/.well-known/apis.json`.",
        "description": "Devolve: `application/json` no formato APIs.json 0.19: `apis[]` com `baseURL`, `humanURL` e `properties[]`.",
        "responses": {
          "200": {
            "description": "`application/json` no formato APIs.json 0.19: `apis[]` com `baseURL`, `humanURL` e `properties[]`."
          }
        }
      }
    },
    "/agent.json": {
      "get": {
        "operationId": "get_agent_json",
        "summary": "Cartão do agente: identidade, quem opera, documentação, o endpoint MCP e as ferramentas que ele serve. Mesmo documento de `/.well-known/agent-card.json`.",
        "description": "Devolve: `application/json`: `name`, `provider`, `protocol` (`mcp`), `interfaces[]` e `skills[]`.",
        "responses": {
          "200": {
            "description": "`application/json`: `name`, `provider`, `protocol` (`mcp`), `interfaces[]` e `skills[]`."
          }
        }
      }
    },
    "/okf/{tipo}/{id}.md": {
      "get": {
        "operationId": "get_okf_by_tipo_by_id_md",
        "summary": "O mesmo registro que a API responde, em markdown OKF: `documento` (Documento do acervo). Via de acesso para quem já tem o id, não catálogo.",
        "description": "Devolve: `text/markdown` com frontmatter OKF; `resource` aponta o JSON equivalente. Sem `.md` responde 301 para o canônico.",
        "parameters": [
          {
            "name": "tipo",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Um de: `documento`.",
            "example": "documento"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "O id do registro, como a API o aceita.",
            "example": "123"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
          },
          {
            "name": "X-Editalmd-Avaliacao",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
          }
        ],
        "responses": {
          "200": {
            "description": "`text/markdown` com frontmatter OKF; `resource` aponta o JSON equivalente. Sem `.md` responde 301 para o canônico."
          },
          "402": {
            "description": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; cinco exemplos são gratuitos."
          },
          "404": {
            "description": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente."
          }
        }
      }
    },
    "/feed.xml": {
      "get": {
        "operationId": "get_feed_xml",
        "summary": "RSS 2.0 das compras publicadas mais recentemente no acervo.",
        "description": "Devolve: `application/rss+xml`.",
        "responses": {
          "200": {
            "description": "`application/rss+xml`."
          }
        }
      }
    },
    "/feed.json": {
      "get": {
        "operationId": "get_feed_json",
        "summary": "JSON Feed 1.1 das compras publicadas mais recentemente — o mesmo stream do RSS.",
        "description": "Devolve: `application/feed+json`.",
        "responses": {
          "200": {
            "description": "`application/feed+json`."
          }
        }
      }
    },
    "/api/busca": {
      "get": {
        "operationId": "get_api_busca",
        "summary": "Busca compras públicas por termo. Consulta grátis.",
        "description": "Devolve: { itens[{id,pncp,objeto,uf,modalidade,situacao,orgao,unidade,valor_estimado,publicado_em,informacao_complementar,processo,abertura_proposta,encerramento_proposta,amparo_legal,amparo_legal_codigo,modalidade_id,situacao_id,municipio,municipio_ibge,orgao_cnpj,ano_compra,sequencial_compra,atualizado_em,prazos,pncp_url,markdown_url,compra_url}], preco_markdown_usd, gratis_acima_de_dias, pago }",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Termo de busca; mínimo 3 letras."
          },
          {
            "name": "uf",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filtra por sigla de UF."
          },
          {
            "name": "abertas",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "`1` devolve só compras com prazo de proposta ainda por vencer."
          },
          {
            "name": "limite",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "1 a 50 (padrão 20)."
          }
        ],
        "responses": {
          "200": {
            "description": "{ itens[{id,pncp,objeto,uf,modalidade,situacao,orgao,unidade,valor_estimado,publicado_em,informacao_complementar,processo,abertura_proposta,encerramento_proposta,amparo_legal,amparo_legal_codigo,modalidade_id,situacao_id,municipio,municipio_ibge,orgao_cnpj,ano_compra,sequencial_compra,atualizado_em,prazos,pncp_url,markdown_url,compra_url}], preco_markdown_usd, gratis_acima_de_dias, pago }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Busca"
                }
              }
            }
          },
          "400": {
            "description": "Termo com menos de 3 letras."
          },
          "502": {
            "description": "Origem indisponível."
          },
          "503": {
            "description": "Busca demorada (combinação rara de filtro e offset acima do teto da origem): `busca_demorada`, com `Retry-After` — refine o termo ou reduza o offset."
          }
        }
      }
    },
    "/api/cnaes": {
      "get": {
        "operationId": "get_api_cnaes",
        "summary": "Atividades econômicas (CNAE), descrições e sugestões de termos para alertas. Grátis.",
        "description": "Sem `q`, lista atividades com mais fornecedores registrados. Com `q`, busca por prefixo do código (`1412`, `1412-6/01`) ou por palavra da descrição. `familia`/`termos` nulos dizem que o CNAE ainda não está no dicionário: um alerta por CNPJ não o usa.\nDevolve: { itens[{codigo,cnae,descricao,familia,familia_nome,termos,fornecedores_sicaf,sicaf_medido_em,ibge_atualizado_em}], limite, q, dicionario, fontes }",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Prefixo do código (2 a 7 dígitos) ou palavra da descrição (2+ letras)."
          },
          {
            "name": "limite",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "1 a 100 (padrão 20), por fornecedores no SICAF, decrescente."
          }
        ],
        "responses": {
          "200": {
            "description": "{ itens[{codigo,cnae,descricao,familia,familia_nome,termos,fornecedores_sicaf,sicaf_medido_em,ibge_atualizado_em}], limite, q, dicionario, fontes }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Cnae"
                      },
                      "description": "Os CNAEs que casam, os com mais fornecedores primeiro."
                    },
                    "limite": {
                      "type": "integer",
                      "description": "Teto aplicado."
                    },
                    "q": {
                      "type": "string",
                      "description": "O filtro aplicado.",
                      "nullable": true
                    },
                    "dicionario": {
                      "type": "object",
                      "description": "`familias`, `cnaes_mapeados` e `medido_em` (quando a cobertura no acervo foi medida)."
                    },
                    "fontes": {
                      "type": "object",
                      "description": "Créditos dos dados apresentados."
                    }
                  },
                  "required": [
                    "itens",
                    "limite",
                    "q",
                    "dicionario",
                    "fontes"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "`q` com menos de 2 caracteres."
          },
          "503": {
            "description": "Banco indisponível."
          }
        }
      }
    },
    "/api/compra/{id}": {
      "get": {
        "operationId": "get_api_compra_by_id",
        "summary": "Ficha da compra com prazos de proposta e impugnação, documentos e o regime de cobrança de cada um.",
        "description": "Servida do cache da borda por até 6 horas — a ficha raramente muda; prazos e preços são calculados a cada pedido. `Cache-Control: no-cache` no pedido lê a origem na hora. O cabeçalho `x-origem-cache` diz `hit`, `miss` ou `bypass`.\nDevolve: { compra{id,pncp,objeto,uf,modalidade,situacao,orgao,unidade,valor_estimado,publicado_em,informacao_complementar,processo,abertura_proposta,encerramento_proposta,amparo_legal,amparo_legal_codigo,modalidade_id,situacao_id,municipio,municipio_ibge,orgao_cnpj,ano_compra,sequencial_compra,atualizado_em,prazos,pncp_url,markdown_url,compra_url}, documentos[{id,titulo,tipo,sequencial,publicado_em,caracteres,paginas,motor,formato,sha256,extraido_em,gratuito,preco_usd,markdown_url,geracao_url,preco_pagina_usd,disponivel}], regime{gratuito,motivo,idade_dias}, prazos{proposta_inicio,proposta_ate,proposta_aberta,impugnacao_ate,impugnacao_aberta,estimado,base_legal,feriados,motivo} }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador da compra, vindo da busca.",
            "example": "42"
          }
        ],
        "responses": {
          "200": {
            "description": "{ compra{id,pncp,objeto,uf,modalidade,situacao,orgao,unidade,valor_estimado,publicado_em,informacao_complementar,processo,abertura_proposta,encerramento_proposta,amparo_legal,amparo_legal_codigo,modalidade_id,situacao_id,municipio,municipio_ibge,orgao_cnpj,ano_compra,sequencial_compra,atualizado_em,prazos,pncp_url,markdown_url,compra_url}, documentos[{id,titulo,tipo,sequencial,publicado_em,caracteres,paginas,motor,formato,sha256,extraido_em,gratuito,preco_usd,markdown_url,geracao_url,preco_pagina_usd,disponivel}], regime{gratuito,motivo,idade_dias}, prazos{proposta_inicio,proposta_ate,proposta_aberta,impugnacao_ate,impugnacao_aberta,estimado,base_legal,feriados,motivo} }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FichaCompra"
                }
              }
            }
          },
          "404": {
            "description": "Compra não encontrada."
          },
          "502": {
            "description": "Origem indisponível."
          }
        }
      }
    },
    "/api/documento/{id}": {
      "get": {
        "operationId": "get_api_documento_by_id",
        "summary": "Título, tipo, páginas e compra vinculada ao documento. Consulta pública, sem iniciar extração.",
        "description": "Devolve: { documento, compra_id }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do documento.",
            "example": "93998"
          }
        ],
        "responses": {
          "200": {
            "description": "{ documento, compra_id }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "documento": {
                      "type": "object",
                      "description": "id, titulo, tipo, paginas (null quando desconhecidas), tem_texto, tem_binario, disponivel e gratuito. Não inclui texto, arquivos ou caminhos internos."
                    },
                    "compra_id": {
                      "type": "integer",
                      "description": "Compra vinculada. Consulte /api/compra/:id para listar seus documentos com títulos, tipos e páginas (até 50 por ficha).",
                      "nullable": true
                    }
                  },
                  "required": [
                    "documento",
                    "compra_id"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "ID inválido."
          },
          "404": {
            "description": "Documento não encontrado."
          },
          "502": {
            "description": "Origem indisponível."
          }
        }
      }
    },
    "/api/documento/{id}/markdown": {
      "get": {
        "operationId": "get_api_documento_by_id_markdown",
        "summary": "Markdown com procedência e hash, com acesso comprado ou premium patrocinado. Cinco exemplos gratuitos.",
        "description": "Devolve: `text/markdown`. Headers: `x-editalmd-regime`, `x-editalmd-sha256`. Leitura não gera recibo ou cobrança.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do documento, vindo da ficha da compra.",
            "example": "123"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
          },
          {
            "name": "X-Editalmd-Avaliacao",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
          }
        ],
        "responses": {
          "200": {
            "description": "`text/markdown`. Headers: `x-editalmd-regime`, `x-editalmd-sha256`. Leitura não gera recibo ou cobrança."
          },
          "202": {
            "description": "Texto em preparação no acervo (`extracao_em_andamento`): `retry_after_s` no corpo e `Retry-After` no header. Repita após esse prazo. A preparação ainda não é uma entrega concluída."
          },
          "402": {
            "description": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; cinco exemplos são gratuitos."
          },
          "404": {
            "description": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente."
          },
          "409": {
            "description": "Texto indisponível ou geração necessária. Use geracao_url para consultar páginas e total e autorizar o pagamento."
          },
          "502": {
            "description": "Origem indisponível; nenhuma cobrança na leitura."
          }
        }
      }
    },
    "/api/documento/{id}/habilitacao": {
      "post": {
        "operationId": "post_api_documento_by_id_habilitacao",
        "summary": "Lista de habilitação com trechos literais. Exige acesso ao documento comprado; sem cobrança adicional nesta fase.",
        "description": "Condições, exceções e evidências por página da análise disponível. A consulta não inicia outra análise. Prazos, propostas e demais obrigações estão no dossie; esta lista cobre habilitação e atestados exigidos, sem afirmar o que a empresa possui.\nDevolve: { documento_id, compra_id, sha256_texto, dossie_versao, modelo, cache, recibo, recibo_url, aviso, habilitacao{juridica,fiscal_social_trabalhista,economico_financeira,tecnica,exclusivo_me_epp,impugnacao_texto,proposta_texto,total,descartados} }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do documento, vindo da ficha da compra.",
            "example": "123"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
          },
          {
            "name": "X-Editalmd-Avaliacao",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
          }
        ],
        "responses": {
          "200": {
            "description": "{ documento_id, compra_id, sha256_texto, dossie_versao, modelo, cache, recibo, recibo_url, aviso, habilitacao{juridica,fiscal_social_trabalhista,economico_financeira,tecnica,exclusivo_me_epp,impugnacao_texto,proposta_texto,total,descartados} }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Habilitacao"
                }
              }
            }
          },
          "402": {
            "description": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; cinco exemplos são gratuitos."
          },
          "404": {
            "description": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente."
          },
          "409": {
            "description": "Dossiê ainda em preparação. Nenhuma nova análise é iniciada por esta consulta."
          },
          "502": {
            "description": "Dossiê inválido ou resposta incompleta da origem."
          },
          "503": {
            "description": "Dossiê temporariamente indisponível."
          }
        }
      }
    },
    "/api/dono": {
      "post": {
        "operationId": "post_api_dono",
        "summary": "Cria o convidado (token edm_…) que abre alertas e vigias, e o segredo que assina os webhooks. Sem cadastro.",
        "description": "O token é emitido e assinado pela biblioteca de conta, com teto por rede e por hora, para a franquia grátis não virar infinita. Ele é mostrado uma única vez e não tem recuperação — entre na conta e traga as listas para ela (`POST /api/auth/claim`, que a página da conta faz sozinha ao entrar) para não depender dele. O `webhook_segredo` pode ser relido em `GET /api/dono`. Todo POST do webhook leva `webhook-id`, `webhook-timestamp` (segundos Unix) e `webhook-signature: v1,<base64>`: HMAC-SHA256 de `id.timestamp.corpo` com a chave do seu `whsec_…` (o base64 depois do prefixo). É o padrão Standard Webhooks — qualquer biblioteca dele confere; rejeite timestamp fora de 5 minutos. Depois de `POST /api/dono/segredo`, o anterior ainda assina por 24 h (duas partes `v1,` no cabeçalho).\nDevolve: { token, aviso, webhook_segredo, webhook_assinatura, franquia }",
        "responses": {
          "200": {
            "description": "{ token, aviso, webhook_segredo, webhook_assinatura, franquia }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Dono"
                }
              }
            }
          },
          "429": {
            "description": "A rede passou do teto de convidados da hora."
          },
          "503": {
            "description": "Conta ou banco indisponível."
          }
        }
      },
      "get": {
        "operationId": "get_api_dono",
        "summary": "O estado do dono: conta ou convidado, e-mail dos avisos, franquia e o segredo que assina os webhooks.",
        "description": "Todo POST do webhook leva `webhook-id`, `webhook-timestamp` (segundos Unix) e `webhook-signature: v1,<base64>`: HMAC-SHA256 de `id.timestamp.corpo` com a chave do seu `whsec_…` (o base64 depois do prefixo). É o padrão Standard Webhooks — qualquer biblioteca dele confere; rejeite timestamp fora de 5 minutos. Depois de `POST /api/dono/segredo`, o anterior ainda assina por 24 h (duas partes `v1,` no cabeçalho).\nDevolve: { tipo, email_alertas, webhook_segredo, assinatura, franquia }",
        "responses": {
          "200": {
            "description": "{ tipo, email_alertas, webhook_segredo, assinatura, franquia }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tipo": {
                      "type": "string",
                      "description": "`conta` (sessão) ou `convidado` (token edm_…)."
                    },
                    "email_alertas": {
                      "type": "string",
                      "description": "E-mail verificado da conta, mascarado, para onde vão os avisos do canal e-mail; nulo no convidado.",
                      "nullable": true
                    },
                    "webhook_segredo": {
                      "type": "string",
                      "description": "`whsec_…` — a chave que assina cada POST de webhook."
                    },
                    "assinatura": {
                      "type": "string",
                      "description": "Como conferir a assinatura, em uma linha."
                    },
                    "franquia": {
                      "type": "object",
                      "description": "`alertas_gratis` e `vigias_gratis` incluídos."
                    }
                  },
                  "required": [
                    "tipo",
                    "email_alertas",
                    "webhook_segredo",
                    "assinatura",
                    "franquia"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Sem token de convidado nem sessão da conta, token desconhecido, ou `session_ended` (cookie de sessão vencida: entre de novo)."
          },
          "403": {
            "description": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token."
          },
          "503": {
            "description": "`conta_indisponivel`: conta fora do ar agora; nada muda."
          }
        }
      }
    },
    "/api/dono/segredo": {
      "post": {
        "operationId": "post_api_dono_segredo",
        "summary": "Rotaciona o segredo do webhook. O anterior ainda assina por 24 h, para trocar sem janela de falha.",
        "description": "Durante as 24 h o cabeçalho `webhook-signature` traz duas partes `v1,…`: uma com o novo, outra com o anterior. Basta o receptor aceitar qualquer uma que bata.\nDevolve: { webhook_segredo, anterior_valido_ate }",
        "responses": {
          "200": {
            "description": "{ webhook_segredo, anterior_valido_ate }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook_segredo": {
                      "type": "string",
                      "description": "O novo `whsec_…`."
                    },
                    "anterior_valido_ate": {
                      "type": "string",
                      "description": "Até quando o segredo anterior ainda assina (ISO 8601)."
                    }
                  },
                  "required": [
                    "webhook_segredo",
                    "anterior_valido_ate"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Sem token de convidado nem sessão da conta, token desconhecido, ou `session_ended` (cookie de sessão vencida: entre de novo)."
          },
          "403": {
            "description": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token."
          },
          "503": {
            "description": "`conta_indisponivel`: conta fora do ar agora; nada muda."
          }
        }
      }
    },
    "/api/documento/{id}/geracao": {
      "get": {
        "operationId": "get_api_documento_by_id_geracao",
        "summary": "Estado, cotação e direito de acesso; consulta gratuita, sem iniciar processamento.",
        "description": "Devolve: { documento_id, status?, error?, retry_after_s?, processing?, markdown_url, geracao_url, acesso_comprado, acesso?, preco_pagina_usd, cotacao, pagamento? }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID positivo do documento retornado pela compra.",
            "example": "2110000"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
          },
          {
            "name": "X-Editalmd-Avaliacao",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
          }
        ],
        "responses": {
          "200": {
            "description": "{ documento_id, status?, error?, retry_after_s?, processing?, markdown_url, geracao_url, acesso_comprado, acesso?, preco_pagina_usd, cotacao, pagamento? }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "documento_id": {
                      "type": "integer",
                      "description": "Documento solicitado."
                    },
                    "status": {
                      "type": "string",
                      "description": "`pronto` quando a leitura pode ser aberta."
                    },
                    "error": {
                      "type": "string",
                      "description": "`geracao_necessaria`, `extracao_em_andamento`, `geracao_falhou` ou causa da indisponibilidade."
                    },
                    "retry_after_s": {
                      "type": "integer",
                      "description": "Intervalo mínimo até o próximo GET de acompanhamento."
                    },
                    "processing": {
                      "type": "object",
                      "description": "Progresso real: `progress.stage` (preparing, reading, verifying, packaging), `pages_total`, `pages_processed`, `pages_completed`, `pass`; `updated_at` e `elapsed_ms`."
                    },
                    "markdown_url": {
                      "type": "string",
                      "description": "GET do Markdown, com o acesso comprado."
                    },
                    "geracao_url": {
                      "type": "string",
                      "description": "GET para estado/cotação; POST para comprar acesso individual."
                    },
                    "acesso_comprado": {
                      "type": "object",
                      "description": "Esta credencial pode ler o documento, independentemente do estado global do texto."
                    },
                    "acesso": {
                      "type": "object",
                      "description": "Após pagamento confirmado fora da sessão da conta: codigo privado e header X-Editalmd-Acesso. Guarde para reabrir ou para vincular a uma conta (POST /vincular). Não publique, não abre outro documento."
                    },
                    "preco_pagina_usd": {
                      "type": "string",
                      "description": "US$ 0,02 por página no site e API (x402 ou crédito)."
                    },
                    "cotacao": {
                      "type": "object",
                      "description": "Páginas confirmadas no documento: paginas, source_sha256, preco_pagina_usd e preco_total_usd. Nulo quando não é possível cotar.",
                      "nullable": true
                    },
                    "pagamento": {
                      "type": "object",
                      "description": "Quando cobrado: `recibo` da porta x402/crédito e `preco_usd`. Conserve mesmo se a origem falhar."
                    }
                  },
                  "required": [
                    "documento_id",
                    "markdown_url",
                    "geracao_url",
                    "acesso_comprado",
                    "preco_pagina_usd",
                    "cotacao"
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Processamento em curso; acompanhe por GET, respeitando Retry-After. Nunca repita POST para fazer polling."
          },
          "404": {
            "description": "Documento inexistente."
          },
          "409": {
            "description": "Geração necessária, falha anterior ou binário indisponível; consulte `error`."
          },
          "502": {
            "description": "Origem indisponível; não repita pagamento sem conferir o estado e o recibo."
          }
        }
      },
      "post": {
        "operationId": "post_api_documento_by_id_geracao",
        "summary": "Compra acesso individual ao documento por US$ 0,02/página, via x402/crédito.",
        "description": "Cada comprador paga, inclusive pronto. Consulte GET ou 402, confira páginas/hash/total e envie cotacao. Sessão da conta (cookie + CSRF do navegador) grava a compra no direito global da conta antes da entrega, sem código avulso; com o convidado edm_… (Bearer), o direito é dele e o código sai junto; agente usa X-Credito. Sem conta, conserve acesso.codigo para reabrir ou vincular depois. Após vínculo somente a conta abre. Texto pronto reutiliza OCR; geração necessária incluída. Cotação desconhecida/alterada não cobra. 152 páginas = US$ 3,04. Corpo até 4096 bytes. Após 202 acompanhe por GET. Pagou e a gravação do direito falhou: 502 `pago_nao_registrado` com o `recibo` — guarde-o, o suporte entrega ou estorna.\nDevolve: { documento_id, status?, error?, retry_after_s?, processing?, markdown_url, geracao_url, acesso_comprado, acesso?, preco_pagina_usd, cotacao, pagamento? }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID positivo do documento retornado pela compra.",
            "example": "2110000"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
          },
          {
            "name": "X-Editalmd-Avaliacao",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
          },
          {
            "name": "X-PAYMENT",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Autorização x402 do desafio 402."
          },
          {
            "name": "X-Credito",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Token cred_… para descontar do saldo, como alternativa ao x402."
          },
          {
            "name": "Authorization",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Bearer cred_… é alternativa ao X-Credito. A conta viaja em cookie, nunca em bearer."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Chave de tentativa, até 80 caracteres; preserve em retries de crédito do mesmo documento."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cotacao": {
                    "type": "object",
                    "description": "Objeto recebido no GET/402: paginas, source_sha256 e preco_total_usd devem coincidir com a cotação atual. Obrigatório ao enviar autorização de pagamento."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ documento_id, status?, error?, retry_after_s?, processing?, markdown_url, geracao_url, acesso_comprado, acesso?, preco_pagina_usd, cotacao, pagamento? }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "documento_id": {
                      "type": "integer",
                      "description": "Documento solicitado."
                    },
                    "status": {
                      "type": "string",
                      "description": "`pronto` quando a leitura pode ser aberta."
                    },
                    "error": {
                      "type": "string",
                      "description": "`geracao_necessaria`, `extracao_em_andamento`, `geracao_falhou` ou causa da indisponibilidade."
                    },
                    "retry_after_s": {
                      "type": "integer",
                      "description": "Intervalo mínimo até o próximo GET de acompanhamento."
                    },
                    "processing": {
                      "type": "object",
                      "description": "Progresso real: `progress.stage` (preparing, reading, verifying, packaging), `pages_total`, `pages_processed`, `pages_completed`, `pass`; `updated_at` e `elapsed_ms`."
                    },
                    "markdown_url": {
                      "type": "string",
                      "description": "GET do Markdown, com o acesso comprado."
                    },
                    "geracao_url": {
                      "type": "string",
                      "description": "GET para estado/cotação; POST para comprar acesso individual."
                    },
                    "acesso_comprado": {
                      "type": "object",
                      "description": "Esta credencial pode ler o documento, independentemente do estado global do texto."
                    },
                    "acesso": {
                      "type": "object",
                      "description": "Após pagamento confirmado fora da sessão da conta: codigo privado e header X-Editalmd-Acesso. Guarde para reabrir ou para vincular a uma conta (POST /vincular). Não publique, não abre outro documento."
                    },
                    "preco_pagina_usd": {
                      "type": "string",
                      "description": "US$ 0,02 por página no site e API (x402 ou crédito)."
                    },
                    "cotacao": {
                      "type": "object",
                      "description": "Páginas confirmadas no documento: paginas, source_sha256, preco_pagina_usd e preco_total_usd. Nulo quando não é possível cotar.",
                      "nullable": true
                    },
                    "pagamento": {
                      "type": "object",
                      "description": "Quando cobrado: `recibo` da porta x402/crédito e `preco_usd`. Conserve mesmo se a origem falhar."
                    }
                  },
                  "required": [
                    "documento_id",
                    "markdown_url",
                    "geracao_url",
                    "acesso_comprado",
                    "preco_pagina_usd",
                    "cotacao"
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Processamento em curso; acompanhe por GET, respeitando Retry-After. Nunca repita POST para fazer polling."
          },
          "400": {
            "description": "Corpo malformado ou campos desconhecidos."
          },
          "401": {
            "description": "Crédito inválido, ou `session_ended` (cookie de sessão vencida: entre de novo); nada cobrado."
          },
          "402": {
            "description": "Pagamento necessário ou recusado; anuncia x402, crédito e cotação."
          },
          "403": {
            "description": "`invalid_origin` / `invalid_csrf`: compra com o cookie da conta exige a mesma origem e X-CSRF-Token; nada cobrado."
          },
          "404": {
            "description": "Documento inexistente."
          },
          "409": {
            "description": "Cotação alterada/ausente, páginas desconhecidas ou geração indisponível; nada cobrado antes da autorização."
          },
          "413": {
            "description": "Corpo excedeu 4096 bytes."
          },
          "502": {
            "description": "Origem indisponível; não repita pagamento sem conferir o estado e o recibo. `pago_nao_registrado`: pagou e a gravação do direito falhou — guarde o `recibo`."
          },
          "503": {
            "description": "Pagamento sem configuração, `conta_indisponivel` ou `acesso_exige_pagamento` (documento nunca sai de graça); nada cobrado."
          }
        }
      }
    },
    "/exemplos": {
      "get": {
        "operationId": "get_exemplos",
        "summary": "Galeria de cinco documentos reais já processados: leitura, original, Markdown e ZIP gratuitos.",
        "description": "Devolve: HTML com exemplos prontos. Abrir ou baixar não gera processamento nem cobrança.",
        "responses": {
          "200": {
            "description": "HTML com exemplos prontos. Abrir ou baixar não gera processamento nem cobrança."
          }
        }
      }
    },
    "/api/exemplos": {
      "get": {
        "operationId": "get_api_exemplos",
        "summary": "Cinco exemplos prontos, com procedência, páginas, imagens, SHA-256 e links de leitura e download.",
        "description": "Devolve: { exemplos }",
        "responses": {
          "200": {
            "description": "{ exemplos }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "exemplos": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "documento_id, compra_id, titulo, local, descricao, paginas, imagens, sha256, gratuito=true, leitura_url, markdown_url, manifesto_url, original_url, arquivos_url e pacote_url."
                    }
                  },
                  "required": [
                    "exemplos"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/documento/{id}/cobranca": {
      "post": {
        "operationId": "post_api_documento_by_id_cobranca",
        "summary": "Reserva endereço/QR exclusivo para comprar seu acesso com USDC na Base.",
        "description": "Consulte GET /geracao e envie cotacao. Cada comprador paga, inclusive pronto. O serviço confirma USDC no bloco safe da Base; safe aguarda inclusão na L1, sem finalidade absoluta. Envie em até 30 min; observação por 24 h. Pagamento tardio, rede/moeda errada ou extração falha exige atendimento. Carteira/corretora pode cobrar taxa. Mesma X-Cobranca conserva cobrança/endereço. GET pago devolve acesso.codigo e cookie; para guardar na conta, POST /api/documento/:id/vincular com esse código (o site faz isso sozinho para quem está conectado). O pagamento simulado do ambiente de desenvolvimento não vale para depósito.\nDevolve: { acesso?, id, documento_id, rede, chain_id, moeda, contrato, endereco, paginas, preco_total_usd, recebido_usdc, restante_usdc, status, expira_em, verificada_em, detalhe, retry_after_s, pagamento_uri, transacoes }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID positivo do documento.",
            "example": "2110000"
          },
          {
            "name": "X-Cobranca",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "32 bytes aleatórios em 64 caracteres hex minúsculos. Gere e guarde antes do POST; reutilize no GET e em retries. Segredo de acesso à sua cobrança."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cotacao": {
                    "type": "object",
                    "description": "Cotação recebida no GET /geracao: paginas, source_sha256 e preco_total_usd."
                  }
                },
                "required": [
                  "cotacao"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ acesso?, id, documento_id, rede, chain_id, moeda, contrato, endereco, paginas, preco_total_usd, recebido_usdc, restante_usdc, status, expira_em, verificada_em, detalhe, retry_after_s, pagamento_uri, transacoes }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "acesso": {
                      "type": "object",
                      "description": "Após pagamento confirmado fora da sessão da conta: codigo privado e header X-Editalmd-Acesso. Guarde para reabrir ou para vincular a uma conta (POST /vincular). Não publique, não abre outro documento."
                    },
                    "id": {
                      "type": "string",
                      "description": "Identificador da cobrança, para atendimento."
                    },
                    "documento_id": {
                      "type": "integer",
                      "description": "Documento cotado."
                    },
                    "rede": {
                      "type": "string",
                      "description": "base; base-sepolia só no ambiente de desenvolvimento."
                    },
                    "chain_id": {
                      "type": "integer",
                      "description": "8453 em produção, 84532 no teste."
                    },
                    "moeda": {
                      "type": "string",
                      "description": "USDC."
                    },
                    "contrato": {
                      "type": "string",
                      "description": "Contrato USDC aceito nesta rede."
                    },
                    "endereco": {
                      "type": "string",
                      "description": "Endereço exclusivo desta cobrança. Nunca reutilize para outra."
                    },
                    "paginas": {
                      "type": "integer",
                      "description": "Páginas físicas confirmadas no documento."
                    },
                    "preco_total_usd": {
                      "type": "string",
                      "description": "Páginas × US$ 0,02; valor em USDC equivalente."
                    },
                    "recebido_usdc": {
                      "type": "string",
                      "description": "Soma de transferências confirmadas, seis casas decimais."
                    },
                    "restante_usdc": {
                      "type": "string",
                      "description": "Valor que falta; taxas da carteira/corretora não entram."
                    },
                    "status": {
                      "type": "string",
                      "description": "aguardando, expirada, pago, solicitada, gerando, pronto ou revisao."
                    },
                    "expira_em": {
                      "type": "string",
                      "description": "ISO UTC: envie em até 30 minutos."
                    },
                    "verificada_em": {
                      "type": "string",
                      "description": "Última observação da rede pelo servidor.",
                      "nullable": true
                    },
                    "detalhe": {
                      "type": "string",
                      "description": "Orientação quando precisar de atendimento.",
                      "nullable": true
                    },
                    "retry_after_s": {
                      "type": "integer",
                      "description": "30 segundos entre consultas."
                    },
                    "pagamento_uri": {
                      "type": "string",
                      "description": "URI EIP-681 para carteira/QR, com rede, contrato, destinatário e valor restante. Ausente após vencer ou pagar.",
                      "nullable": true
                    },
                    "transacoes": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "hash, valor_usdc e url do explorador para cada transferência."
                    }
                  },
                  "required": [
                    "id",
                    "documento_id",
                    "rede",
                    "chain_id",
                    "moeda",
                    "contrato",
                    "endereco",
                    "paginas",
                    "preco_total_usd",
                    "recebido_usdc",
                    "restante_usdc",
                    "status",
                    "expira_em",
                    "verificada_em",
                    "detalhe",
                    "retry_after_s",
                    "pagamento_uri",
                    "transacoes"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Documento/corpo inválido ou cotação ausente."
          },
          "401": {
            "description": "X-Cobranca inválido."
          },
          "404": {
            "description": "Cobrança inexistente para este documento e token."
          },
          "409": {
            "description": "Cotação alterada, páginas desconhecidas ou teto de cobranças atingido; não envie dinheiro."
          },
          "413": {
            "description": "Corpo maior que 4096 bytes."
          },
          "502": {
            "description": "Origem indisponível."
          },
          "503": {
            "description": "Checkout por depósito indisponível."
          }
        }
      },
      "get": {
        "operationId": "get_api_documento_by_id_cobranca",
        "summary": "Consulta endereço, confirmação, recibo e liberação da sua cobrança gratuitamente.",
        "description": "Reutilize X-Cobranca e respeite Retry-After. Consulta não escreve nem faz RPC blockchain. Quando gerando, use GET /geracao para fases/páginas; pronto libera os links de leitura. Em revisao, conserve ID e transações para atendimento, sem pagar novamente.\nDevolve: { acesso?, id, documento_id, rede, chain_id, moeda, contrato, endereco, paginas, preco_total_usd, recebido_usdc, restante_usdc, status, expira_em, verificada_em, detalhe, retry_after_s, pagamento_uri, transacoes }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID positivo do documento.",
            "example": "2110000"
          },
          {
            "name": "X-Cobranca",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "32 bytes aleatórios em 64 caracteres hex minúsculos. Gere e guarde antes do POST; reutilize no GET e em retries. Segredo de acesso à sua cobrança."
          }
        ],
        "responses": {
          "200": {
            "description": "{ acesso?, id, documento_id, rede, chain_id, moeda, contrato, endereco, paginas, preco_total_usd, recebido_usdc, restante_usdc, status, expira_em, verificada_em, detalhe, retry_after_s, pagamento_uri, transacoes }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "acesso": {
                      "type": "object",
                      "description": "Após pagamento confirmado fora da sessão da conta: codigo privado e header X-Editalmd-Acesso. Guarde para reabrir ou para vincular a uma conta (POST /vincular). Não publique, não abre outro documento."
                    },
                    "id": {
                      "type": "string",
                      "description": "Identificador da cobrança, para atendimento."
                    },
                    "documento_id": {
                      "type": "integer",
                      "description": "Documento cotado."
                    },
                    "rede": {
                      "type": "string",
                      "description": "base; base-sepolia só no ambiente de desenvolvimento."
                    },
                    "chain_id": {
                      "type": "integer",
                      "description": "8453 em produção, 84532 no teste."
                    },
                    "moeda": {
                      "type": "string",
                      "description": "USDC."
                    },
                    "contrato": {
                      "type": "string",
                      "description": "Contrato USDC aceito nesta rede."
                    },
                    "endereco": {
                      "type": "string",
                      "description": "Endereço exclusivo desta cobrança. Nunca reutilize para outra."
                    },
                    "paginas": {
                      "type": "integer",
                      "description": "Páginas físicas confirmadas no documento."
                    },
                    "preco_total_usd": {
                      "type": "string",
                      "description": "Páginas × US$ 0,02; valor em USDC equivalente."
                    },
                    "recebido_usdc": {
                      "type": "string",
                      "description": "Soma de transferências confirmadas, seis casas decimais."
                    },
                    "restante_usdc": {
                      "type": "string",
                      "description": "Valor que falta; taxas da carteira/corretora não entram."
                    },
                    "status": {
                      "type": "string",
                      "description": "aguardando, expirada, pago, solicitada, gerando, pronto ou revisao."
                    },
                    "expira_em": {
                      "type": "string",
                      "description": "ISO UTC: envie em até 30 minutos."
                    },
                    "verificada_em": {
                      "type": "string",
                      "description": "Última observação da rede pelo servidor.",
                      "nullable": true
                    },
                    "detalhe": {
                      "type": "string",
                      "description": "Orientação quando precisar de atendimento.",
                      "nullable": true
                    },
                    "retry_after_s": {
                      "type": "integer",
                      "description": "30 segundos entre consultas."
                    },
                    "pagamento_uri": {
                      "type": "string",
                      "description": "URI EIP-681 para carteira/QR, com rede, contrato, destinatário e valor restante. Ausente após vencer ou pagar.",
                      "nullable": true
                    },
                    "transacoes": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "hash, valor_usdc e url do explorador para cada transferência."
                    }
                  },
                  "required": [
                    "id",
                    "documento_id",
                    "rede",
                    "chain_id",
                    "moeda",
                    "contrato",
                    "endereco",
                    "paginas",
                    "preco_total_usd",
                    "recebido_usdc",
                    "restante_usdc",
                    "status",
                    "expira_em",
                    "verificada_em",
                    "detalhe",
                    "retry_after_s",
                    "pagamento_uri",
                    "transacoes"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Documento/corpo inválido ou cotação ausente."
          },
          "401": {
            "description": "X-Cobranca inválido."
          },
          "404": {
            "description": "Cobrança inexistente para este documento e token."
          },
          "409": {
            "description": "Cotação alterada, páginas desconhecidas ou teto de cobranças atingido; não envie dinheiro."
          },
          "413": {
            "description": "Corpo maior que 4096 bytes."
          },
          "502": {
            "description": "Origem indisponível."
          },
          "503": {
            "description": "Checkout por depósito indisponível."
          }
        }
      }
    },
    "/api/cobranca/{id}/registrar": {
      "post": {
        "operationId": "post_api_cobranca_by_id_registrar",
        "summary": "Operação interna para registrar transferência confirmada no razão financeiro.",
        "description": "Uso exclusivo da origem autenticada. A prova é verificada pelo serviço, nunca aceita do corpo. Repetição registra cada evento uma única vez.\nDevolve: { registrado }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "UUID da cobrança.",
            "example": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
          },
          {
            "name": "X-Editalmd-Secret",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Segredo compartilhado da origem; somente operador."
          }
        ],
        "responses": {
          "200": {
            "description": "{ registrado }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "registrado": {
                      "type": "object",
                      "description": "Todos os eventos registrados ou já existentes."
                    }
                  },
                  "required": [
                    "registrado"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Sem autoridade da origem."
          },
          "404": {
            "description": "Cobrança inexistente na origem."
          },
          "409": {
            "description": "Pagamento não confirmado."
          },
          "503": {
            "description": "Registro indisponível; tente novamente conforme a orientação do serviço."
          }
        }
      }
    },
    "/api/documento/{id}/dossie": {
      "get": {
        "operationId": "get_api_documento_by_id_dossie",
        "summary": "Dados estruturados: exigências, itens, atestados, prazos, condições e evidências por página.",
        "description": "Dossiê incluído no acesso documental, sem nova análise ao consultar. Dados parciais informam cobertura; exportação exige versão concluída.\nDevolve: Página: data.version, data.complete, data.facts e data.next. Fatos conservam details tipados, applicability, exceptions, evidence (page/start/end/quote) e references. Duração exige quantidade e unidade associadas na evidência; duration_verification identifica correção ou revisão necessária, sem alterar a fonte. format=json: schema licitech-document-dossier-v1, version e facts completos, até 16 MiB.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do documento na ficha da compra.",
            "example": "9558909"
          },
          {
            "name": "v",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "SHA-256 do texto exibido; recusa versão diferente."
          },
          {
            "name": "after",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Cursor next anterior, padrão 0."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1 a 30 registros, padrão 30."
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "identity, item, requirement, attestation, deadline ou obligation."
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "page (padrão) ou json para download completo sem filtro/paginação."
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
          },
          {
            "name": "X-Editalmd-Avaliacao",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
          }
        ],
        "responses": {
          "200": {
            "description": "Página: data.version, data.complete, data.facts e data.next. Fatos conservam details tipados, applicability, exceptions, evidence (page/start/end/quote) e references. Duração exige quantidade e unidade associadas na evidência; duration_verification identifica correção ou revisão necessária, sem alterar a fonte. format=json: schema licitech-document-dossier-v1, version e facts completos, até 16 MiB."
          },
          "400": {
            "description": "Consulta inválida."
          },
          "402": {
            "description": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; cinco exemplos são gratuitos."
          },
          "404": {
            "description": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente."
          },
          "409": {
            "description": "Versão mudou ou exportação ainda em preparo."
          },
          "502": {
            "description": "Origem indisponível."
          }
        }
      }
    },
    "/licitacoes/": {
      "get": {
        "operationId": "get_licitacoes",
        "summary": "Navegação pública do acervo por modalidade, UF, data e município.",
        "description": "Devolve: HTML com navegação do EditalMD. Cada recorte oferece links para JSON, Markdown e OKF dos metadados.",
        "responses": {
          "200": {
            "description": "HTML com navegação do EditalMD. Cada recorte oferece links para JSON, Markdown e OKF dos metadados."
          }
        }
      }
    },
    "/licitacoes/compra/{id}/": {
      "get": {
        "operationId": "get_licitacoes_compra_by_id",
        "summary": "Ficha pública com documentos em modo de leitura: Markdown paginado, original e arquivos.",
        "description": "Devolve: HTML navegável. O leitor usa /api/compra/:id e a família /api/documento/:id; agentes devem consumir essas APIs diretamente.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador da compra.",
            "example": "1996190"
          },
          {
            "name": "doc",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Documento a abrir."
          },
          {
            "name": "pagina",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Página inicial, a partir de 1."
          },
          {
            "name": "vista",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "leitura, markdown, dados, exigencias, original, arquivos ou procedencia."
          },
          {
            "name": "tipo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Subaba: dados usa identity, item ou deadline; exigencias usa requirement, attestation ou obligation."
          }
        ],
        "responses": {
          "200": {
            "description": "HTML navegável. O leitor usa /api/compra/:id e a família /api/documento/:id; agentes devem consumir essas APIs diretamente."
          },
          "404": {
            "description": "Compra não encontrada."
          }
        }
      }
    },
    "/api/documento/{id}/original": {
      "get": {
        "operationId": "get_api_documento_by_id_original",
        "summary": "Baixar o original preservado, com o acesso comprado.",
        "description": "Entrega o arquivo disponível no acervo, sem iniciar nova extração.\nDevolve: Binário original (PDF, ZIP ou outro formato), até 96 MiB, com MIME e nome do arquivo.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do documento na ficha da compra.",
            "example": "9558909"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
          },
          {
            "name": "X-Editalmd-Avaliacao",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
          }
        ],
        "responses": {
          "200": {
            "description": "Binário original (PDF, ZIP ou outro formato), até 96 MiB, com MIME e nome do arquivo."
          },
          "402": {
            "description": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; cinco exemplos são gratuitos."
          },
          "404": {
            "description": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente."
          },
          "502": {
            "description": "Origem indisponível."
          }
        }
      }
    },
    "/api/documento/{id}/partes": {
      "get": {
        "operationId": "get_api_documento_by_id_partes",
        "summary": "Arquivos internos disponíveis no documento comprado.",
        "description": "Devolve: { data }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do documento na ficha da compra.",
            "example": "9558909"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
          },
          {
            "name": "X-Editalmd-Avaliacao",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
          }
        ],
        "responses": {
          "200": {
            "description": "{ data }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "description": "document_id e parts (até 200): id, idx, label, content_type, size_bytes, page_count, page_offset e arquivo_url relativo a /api/documento/:id/partes/:partId/arquivo. Lista vazia indica documento sem peças."
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; cinco exemplos são gratuitos."
          },
          "404": {
            "description": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente."
          },
          "409": {
            "description": "Arquivo ou índice ainda indisponível."
          },
          "422": {
            "description": "Pacote não pôde ser lido."
          },
          "502": {
            "description": "Origem indisponível."
          },
          "503": {
            "description": "Acervo ocupado; respeite Retry-After."
          }
        }
      }
    },
    "/api/documento/{id}/partes/{partId}/arquivo": {
      "get": {
        "operationId": "get_api_documento_by_id_partes_by_partid_arquivo",
        "summary": "Abrir ou baixar uma peça original com o acesso comprado ao documento.",
        "description": "Devolve: Binário pronto, até 96 MiB. PDF pode ser exibido no navegador; outros formatos podem ser baixados.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do documento na ficha da compra.",
            "example": "9558909"
          },
          {
            "name": "partId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "id da peça retornado em partes.",
            "example": "1"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
          },
          {
            "name": "X-Editalmd-Avaliacao",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
          }
        ],
        "responses": {
          "200": {
            "description": "Binário pronto, até 96 MiB. PDF pode ser exibido no navegador; outros formatos podem ser baixados."
          },
          "402": {
            "description": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; cinco exemplos são gratuitos."
          },
          "404": {
            "description": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente."
          },
          "502": {
            "description": "Origem indisponível."
          }
        }
      }
    },
    "/api/documento/{id}/leitura": {
      "get": {
        "operationId": "get_api_documento_by_id_leitura",
        "summary": "Manifesto do documento comprado: páginas físicas, imagens e hashes da extração atual.",
        "description": "Somente recursos prontos. Não inicia OCR. `document_approved: false` identifica a extração automática e não impede sua leitura.\nDevolve: { data }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do documento na ficha da compra.",
            "example": "9558909"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
          },
          {
            "name": "X-Editalmd-Avaliacao",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
          }
        ],
        "responses": {
          "200": {
            "description": "{ data }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "description": "schema licitech-document-package-v1; document_id, source_sha256, text_sha256, markdown_sha256, pages (number/start/end), images (sha256/filename/size_bytes/mime/width/height), occurrences (page/reference/start/end/sha256). Offsets UTF-16 de fonte.md."
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; cinco exemplos são gratuitos."
          },
          "404": {
            "description": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente."
          },
          "409": {
            "description": "Versão do texto alterada; abra o manifesto atual."
          },
          "502": {
            "description": "Origem indisponível."
          }
        }
      }
    },
    "/api/documento/{id}/pacote": {
      "get": {
        "operationId": "get_api_documento_by_id_pacote",
        "summary": "Baixar ZIP com Markdown e imagens do documento comprado para leitura fora do site.",
        "description": "Devolve: `application/zip`, até 96 MiB: documento.md, pasta imagens, fonte.md literal, manifesto.json e LEIA-ME.txt. Mantenha a pasta imagens junto do Markdown.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do documento na ficha da compra.",
            "example": "9558909"
          },
          {
            "name": "v",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "text_sha256 do manifesto; fixa a versão exibida no leitor."
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
          },
          {
            "name": "X-Editalmd-Avaliacao",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
          }
        ],
        "responses": {
          "200": {
            "description": "`application/zip`, até 96 MiB: documento.md, pasta imagens, fonte.md literal, manifesto.json e LEIA-ME.txt. Mantenha a pasta imagens junto do Markdown."
          },
          "400": {
            "description": "Versão inválida."
          },
          "402": {
            "description": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; cinco exemplos são gratuitos."
          },
          "404": {
            "description": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente."
          },
          "409": {
            "description": "Versão do texto alterada; abra o manifesto atual."
          },
          "502": {
            "description": "Origem indisponível."
          }
        }
      }
    },
    "/api/documento/{id}/imagens/{version}/{imageSha}": {
      "get": {
        "operationId": "get_api_documento_by_id_imagens_by_version_by_imagesha",
        "summary": "Imagem PNG/JPEG do documento comprado, conferida por hash.",
        "description": "Devolve: `image/png` ou `image/jpeg`, até 20 MiB por imagem. Não aceita URLs nem caminhos externos.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do documento na ficha da compra.",
            "example": "9558909"
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "text_sha256 do manifesto.",
            "example": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
          },
          {
            "name": "imageSha",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "sha256 da imagem presente no manifesto.",
            "example": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
          },
          {
            "name": "X-Agent-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
          },
          {
            "name": "X-Editalmd-Avaliacao",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
          },
          {
            "name": "X-Editalmd-Acesso",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
          }
        ],
        "responses": {
          "200": {
            "description": "`image/png` ou `image/jpeg`, até 20 MiB por imagem. Não aceita URLs nem caminhos externos."
          },
          "402": {
            "description": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; cinco exemplos são gratuitos."
          },
          "404": {
            "description": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente."
          },
          "409": {
            "description": "Versão do texto alterada; abra o manifesto atual."
          },
          "502": {
            "description": "Origem indisponível."
          }
        }
      }
    },
    "/api/precos": {
      "get": {
        "operationId": "get_api_precos",
        "summary": "O preço que ganha para um item parecido: mediana, quartis, desconto sobre a referência, quem vence e quem compra. Grátis.",
        "description": "Consulte resultados homologados por descrição do item. Além da amostra (`itens`), a resposta traz `resumo` (n, mediana, p25/p75, menor, maior, desconto mediano sobre o valor estimado pelo órgão, participação de ME/EPP, fornecedores e compradores distintos), `por_uf`, `por_mes`, `vencedores` (top 10 por itens ganhos e valor, com porte) e `compradores` (top 10 órgãos, com a última compra) — calculados sobre todos os candidatos do período, não só sobre a amostra. `amostra` diz o critério (até 2.000 itens mais parecidos pelo texto) e se bateu no teto. Unidade de medida é a publicada, sem normalização: compare `unidade` antes de comparar preço. Valores sem saneamento — a exclusão de inexequíveis/excessivos é decisão de quem pesquisa. Pessoa física vencedora sai sem CPF. Aceita também POST, PUT ou PATCH com os mesmos parâmetros em JSON ou formulário; `query`, `termo`, `busca` e `search` valem como `q`, `estado` como `uf`, `limit` como `limite`. Todo 400 traz `exemplo` e `doc`. `Accept: text/html` abre a aba Preços pagos com a consulta.\nDevolve: { consulta{q,expressao,uf,catmat,meses,desde,limite}, estatisticas{total,media,mediana,menor,maior,desvio_padrao}, resumo{n,mediana,p25,p75,menor,maior,media,desconto_mediano,com_referencia,me_epp,valor_total,fornecedores,compradores,ultima_homologacao}, por_uf[{uf,n,mediana,menor,maior,fornecedores,compradores,ultima_homologacao}], por_mes[{mes,n,mediana,menor,maior}], vencedores[{fornecedor_cnpj,pessoa_fisica,fornecedor,porte,itens,valor_total,menor,maior,compradores,ultima_homologacao}], compradores[{orgao_cnpj,orgao,uf,itens,compras,valor_total,fornecedores,ultima_homologacao}], amostra{candidatos,limitada,criterio,desde,ate}, itens[{compra_id,item,resultado,pncp,referencia,descricao,unidade,catmat,material_ou_servico,valor_unitario,valor_unitario_estimado,quantidade_homologada,fornecedor,fornecedor_cnpj,pessoa_fisica,fornecedor_porte,orgao,orgao_cnpj,municipio,uf,modalidade,homologado_em,publicado_em,compra_url}], base_legal, pago }",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Descrição do item; mínimo 3 letras, até 200."
          },
          {
            "name": "uf",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Sigla da UF do órgão comprador."
          },
          {
            "name": "meses",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 12
            },
            "description": "Janela de homologação em meses, 1 a 36."
          },
          {
            "name": "catmat",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Código do item no catálogo do governo, até 64 caracteres."
          },
          {
            "name": "limite",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50
            },
            "description": "1 a 100 itens."
          }
        ],
        "responses": {
          "200": {
            "description": "{ consulta{q,expressao,uf,catmat,meses,desde,limite}, estatisticas{total,media,mediana,menor,maior,desvio_padrao}, resumo{n,mediana,p25,p75,menor,maior,media,desconto_mediano,com_referencia,me_epp,valor_total,fornecedores,compradores,ultima_homologacao}, por_uf[{uf,n,mediana,menor,maior,fornecedores,compradores,ultima_homologacao}], por_mes[{mes,n,mediana,menor,maior}], vencedores[{fornecedor_cnpj,pessoa_fisica,fornecedor,porte,itens,valor_total,menor,maior,compradores,ultima_homologacao}], compradores[{orgao_cnpj,orgao,uf,itens,compras,valor_total,fornecedores,ultima_homologacao}], amostra{candidatos,limitada,criterio,desde,ate}, itens[{compra_id,item,resultado,pncp,referencia,descricao,unidade,catmat,material_ou_servico,valor_unitario,valor_unitario_estimado,quantidade_homologada,fornecedor,fornecedor_cnpj,pessoa_fisica,fornecedor_porte,orgao,orgao_cnpj,municipio,uf,modalidade,homologado_em,publicado_em,compra_url}], base_legal, pago }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Precos"
                }
              }
            }
          },
          "400": {
            "description": "Termo com menos de 3 letras, UF, meses, limite ou catmat fora do contrato — com `exemplo` e `doc`."
          },
          "502": {
            "description": "Origem indisponível."
          },
          "503": {
            "description": "Busca demorada: `busca_demorada`, com `Retry-After` — refine o termo ou filtre por UF."
          }
        }
      }
    },
    "/api/alertas/previa": {
      "post": {
        "operationId": "post_api_alertas_previa",
        "summary": "Testa termos e filtros ou sugere termos pelo CNPJ, sem criar alerta.",
        "description": "Devolve: { sugestoes, itens[{id,pncp,objeto,uf,modalidade,situacao,orgao,unidade,valor_estimado,publicado_em,informacao_complementar,processo,abertura_proposta,encerramento_proposta,amparo_legal,amparo_legal_codigo,modalidade_id,situacao_id,municipio,municipio_ibge,orgao_cnpj,ano_compra,sequencial_compra,atualizado_em,prazos,pncp_url,markdown_url,compra_url}], aviso, periodo_dias?, limite? }",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "termos": {
                    "type": "string",
                    "description": "3 a 200 caracteres; obrigatório sem CNPJ."
                  },
                  "cnpj": {
                    "type": "string",
                    "description": "CNPJ para sugerir até 8 famílias de termos, sem ativá-las."
                  },
                  "uf": {
                    "type": "string",
                    "description": "Sigla da UF."
                  },
                  "filtros": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/FiltrosInteresse"
                      }
                    ],
                    "description": "Recorte adicional: modalidades, municípios, exclusões, valores e propostas abertas. PATCH substitui o recorte inteiro; {} limpa."
                  }
                }
              },
              "example": {
                "termos": "uniforme escolar",
                "uf": "GO",
                "filtros": {
                  "modalidades": [
                    6
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ sugestoes, itens[{id,pncp,objeto,uf,modalidade,situacao,orgao,unidade,valor_estimado,publicado_em,informacao_complementar,processo,abertura_proposta,encerramento_proposta,amparo_legal,amparo_legal_codigo,modalidade_id,situacao_id,municipio,municipio_ibge,orgao_cnpj,ano_compra,sequencial_compra,atualizado_em,prazos,pncp_url,markdown_url,compra_url}], aviso, periodo_dias?, limite? }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sugestoes": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Família, nome, termos editáveis e CNAEs; só no modo CNPJ."
                    },
                    "itens": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Compra"
                      },
                      "description": "Até 20 compras dos últimos 7 dias; cada uma tem url para a ficha."
                    },
                    "aviso": {
                      "type": "string",
                      "description": "Limites da amostra ou da sugestão."
                    },
                    "periodo_dias": {
                      "type": "integer",
                      "description": "7, só na amostra por termos."
                    },
                    "limite": {
                      "type": "integer",
                      "description": "20, só na amostra por termos."
                    }
                  },
                  "required": [
                    "sugestoes",
                    "itens",
                    "aviso"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Termos, CNPJ, UF ou filtros inválidos."
          },
          "404": {
            "description": "Empresa não encontrada."
          },
          "503": {
            "description": "Origem indisponível."
          }
        }
      }
    },
    "/api/salvas": {
      "get": {
        "operationId": "get_api_salvas",
        "summary": "Lista até 200 licitações salvas pelo dono, gratuitamente.",
        "description": "Devolve: { itens[{compra_id,compra,salvo_em,url}], limite }",
        "responses": {
          "200": {
            "description": "{ itens[{compra_id,compra,salvo_em,url}], limite }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CompraSalva"
                      },
                      "description": "Mais recentes primeiro; retrato obtido ao salvar."
                    },
                    "limite": {
                      "type": "integer",
                      "description": "200 por dono."
                    }
                  },
                  "required": [
                    "itens",
                    "limite"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Token de dono ausente ou inválido."
          },
          "503": {
            "description": "Banco indisponível."
          }
        }
      }
    },
    "/api/salvas/{id}": {
      "get": {
        "operationId": "get_api_salvas_by_id",
        "summary": "Consulta uma licitação salva pelo dono.",
        "description": "Salvar não cria vigia nem notificação. O cliente fornece somente o ID; o retrato vem do acervo.\nDevolve: { salva{compra_id,compra,salvo_em,url} }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador da compra no acervo.",
            "example": "42"
          }
        ],
        "responses": {
          "200": {
            "description": "{ salva{compra_id,compra,salvo_em,url} }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "salva": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/CompraSalva"
                        }
                      ],
                      "description": "Licitação salva."
                    }
                  },
                  "required": [
                    "salva"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Token de dono ausente ou inválido."
          },
          "404": {
            "description": "Compra não encontrada."
          },
          "409": {
            "description": "Limite de 200 salvas atingido."
          },
          "503": {
            "description": "Banco, origem ou orçamento diário indisponível."
          }
        }
      },
      "put": {
        "operationId": "put_api_salvas_by_id",
        "summary": "Salva a licitação gratuitamente; repetir não duplica.",
        "description": "Salvar não cria vigia nem notificação. O cliente fornece somente o ID; o retrato vem do acervo.\nDevolve: { salva{compra_id,compra,salvo_em,url} }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador da compra no acervo.",
            "example": "42"
          }
        ],
        "responses": {
          "200": {
            "description": "{ salva{compra_id,compra,salvo_em,url} }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "salva": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/CompraSalva"
                        }
                      ],
                      "description": "Licitação salva."
                    }
                  },
                  "required": [
                    "salva"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Token de dono ausente ou inválido."
          },
          "404": {
            "description": "Compra não encontrada."
          },
          "409": {
            "description": "Limite de 200 salvas atingido."
          },
          "503": {
            "description": "Banco, origem ou orçamento diário indisponível."
          }
        }
      },
      "delete": {
        "operationId": "delete_api_salvas_by_id",
        "summary": "Remove a licitação da lista pessoal; repetir é seguro.",
        "description": "Salvar não cria vigia nem notificação. O cliente fornece somente o ID; o retrato vem do acervo.\nDevolve: 204 sem corpo.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador da compra no acervo.",
            "example": "42"
          }
        ],
        "responses": {
          "200": {
            "description": "204 sem corpo."
          },
          "401": {
            "description": "Token de dono ausente ou inválido."
          },
          "404": {
            "description": "Compra não encontrada."
          },
          "409": {
            "description": "Limite de 200 salvas atingido."
          },
          "503": {
            "description": "Banco, origem ou orçamento diário indisponível."
          }
        }
      }
    },
    "/api/alertas": {
      "post": {
        "operationId": "post_api_alertas",
        "summary": "Cria alertas de compra nova: por termos do objeto e UF, ou pelo CNPJ da empresa (um alerta por família de atividade), entregues por pull, webhook ou e-mail.",
        "description": "Dois modos. Por `termos`: espaço exige todas as palavras, `|` aceita qualquer uma do grupo (`uniforme|fardamento escolar`). Por `cnpj`: o cadastro da empresa informa as atividades (CNAE), o dicionário (`GET /api/cnaes`) transforma cada CNAE numa família de termos e sai um alerta por família distinta, principal primeiro, até `max_familias`; CNAE fora do dicionário não vira alerta e é listado em `empresa.cnaes` com `familia: null`. O primeiro alerta ativo é grátis (`FRANQUIA_ALERTAS`); os seguintes custam `PRECO_ALERTA` por 30 dias cada — no modo CNPJ, numa cobrança só (N × preço), por x402 ou crédito. O cron confere a cada 30 minutos. Canal e-mail exige a sessão da conta — o aviso vai para o e-mail verificado dela, sem código de confirmação — e só existe com `EMAIL_ALERTAS=1`.\nDevolve: { alerta?{id,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url}, alertas?[{id,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url}], empresa?{cnpj,cnpj_formatado,razao_social,nome_fantasia,situacao,uf,municipio,cnaes}, nao_criados?[{familia,nome,termos,cnaes,motivo}], pagamento }",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "termos": {
                    "type": "string",
                    "description": "Palavras do objeto da compra (3 a 200 letras); espaço = todas, `|` = qualquer uma do grupo. Obrigatório sem `cnpj`; ignorado com `cnpj`."
                  },
                  "cnpj": {
                    "type": "string",
                    "description": "CNPJ da empresa (14 dígitos, com ou sem pontuação): os termos saem das atividades (CNAE) dela, um alerta por família."
                  },
                  "max_familias": {
                    "type": "integer",
                    "description": "Só com `cnpj`: quantas famílias viram alerta, principal primeiro (1 a 8)."
                  },
                  "uf": {
                    "type": "string",
                    "description": "Sigla da UF para restringir; sem UF vale o Brasil inteiro."
                  },
                  "filtros": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/FiltrosInteresse"
                      }
                    ],
                    "description": "Recorte adicional: modalidades, municípios, exclusões, valores e propostas abertas. PATCH substitui o recorte inteiro; {} limpa."
                  },
                  "canal": {
                    "type": "string",
                    "description": "`pull` (só a API), `webhook` (POST na sua URL https) ou `email` (e-mail verificado da conta; exige sessão)."
                  },
                  "destino": {
                    "type": "string",
                    "description": "URL https pública na porta 443, sem credencial (webhook). Ignorado no pull e no e-mail."
                  }
                }
              },
              "example": {
                "termos": "uniforme|fardamento escolar",
                "uf": "GO",
                "canal": "pull"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ alerta?{id,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url}, alertas?[{id,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url}], empresa?{cnpj,cnpj_formatado,razao_social,nome_fantasia,situacao,uf,municipio,cnaes}, nao_criados?[{familia,nome,termos,cnaes,motivo}], pagamento }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "alerta": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Alerta"
                        }
                      ],
                      "description": "O alerta criado (modo termos)."
                    },
                    "alertas": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Alerta"
                      },
                      "description": "Os alertas criados, um por família (modo CNPJ)."
                    },
                    "empresa": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Empresa"
                        }
                      ],
                      "description": "A ficha resumida e cada CNAE com a família que o acionou (modo CNPJ)."
                    },
                    "nao_criados": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FamiliaNaoCriada"
                      },
                      "description": "Famílias que ficaram de fora por `max_familias` (modo CNPJ)."
                    },
                    "pagamento": {
                      "type": "object",
                      "description": "`via` (franquia, credito ou x402), `preco_usd`, `pago_ate` e, no modo CNPJ, `alertas_pagos` e `preco_unitario_usd`."
                    }
                  },
                  "required": [
                    "pagamento"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Termos, CNPJ, UF, canal ou destino inválidos."
          },
          "401": {
            "description": "Sem token de convidado nem sessão da conta, token desconhecido, ou `session_ended` (cookie de sessão vencida: entre de novo)."
          },
          "402": {
            "description": "Acima da franquia sem pagamento — `accepts[]` do x402 e o caminho do crédito."
          },
          "403": {
            "description": "`email_exige_conta`: canal e-mail sem a sessão da conta (convidado não tem e-mail); ou `invalid_origin`/`invalid_csrf` na escrita com o cookie da conta."
          },
          "404": {
            "description": "CNPJ não encontrado na base consultada."
          },
          "422": {
            "description": "CNPJ sem nenhuma atividade no dicionário: crie por termos (a resposta traz os CNAEs)."
          },
          "502": {
            "description": "`pago_nao_registrado`: o pagamento entrou e a gravação da compra falhou — guarde o `recibo`; o alerta não foi criado."
          },
          "503": {
            "description": "Canal e-mail desligado, ou a consulta ao CNPJ indisponível agora (`retry_after`)."
          }
        }
      },
      "get": {
        "operationId": "get_api_alertas",
        "summary": "Lista os alertas deste dono, os mais novos primeiro.",
        "description": "Devolve: { itens[{id,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url}], total, franquia_alertas }",
        "responses": {
          "200": {
            "description": "{ itens[{id,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url}], total, franquia_alertas }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Alerta"
                      },
                      "description": "Até 50 alertas do dono."
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total de alertas deste dono, incluindo pausados; não se limita aos 50 itens da resposta."
                    },
                    "franquia_alertas": {
                      "type": "integer",
                      "description": "Quantos alertas ativos são grátis."
                    }
                  },
                  "required": [
                    "itens",
                    "total",
                    "franquia_alertas"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Sem token de convidado nem sessão da conta, token desconhecido, ou `session_ended` (cookie de sessão vencida: entre de novo)."
          },
          "403": {
            "description": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token."
          },
          "503": {
            "description": "`conta_indisponivel`: conta fora do ar agora; nada muda."
          }
        }
      }
    },
    "/api/alertas/{id}": {
      "get": {
        "operationId": "get_api_alertas_by_id",
        "summary": "Um alerta do dono, com os filtros e a data da última verificação.",
        "description": "Devolve: { alerta{id,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url} }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do alerta, devolvido na criação.",
            "example": "9f3c…"
          }
        ],
        "responses": {
          "200": {
            "description": "{ alerta{id,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url} }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "alerta": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Alerta"
                        }
                      ],
                      "description": "O alerta."
                    }
                  },
                  "required": [
                    "alerta"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Sem token de convidado nem sessão da conta, token desconhecido, ou `session_ended` (cookie de sessão vencida: entre de novo)."
          },
          "403": {
            "description": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token."
          },
          "404": {
            "description": "Alerta inexistente ou de outro dono."
          },
          "503": {
            "description": "`conta_indisponivel`: conta fora do ar agora; nada muda."
          }
        }
      },
      "patch": {
        "operationId": "patch_api_alertas_by_id",
        "summary": "Pausa, reativa ou muda termos, UF, filtros, canal e destino de um alerta.",
        "description": "Devolve: { alerta{id,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url} }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do alerta.",
            "example": "9f3c…"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ativo": {
                    "type": "boolean",
                    "description": "`false` pausa sem apagar; `true` reativa."
                  },
                  "termos": {
                    "type": "string",
                    "description": "Novos termos do objeto (3 a 200 letras; `|` = qualquer uma do grupo)."
                  },
                  "uf": {
                    "type": "string",
                    "description": "Nova UF; vazio tira a restrição."
                  },
                  "filtros": {
                    "allOf": [
                      {
                        "$ref": "#/components/schemas/FiltrosInteresse"
                      }
                    ],
                    "description": "Recorte adicional: modalidades, municípios, exclusões, valores e propostas abertas. PATCH substitui o recorte inteiro; {} limpa."
                  },
                  "canal": {
                    "type": "string",
                    "description": "Novo canal: `pull`, `webhook` ou `email` (e-mail verificado da conta; exige sessão)."
                  },
                  "destino": {
                    "type": "string",
                    "description": "Nova URL https na porta 443 (webhook). Ignorado no pull e no e-mail."
                  }
                }
              },
              "example": {
                "ativo": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ alerta{id,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url} }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "alerta": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Alerta"
                        }
                      ],
                      "description": "O alerta depois da mudança."
                    }
                  },
                  "required": [
                    "alerta"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Nada para mudar ou valor inválido."
          },
          "401": {
            "description": "Sem token de convidado nem sessão da conta, token desconhecido, ou `session_ended` (cookie de sessão vencida: entre de novo)."
          },
          "402": {
            "description": "Reativar além da franquia, fora da janela paga, sem pagamento — `accepts[]` do x402 e o caminho do crédito."
          },
          "403": {
            "description": "`email_exige_conta`: canal e-mail sem a sessão da conta; ou `invalid_origin`/`invalid_csrf` na escrita com o cookie da conta."
          },
          "404": {
            "description": "Alerta inexistente ou de outro dono."
          },
          "502": {
            "description": "`pago_nao_registrado`: o pagamento da reativação entrou e a gravação falhou — guarde o `recibo`; o alerta segue pausado."
          },
          "503": {
            "description": "Canal e-mail desligado."
          }
        }
      },
      "delete": {
        "operationId": "delete_api_alertas_by_id",
        "summary": "Apaga o alerta e o histórico de compras casadas. Sem volta.",
        "description": "Devolve: 204 sem corpo.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do alerta.",
            "example": "9f3c…"
          }
        ],
        "responses": {
          "200": {
            "description": "204 sem corpo."
          },
          "401": {
            "description": "Sem token de convidado nem sessão da conta, token desconhecido, ou `session_ended` (cookie de sessão vencida: entre de novo)."
          },
          "403": {
            "description": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token."
          },
          "404": {
            "description": "Alerta inexistente ou de outro dono."
          },
          "503": {
            "description": "`conta_indisponivel`: conta fora do ar agora; nada muda."
          }
        }
      }
    },
    "/api/alertas/{id}/compras": {
      "get": {
        "operationId": "get_api_alertas_by_id_compras",
        "summary": "As compras que já casaram com o alerta — é o canal pull, e a prova do que foi entregue.",
        "description": "Devolve: { alerta{id,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url}, itens[{compra_id,status,visto_em,compra}], limite, proximo_antes }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do alerta.",
            "example": "9f3c…"
          },
          {
            "name": "limite",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "1 a 100 (padrão 50), IDs mais altos primeiro."
          },
          {
            "name": "antes_compra",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Use proximo_antes da página anterior para continuar."
          }
        ],
        "responses": {
          "200": {
            "description": "{ alerta{id,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url}, itens[{compra_id,status,visto_em,compra}], limite, proximo_antes }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "alerta": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Alerta"
                        }
                      ],
                      "description": "O alerta."
                    },
                    "itens": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AlertaCompra"
                      },
                      "description": "Compras casadas, com o status da entrega."
                    },
                    "limite": {
                      "type": "integer",
                      "description": "Teto aplicado."
                    },
                    "proximo_antes": {
                      "type": "integer",
                      "description": "Cursor da próxima página; nulo no fim.",
                      "nullable": true
                    }
                  },
                  "required": [
                    "alerta",
                    "itens",
                    "limite",
                    "proximo_antes"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Sem token de convidado nem sessão da conta, token desconhecido, ou `session_ended` (cookie de sessão vencida: entre de novo)."
          },
          "403": {
            "description": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token."
          },
          "404": {
            "description": "Alerta inexistente ou de outro dono."
          },
          "503": {
            "description": "`conta_indisponivel`: conta fora do ar agora; nada muda."
          }
        }
      }
    },
    "/api/vigias": {
      "post": {
        "operationId": "post_api_vigias",
        "summary": "Vigia uma compra: fotografa agora e avisa quando mudar — documento novo, suspensão, prazo adiado, valor — e nos prazos.",
        "description": "A primeira vigia ativa é grátis (`FRANQUIA_VIGIAS`); as seguintes custam `PRECO_VIGIA` até 30 dias após o encerramento. As verificações são periódicas; confira a data da última verificação na vigia. Avisos `prazo_impugnacao` (no dia) e `prazo_proposta` (24 h antes) saem uma vez cada.\nDevolve: { vigia{id,compra_id,canal,destino,ativo,pago_ate,ultimo_check,criado_em,vigia_url,eventos_url,compra_url}, snapshot{situacao_id,situacao,encerramento_proposta,valor_estimado,atualizado_em,documentos}, pagamento }",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "compra_id": {
                    "type": "integer",
                    "description": "Identificador da compra no acervo, vindo da busca."
                  },
                  "canal": {
                    "type": "string",
                    "description": "`pull` (ler em `/eventos`), `webhook` ou `email` (e-mail verificado da conta; exige sessão)."
                  },
                  "destino": {
                    "type": "string",
                    "description": "URL https pública na porta 443, sem credencial (webhook). Ignorado no pull e no e-mail."
                  }
                },
                "required": [
                  "compra_id"
                ]
              },
              "example": {
                "compra_id": 42,
                "canal": "pull"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ vigia{id,compra_id,canal,destino,ativo,pago_ate,ultimo_check,criado_em,vigia_url,eventos_url,compra_url}, snapshot{situacao_id,situacao,encerramento_proposta,valor_estimado,atualizado_em,documentos}, pagamento }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "vigia": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Vigia"
                        }
                      ],
                      "description": "A vigia criada."
                    },
                    "snapshot": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Snapshot"
                        }
                      ],
                      "description": "A fotografia inicial da compra."
                    },
                    "pagamento": {
                      "type": "object",
                      "description": "`via` (franquia, credito ou x402), `preco_usd` e `pago_ate`."
                    }
                  },
                  "required": [
                    "vigia",
                    "snapshot",
                    "pagamento"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "`compra_id`, canal ou destino inválidos."
          },
          "401": {
            "description": "Sem token de convidado nem sessão da conta, token desconhecido, ou `session_ended` (cookie de sessão vencida: entre de novo)."
          },
          "402": {
            "description": "Acima da franquia sem pagamento — `accepts[]` do x402 e o caminho do crédito."
          },
          "403": {
            "description": "`email_exige_conta`: canal e-mail sem a sessão da conta; ou `invalid_origin`/`invalid_csrf` na escrita com o cookie da conta."
          },
          "404": {
            "description": "Compra não encontrada no acervo."
          },
          "502": {
            "description": "`pago_nao_registrado`: o pagamento entrou e a gravação da compra falhou — guarde o `recibo`; a vigia não foi criada."
          },
          "503": {
            "description": "Canal e-mail desligado, ou origem indisponível."
          }
        }
      },
      "get": {
        "operationId": "get_api_vigias",
        "summary": "Lista as vigias deste dono, as mais novas primeiro.",
        "description": "Devolve: { itens[{id,compra_id,canal,destino,ativo,pago_ate,ultimo_check,criado_em,vigia_url,eventos_url,compra_url}], franquia_vigias }",
        "responses": {
          "200": {
            "description": "{ itens[{id,compra_id,canal,destino,ativo,pago_ate,ultimo_check,criado_em,vigia_url,eventos_url,compra_url}], franquia_vigias }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Vigia"
                      },
                      "description": "Até 50 vigias do dono."
                    },
                    "franquia_vigias": {
                      "type": "integer",
                      "description": "Quantas vigias ativas são grátis."
                    }
                  },
                  "required": [
                    "itens",
                    "franquia_vigias"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Sem token de convidado nem sessão da conta, token desconhecido, ou `session_ended` (cookie de sessão vencida: entre de novo)."
          },
          "403": {
            "description": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token."
          },
          "503": {
            "description": "`conta_indisponivel`: conta fora do ar agora; nada muda."
          }
        }
      }
    },
    "/api/vigias/{id}": {
      "get": {
        "operationId": "get_api_vigias_by_id",
        "summary": "Uma vigia do dono com a fotografia mais recente da compra.",
        "description": "Devolve: { vigia{id,compra_id,canal,destino,ativo,pago_ate,ultimo_check,criado_em,vigia_url,eventos_url,compra_url}, snapshot{situacao_id,situacao,encerramento_proposta,valor_estimado,atualizado_em,documentos} }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador da vigia, devolvido na criação.",
            "example": "2b7e…"
          }
        ],
        "responses": {
          "200": {
            "description": "{ vigia{id,compra_id,canal,destino,ativo,pago_ate,ultimo_check,criado_em,vigia_url,eventos_url,compra_url}, snapshot{situacao_id,situacao,encerramento_proposta,valor_estimado,atualizado_em,documentos} }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "vigia": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Vigia"
                        }
                      ],
                      "description": "A vigia."
                    },
                    "snapshot": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Snapshot"
                        }
                      ],
                      "description": "O que o cron viu por último."
                    }
                  },
                  "required": [
                    "vigia",
                    "snapshot"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Sem token de convidado nem sessão da conta, token desconhecido, ou `session_ended` (cookie de sessão vencida: entre de novo)."
          },
          "403": {
            "description": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token."
          },
          "404": {
            "description": "Vigia inexistente ou de outro dono."
          },
          "503": {
            "description": "`conta_indisponivel`: conta fora do ar agora; nada muda."
          }
        }
      },
      "delete": {
        "operationId": "delete_api_vigias_by_id",
        "summary": "Apaga a vigia e seus eventos. Sem volta.",
        "description": "Devolve: 204 sem corpo.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador da vigia.",
            "example": "2b7e…"
          }
        ],
        "responses": {
          "200": {
            "description": "204 sem corpo."
          },
          "401": {
            "description": "Sem token de convidado nem sessão da conta, token desconhecido, ou `session_ended` (cookie de sessão vencida: entre de novo)."
          },
          "403": {
            "description": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token."
          },
          "404": {
            "description": "Vigia inexistente ou de outro dono."
          },
          "503": {
            "description": "`conta_indisponivel`: conta fora do ar agora; nada muda."
          }
        }
      }
    },
    "/api/vigias/{id}/eventos": {
      "get": {
        "operationId": "get_api_vigias_by_id_eventos",
        "summary": "O que mudou na compra vigiada, evento a evento — é a série temporal e o canal pull.",
        "description": "Devolve: { vigia{id,compra_id,canal,destino,ativo,pago_ate,ultimo_check,criado_em,vigia_url,eventos_url,compra_url}, snapshot{situacao_id,situacao,encerramento_proposta,valor_estimado,atualizado_em,documentos}, itens[{id,tipo,antes,depois,visto_em,entregue_em}], limite }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador da vigia.",
            "example": "2b7e…"
          },
          {
            "name": "limite",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "1 a 100 (padrão 50), mais recentes primeiro."
          }
        ],
        "responses": {
          "200": {
            "description": "{ vigia{id,compra_id,canal,destino,ativo,pago_ate,ultimo_check,criado_em,vigia_url,eventos_url,compra_url}, snapshot{situacao_id,situacao,encerramento_proposta,valor_estimado,atualizado_em,documentos}, itens[{id,tipo,antes,depois,visto_em,entregue_em}], limite }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "vigia": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Vigia"
                        }
                      ],
                      "description": "A vigia."
                    },
                    "snapshot": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Snapshot"
                        }
                      ],
                      "description": "A fotografia atual."
                    },
                    "itens": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Evento"
                      },
                      "description": "Eventos registrados."
                    },
                    "limite": {
                      "type": "integer",
                      "description": "Teto aplicado."
                    }
                  },
                  "required": [
                    "vigia",
                    "snapshot",
                    "itens",
                    "limite"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Sem token de convidado nem sessão da conta, token desconhecido, ou `session_ended` (cookie de sessão vencida: entre de novo)."
          },
          "403": {
            "description": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token."
          },
          "404": {
            "description": "Vigia inexistente ou de outro dono."
          },
          "503": {
            "description": "`conta_indisponivel`: conta fora do ar agora; nada muda."
          }
        }
      }
    },
    "/api/credito": {
      "post": {
        "operationId": "post_api_credito",
        "summary": "Recarrega crédito pré-pago: paga uma vez com x402 e recebe o token que desconta em qualquer API da casa.",
        "description": "Devolve: { token, saldo_usd, guarde, usar, saldo_em }",
        "parameters": [
          {
            "name": "usd",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Pacote: 1, 5, 10 ou 25 dólares."
          }
        ],
        "responses": {
          "200": {
            "description": "{ token, saldo_usd, guarde, usar, saldo_em }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string",
                      "description": "Token portador do saldo (`cred_…`). Mostrado UMA vez — não há como recuperá-lo."
                    },
                    "saldo_usd": {
                      "type": "string",
                      "description": "Saldo creditado."
                    },
                    "guarde": {
                      "type": "string",
                      "description": "Aviso de que o token é o portador do crédito."
                    },
                    "usar": {
                      "type": "string",
                      "description": "Como apresentar o token nas rotas pagas."
                    },
                    "saldo_em": {
                      "type": "string",
                      "description": "Onde consultar saldo e extrato."
                    }
                  },
                  "required": [
                    "token",
                    "saldo_usd",
                    "guarde",
                    "usar",
                    "saldo_em"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Pacote fora da lista (1, 5, 10 ou 25)."
          },
          "402": {
            "description": "Sem pagamento — o corpo traz `accepts[]` do x402."
          }
        }
      },
      "get": {
        "operationId": "get_api_credito",
        "summary": "Saldo e extrato do crédito — as últimas movimentações, sem devolver o token.",
        "description": "Devolve: { saldo_micros, saldo_usd, criado_em, movimentos }",
        "responses": {
          "200": {
            "description": "{ saldo_micros, saldo_usd, criado_em, movimentos }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "saldo_micros": {
                      "type": "integer",
                      "description": "Saldo em micro-dólares (1e-6 USD)."
                    },
                    "saldo_usd": {
                      "type": "string",
                      "description": "Saldo formatado."
                    },
                    "criado_em": {
                      "type": "string",
                      "description": "Quando o crédito foi aberto."
                    },
                    "movimentos": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Entradas e saídas recentes, com produto e recurso."
                    }
                  },
                  "required": [
                    "saldo_micros",
                    "saldo_usd",
                    "criado_em",
                    "movimentos"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Sem token ou token desconhecido."
          }
        }
      }
    },
    "/api/visit": {
      "post": {
        "operationId": "post_api_visit",
        "summary": "Ping da interface que incrementa a visita do dia no painel do operador. Agente não precisa chamar.",
        "description": "Smoke não conta: `X-MM-Smoke`, User-Agent `mm-smoke` ou `smoke: true` no corpo entram como `counted: false`.\nDevolve: { ok, counted, reason? }",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "p": {
                    "type": "string",
                    "description": "Caminho da página visitada, só para agrupar."
                  },
                  "smoke": {
                    "type": "boolean",
                    "description": "`true` marca a chamada como teste e ela fica fora da contagem."
                  }
                }
              },
              "example": {
                "p": "/"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ ok, counted, reason? }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sempre `true`."
                    },
                    "counted": {
                      "type": "boolean",
                      "description": "Se a visita entrou na contagem do dia."
                    },
                    "reason": {
                      "type": "string",
                      "description": "Por que não contou, quando `counted` é `false`."
                    }
                  },
                  "required": [
                    "ok",
                    "counted"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/contact": {
      "post": {
        "operationId": "post_api_contact",
        "summary": "Contato e proposta de parceria: humano com Turnstile (grátis) ou agente com x402 $0.10.",
        "description": "O mesmo endereço para dúvida de quem usa e para proposta de patrocínio, parceria ou anúncio (`GET /api/partners` tem os espaços e os preços). Com `tipo`, o assunto identifica a proposta na caixa e o corpo abre com o bloco estruturado. Sem captcha e sem pagamento é 402 com as duas portas.\nDevolve: { ok, path }",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Nome de quem escreve (alias `nome`)."
                  },
                  "email": {
                    "type": "string",
                    "description": "Para onde responder."
                  },
                  "message": {
                    "type": "string",
                    "description": "A mensagem (alias `mensagem`)."
                  },
                  "form_ts": {
                    "type": "integer",
                    "description": "Epoch ms de quando o formulário abriu (2 s–12 h). Só o caminho humano exige."
                  },
                  "tipo": {
                    "type": "string",
                    "description": "Proposta: `patrocinio`, `parceria` ou `anuncio`. Liga os campos abaixo."
                  },
                  "empresa": {
                    "type": "string",
                    "description": "Quem propõe, quando é empresa."
                  },
                  "site": {
                    "type": "string",
                    "description": "Site de quem propõe."
                  },
                  "orcamento": {
                    "type": "string",
                    "description": "`ate_100`, `100_500`, `500_2000`, `2000_mais` ou `a_combinar`."
                  },
                  "espaco": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Ids de placement de `GET /api/partners`, até 6."
                  },
                  "duracao": {
                    "type": "string",
                    "description": "Dias de exposição: `30`, `90` ou `365`."
                  },
                  "pagamento": {
                    "type": "string",
                    "description": "`usdc`, `deposito` ou `a_combinar`."
                  }
                },
                "required": [
                  "name",
                  "email",
                  "message"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ ok, path }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Sempre `true` quando a mensagem foi aceita."
                    },
                    "path": {
                      "type": "string",
                      "description": "Por onde entrou: `human` com captcha ou `agent` pago."
                    }
                  },
                  "required": [
                    "ok",
                    "path"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Validação — o `code` diz o campo."
          },
          "402": {
            "description": "Agente: pague $0.10 e repita com X-PAYMENT."
          },
          "403": {
            "description": "Turnstile inválido."
          },
          "503": {
            "description": "Envio de e-mail indisponível."
          }
        }
      }
    },
    "/api/erro-cliente": {
      "post": {
        "operationId": "post_api_erro_cliente",
        "summary": "Relato de erro do navegador, enviado pela própria interface. Agente não precisa chamar.",
        "description": "A interface relata sozinha erro de JS, promessa rejeitada, script/CSS que não carregou e bloqueio de CSP — uma vez por sessão — e o app relata falha tratada por `window.mmErro.relata`. O servidor valida o envelope, redige credencial, e-mail e telefone, junta repetições da mesma falha por minuto e registra um evento operacional; nada é gravado em banco. Não guarda IP, cookie, query nem o User-Agent inteiro. Responde 204 sempre, inclusive para relato inválido.\nDevolve: 204 sem corpo, sempre — relato inválido, repetido ou acima do teto também recebe 204.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "description": "Código da falha, `UI-` + letras/dígitos (`UI-JS-001` erro global, `UI-PROMESSA-001`, `UI-RECURSO-001`, `UI-CSP-001`, `UI-APP-001` relato do app)."
                  },
                  "phase": {
                    "type": "string",
                    "description": "Fase em que quebrou, minúsculas: `global`, `promessa`, `script`, `carregar_lista`…"
                  },
                  "path": {
                    "type": "string",
                    "description": "Caminho da página aberta, sem query."
                  },
                  "message": {
                    "type": "string",
                    "description": "Mensagem do erro, até 2000 caracteres."
                  },
                  "stack": {
                    "type": "string",
                    "description": "Stack trace, até 12000 caracteres."
                  },
                  "source": {
                    "type": "string",
                    "description": "Script de origem; só o caminho é guardado."
                  },
                  "line": {
                    "type": "integer",
                    "description": "Linha no script de origem."
                  },
                  "column": {
                    "type": "integer",
                    "description": "Coluna no script de origem."
                  },
                  "visivel": {
                    "type": "boolean",
                    "description": "Se a aba estava visível quando quebrou."
                  }
                },
                "required": [
                  "code",
                  "phase"
                ]
              },
              "example": {
                "code": "UI-APP-001",
                "phase": "carregar_lista",
                "path": "/",
                "message": "lista 500"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "204 sem corpo, sempre — relato inválido, repetido ou acima do teto também recebe 204."
          }
        }
      }
    },
    "/api/pagamento/aberto": {
      "post": {
        "operationId": "post_api_pagamento_aberto",
        "summary": "A interface relata que exibiu uma cobrança. Agentes não devem chamar.",
        "description": "Relato sem corpo, da mesma origem, enviado automaticamente quando uma cobrança fica visível. Não inicia pagamento, não concede acesso e não recebe identidade ou credencial. Não grava banco por relato. Conta eventos, não pessoas únicas. O painel privado do operador separa pedidos de pagamento da API e aberturas da interface por dia UTC; os dois números podem se sobrepor.\nDevolve: 202 sem corpo se aceito; 204 se ignorado. Sempre no-store.",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "A origem da página, idêntica à desta rota."
          },
          {
            "name": "Sec-Fetch-Site",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "`same-origin`, definido pelo navegador."
          },
          {
            "name": "X-MM-Payment-View",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "`1`, definido pelo componente comum."
          }
        ],
        "responses": {
          "202": {
            "description": "202 sem corpo se aceito; 204 se ignorado. Sempre no-store."
          }
        }
      }
    },
    "/api/vitrine": {
      "get": {
        "operationId": "get_api_vitrine",
        "summary": "Os números públicos do produto: tráfego, agentes, uso e confiabilidade, sem dinheiro.",
        "description": "Projeção publicada de hora em hora pelo coletor da casa, arredondada a dois dígitos significativos; `null` é medição ausente, nunca zero. Cache de 15 minutos com ETag (`If-None-Match` → 304). Não há como enviar números por esta rota: a publicação é do coletor, com token próprio.\nDevolve: { v, produto, publicado, atualizado_em, stale, nome?, desde?, fuso?, hoje?, dias?, janelas?, visitantes?, pessoas?, agentes?, superficies?, mcp?, uso?, contas?, confiabilidade?, catalogo?, apoio? }",
        "responses": {
          "200": {
            "description": "{ v, produto, publicado, atualizado_em, stale, nome?, desde?, fuso?, hoje?, dias?, janelas?, visitantes?, pessoas?, agentes?, superficies?, mcp?, uso?, contas?, confiabilidade?, catalogo?, apoio? }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "v": {
                      "type": "integer",
                      "description": "Versão do contrato (1)."
                    },
                    "produto": {
                      "type": "string",
                      "description": "Id do produto."
                    },
                    "publicado": {
                      "type": "boolean",
                      "description": "`false` antes da primeira publicação do coletor; aí só estas cinco chaves vêm."
                    },
                    "atualizado_em": {
                      "type": "string",
                      "description": "Quando o coletor publicou (ISO 8601).",
                      "nullable": true
                    },
                    "stale": {
                      "type": "boolean",
                      "description": "`true` quando a projeção tem mais de 26 h."
                    },
                    "nome": {
                      "type": "string",
                      "description": "Nome do produto."
                    },
                    "desde": {
                      "type": "string",
                      "description": "Dia a partir do qual a série vale.",
                      "nullable": true
                    },
                    "fuso": {
                      "type": "string",
                      "description": "Fuso dos dias (`UTC`)."
                    },
                    "hoje": {
                      "type": "object",
                      "description": "O dia de hoje: páginas por classe (pessoa, IA, bot), chamadas de API por classe, leituras das superfícies de máquina e uso do produto."
                    },
                    "dias": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Até 31 dias, o mais antigo primeiro: `dia`, `paginas`, `api`, `api_ia`, `maquina`, `visitantes`, `uso`."
                    },
                    "janelas": {
                      "type": "object",
                      "description": "Somas de 7 e 30 dias (`d7`, `d30`)."
                    },
                    "visitantes": {
                      "type": "object",
                      "description": "Visitantes únicos na borda em 7 dias."
                    },
                    "pessoas": {
                      "type": "object",
                      "description": "GA4 quando há: usuários, sessões, países, aparelhos e quem chegou de IA.",
                      "nullable": true
                    },
                    "agentes": {
                      "type": "object",
                      "description": "Os agentes de IA e os bots que mais leem, 7 dias."
                    },
                    "superficies": {
                      "type": "object",
                      "description": "Leituras de OKF, llms, well-known, OpenAPI e MCP em 7 dias."
                    },
                    "mcp": {
                      "type": "object",
                      "description": "Chamadas MCP em 7 dias."
                    },
                    "uso": {
                      "type": "object",
                      "description": "Uso real do produto por recurso: rótulo, hoje, 7 e 30 dias."
                    },
                    "contas": {
                      "type": "object",
                      "description": "Usuários e convidados.",
                      "nullable": true
                    },
                    "confiabilidade": {
                      "type": "object",
                      "description": "Percentual de pedidos sem 5xx em 7 dias e o build no ar."
                    },
                    "catalogo": {
                      "type": "object",
                      "description": "Tamanho do acervo, quando o produto tem um.",
                      "nullable": true
                    },
                    "apoio": {
                      "type": "object",
                      "description": "Impressões e cliques por patrocinador, quando houver."
                    }
                  },
                  "required": [
                    "v",
                    "produto",
                    "publicado",
                    "atualizado_em",
                    "stale"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/vitrine/operador": {
      "get": {
        "operationId": "get_api_vitrine_operador",
        "summary": "O documento completo do produto no painel do operador — só com o token do operador.",
        "description": "Devolve: { produto, atualizado_em, operador }",
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "`Bearer <METRICS_TOKEN>` — a classe operador."
          }
        ],
        "responses": {
          "200": {
            "description": "{ produto, atualizado_em, operador }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "produto": {
                      "type": "string",
                      "description": "Id do produto."
                    },
                    "atualizado_em": {
                      "type": "string",
                      "description": "Quando o coletor publicou.",
                      "nullable": true
                    },
                    "operador": {
                      "type": "object",
                      "description": "O documento completo do coletor, com o que a projeção pública não carrega.",
                      "nullable": true
                    }
                  },
                  "required": [
                    "produto",
                    "atualizado_em",
                    "operador"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token errado ou token de outra classe."
          },
          "503": {
            "description": "Worker sem `METRICS_TOKEN` ou sem o control plane."
          }
        }
      }
    },
    "/api/vitrine/painel": {
      "get": {
        "operationId": "get_api_vitrine_painel",
        "summary": "O painel da casa inteira, na forma que o gm lê — só com o token do operador.",
        "description": "Devolve: { apps, updated?, totals? }",
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "`Bearer <METRICS_TOKEN>` — a classe operador."
          }
        ],
        "responses": {
          "200": {
            "description": "{ apps, updated?, totals? }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "apps": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Um documento do operador por produto, em ordem de id."
                    },
                    "updated": {
                      "type": "string",
                      "description": "Quando o coletor fechou a rodada."
                    },
                    "totals": {
                      "type": "object",
                      "description": "Os totais da casa."
                    }
                  },
                  "required": [
                    "apps"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token errado ou token de outra classe."
          },
          "503": {
            "description": "Worker sem `METRICS_TOKEN` ou sem o control plane."
          }
        }
      }
    },
    "/api/vitrine/cursores": {
      "get": {
        "operationId": "get_api_vitrine_cursores",
        "summary": "O cursor de erro resolvido por produto (`borda`, `cli`) — só com o token do operador.",
        "description": "Devolve: JSON: `{ [produto]: { borda?: ISO, cli?: ISO } }`; vazio é `{}`.",
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "`Bearer <METRICS_TOKEN>` — a classe operador."
          }
        ],
        "responses": {
          "200": {
            "description": "JSON: `{ [produto]: { borda?: ISO, cli?: ISO } }`; vazio é `{}`."
          },
          "401": {
            "description": "Sem token, token errado ou token de outra classe."
          },
          "503": {
            "description": "Worker sem `METRICS_TOKEN` ou sem o control plane."
          }
        }
      }
    },
    "/api/partners": {
      "get": {
        "operationId": "get_api_partners",
        "summary": "Parceria, patrocínio e anúncio: os espaços do produto com preço sugerido, os números públicos ao lado e como propor.",
        "description": "Informação sob consulta, sem ativação: espaços do catálogo da casa com preço em USD por 30 dias (90 e 365 dias com desconto), patrocinadores em vigor, recorte de `/api/vitrine`, carteira da casa (USDC na Base) e o caminho de contato — depósito, PIX ou fatura são combinados na resposta. Cache de 1 hora.\nDevolve: { status, produto, idioma, titulo, descricao, publico, modalidades, placements, house_bundle, parcerias, current_sponsors, stats, payment, contact, politica, _links }",
        "responses": {
          "200": {
            "description": "{ status, produto, idioma, titulo, descricao, publico, modalidades, placements, house_bundle, parcerias, current_sponsors, stats, payment, contact, politica, _links }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "`sob_consulta`: informação e proposta, sem ativação nem cobrança."
                    },
                    "produto": {
                      "type": "string",
                      "description": "Nome do produto."
                    },
                    "idioma": {
                      "type": "string",
                      "description": "Idioma dos textos (o do produto)."
                    },
                    "titulo": {
                      "type": "string",
                      "description": "Título da oferta."
                    },
                    "descricao": {
                      "type": "string",
                      "description": "Uma frase sobre a oferta."
                    },
                    "publico": {
                      "type": "string",
                      "description": "Quem usa o produto — o público que o patrocinador alcança."
                    },
                    "modalidades": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "`{ id, nome }`: patrocinio, parceria, anuncio."
                    },
                    "placements": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Os espaços do produto: `id`, `nome`, `onde`, `formato`, `exclusivo`, `medicao`, `price_usd_30d` (sugestão; `null` é sob consulta), `exposure[{ dias, price_usd }]` para 30, 90 e 365 dias, `disponivel`."
                    },
                    "house_bundle": {
                      "type": "object",
                      "description": "O pacote da casa: rodapé e menção para agentes nos dez produtos, com desconto."
                    },
                    "parcerias": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Ideias de parceria que o produto aceita discutir."
                    },
                    "current_sponsors": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Patrocinadores em vigor: `id`, `nome`, `url`, `frase`, `espacos`, `ate`."
                    },
                    "stats": {
                      "type": "object",
                      "description": "Recorte dos números públicos (`hoje`, `janelas`, `agentes`, `confiabilidade`) e o `link` para `/api/vitrine`; `publicado: false` antes da primeira publicação."
                    },
                    "payment": {
                      "type": "object",
                      "description": "Como pagar: `rede`, `chain_id`, `ativo`, `pay_to`, `eip681` (a carteira da casa, quando declarada), `alternativas` e a `nota` — depósito, PIX ou fatura pela resposta."
                    },
                    "contact": {
                      "type": "object",
                      "description": "`email`, `form_url`, `api_url` (`POST /api/contact` onde há handler), `campos` (os obrigatórios), `campos_proposta` (os opcionais da proposta, com os valores aceitos de cada um), `price_agent_usd`, `message_template`, `instructions`."
                    },
                    "politica": {
                      "type": "object",
                      "description": "Rótulo do espaço, setores recusados, pagamento adiantado, prazos."
                    },
                    "_links": {
                      "type": "object",
                      "description": "`self`, `stats`, `page` (`null` até a página existir), `contact`, `casa` (o mesmo caminho nos dez produtos)."
                    }
                  },
                  "required": [
                    "status",
                    "produto",
                    "idioma",
                    "titulo",
                    "descricao",
                    "publico",
                    "modalidades",
                    "placements",
                    "house_bundle",
                    "parcerias",
                    "current_sponsors",
                    "stats",
                    "payment",
                    "contact",
                    "politica",
                    "_links"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/metrics": {
      "get": {
        "operationId": "get_api_metrics",
        "summary": "Métricas dos últimos 7 dias para o painel do operador; com o token, inclui os pagamentos.",
        "description": "Sem credencial devolve visitas, uso (entregas de markdown, alertas, vigias). Com `METRICS_TOKEN` em Bearer acrescenta `payments` — só x402 liquidado em Base mainnet.\nDevolve: { app, today, today_visits, today_contacts?, days, usage, accounts, financeiro?, payments? }",
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "`Bearer <METRICS_TOKEN>` para incluir o bloco financeiro; token errado é 401."
          }
        ],
        "responses": {
          "200": {
            "description": "{ app, today, today_visits, today_contacts?, days, usage, accounts, financeiro?, payments? }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Metricas"
                }
              }
            }
          },
          "401": {
            "description": "Token de operador errado."
          },
          "503": {
            "description": "Worker sem METRICS_TOKEN configurado."
          }
        }
      }
    },
    "/api/recibo/{id}": {
      "get": {
        "operationId": "get_api_recibo_by_id",
        "summary": "Recibo de uma entrega — a prova de o que saiu, quanto custou e com qual hash.",
        "description": "Devolve: { recibo{id,recurso,documento_id,preco_usd,modo,sha256_entregue,bytes,criado_em} }",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identificador do recibo (32 hex), do header `x-editalmd-recibo`.",
            "example": "0c8f2b…"
          }
        ],
        "responses": {
          "200": {
            "description": "{ recibo{id,recurso,documento_id,preco_usd,modo,sha256_entregue,bytes,criado_em} }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "recibo": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Recibo"
                        }
                      ],
                      "description": "O recibo."
                    }
                  },
                  "required": [
                    "recibo"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Recibo não encontrado."
          }
        }
      }
    },
    "/api/acesso": {
      "get": {
        "operationId": "get_api_acesso",
        "summary": "Discover the monthly data package or inspect a private purchase.",
        "description": "Devolve: { offer{id,price_usd,credits,days,auto_renew,unit,products,purchase,method,status,header,payment_methods,instructions,generate_pass,client,guide,workflow,evaluation}, enabled?, id?, status?, granted_credits?, expires_at?, receipt?, via?, message? }",
        "parameters": [
          {
            "name": "X-API-Pass",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Private pass: api_<32 random hex>_<64 random hex>. Save before buying."
          }
        ],
        "responses": {
          "200": {
            "description": "{ offer{id,price_usd,credits,days,auto_renew,unit,products,purchase,method,status,header,payment_methods,instructions,generate_pass,client,guide,workflow,evaluation}, enabled?, id?, status?, granted_credits?, expires_at?, receipt?, via?, message? }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiAccess"
                }
              }
            }
          },
          "400": {
            "description": "Invalid pass."
          },
          "404": {
            "description": "Unknown purchase or wrong owner."
          },
          "503": {
            "description": "Purchases disabled."
          }
        }
      },
      "post": {
        "operationId": "post_api_acesso",
        "summary": "Buy 1000 basic data reads for US$1, valid for 30 days.",
        "description": "Same pass in retries recovers the same purchase. No automatic renewal. OCR, AI, documents and delivery keep their own tariffs. Send X-API-Pass on eligible data reads; remaining credits come in X-API-Credits-Remaining.\nDevolve: { offer{id,price_usd,credits,days,auto_renew,unit,products,purchase,method,status,header,payment_methods,instructions,generate_pass,client,guide,workflow,evaluation}, enabled?, id?, status?, granted_credits?, expires_at?, receipt?, via?, message? }",
        "parameters": [
          {
            "name": "X-API-Pass",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Private pass: api_<32 random hex>_<64 random hex>. Save before buying."
          },
          {
            "name": "X-Credito",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Existing prepaid credit token; alternative to x402."
          },
          {
            "name": "Authorization",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Bearer cred_… alternative to X-Credito."
          },
          {
            "name": "X-PAYMENT",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Signed x402 authorization from the 402 quote, maximum 16 KiB."
          },
          {
            "name": "PAYMENT-SIGNATURE",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Alternative name for X-PAYMENT."
          },
          {
            "name": "X-API-Transaction",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Confirmed Base transaction hash for reconciliation with the original pass and signed payment. Never creates another charge."
          }
        ],
        "responses": {
          "200": {
            "description": "{ offer{id,price_usd,credits,days,auto_renew,unit,products,purchase,method,status,header,payment_methods,instructions,generate_pass,client,guide,workflow,evaluation}, enabled?, id?, status?, granted_credits?, expires_at?, receipt?, via?, message? }",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiAccess"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid pass/payment."
          },
          "401": {
            "description": "Invalid prepaid credit."
          },
          "402": {
            "description": "Payment required: x402 accepts[] and prepaid-credit instructions."
          },
          "409": {
            "description": "Payment pending; retain the same pass and do not pay again."
          },
          "429": {
            "description": "Purchase attempt limit; respect Retry-After."
          },
          "503": {
            "description": "Payment unavailable or pending reconciliation."
          }
        }
      }
    },
    "/api/pricing": {
      "get": {
        "operationId": "get_api_pricing",
        "summary": "Preços vigentes e franquias gratuitas.",
        "description": "Devolve: { product, quota{free,paid,how_to_pay,live,free_now?,trial?}, pricing, billing, api_index }",
        "responses": {
          "200": {
            "description": "{ product, quota{free,paid,how_to_pay,live,free_now?,trial?}, pricing, billing, api_index }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "product": {
                      "type": "string",
                      "description": "Product name."
                    },
                    "quota": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/PaymentQuota"
                        }
                      ],
                      "description": "Public allowances and current list prices; not personal usage."
                    },
                    "pricing": {
                      "type": "string",
                      "description": "Absolute URL of the current price list."
                    },
                    "billing": {
                      "type": "string",
                      "description": "Absolute URL of payment discovery or the existing billing summary."
                    },
                    "api_index": {
                      "type": "string",
                      "description": "Absolute URL of the API catalog."
                    }
                  },
                  "required": [
                    "product",
                    "quota",
                    "pricing",
                    "billing",
                    "api_index"
                  ]
                }
              }
            }
          },
          "405": {
            "description": "Use GET ou HEAD."
          }
        }
      }
    },
    "/api/billing": {
      "get": {
        "operationId": "get_api_billing",
        "summary": "Descoberta pública de pagamento e crédito pré-pago.",
        "description": "Devolve: { product, quota{free,paid,how_to_pay,live,free_now?,trial?}, pricing, billing, api_index, payment{provider,mode,network,chain_id,pay_to,homolog,dev,dev_gate,gratis?,facilitator,asset,asset_address,faucet,wallets}, credit{url,header} }",
        "responses": {
          "200": {
            "description": "{ product, quota{free,paid,how_to_pay,live,free_now?,trial?}, pricing, billing, api_index, payment{provider,mode,network,chain_id,pay_to,homolog,dev,dev_gate,gratis?,facilitator,asset,asset_address,faucet,wallets}, credit{url,header} }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "product": {
                      "type": "string",
                      "description": "Product name."
                    },
                    "quota": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/PaymentQuota"
                        }
                      ],
                      "description": "Public allowances and current list prices; not personal usage."
                    },
                    "pricing": {
                      "type": "string",
                      "description": "Absolute URL of the current price list."
                    },
                    "billing": {
                      "type": "string",
                      "description": "Absolute URL of payment discovery or the existing billing summary."
                    },
                    "api_index": {
                      "type": "string",
                      "description": "Absolute URL of the API catalog."
                    },
                    "payment": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/PaymentX402"
                        }
                      ],
                      "description": "Public x402 configuration; pay_to=null means not configured."
                    },
                    "credit": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/PaymentCredit"
                        }
                      ],
                      "description": "Prepaid credit entry point. Never contains a balance or token."
                    }
                  },
                  "required": [
                    "product",
                    "quota",
                    "pricing",
                    "billing",
                    "api_index",
                    "payment",
                    "credit"
                  ]
                }
              }
            }
          },
          "405": {
            "description": "Use GET ou HEAD."
          }
        }
      }
    }
  }
}