# API de Dados Públicos — Portos, Hidrovias, Comércio Exterior, Leilões e Publicações Oficiais (ANTAQ · ONTL · Comex Stat)

> Quatro acervos: (1) microdados dos painéis públicos do setor aquaviário brasileiro — 15
> painéis, ~250 quadros, ~350 mil linhas, coleta diária das aplicações Qlik Sense da ANTAQ e
> do ONTL/Infra S.A., que exibem os números mas não publicam os microdados; (2) o Comex Stat
> (MDIC/SECEX) inteiro, 1989→hoje, 141,8 milhões de registros, cadência mensal; (3) o
> histórico dos leilões e audiências públicas da ANTAQ — 174 processos,
> 1.934 documentos e 157.222 cláusulas de editais e minutas de
> contrato, pesquisáveis no texto integral; (4) as publicações oficiais da ANTAQ no sistema
> Sophia — 21.091 atos de 2000 a
> 2026 (acórdãos, resoluções, portarias, deliberações) com o texto integral do
> PDF, 88.972.433 caracteres. Os dois últimos são **cópia manual, sem atualização
> automática**.

Acesso livre, sem credencial. Dados públicos (Lei 12.527/2011) — cite a fonte.

## As cinco regras do Comex Stat, antes da primeira chamada

Estas existem porque cada uma delas produz, se ignorada, um número plausível e errado.

1. **Código é texto, sempre.** 1.064 das 13.746 NCM começam com zero. `'0201...'` passado
   como número não casa com nada — e o sintoma é "sem comércio", não um erro.
2. **`ncm` e `municipio` são o MESMO comércio**, recortado de formas diferentes: os totais
   anuais são idênticos por construção, e somar as duas dobra a balança comercial do Brasil.
   A base `municipio` **não tem via, URF nem porto** — o cruzamento porto × município é
   impossível por construção da fonte, e o município é onde a EMPRESA é registrada, não por
   onde a carga passou.
3. **URF não é porto.** O Comex publica por unidade da Receita Federal (jurisdição
   aduaneira). Um porto pode ter várias URFs, uma URF pode cobrir vários portos, e há URF
   grande que não tem cais nenhum — a de Campos dos Goytacazes é petróleo offshore da Bacia
   de Campos. Use `/v1/comex/portos`, e não o nome da URF.
4. **Não compare tonelagem do Comex com movimentação da ANTAQ sem ler
   `/v1/comex/reconciliacao`.** O KG do Comex é LÍQUIDO, o da ANTAQ é BRUTO; a ANTAQ inclui
   cabotagem, transbordo e hidrovia interior, o Comex é só internacional. Medido em 2024: o
   Comex é 4,4% MAIOR na exportação aquaviária apesar de medir menos por tonelada. A
   reconciliação devolve a diferença decomposta, e ela **não fecha** — isso é resultado.
5. **Não há empresa, e não há contêiner.** O Comex Stat é anonimizado NA ORIGEM (Portaria
   SECINT 7.017/2020 art. 8): não existe CNPJ nem razão social. Nunca conclua que uma empresa
   não exporta a partir desta API. Contêiner e TEU não existem no Comex — para isso, o painel
   `estatistico_aquaviario`.

Bônus, porque usuários citam o manual: o manual v1.1 (2020) do MDIC manda **não usar VIA DE
TRANSPORTE a partir de 2018**. O aviso está vencido e foi medido neste acervo: `VIA
DESCONHECIDA` é 0,00% do FOB exportado em 2016-2025 e `NAO DECLARADA` no máximo 0,28%.
Cuidado inverso: a exportação amazônica sai codificada como `01 MARITIMA`, então somar só
fluvial e lacustre para dimensionar hidrovia interior conclui que ela não movimenta nada.

## As quatro regras dos leilões e audiências, antes da primeira chamada

1. **O tipo declarado discorda do NOME em 20,4%.** O campo de modalidade
   da origem e o nome do processo dizem coisas diferentes em 34 dos
   167 registros em que os dois se pronunciam — inclusive um
   "LEILÃO Nº 01/2026-ANTAQ" marcado como Audiência Pública. **A discordância vem da origem** e
   não há campo em base nenhuma que a resolva. Por isso `tipo` anda com `criterio_tipo`
   (`concordantes`, padrão; `declarado`; `nome`), e toda resposta filtrada por tipo conta e
   LISTA os divergentes. Nunca some por conta própria os totais de dois critérios.
