Skip to content

API Pública v1

A API pública do Futuros é dado estático versionado. O Futuros é uma plataforma somente-frontend: não há servidor de consultas por trás de /api/v1/. Tudo é assado a partir de public/data/ por scripts/bake-api.ts e servido como arquivos simples pela CDN. Um portão pós-bake (scripts/check-api.ts, executado no mesmo passo de prebuild) verifica que o bake corresponde ao corpus — as contagens de citações batem, cada célula está coberta, os dumps em massa fazem parse, generated_at é pelo menos tão novo quanto o arquivo de dados mais recente — e falha o build diante de qualquer desvio, de modo que a árvore servida não pode ficar defasada. Cada endpoint abaixo é um simples HTTP GET de um arquivo — sem auth, sem chave de API, sem rate limit, totalmente cacheável.

  • URL base: https://futuros.xyz/api/v1/
  • Descoberta (catálogo DCAT): https://futuros.xyz/data.json (na raiz do site, não sob /api/v1/)
  • Página de docs para humanos: https://futuros.xyz/datos-abiertos?lang=pt

Como as respostas são arquivos estáticos, um endpoint é apenas o seu caminho. Busque um com curl, um navegador, fetch(), pandas.read_csv, R, ou qualquer cliente SDMX/DCAT.

Como a árvore é assada

bake-api.ts e depois check-api.ts rodam como os dois passos finais do prebuild (após o typecheck, a suíte de testes e os demais portões de dados), de modo que cada deploy re-assa /api/v1 a partir do public/data/ atual e prova o resultado antes que o vite build o embarque:

Invariantes do bake (scripts/bake-api.ts):

  • Promoção atômica. A árvore inteira é escrita em public/api/v1.tmp (mais public/data.json.tmp) e trocada sobre os caminhos vivos com renameSync como o último passo. Uma queda no meio do bake deixa a árvore anterior intacta — o fluxo antigo de apagar-e-repopular podia embarcar um /api/v1 escrito pela metade.
  • Fonte da célula. Uma célula = um envelope public/data/parameter-cache/<param>__<ISO3>.json; uma célula cujo payload não tem indicadores é pulada (o portão as conta como legitimamente ausentes, não como faltantes).
  • Achatamento em linhas. Uma linha CSV/SDMX por (indicador, ano). Anos duplicados dentro de uma série são descartados (a primeira ocorrência vence), e a linha da safra mais recente só é anexada quando a série ainda não contém aquele ano — um valor nunca é emitido duas vezes.
  • Neutralização de injeção de fórmulas (OWASP). Qualquer célula de texto começando com = + - @ (ou tab/CR inicial) recebe o prefixo ' antes de chegar ao CSV ou XLSX, para que Excel/Sheets/LibreOffice a renderizem como texto literal em vez de executá-la como fórmula. Números passam intocados.
  • Colunas somente anexadas. Novas colunas CSV são anexadas, nunca inseridas (label_en,label_pt ficam depois de citation_id), então parsers posicionais continuam funcionando e parsers por nome de cabeçalho captam as adições.
  • M49 vem assado. O mapa ISO3→M49 é uma tabela fixa de 26 entradas no baker (25 países + LATAM = 419), não um lookup em tempo de execução.

O que check-api.ts verifica (qualquer falha imprime um diff e sai com 1):

#AsserçãoDesvio que bloqueia
1index.json.counts.citations = comprimento de public/data/citations.jsonmanifesto fora de sincronia com o registro de citações
2toda célula de cache não vazia tem seu observations/<param>__<ISO3>.json assadocélulas descartadas silenciosamente
3CSV/SDMX/XLSX em massa existem, não estão vazios e fazem parse (CSV: cabeçalho + ≥1 linha; XLSX: abre)dumps em massa corrompidos
4mtime do arquivo index.json ≥ mtime mais novo de public/data − tolerância de 5 minbake defasado. Comparado mtime-vs-mtime porque checkouts do git reescrevem os mtimes dos arquivos de dados — a comparação antiga por generated_at falhava falsamente em checkouts frescos
5linhas de observação < 1.000.000estourar o teto de planilha única do XLSX (1.048.576 linhas)
6toda referência a persona/caso do índice de busca resolve para um arquivo em discoacertos de recuperação mortos (137 refs de persona mortas embarcaram em julho de 2026)
7rótulos ES/EN/PT completos e com correspondência exata ao registro de métricas, com piso de cobertura de instâncias ≥90%a API pública regredir a somente-espanhol, ou um join de rótulos silenciosamente dessincronizado

