Índice CNN — pesquisas eleitorais

Aprovação, presidente (1º e 2º turno) e governadores em JSON

A Índice CNN API entrega as séries do Índice CNN em JSON pronto para GC, dashboard ou template: aprovação do presidente, intenção de voto para presidente no 1º e no 2º turno, e para governador em cada estado. Cada rota devolve a lista de candidatos (com partido) e a série histórica de percentuais.

Base: https://indice-cnn.api.insyde.one — todas as rotas de dados exigem ?key=.

Chave de acesso. O token tem o formato empresa:hash e vai na query string: ?key=cnn:xxxxxxxxxx. É individual por cliente — não publique em repositório, front-end aberto ou template compartilhado. Sem chave (ou com chave inválida) a resposta é 401. Só /health é aberta.

1. Rotas

RotaRetorna
GET /aprovacao-lulaSérie de aprovação e desaprovação
GET /presidenteIntenção de voto p/ presidente — 1º turno
GET /presidente-2tIntenção de voto p/ presidente — 2º turno, por cenário
GET /governadoresIntenção de voto p/ governador, por estado
GET /healthStatus do serviço — sem chave, sem cache

A barra final é tolerada (/presidente = /presidente/). CORS é liberado, então dá para chamar direto do browser. Rota inexistente → 404.

2. Aprovação — /aprovacao-lula

Duas visões da mesma história: pesquisas traz cada levantamento individual com o instituto que assina, e indiceCNN traz a série mensal consolidada — use esta para a linha do gráfico e aquela para citar a fonte.

GET /aprovacao-lula?key=cnn:xxxxxxxxxx
{
  "aprovacao_lula": {
    "pesquisas": [
      { "Instituto": "PoderData", "Data": "31/01/2023", "Aprovação": 52, "Desaprovação": 39 },
      { "Instituto": "IPESPE",    "Data": "14/02/2023", "Aprovação": 51, "Desaprovação": 36 }
      // ~198 registros desde jan/2023
    ],
    "indiceCNN": [
      { "Data": "jan.-23",  "Aprovação": 52, "Desaprovação": 39 },
      { "Data": "fev.- 23", "Aprovação": 54, "Desaprovação": 32 }
      // ~47 pontos mensais
    ]
  }
}
Esta é a única rota sem last_updated — a referência temporal é o último ponto da série. E atenção ao formato da data: pesquisas usa DD/MM/AAAA, indiceCNN usa mês-AA.

3. Presidente, 1º turno — /presidente

GET /presidente?key=cnn:xxxxxxxxxx
{
  "last_updated": "2026-08-20T20:04:34.145Z",
  "presidente": {
    "candidates": [
      { "name": "Lula", "party": "PT" },
      { "name": "Flávio Bolsonaro", "party": "PL" },
      { "name": "Ronaldo Caiado", "party": "PSD" }
      // 15 candidatos, em ordem
    ],
    "indiceCNN": [
      { "Data": "06/07/2026", "Lula": 41, "Flávio Bolsonaro": 31, "Ronaldo Caiado": 4 /* … */ }
      // um objeto por data de apuração
    ]
  }
}
As chaves de indiceCNN são os nomes dos candidatos, não IDs. Para montar o gráfico, percorra candidates (que define a ordem e o partido) e busque ponto[candidate.name].

4. Presidente, 2º turno — /presidente-2t

O 2º turno é organizado por cenário de confronto. Cada cenário é independente: tem sua própria dupla de candidatos e sua própria série.

ParamPadrãoDescrição
keyObrigatório.
cenariostodosFiltra os cenários. Vários separados por vírgula; não diferencia maiúsculas/minúsculas.
GET /presidente-2t?key=cnn:xxxxxxxxxx                            // todos os cenários
GET /presidente-2t?cenarios=lula_zema&key=…                     // só um
GET /presidente-2t?cenarios=lula_zema,lula_caiado&key=…         // dois
ChaveConfronto
lula_flavioLula (PT) x Flávio Bolsonaro (PL)
lula_caiadoLula (PT) x Ronaldo Caiado (PSD)
lula_zemaLula (PT) x Romeu Zema (Novo)
lula_renanLula (PT) x Renan Santos (Missão)
// GET /presidente-2t?cenarios=lula_zema&key=…
{
  "last_updated": "2026-08-20T20:04:36.422Z",
  "segundo_turno": {
    "cenarios": {
      "lula_zema": {
        "label": "Lula x Romeu Zema",
        "candidates": [
          { "name": "Lula", "party": "PT" },
          { "name": "Romeu Zema", "party": "Novo" }
        ],
        "indiceCNN": [
          { "Data": "12/08/2026", "Lula": 47, "Romeu Zema": 37 }
        ]
      }
    }
  }
}