2. **Só 361 dos 1.934 documentos têm texto pesquisável.** Os
   outros a ANTAQ não publicou em cláusulas, e para a busca eles são invisíveis. "Não achei"
   aqui quase sempre significa "a ANTAQ não publicou o texto deste documento", e NÃO "a ANTAQ
   não tratou do assunto" — o bloco `cobertura_da_busca` vem medido na hora exatamente para
   essa leitura não ser feita no escuro. O PDF não está em banco nenhum (é nulo na ORIGEM,
   não nesta cópia): documento sem arquivo responde 200 com o motivo e o caminho esperado,
   nunca 404.
3. **E do texto que existe, 12,2% vem CORTADO da origem** —
   19.140 dos 157.222 itens, em 186
   documentos, terminam no meio de uma palavra, porque o caminho de importação por planilha do
   SCLA trunca a cláusula em 255 caracteres. A cópia é fiel ao corte (a soma de caracteres bate
   com a medida feita na origem) e o que falta não está em lugar nenhum. Cada item traz
   `texto_cortado_na_origem`; cláusula marcada assim não é texto íntegro e não deve ser citada
   como tal.
4. **O acervo é uma cópia manual e congelada** — extraída em 2026-08-19, com
   dado até 2026-04-17. A ausência de um certame recente é falta de atualização,
   não ausência de certame. `/v1/leiloes/estado` diz exatamente quando foi copiado.
   67 processos têm **data-sentinela** (fim ou início em 2030 ou depois —
   "sem prazo definido" digitado como data) e saem como
   `situacao=indeterminada_por_data_sentinela`, nunca como oportunidade aberta.

Contribuições de audiência pública são **dado restrito** e saem só como contagem: nome,
CPF/CNPJ, e-mail, telefone, endereço e o teor de cada uma não foram copiados e não existem
neste banco. A distribuição por UF publica os baldes `--` (UF não declarada,
42,8% do total) e `--suprimido` (célula pequena demais), que
**aparecem** para a soma por estado continuar fechando com o total do processo.

## As quatro regras das publicações oficiais, antes da primeira chamada

1. **A espécie do ato é INFERÊNCIA nossa, tirada do título.** A origem não publica esse campo:
   `tipo_material` diz "Legislação" em 21.091 de 21.091
   registros, e por isso `autor`, `esfera` e `tipo_material` são **recusados** como filtro, com
   a medição junto — filtrar por eles devolveria o acervo inteiro com cara de recorte. As
   33 espécies saem do padrão `<Espécie> nº/<ano>` e se agrupam em
   23 FAMÍLIAS, que são o vocabulário para perguntar: `portaria_de_pessoal`
   (1.013 atos) é a família que responde "quem foi exonerado".
   18 títulos não têm chave nenhuma e ficam num balde que APARECE no
   resultado em vez de sumir da soma.
2. **A Ementa de Acórdão NÃO é o acórdão, e tem o mesmo número e o mesmo ano.** São
   2.852 ementas contra 4.177 acórdãos;
   2.842 pares resolvem 1-para-1 e
   4 chaves são ambíguas NA ORIGEM — nessas o par não é
   escolhido. A ementa é o RESUMO (1.085 caracteres de mediana
   contra 2.196): servi-la como "o texto do acórdão" entrega
   resumo como fundamentação, e resumo é completo, bem formado e citável. Toda resposta que
   toca num dos dois diz qual é qual e traz o par.
3. **Número sem ano não identifica ato.** A numeração da Resolução reiniciou em
   2021, e 55 números servem duas
   resoluções diferentes — pedido ambíguo é RECUSADO com os candidatos, nunca resolvido por
   escolha. E a **data de publicação é nula em 3.492 registros**,
   não ao acaso: são 99,9% das Ementas de Acórdão e
   35,4% das Portarias DG, que um recorte por
   data de publicação sumiria em silêncio. O padrão é `data_efetiva` (publicação, ou assinatura
   quando ela falta) e a resposta diz quantos CADA critério devolveria — "publicadas em 2025"
   tem mais de uma resposta certa. Pela mesma razão, **"Em vigor" é a situação DECLARADA pelo
   cadastro da biblioteca, não a garantia de que o texto está atual**: 18.433
   constam "Em vigor", 730 vêm em BRANCO (um terceiro estado,
   não um "não") e 98 atos "Em vigor" dizem no PRÓPRIO
   cabeçalho que foram alterados. Este acervo não publica o grafo de revogações.