Contrato de estabilidade

O manifesto o declara literalmente:

Shapes are additive-only within v1; breaking changes go to /api/v2/.

Na prática:

  • Campos podem ser adicionados a qualquer objeto dentro da v1. Não assuma um conjunto fixo de chaves — leia por chave, ignore desconhecidas.
  • Nomes, tipos e significados de campos existentes não mudarão dentro da v1.
  • Uma mudança incompatível (renomear/remover um campo, mudar unidades ou semântica) sai como uma nova árvore /api/v2/; /api/v1/ continua funcionando.
  • index.json carrega api_version, generated_at e uma string stability — leia generated_at para detectar um rebuild.

CORS e cache

Definido em vercel.json para o caminho /api/v1/(.*):

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, OPTIONS
Cache-Control: public, max-age=3600, s-maxage=86400

Portanto a API de leitura é legível cross-origin de qualquer app de navegador (somente GET/OPTIONS — ela é somente-leitura), com cache de borda por um dia. Não há superfície de escrita aqui. Os endpoints dinâmicos (/api/chat, /api/mcp, …) definem seus próprios cabeçalhos em código; desses, apenas /api/mcp é cross-origin (*, POST, OPTIONS) — os demais são same-origin.

Licença e atribuição

De index.json:

  • license_url: https://creativecommons.org/licenses/by/4.0/ (CC BY 4.0)
  • license (literal): "Datos redistribuidos de fuentes abiertas; cada observación conserva su fuente primaria (source_name, source_url, citation_id). Al reutilizar: cite la fuente primaria de cada observación y «Futuros» como agregador."

Em português: os dados são redistribuídos de fontes abertas; cada observação conserva sua fonte primária (nome, URL de deep-link e citation_id). Ao reutilizá-los, cite a fonte primária de cada observação e credite o Futuros como agregador. Nada é imputado ou sintetizado — o contrato de honestidade do baker é que todo valor no fio carrega a fonte de onde veio.

Padrões de interoperabilidade

index.json → standards declara os códigos que a API fala, para que UNSD-SDG, World Bank Data360, OECD.AI e CEPALSTAT possam ingeri-la diretamente:

PadrãoOnde
REF_AREA = M49 numérico da ONU + alpha-3 ISO 3166-1toda geografia e observação
Marco global de indicadores ODS (A/RES/71/313)bloco sdg por indicador + sdg-crosswalk.json
SDMX-CSV (ISO 17369)observations.sdmx.csv
DCAT (project-open-data v1.1)/data.json

O manifesto — index.json

Comece aqui. Ele lista cada dataset, contagens ao vivo, a licença, a declaração de estabilidade e um mapa endpoints legível por máquina (templates de caminho para o restante).

bash
curl -s https://futuros.xyz/api/v1/index.json
jsonc
{
  "name": "Futuros — API de datos abiertos",
  "api_version": "1",
  "generated_at": "2026-08-29T04:17:28.143Z",
  "docs": "/datos-abiertos",
  "license": "Datos redistribuidos de fuentes abiertas; …",
  "license_url": "https://creativecommons.org/licenses/by/4.0/",
  "delta_basis": "latest value vs mean of the prior 3 years (smooths COVID-era volatility)",
  "stability": "Shapes are additive-only within v1; breaking changes go to /api/v2/.",
  "languages": ["es", "en", "pt"],
  "label_fields": { "parameters": ["name_es", "name_en", "name_pt"],
                    "geographies": ["name_es", "name_en", "name_pt"],
                    "observations": ["label_es", "label_en", "label_pt"] },
  "standards": {
    "ref_area": "UN M49 numeric (REF_AREA) + ISO 3166-1 alpha-3",
    "sdg": "UN SDG global indicator framework (A/RES/71/313); see /api/v1/sdg-crosswalk.json",
    "sdmx": "SDMX-CSV (ISO 17369) at /api/v1/observations.sdmx.csv",
    "catalog": "DCAT (project-open-data v1.1) at /data.json"
  },
  "counts": {
    "parameters": 10, "geographies": 26, "cells": 260,
    "observations": 397898, "sdg_tagged_indicator_instances": 2848,
    "citations": 15098, "signal_files": 260, "governance_datasets": 3, "contributions": 0
  },
  "bulk": {
    "observations_csv": { "path": "/api/v1/observations.csv", "bytes": 170533700, "rows": 397898 },
    "observations_sdmx_csv": { "…": "…" }, "workbook_xlsx": { "…": "…" }
  },
  "endpoints": { "openapi": "/api/v1/openapi.json", "schemas": "/api/v1/schemas/",
                 "parameters": "/api/v1/parameters.json", "…": "…" }
}

