# Construindo um pipeline de dados sobre as APIs de dados abertos da Câmara e do Senado

> Lições de design para um pipeline automatizado sobre os dados abertos da Câmara dos Deputados e do Senado: cargas idempotentes, sincronização incremental e reconciliação.

- Autor: Adriano Leão (https://adrianoleao.com/pt)
- Publicado: 2026-11-04
- Tempo de leitura: 3 min de leitura
- Temas: Engenharia de dados, Dados abertos, Civic tech
- URL: https://adrianoleao.com/pt/writing/pipeline-brazil-legislative-open-data

**Em resumo:** Buscar dados legislativos públicos de forma agendada é fácil. Mantê-los corretos é o trabalho. Os padrões que importam são cargas idempotentes, sincronização incremental guiada pelo próprio feed de mudanças da fonte e uma etapa de reconciliação separada que confere o que você guardou com o que a fonte informa.

![Senadores sentados à mesa de uma comissão com notebooks e microfones no Senado Federal](https://adrianoleao.com/images/writing/pipeline-brazil-legislative-open-data-og.jpg)

*Capa: [2024-11-12, Senado Federal do Brasil - 399, Senado Federal, CC BY 2.0, via Wikimedia Commons](https://commons.wikimedia.org/wiki/File:2024-11-12,_Senado_Federal_do_Brasil_-_399.jpg)*

## A fonte: duas APIs públicas

As duas casas legislativas do Brasil publicam dados abertos. A [Câmara dos Deputados](https://dadosabertos.camara.leg.br/) expõe coleções como deputados, partidos, órgãos, proposições e votações, com documentação interativa em Swagger e uma coleção que lista as atualizações recentes. O [Senado Federal](https://legis.senado.leg.br/dadosabertos/) tem seu próprio serviço de dados abertos, com estrutura diferente.

Para o [Como Votam](https://comovotam.com.br/), construí um pipeline automatizado que coleta das duas e mantém nosso banco atualizado, com orçamento de ONG. Este artigo reúne as lições de design que valem para qualquer pipeline sobre dados públicos, sem entrar nos detalhes internos do projeto.

## Duas fontes, um modelo

A Câmara e o Senado descrevem coisas parecidas (pessoas, partidos, matérias, votos) em formatos diferentes. A primeira decisão é onde a diferença mora. Mantenha cada fonte atrás de seu próprio adaptador, que fala o formato dela e entrega um modelo interno comum. Tudo o que vem depois, do armazenamento à análise, não sabe de qual casa o dado veio.

Essa única fronteira se paga toda vez que uma fonte muda o nome de um campo ou um endpoint.

## Faça toda carga idempotente

Um pipeline agendado, mais cedo ou mais tarde, vai rodar duas vezes, ou quebrar no meio e rodar de novo. A única regra sensata é que repetir uma carga produza o mesmo resultado que rodá-la uma vez.

Em um banco relacional, isso normalmente significa upserts por um identificador estável da fonte:

```sql
INSERT INTO votes (source, source_id, matter_id, choice, voted_at)
VALUES ($1, $2, $3, $4, $5)
ON CONFLICT (source, source_id)
DO UPDATE SET
  choice = EXCLUDED.choice,
  voted_at = EXCLUDED.voted_at;
```

O trecho é ilustrativo. Repare na chave composta: as duas casas podem reutilizar os mesmos identificadores numéricos, então a fonte faz parte da chave.

## Sincronize de forma incremental, usando o sinal da própria fonte

Baixar tudo de novo a cada execução é lento e deselegante com um serviço público. Quando a fonte informa o que mudou, use isso. Os dados abertos da Câmara incluem uma coleção de atualizações exatamente para esse fim: pergunte o que mudou em uma janela de tempo e busque só esses registros.

Dois hábitos tornam a sincronização incremental segura:

- **Sobreponha as janelas.** Peça um pouco mais do que o tempo desde a última execução e conte com cargas idempotentes para absorver as duplicatas.
- **Grave o cursor só depois que a carga der certo.** Se uma execução falhar, a próxima recomeça do mesmo ponto.

## Reconcilie, porque a sincronização pode derivar

A sincronização incremental é eficiente, e também pode derivar em silêncio: uma atualização perdida, um registro corrigido na origem sem aviso, um bug do seu lado. A resposta é uma etapa de reconciliação separada, que compara periodicamente o que você tem com o que a fonte informa (contagens, totais, uma amostra de registros) e sinaliza diferenças.

Manter sincronização e reconciliação como preocupações distintas importa. A sincronização é otimizada para velocidade. A reconciliação é otimizada para confiança, e é ela que permite dizer aos usuários, com honestidade, que os números batem com o registro oficial.

## Seja um bom cidadão de uma API pública

Serviços públicos têm limites que talvez você não veja na documentação. Limite a concorrência, faça recuo em caso de erro, identifique bem o seu cliente e guarde em cache o que não muda. Isso mantém o pipeline confiável e o serviço disponível para todos.

## Resumo

- Isole cada fonte atrás de um adaptador e de um modelo comum.
- Cargas idempotentes tornam a falha entediante.
- Use o feed de mudanças da fonte, sobreponha as janelas e grave o cursor por último.
- Reconcilie separadamente, porque a confiança precisa de uma verificação própria.

## Referências

- [Dados abertos da Câmara dos Deputados](https://dadosabertos.camara.leg.br/)
- [Dados abertos do Senado Federal](https://legis.senado.leg.br/dadosabertos/)
- [Como Votam](https://comovotam.com.br/)
- [Estudo de caso do Como Votam em adrianoleao.com](https://adrianoleao.com/pt/case-study/como-votam)

[Todos os artigos](https://adrianoleao.com/pt/writing.md)