4. **O texto é íntegro, mas íntegro não é FIEL.** Em 8.247 documentos o
   extrator não soube que letra era um glifo e escreveu `(cid:N)` ou um NUL no lugar dela — é o
   que faz uma busca por "artigo" não achar `ar(cid:68)go`. A regra reconstrói
   123.020 ocorrências pelo léxico do próprio corpus; sobram
   8.588 em 1.033 documentos, marcados
   trecho a trecho com `tem_residuo_de_extracao` — esses não devem ser colados em peça sem
   conferir o PDF. 964 documentos vieram de OCR, e 101 não têm
   texto nenhum: existem no catálogo e são INVISÍVEIS para a busca, que diz isso em
   `cobertura_da_busca`. **E a cópia é manual e termina em 2026-08-27** — não há um
   único ato de 2027 aqui, e ausência aqui não é ausência na ANTAQ.

O texto sai **sem máscara**: é ato publicado no Diário Oficial. O que não se faz é transformá-lo
em índice de pessoas — `assunto` não é filtro, não é coluna do CSV e não é campo de payload do
índice vetorial; ele é alcançável por `termo` e sai inteiro num ato por vez. E não há exportação
em massa do texto: `formato=csv` exporta o CATÁLOGO, e a recusa nomeia o que existe no lugar.

## Antes de sair consultando

- Baixe o catálogo inteiro de uma vez: `https://api-dados-antaq.up.railway.app/v1/dicionario` (~100 KB, painéis -> quadros -> colunas).
- Para um quadro inteiro, use `...?formato=csv` — uma requisição, streaming, em vez de paginar.
- Leia as `notas` de cada painel: elas descrevem defasagens e armadilhas reais da fonte, e o
  bloco `divergencias` traz, como DADO, os pontos em que dois quadros do mesmo painel não fecham.
- Só precisa de duas colunas? `...&coluna=Ano&coluna=UF` projeta no servidor (vale no CSV também).
- "Quantos X distintos **no total**?" é `.../valores?campo=X` → `n_valores`. Uma chamada só.
- "Quantos X distintos **por Ano**?" é `.../agregar?agrupar_por=Ano&operacao=contagem_distinta&medida=X`.
  Não some esses valores para obter o total: um X que aparece em dois anos seria contado duas vezes.
- `n_grupos` é o total REAL de grupos do recorte e `grupos_retornados` quantos couberam no
  `limite` (teto 1.000, sem paginação de grupos). Atenção: `n_grupos` conta também o grupo de
  célula vazia ou ausente; `n_valores` e `contagem_distinta` não contam.
- `&recorte=granel_solido_mineral` no `agregar` aplica uma **curadoria deste servidor** sobre a
  coluna de mercadoria do Estatístico Aquaviário. A ANTAQ **não** publica esse agrupamento, e a
  convenção inteira volta no bloco `recorte` do payload — definição, lista aplicada, itens de
  fronteira e as magnitudes medidas. Ele existe porque `Perfil da Carga = 'Granel Sólido'` não
  quer dizer mineral: a metodologia da própria ANTAQ classifica trigo e soja como granel sólido,
  e em Fortaleza o perfil sozinho dá 2,3x a 2,9x o recorte mineral, quase tudo trigo. Por padrão
  **filtra**; com `agrupar_por=recorte` (ou `recorte_balde`) devolve a **partição inteira**, em
  que somar os grupos reproduz o total do quadro e o balde `nao-catalogado` mostra a mercadoria
  que a fonte passou a publicar e a curadoria ainda não classificou.

## Endpoints

- `GET https://api-dados-antaq.up.railway.app/v1/paineis` — painéis disponíveis
- `GET https://api-dados-antaq.up.railway.app/v1/paineis/{painel}` — estrutura, colunas, filtros e notas
- `GET https://api-dados-antaq.up.railway.app/v1/paineis/{painel}/indicadores` — KPIs
- `GET https://api-dados-antaq.up.railway.app/v1/paineis/{painel}/quadros/{quadro}/dados` — linhas (`formato=csv` exporta tudo)
- `GET https://api-dados-antaq.up.railway.app/v1/paineis/{painel}/quadros/{quadro}/agregar` — contagem/contagem_distinta/soma/média/mín/máx por dimensão
- `GET https://api-dados-antaq.up.railway.app/v1/paineis/{painel}/quadros/{quadro}/valores?campo=` — valores distintos de uma coluna
- `GET https://api-dados-antaq.up.railway.app/v1/empresas/dossie?termo=` — cruza um CNPJ ou razão social por todos os painéis
  (painéis da ANTAQ apenas; o Comex Stat não identifica ninguém — ver regra 5)