counts.geographies é 26 porque os 25 países incluem o agregado regional LATAM (M49 419). Uma célula é um parâmetro × uma geografia; uma observação é uma linha indicador-ano.

O bloco bulk carrega bytes + contagens de linhas de cada dump em massa — atualmente cerca de 171 MB (observations.csv), 111 MB (observations.sdmx.csv) e 91 MB (futuros-data.xlsx), ~398 mil linhas cada — então consulte-o antes de iniciar um download em massa. languages + label_fields (o substituto legível por máquina da antiga nota em prosa language_coverage) declaram que todo parâmetro e geografia carrega name_es/name_en/name_pt e toda observação label_es/label_en/label_pt. label_es é o rótulo canônico do payload e nunca é renomeado; os irmãos EN/PT são unidos a partir de public/data/metrics/registry.json por indicator_id e são null (JSON) / vazios (CSV) para ids que o registro ainda não cobre. Contagens e tamanhos aqui são ilustrativos; o manifesto ao vivo é o autoritativo.

Contrato legível por máquina — openapi.json e schemas/

O próprio contrato da v1 é publicado como dado, listado primeiro em index.json → endpoints:

  • /api/v1/openapi.json — spec OpenAPI 3.1.0 cobrindo 15 caminhos centrais de leitura (sdg-crosswalk.json, citations.csv e o catálogo DCAT /data.json ainda não estão na spec).
  • /api/v1/schemas/{manifest,parameter,geography,observation-cell,citation}.schema.jsonJSON Schema para cada forma de resposta.

Aponte uma ferramenta de codegen ou validação para eles em vez de transcrever formas à mão a partir desta página.


Parâmetros — parameters.json

Os 10 pilares do Futuros, em ordem de exibição, cada um com seus ODS primários/secundários.

bash
curl -s https://futuros.xyz/api/v1/parameters.json
jsonc
[
  { "slug": "salud", "name_es": "Salud", "name_en": "Salud",
    "display_order": 1, "sdg_primary": [3], "sdg_secondary": [2, 6] },
  { "slug": "educacion", "name_es": "Educación", "…": "…" }
]

Use slug (por exemplo salud, educacion, cohesion-social-inclusion) como o segmento <param> nos caminhos de observações.

Geografias — geographies.json

Os 25 países mais a região LATAM, cada um com ISO3 e M49.

bash
curl -s https://futuros.xyz/api/v1/geographies.json
jsonc
[
  { "iso3": "LATAM", "m49": "419", "slug": "latam",
    "name_es": "América Latina y el Caribe", "name_en": "Latin America and the Caribbean",
    "level": "region", "sub_region": null, "population_2024": null },
  { "iso3": "ARG", "m49": "032", "slug": "arg", "level": "country", "…": "…" }
]

Os slugs de países são o ISO3 em minúsculas (arg, mex, bra; a região é latam). Use iso3 (por exemplo MEX, ARG, BRA) como o segmento <ISO> nos caminhos de observações. Códigos M49 são strings com zeros à esquerda ("032", "484").


Observações — uma célula

O dataset central. Um arquivo por parâmetro × país, endereçado como observations/<param>__<ISO3>.json (note o separador de underscore duplo).

JSON