Use label direto como título do GC — ele já vem no formato "Lula x Romeu Zema".

Cenário inexistente não gera erro: é simplesmente omitido. Se nenhum dos pedidos existir, a resposta é 200 com "cenarios": {}. O last_updated é sempre preservado, mesmo com filtro.

5. Governadores — /governadores

Mesma estrutura do presidente, replicada por UF.

ParamPadrãoDescrição
keyObrigatório.
estadostodosFiltra por UF. Várias separadas por vírgula; não diferencia maiúsculas/minúsculas.
GET /governadores?estados=MG,SP&key=cnn:xxxxxxxxxx
{
  "last_updated": "2026-08-20T18:27:24.744Z",
  "governadores": {
    "MG": {
      "candidates": [
        { "name": "Cleitinho", "party": "Republicanos" },
        { "name": "Alexandre Kalil", "party": "PDT" }
        // … demais candidatos
      ],
      "indiceCNN": [
        { "Data": "23/06/2026", "Cleitinho": 34, "Alexandre Kalil": 14 /* … */ }
      ]
    }
    // … demais estados
  }
}

26 UFs disponíveis: AC AL AM AP BA CE DF ES GO MA MG MS MT PA PB PE PI PR RJ RN RO RS SC SE SP TO

UF sem pesquisa (hoje, RR) ou sigla inválida é omitida da resposta, sem erro — pedir só siglas inexistentes retorna 200 com "governadores": {}.

6. Exemplos

JavaScript (fetch):

const BASE = 'https://indice-cnn.api.insyde.one';
const KEY  = 'cnn:xxxxxxxxxx';

// um cenário de 2º turno, pronto para o GC
const res = await fetch(`${BASE}/presidente-2t?cenarios=lula_zema&key=${KEY}`);
if (!res.ok) throw new Error((await res.json()).error);

const { last_updated, segundo_turno } = await res.json();
const cenario = segundo_turno.cenarios.lula_zema;
const ultimo  = cenario.indiceCNN.at(-1);

// título + barras, na ordem oficial dos candidatos
const titulo = cenario.label;                       // "Lula x Romeu Zema"
const barras = cenario.candidates.map(c => ({
  nome: c.name, partido: c.party, pct: ultimo[c.name]
}));

Python (requests):

import requests

BASE = "https://indice-cnn.api.insyde.one"
KEY  = "cnn:xxxxxxxxxx"

r = requests.get(f"{BASE}/governadores", params={"estados": "MG,SP", "key": KEY})
r.raise_for_status()

for uf, dados in r.json()["governadores"].items():
    ultimo = dados["indiceCNN"][-1]
    print(uf, ultimo["Data"])
    for c in dados["candidates"]:
        print(f"  {c['name']} ({c['party']}): {ultimo[c['name']]}%")

7. Erros e cache

HTTPCorpoQuando
401{"error":"unauthorized"}?key= ausente ou inválida
404{"error":"not found"}Rota inexistente
502{"error":"upstream fetch failed"}Origem indisponível ou timeout (8 s)
502{"error":"invalid upstream response"}Origem respondeu algo que não é JSON válido
Cache: respostas com sucesso são public, max-age=60, s-maxage=180 — a CDN revalida a cada 3 min, o navegador a cada 60 s. Erros e /health nunca são cacheados. O cache é por URL completa, então ?cenarios=lula_zema e ?cenarios=lula_caiado são entradas distintas: filtrar no servidor é mais barato que baixar tudo e filtrar no cliente.

Os dados mudam algumas vezes ao dia. Consultar mais de uma vez por minuto não traz informação nova — a CDN devolve a mesma resposta.

Back to Insyde APIs