- `GET https://api-dados-antaq.up.railway.app/v1/empresas/frota?cnpj=` — as embarcações que a empresa opera (`formato=csv`),
  com `idade_media_das_embarcacoes`. Ela NÃO vem do painel (que não publica ano de
  construção): vem do cadastro de embarcações da ANTAQ, ligado pelo NOME da embarcação —
  ponte deste repositório, 96,1% de cobertura. O que não resolve
  aparece em `nao_entraram` com o motivo; cite a média junto de `embarcacoes_na_conta` e
  `embarcacoes_na_frota`. A média nacional por tipo vai junto, nomeada como do SETOR — não é
  substituto. Rebocador entra por padrão; `excluir_tipos=rebocador` tira, e as excluídas são
  contadas.
- `GET https://api-dados-antaq.up.railway.app/v1/empresas/outorgas?cnpj=` — as outorgas de navegação e há quanto tempo a
  empresa é autorizada (`formato=csv`), com `termos_vigentes` (uma LISTA — dá para ter várias
  ao mesmo tempo), o número do processo em NUP e `linha_da_outorga`, a travessia **daquele
  termo**. A linha não vem do painel, que não liga instrumento a travessia: vem do cadastro
  interno de outorgas da ANTAQ (811 vínculos para
  730 termos), e é assim que deve ser citada. O singular só é
  preenchido quando o termo cobre uma travessia só — a regra, em
  654 dos 730 termos —, e
  `linha_da_outorga_estado` diz sempre por que está vazio; o código da travessia sai em campo
  próprio, ao lado do nome. Do mesmo cadastro vem o **número do ato**, ausente de todos os
  111 quadros do painel: `numero_do_termo_de_autorizacao`
  (2.425 dos 2.476 termos) é o número da
  autorização e não muda entre publicações; `instrumento_de_outorga` é o ato de cada uma, e
  `resolucao_da_outorga` a Resolução, sempre com o ano. O número do termo **não é chave** —
  150 servem mais de um termo. `n_outorgas` conta **termos**
  (processo × tipo de navegação), não publicações no DOU; o grão de registro sai ao lado, em
  `n_registros_de_outorga`. `tempo_de_outorga` é a **união** dos períodos: somar
  as linhas conta duas vezes o tempo de outorgas simultâneas — em
  740 das 1.893 empresas
  outorgadas, e no extremo dá 467,7 anos onde o real são
  19,3. A vigência sai da DATA, não do campo `Outorga Vigente` da origem,
  que diz 'Sim' em todas as linhas do acervo.
- `GET https://api-dados-antaq.up.railway.app/v1/status` — frescor dos dados
- `GET https://api-dados-antaq.up.railway.app/v1/limites` — sua cota agora
- OpenAPI: `https://api-dados-antaq.up.railway.app/openapi.json` · Documentação: `https://api-dados-antaq.up.railway.app/docs`

### Painéis, em português comum

Estas rotas leem os MESMOS painéis que `/v1/paineis/...`, mas o servidor escolhe o quadro e
declara qual escolheu. Use-as primeiro; a superfície genérica está lá para o que elas não
alcançam (etiqueta "Avançado — acesso genérico" no `/docs`).

- `GET https://api-dados-antaq.up.railway.app/v1/movimentacao?ano=&agrupar_por=&filtro=` — quanto se movimentou e
  transportou (`formato=csv`). **Dois painéis** publicam esta série e divergem no ano
  corrente: o Estatístico Aquaviário começa em 2021 e o ONTL vai a
  2010; `fonte` diz qual serviu e `ano_parcial` mede os dois na hora.
  **`medida=transporte` exige `navegacao`**: 'Vias Interiores' é um recorte por VIA e não um
  tipo de navegação — somar as três famílias infla 91,6 Mt com
  cara de total nacional. E as dimensões são declaradas por painel: das
  144 mercadorias de um e das 103 do outro
  só 27 nomes coincidem, então misturá-las é RECUSADO em vez de
  devolver vazio.