bash
curl -s https://futuros.xyz/api/v1/observations/salud__MEX.json
jsonc
{
  "api_version": "1",
  "generated_at": "2026-08-29T04:17:28.143Z",
  "parameter": { "slug": "salud", "label_es": "Salud" },
  "geography": { "iso3": "MEX", "m49": "484", "name_es": "México",
                 "name_en": "México", "level": "country" },
  "confidence": "high",
  "last_refreshed": "2026-06-15T16:20:52.364Z",
  "indicators": [
    {
      "indicator_id": "sp_dyn_le00_in",
      "label_es": "Esperanza de vida al nacer",
      "label_en": "Life expectancy at birth",
      "label_pt": "Expectativa de vida ao nascer",
      "unit": "años",
      "latest": { "year": 2024, "value": 75.264 },
      "delta_pct": 3.199,
      "delta_basis": "latest value vs mean of the prior 3 years (smooths COVID-era volatility)",
      "good_direction": "up",
      "coverage": "primary",
      "benchmark": { "oecd": 80.39, "world": 73.48, "sea_peers": 73.87, "oecd_vintage": 2024 },
      "sdg": { "code": "3", "level": "goal",
               "indicator_name": "Ensure healthy lives and well-being …", "goal": 3 },
      "source": {
        "name": "World Bank Open Data",
        "url": "https://data.worldbank.org/indicator/SP.DYN.LE00.IN?locations=MX",
        "citation_id": "wb-sp-dyn-le00-in-mex-2024"
      },
      "series": [ { "year": 2000, "value": 72.562 }, { "year": 2001, "value": 72.912 }, "…" ]
    }
  ]
}

Cada indicador carrega latest (ano + valor), a series completa até ~2000, sua source (nome + deep-link para a fonte primária + citation_id), um código sdg oficial quando existe (level é indicator, target ou goal) e delta_pct (veja delta_basis: valor mais recente vs. a média dos 3 anos anteriores). sdg é null quando nenhum código ODS oficial se aplica — nunca fabricado.

CSV

A mesma célula achatada em uma linha por indicador-ano:

bash
curl -s https://futuros.xyz/api/v1/observations/salud__MEX.csv

Cabeçalho:

parameter,iso3,m49,indicator_id,label_es,unit,year,value,delta_pct_latest,
good_direction,coverage,vintage_year,sdg_code,sdg_level,source_name,source_url,citation_id,
label_en,label_pt

label_en,label_pt ficam no final da linha — a ordem das colunas faz parte do contrato CSV, então adições são sempre anexadas, nunca inseridas.

Observações — em massa

Todas as células concatenadas em um único CSV — o corpus inteiro em um só download (~164 mil linhas):

bash
curl -s https://futuros.xyz/api/v1/observations.csv -o futuros-observations.csv

Mesmo cabeçalho do CSV por célula. Carregue diretamente:

python
import pandas as pd
df = pd.read_csv("https://futuros.xyz/api/v1/observations.csv")

Observações — SDMX-CSV

Os dados em massa como SDMX-CSV (ISO 17369), com REF_AREA chaveado no M49 da ONU para casar com as convenções da UNSD-SDG / Data360:

bash
curl -s https://futuros.xyz/api/v1/observations.sdmx.csv
DATAFLOW,FREQ,REF_AREA,INDICATOR,TIME_PERIOD,OBS_VALUE,UNIT_MEASURE,
SDG_INDICATOR,REF_AREA_ISO3,FUTUROS_PARAMETER,SOURCE,SOURCE_URL,CITATION_ID
FUTUROS:DF_OBSERVATIONS(1.0),A,032,si_pov_gini,2000,51,índice,10,ARG,
cohesion-social-inclusion,World Bank Open Data,https://data.worldbank.org/…,wb-si-pov-gini-arg-2024

DATAFLOW é FUTUROS:DF_OBSERVATIONS(1.0), FREQ é A (anual).

Pasta de trabalho Excel — futuros-data.xlsx

Uma pasta de trabalho com cinco planilhas — README (licença + base do delta_pct), parameters, geographies, observations (todas as linhas) e citations:

bash
curl -s https://futuros.xyz/api/v1/futuros-data.xlsx -o futuros-data.xlsx

Citações — citations.json / citations.csv

O registro completo de fontes contra o qual todo citation_id resolve.

bash
curl -s https://futuros.xyz/api/v1/citations.json
curl -s https://futuros.xyz/api/v1/citations.csv

Colunas do CSV: id,source,title,url,year,retrieved_at. Faça o join do citation_id de observations.* com o id de citations.* para anexar metadados completos de fonte a qualquer valor.

Livro-razão de atualidade — freshness.json

Cadência de atualização por fonte — quando cada indicador foi puxado pela última vez e quando vence o próximo. Um passthrough do refresh-meta.json do build. Chaves de nível superior: generated_at, total_indicators, indicators, mais um bloco sources.

bash
curl -s https://futuros.xyz/api/v1/freshness.json
jsonc
{
  "generated_at": "2026-06-15T16:20:52.364Z",
  "total_indicators": 48,
  "indicators": {
    "SI.POV.GINI": {
      "source": "World Bank Open Data",
      "source_url": "https://data.worldbank.org/indicator/SI.POV.GINI",
      "cadence_months": 12,
      "last_refreshed": "2026-06-15T16:20:52.364Z",
      "next_refresh_due": "2027-08-15T20:11:16.364Z",
      "countries_with_data": 0, "total_countries": 25
    }
  }
}

Crosswalk ODS — sdg-crosswalk.json

O mapa verificado de pilares e indicadores para códigos ODS oficiais (goals, pillars, indicators). Faça o join por indicator_id.

bash
curl -s https://futuros.xyz/api/v1/sdg-crosswalk.json

Sinais — signals/<param>__<ISO3>.json

Sinais de "o que está se movendo" por célula, extraídos por LLM e citados (presentes porque a camada multi-fonte é assada). Mesmo endereçamento <param>__<ISO3> das observações, e desde o assamento de 2026-08-05 a cobertura é total: as 260 células têm arquivo (counts.signal_files no manifesto). As 10 células do agregado regional (<param>__LATAM), que a colheita de sinais não escreve, são assadas como array vazio []; antes não tinham arquivo e respondiam HTTP 404. Trate um [] como "esta célula não tem sinais", não como um erro; um 404 sob signals/ agora indica de fato um caminho digitado errado.

bash
curl -s https://futuros.xyz/api/v1/signals/salud__ARG.json

Contribuições — contributions.json

Dados contribuídos por meio do Fundo Fiduciário de Dados (Pilar 1), com portão de licença, publicados apenas para posturas que permitem republicar valores. Atualmente count: 0.

bash
curl -s https://futuros.xyz/api/v1/contributions.json