- `GET https://api-dados-antaq.up.railway.app/v1/instalacoes?termo=` — acha a grafia que a origem usa (`Tubarao` não casa
  `Terminal de Tubarão`); `GET https://api-dados-antaq.up.railway.app/v1/instalacoes/{nome}` traz o perfil completo de uma.
- `GET https://api-dados-antaq.up.railway.app/v1/acidentes?ano=&agrupar_por=` — acidentes, vítimas fatais, feridos e
  desaparecidos (`formato=csv`). Os seis recortes são a MESMA série — em
  2025 os 6 somam exatamente
  695 acidentes — e por isso `agrupar_por` aceita UMA dimensão: a
  origem não publica o cruzamento. Não há grão de acidente individual em lugar nenhum deste
  acervo. `GET https://api-dados-antaq.up.railway.app/v1/acidentes/valores?dimensao=` lista o vocabulário.
- `GET https://api-dados-antaq.up.railway.app/v1/hidrovias` — 61.969 km navegáveis em
  136 rios. **Nem toda coluna chamada "Extensão" é extensão**: o
  painel tem outra família com esse nome, 6.037x maior e
  usando os mesmos nomes de região. Esta rota serve a coerente e NOMEIA a outra em
  `medida_divergente_na_origem`, sem converter — a razão entre elas não é constante.
- `GET https://api-dados-antaq.up.railway.app/v1/hidrovias/carga?agrupar_por=` — carga em vias interiores (`formato=csv`).
  Os quadros da família **não somam o mesmo total**: rio dá 1,3x e
  hidrovia 1,4x o canônico (a viagem é contada uma vez por via), e os
  de UF dão 0,4x (cobrem só navegação interior). `grao_da_contagem` traz o
  fator MEDIDO no seu recorte e o total canônico ao lado.
- `GET https://api-dados-antaq.up.railway.app/v1/hidrovias/tku` e `GET https://api-dados-antaq.up.railway.app/v1/hidrovias/eclusas`. **Não existe TKU de
  longo curso**: a origem publica só interior (42,7 bi) e cabotagem
  (27,0 bi), e somar os dois dá o TKU de metade da carga.
- `GET https://api-dados-antaq.up.railway.app/v1/fiscalizacao?ano=&agrupar_por=` — processos sancionadores agregados; `GET
  https://api-dados-antaq.up.railway.app/v1/fiscalizacao/processos` traz o detalhe linha a linha (`formato=csv`).
  **A linha é uma infração julgada, não um processo**: 19.708 linhas para
  17.505 processos. **`Valor da Multa` tem três ausências** —
  3.319 com número, 11.876 arquivados
  sem irregularidade e 4.513 julgados sem multa —, e as três viram
  zero numa planilha. E a Base é 710 registros mais curta que os
  contadores do próprio painel: `cobertura_da_base` mede a diferença na hora.
  O CPF sai **mascarado** e **não é filtrável** (124 linhas da coluna que
  a origem chama de CNPJ são CPF de pessoa natural): o registro continua servido, com nome,
  infração e valor. `GET https://api-dados-antaq.up.railway.app/v1/fiscalizacao/valores?campo=` e
  `GET https://api-dados-antaq.up.railway.app/v1/fiscalizacao/normas` completam o vocabulário.
- `GET https://api-dados-antaq.up.railway.app/v1/multas` — a COBRANÇA (CADIN, arrecadação, AGU, parcelamentos). Painel
  diferente, grão diferente: **não se junta com `/v1/fiscalizacao` por ano** — o valor
  multado e o arrecadado num exercício são de processos diferentes, e a diferença não é
  inadimplência.
- `GET https://api-dados-antaq.up.railway.app/v1/terminais` — os 666 TUP, ETC e IP4 (`formato=csv`);
  `GET https://api-dados-antaq.up.railway.app/v1/arrendamentos?vigencia=` os 559 contratos de porto
  público (`formato=csv`). A vigência sai da DATA (234 vigentes,
  325 expirados), e os contadores do painel — que classificam
  491 — viajam ao lado para conferência.
  Perfil de carga e situação operacional existem **só no agregado**: o detalhe não tem a
  coluna, e filtrar por eles é pergunta que esta fonte não responde.
- `GET https://api-dados-antaq.up.railway.app/v1/tarifas?porto=` — a tarifa-teto como **distribuição**, nunca como um número:
  5.565 dos 36.820 pares (porto, forma)
  carregam mais de um valor, e a hierarquia que os separa está em quadros sem chave de
  junção. `cobertura_da_captura` diz que o detalhe é
  26,6% do que o
  painel conta. `GET https://api-dados-antaq.up.railway.app/v1/tarifas/homologacoes` e `GET https://api-dados-antaq.up.railway.app/v1/portos` completam.