Motor de Governança — governance/*.json

Os datasets do Motor de Governança (Pilar 3) fazem parte do contrato versionado desde o assamento de 2026-08-05 (antes só eram acessíveis via MCP ou como arquivo sem versionamento). Cada um é um passthrough do arquivo que a UI consome, servido com o mesmo contrato de estabilidade aditivo, CORS e cache do resto da v1:

CaminhoO que é
/api/v1/governance/resilience.jsonÍndice de Resiliência Democrática: subíndices + composto, citado por país
/api/v1/governance/regulation-index.jsonObservatório Regulatório: instrumentos por país e pilar
/api/v1/governance/scores.jsonÍndice composto goalpost por geografia (séries 2010-2024)
bash
curl -s https://futuros.xyz/api/v1/governance/resilience.json

A via MCP continua disponível: get_dataset com dataset_id: "democracy-resilience" no servidor MCP retorna o mesmo índice de resiliência com cômputo determinista. O arquivo sem versionamento GET /data/democracy/resilience.json também continua existindo, mas sem contrato de estabilidade; prefira os caminhos /api/v1/governance/ acima.


Descoberta — catálogo DCAT em /data.json

Um catálogo DCAT / project-open-data v1.1 na raiz do site (não sob /api/v1/) para que portais de dados e crawlers descubram os datasets automaticamente:

bash
curl -s https://futuros.xyz/data.json

Ele anuncia os datasets em massa CSV, SDMX-CSV, XLSX, citações, crosswalk ODS e atualidade, cada um com downloadURL, mediaType e licença CC BY 4.0.

Feeds RSS · /feeds/

Os sinais citados também são publicados como 267 feeds RSS 2.0 estáticos sob /feeds/ (na raiz do site, não sob /api/v1/), feitos para leitores RSS e monitoramento institucional. Mesmo regime da API de leitura: GET estático, sem auth, cacheável.

CaminhoO quê
/feeds/futuros.xmlMestre regional: todos os sinais da região em um só feed
/feeds/<ISO3>.xmlPor país: união de seus 10 feeds de pilar, máximo 50 itens
/feeds/<param>__<ISO3>.xmlPor célula (pilar × país): sinais citados com deep-link para a fonte
/feeds/index.jsonManifesto: total_feeds, cells_written, cells_skipped_empty, countries_written, forecasts_included, forecasts_skipped_unverifiable, e feeds[] com título, caminho, tipo e contagem de itens
bash
curl -s https://futuros.xyz/feeds/salud__BRA.xml

Os feeds não estão mais congelados: scripts/bake-feeds.ts roda dentro da cadeia de prebuild (junto a bake-data-health, bake-source-ledger e bake-api, logo antes de check-api), então são re-assados a cada deploy a partir do corpus de sinais vigente. O manifesto é explícito sobre o que não publicou: cells_skipped_empty conta as células sem sinal — nenhum feed vazio é emitido para simular cobertura — e forecasts_skipped_unverifiable conta as previsões deixadas de fora por não serem verificáveis.

Backlog de lacunas de dados — GET /api/backlog

Diferente de tudo acima, este não é um arquivo assado sob /api/v1/: é uma função ao vivo (api/backlog.ts), porque o que ela serve é gerado em tempo de requisição e não no assado. É documentado aqui porque é público, sem autenticação e somente leitura, como o resto desta página.

Sempre que o assistente consulta o corpus e uma ferramenta do corpus volta vazia, o servidor abre um ticket estruturado em vez de deixar o sinal morrer. Este endpoint é como esse backlog se torna visível — para a SPA (/vacios), para a linha de ingestão que decide o que buscar em seguida, e para quem quiser conferir que um "não temos esse dado" é seguido de algo.

Parâmetros

ParâmetroPadrãoO que faz
limit100 (máx. 500)Quantos tickets devolver
countryFiltra por ISO3 (normalizado para maiúsculas)
pillarFiltra por slug de eixo

Limite de taxa: 60 requisições por minuto e por IP; ao exceder responde 429 com Retry-After. Cache: s-maxage=60, stale-while-revalidate=300.

Resposta

json
{
  "ok": true,
  "configured": true,
  "count": 2,
  "gaps": [
    {
      "id": "gap-ecu-medio-ambiente-clima-1a2b3c4d",
      "created_at": "2026-08-16T09:12:44.031Z",
      "lang": "es",
      "country": "ECU",
      "pillar": "medio-ambiente-clima",
      "route": "/atlas",
      "empty": ["get_dataset:regulation", "get_dataset:signals"],
      "candidate_sources": [
        { "title": "SIMAS", "url": "https://ambiente.gob.ec/simas", "source": "ambiente.gob.ec", "date": "2026" }
      ],
      "missing_indicators": ["Área com concessão de mineração"],
      "hits": 7
    }
  ]
}
  • configured: false significa que o armazenamento durável (Upstash) não está cabeado naquele ambiente: gaps é então o anel em memória daquela instância, nem compartilhado nem persistente. Isso é declarado em vez de fingir que existe um backlog comum.
  • hits é quantas vezes essa mesma lacuna foi levantada. O id deduplica pela forma do vazio (país + eixo + ferramentas vazias), não pelo texto, então a mesma lacuna perguntada de duas maneiras incrementa um único ticket. Essa ordem por demanda é a fila de ingestão.
  • candidate_sources contém apenas URLs que uma ferramenta externa devolveu naquele mesmo turno. Nunca uma fonte que o modelo nomeou de memória.

Sem texto do usuário, por desenho

Um ticket descreve a lacuna, não quem a encontrou. Leva o país, o eixo, a rota, as ferramentas que voltaram vazias e os indicadores ausentes; todos esses campos saem de vocabulário controlado pela plataforma (códigos ISO3, slugs de eixo, chaves de ferramenta, rótulos assados de indicador).

O ticket não persiste nem serve a pergunta do usuário. É lida apenas para estabelecer que houve um turno real, e então descartada. Como este endpoint é público e sem autenticação, qualquer coisa que o ticket conservasse seria algo que quem perguntou publicou sem pretender — e a postura de consentimento do Fideicomisso de Dados tem que valer para quem usa o chat, não só para as instituições que contribuem.

O texto é guardado, mas em outro lugar e sob outras regras: o registro privado de perguntas vive sob uma chave diferente (chat:questions:v1, nunca backlog:gaps:v1) e só é legível com Authorization: Bearer $QUESTION_LOG_TOKEN — sem token, GET /api/questions recusa tudo. Nenhum caminho público o alcança: o backlog reconstrói cada ticket campo a campo, então a garantia deste endpoint fica exatamente a mesma.

A garantia é aplicada na leitura além da escrita: os tickets escritos antes desta regra seguem no armazenamento, então readGaps reconstrói cada linha campo a campo contra uma lista de permitidos e descarta todo o resto. Um campo novo também não pode chegar à superfície pública por acidente: tem que ser adicionado lá de propósito.

Não há superfície de escrita. Os tickets são escritos pelo servidor de chat, no mesmo processo que observou a recuperação vazia; não existe rota de escrita alcançável pelo navegador.

Referência de endpoints

CaminhoO quê
/api/v1/index.jsonManifesto: datasets, contagens, tamanhos em massa, licença, padrões
/api/v1/openapi.jsonSpec OpenAPI 3.1 da API de leitura (15 caminhos centrais)
/api/v1/schemas/*.schema.jsonJSON Schema: manifesto, parâmetro, geografia, célula de observação, citação
/api/v1/parameters.json10 pilares + ODS primários/secundários
/api/v1/geographies.json25 países + LATAM, ISO3 + M49
/api/v1/observations/<param>__<ISO3>.jsonUma célula: indicadores, séries, citações, ODS
/api/v1/observations/<param>__<ISO3>.csvMesma célula, uma linha por indicador-ano
/api/v1/observations.csvEm massa: todas as células concatenadas
/api/v1/observations.sdmx.csvEm massa, SDMX-CSV (ISO 17369), REF_AREA = M49
/api/v1/futuros-data.xlsxPasta de trabalho (README/parameters/geographies/observations/citations)
/api/v1/citations.json · .csvRegistro completo de citações
/api/v1/freshness.jsonLivro-razão de atualização por fonte
/api/v1/sdg-crosswalk.jsonPilar → ODS + indicador → código ODS oficial
/api/v1/signals/<param>__<ISO3>.jsonSinais citados por célula (260/260 células; as 10 regionais __LATAM são [])
/api/v1/governance/{resilience,regulation-index,scores}.jsonMotor de Governança: resiliência democrática, observatório regulatório, índice composto
/api/v1/contributions.jsonDados contribuídos com portão de licença
/data.jsonCatálogo DCAT (raiz do site)
/feeds/futuros.xml · /feeds/<ISO3>.xml · /feeds/<param>__<ISO3>.xmlFeeds RSS 2.0 estáticos de sinais, re-assados a cada deploy por bake-feeds dentro de prebuild
/feeds/index.jsonManifesto dos 267 feeds RSS, com as contagens do que foi omitido
GET /api/backlogBacklog de lacunas de dados (função ao vivo, não assada) — ver acima
GET /api/env-leversPostura pública das 15 alavancas de produção que falham fechadas: por alavanca, seu id, as variáveis que a compõem, opens (o que habilita) e probe (como verificá-la de fora), mais um booleano set. Nunca devolve valores de segredos; Cache-Control: no-store. É a superfície legível por máquina por trás de /confianza — ver auto-hospedagem

Para acesso agêntico, baseado em ferramentas, ao mesmo corpus (com cálculo determinístico e citações), veja o servidor MCP.

Política de rastreamento (crawling)

Os dados são abertos por design, então o rastreamento não é bloqueado — mas é declarado e observado:

  • robots.txt (https://futuros.xyz/robots.txt) permite tudo exceto /admin/ e um caminho-armadilha interno. Os rastreadores de treinamento de IA (GPTBot, ClaudeBot, CCBot, Bytespider, etc.) estão explicitamente permitidos hoje; a política por bot muda com uma linha nesse arquivo (a lista de tokens é mantida em server/scrape/known-agents.ts).
  • Raspar o HTML é inútil: cada rota da app devolve o mesmo shell de SPA sem conteúdo. As superfícies para máquinas são esta API, o servidor MCP e o catálogo DCAT (/data.json) — use-as.
  • O acesso é observado, nunca bloqueado: um middleware somente-observação (middleware.ts + server/scrape/, runbook em server/scrape/README.md) marca padrões de raspagem em massa e de cópia-por-IA como eventos internos. Nenhuma requisição é atrasada ou recusada por esta camada.

Cada número com sua fonte — a rastreabilidade é o contrato.