### Comércio exterior

- `GET https://api-dados-antaq.up.railway.app/v1/comex/codigos` — sem parâmetro, o mapa das bases; `?termo=soja` acha o
  código **ordenado por valor comerciado**; `?dimensao=via` lista o vocabulário inteiro;
  `?nbm_ncm=12019000` atravessa a fronteira de 1997
- `GET https://api-dados-antaq.up.railway.app/v1/comex/consulta?periodo=&agrupar_por=` — a soma no grão pedido
  (`formato=csv` exporta o recorte inteiro; **não trunca** — recusa com 422 acima do teto)
- `GET https://api-dados-antaq.up.railway.app/v1/comex/portos` — a ponte URF → porto (`?cobertura=true` para o que falta curar)
- `GET https://api-dados-antaq.up.railway.app/v1/comex/reconciliacao?ano=` — a diferença Comex × ANTAQ, decomposta
- `GET https://api-dados-antaq.up.railway.app/v1/comex/estado` — cobertura e frescor do acervo do Comex

### Leilões e audiências

- `GET https://api-dados-antaq.up.railway.app/v1/leiloes` — a lista de processos; recorte por `tipo`, `criterio_tipo`,
  `situacao`, `ano`, `instalacao` (código do terminal no nome: STS10, RDJ07) e `termo` (no
  NOME). `formato=csv` baixa o catálogo inteiro — e **não filtra por tipo**: num CSV não há
  onde publicar o bloco dos divergentes, então as três colunas de tipo saem e o corte é seu
- `GET https://api-dados-antaq.up.railway.app/v1/leiloes/{cod}` — um processo inteiro: documentos, comunicados, cronograma,
  prazos e as contagens de participação social
- `GET https://api-dados-antaq.up.railway.app/v1/leiloes/documentos/{cod}` — um documento e seu texto em Markdown (acima de
  120 mil caracteres sai **paginado por item**, nunca cortado)
- `GET https://api-dados-antaq.up.railway.app/v1/leiloes/busca?termo=` — procura nas cláusulas; sem acento é igual a com
  (`licitacao` = `licitação`). Sempre volta com `cobertura_da_busca` e com
  `casamento_literal`, que confere palavra a palavra quantos acertos contêm o termo
  LITERALMENTE — a busca casa por radical, e `Pecém` casa também com `peças`. `formato=csv`
  é RECUSADO nesta rota e na de documento, com o motivo: o corpus tem 27 MB
- `GET https://api-dados-antaq.up.railway.app/v1/leiloes/estado` — de onde o acervo veio, quando foi copiado e o que a origem
  publica vazio

### Publicações oficiais

- `GET https://api-dados-antaq.up.railway.app/v1/publicacoes` — o catálogo; recorte por `termo` (título e assunto), `familia`
  (o vocabulário: `acordao`, `resolucao`, `portaria_de_pessoal`…), `especie` (as
  33 cruas), `ano` + `criterio_ano`, `de`/`ate`, `vigencia` e
  `com_nota_de_alteracao`. `formato=csv` baixa o catálogo inteiro **sem o texto** — e é a
  única exportação em massa deste acervo
- `GET https://api-dados-antaq.up.railway.app/v1/publicacoes/{codigo_registro}` — um ato inteiro, com o texto integral. Aceita
  também `?documento=Resolução 1274/2009` no catálogo, que resolve o ato pelo nome como ele é
  citado — e **RECUSA com os candidatos** quando o número sem ano serve mais de um
  (55 números de Resolução servem dois anos, porque a
  numeração reiniciou em 2021)
- `GET https://api-dados-antaq.up.railway.app/v1/publicacoes/busca?termo=` — procura no TEXTO, no grão do trecho.
  `modo=lexical` (padrão), `semantica` ou `hibrida` — as duas últimas dependem do índice
  vetorial e **dizem quando ele não está de pé**, em vez de devolver o lexical com cara de
  semântico. Toda resposta traz `cobertura_da_busca` (101 atos não têm texto e
  são invisíveis para ela) e `casamento_literal`, que é o que impede `2027` — dígitos
  colados a número de SEI em 67,3% das ocorrências — de sair
  como lista limpa num acervo que **termina em 2026-08-27**
- `GET https://api-dados-antaq.up.railway.app/v1/publicacoes/estado` — de onde o acervo veio, o teto da cópia, a distribuição
  por família e o que a origem publica vazio

Para o **articulado curado**, ancorado em artigo — o que a norma DIZ, e não o que a agência
publicou —, a seção é **Corpus normativo**, logo abaixo. As duas se apontam de propósito: uma
seta só orienta quem já abriu a rota certa, e procurar a LESTA aqui devolve o que o Diário
publicou sobre ela, que é uma resposta completa, bem formada e de outra pergunta.

### Corpus normativo

O que a norma **diz** — e não quanto/quantos. Não confunda com o acervo acima: lá está o que a
ANTAQ **publicou** (21.091 atos, inclusive o que nunca virou norma
consolidada); aqui estão 50 documentos **curados** e ancorados em artigo,
2.530 trechos, de 1954 a 2023. A escolha errada NÃO dá
erro: procurar um acórdão aqui devolve lista vazia, que se lê como "não houve".

- `GET https://api-dados-antaq.up.railway.app/v1/normas` — o catálogo, com a contagem por tipo; recorte por `tipo_documento`
  (`lei`, `decreto`, `resolucao`, `resolucao_normativa`, `portaria`, `manual`, `dicionario`,
  `glossario`), `ano` e `tema`. Os dois vocabulários são FECHADOS e o que está fora deles é
  **recusado com a lista**, nunca devolvido como zero — `tipo_documento=parecer` e "não há
  norma sobre isso" são respostas diferentes
- `GET https://api-dados-antaq.up.railway.app/v1/normas?documento=Lei 12.815` — um documento pela CITAÇÃO. É por aqui que se
  cita pelo nome: `Resolução 62/2021` tem barra e não caberia num segmento de caminho
- `GET https://api-dados-antaq.up.railway.app/v1/normas/{slug}` — o documento em ORDEM DE LEITURA, trecho a trecho, com
  `artigo` recortando um dispositivo
- `GET https://api-dados-antaq.up.railway.app/v1/normas/busca?termo=` — procura no TEXTO e devolve trechos com **citação
  canônica**. `modo=lexical` (padrão, full-text, cobre o corpus INTEIRO e é determinístico),
  `semantica` ou `hibrida` — as duas últimas dependem do índice vetorial e **dizem quando ele
  não está de pé**, em `busca_semantica` e `modo_efetivo`, em vez de devolver o lexical com
  cara de semântico. A lexical liga os termos por **AND**: frase longa devolve pouco por
  efeito da conjunção, não do corpus

Três coisas antes de citar. O **rótulo de artigo da base de origem erra o dispositivo em
68% dos trechos**, então a citação só nomeia artigo quando o próprio
texto ABRE o dispositivo — remissão e preâmbulo não contam, e nesses casos ela sai no grão do
documento com `artigo` nulo, em vez de nomear o artigo errado. **Íntegro não é fiel**: em dois
documentos (as duas resoluções do procedimento sancionador) a extração do PDF comeu letras, e
todo trecho deles vem com `texto_com_defeito_de_extracao` — serve para achar e ler o
dispositivo, não para transcrever. E **não há metadado de vigência em lugar nenhum deste
corpus**: um dispositivo revogado é indistinguível de um vigente, e nada aqui é posterior a
2023.

## Limites

Cota em unidades por faixa de IP: 120/minuto e 2000/hora. Custos: consulta 2, agregação 5,
rota amigável de painel 6 (8 nas exportações pequenas, 60 nas de `/v1/movimentacao` e
`/v1/fiscalizacao/processos`, que são os mesmos bytes de um quadro inteiro),
dossiê 10, exportação CSV 60, rotas do Comex 20, **exportação CSV do Comex 240**, rotas de
leilões 4 (20 na de documento), rotas de publicações 6 (20 no ato inteiro, 60 na exportação do
catálogo), rotas do corpus normativo 4 — com ou sem `modo=semantica`, e sem exportação CSV,
que esse acervo não oferece em interface nenhuma. A cota
corrente está em `/v1/limites` (as respostas de dados são cacheáveis e trazem só a política).
Respeite `Retry-After` em 429/503 e use `If-Modified-Since`/`If-None-Match` — resposta servida
do CDN não consome cota.

## MCP

Os mesmos dados como servidor MCP (Streamable HTTP): `https://dados-antaq.up.railway.app/mcp`
