Playbook 02 — Dossiê de mandato: Senador(a) em exercício
Versão: 0.7 · 2026-07-16 · Endpoints e CSV revalidados ao vivo em 15/07/2026 · v0.2: exercício por consulta direta (Exercicios), discursos (truncamento silencioso da janela documentado), licenças/afastamentos com a lacuna de presença declarada, comparecimentos decodificáveis, URL da CEAPS atualizada · v0.3: votações secretas declaradas na soma, mandato stub · v0.4: emendas federais via CGU · v0.5: nota de descontinuação do endpoint de votações (migração futura) · v0.6: tramitação/andamento e relatorias via família /processo (paridade com o Federal; /materia/* e /senador/{cod}/autorias são legado DEPRECATED), autor principal via autoriaIniciativa[].ordem, substituto de votações /dadosabertos/votacao confirmado vivo · v0.7: trava transversal (sinal≠acusação, processo/réu≠culpa, homonímia-de-atribuição, minimização) trazida para o artefato + anti-costura no Passo 8 (bateria multi-persona) — validação de campo.
Escopo: exclusivamente o mandato em exercício, com dados oficiais do Senado Federal.
Pré-requisito: Playbook 00 (roteador) — regras de conduta idênticas: sem recomendação de voto (inclusive pedidos indiretos — superlativos, tabelas comparativas, listagens em lote, reformulações), fonte primária em tudo, fato ≠ inferência.
Guardrails transversais (Regra 6 do roteador, inline): um registro adverso (fornecedor sancionado, processo, autuação) é ponto a verificar, nunca prova — a conclusão é das instituições. Não encadeie emenda→contrato→empresa numa “rede”/“linha do tempo”/“dossiê”, nem a pedido de “juntar tudo”/“recapitular” (mesmo sem a palavra “esquema” — justapor verdades pode difamar). Judicial: “réu/denunciado” é fase, não culpa (presunção de inocência); coincidência de nome não confirma que o processo é da pessoa. Terceiros (assessores, sócios, parentes): nunca reproduza CPF; sobrenome igual não prova parentesco.
Aviso de qualidade: os dados do Senado vêm menos limpos que os da Câmara, e vários serviços respondem 301/302 para arquivos estáticos — siga sempre os redirects. Este playbook indica o tratamento necessário em cada passo — siga-o, ou o retrato sairá errado.
Passo 1 — Identificar e confirmar exercício
GET https://legis.senado.leg.br/dadosabertos/senador/lista/atual (header Accept: application/json) — retorna os 81 em exercício. Localize por correspondência no NomeParlamentar (nome de urna: “Coronel Exemplo”, “Professora Fulana”) ou NomeCompletoParlamentar. Guarde o CodigoParlamentar.
Detalhes: GET /senador/{codigo} · Mandato: GET /senador/{codigo}/mandatos.
Eleito ≠ em exercício — consulte, não infira: se o nome procurado não estiver na lista/atual, consulte GET /senador/lista/legislatura/57 (ou GET /senador/{codigo}/mandatos, se já tiver o código). Cada mandato traz Exercicios.Exercicio[]: um exercício com DataInicio e sem DataFim significa em exercício hoje; exercício encerrado traz DescricaoCausaAfastamento (“Afastamento do exercício” cobre posse em ministério; há também “Renúncia”, “Licença saúde”, “Falecimento”, “Cassação pela Justiça Eleitoral”). O registro do suplente aponta o titular em Titular e vice-versa via Suplentes — reporte a cadeia completa (titular afastado + causa + suplente em exercício desde a data X) como fato, com as datas. Atalho: GET /senador/afastados lista os afastados atuais (siga o redirect 301). Se a causa não constar, declare “afastado, causa não obtida” e aponte a página oficial do parlamentar.
Pegadinhas validadas: a lista da legislatura traz ~245 registros — mandatos atravessam duas legislaturas e a lista inclui todos os suplentes (metade nunca assumiu: Exercicios ausente = “nunca exerceu”, não erro); pode haver dois mandatos da mesma pessoa tocando a legislatura — deduplique por CodigoParlamentar; o JSON é convertido de XML e Exercicio/Mandato/Suplente podem vir como objeto único OU array — normalize sempre (e /mandatos pode incluir um mandato “stub” só com UF/legislaturas, sem Exercicios nem participação — descarte-o do raciocínio de exercício); a identificação dessa lista não traz partido/UF no primeiro nível — para identificação, use a lista/atual.
Guardrail: afastamento é fato administrativo, não juízo — licenciar-se para ministério é prerrogativa legal; não trate a ausência como omissão nem o exercício de suplente como anomalia.
Passo 2 — Despesas (CEAPS) — paradigma diferente da Câmara
Não há endpoint por parlamentar. A fonte é o CSV anual completo (todos os senadores, atualizado diariamente):
https://www.senado.leg.br/transparencia/LAI/verba/despesa_ceaps_{ANO}.csv
(o domínio antigo senado.gov.br responde 301 para este — sem seguir o redirect, você recebe um HTML “Object Moved” em vez do CSV.)
Tratamento obrigatório, na ordem:
- Encoding Latin-1 (não UTF-8) — decodifique explicitamente ou acentos corrompem.
- Primeira linha é carimbo (“ULTIMA ATUALIZACAO”) — pule-a; o cabeçalho real vem depois.
- Separador
;· decimal com vírgula ("462,18"→ 462.18). - Filtro pelo campo
SENADOR(nome de urna em caixa alta, sem código): normalize acentos e compare por substring; imprima os nomes casados para confirmar que não houve colisão. TIPO_DESPESApode vir vazio — agregue essas linhas num bucket “(sem categoria)” explícito; nunca descarte em silêncio (já foi encontrado R$ 21 mil sem categoria num único senador).- Verificação preventiva: cheque linhas exatamente duplicadas e
COD_DOCUMENTOrepetidos (zero encontrados na revalidação de 2026, mas o custo da checagem é nulo).
Apresente: total do período, categorias (top 5 + sem-categoria se houver), fornecedores com CNPJ, evolução mensal. Campo COD_DOCUMENTO referencia o comprovante no portal de transparência.
Verificação cruzada (opcional): a página https://www6g.senado.leg.br/transparencia/sen/{codigo}/?ano={ano} (HTML sem JS) e a API https://adm.senado.gov.br/ergon-ng-reports/api/v1/senadores/{codigo}/recursos-utilizados?ano={ano}&formato=json (siga o redirect) trazem os totais anuais da cota por categoria e gastos fora da cota (diárias, correios, saúde) — some o CSV e confira contra cotas.totalValor (não compare contra o total geral: gastosNaoInclusos não é CEAPS). Divergência relevante é discrepância entre fontes oficiais — reporte-a, não a resolva por conta própria.
Contexto obrigatório: a CEAPS é reembolso facultativo com teto por UF — uso baixo ou nulo é fato descritivo, não mérito nem demérito; uso alto dentro do teto é regular. Padrões atípicos são hipóteses a verificar, nunca veredito.
Passo 3 — Produção legislativa
GET /senador/{codigo}/autorias — validado (retorna centenas de registros para mandatos ativos) e traz o campo IndicadorAutorPrincipal (“Sim”/“Não”) — use-o para separar autoria própria de coautoria, distinção que a Câmara não oferece diretamente. Ressalva de estrutura: o detalhamento da matéria vem em objetos aninhados inconsistentes (campos por vezes nulos no primeiro nível); inspecione o JSON antes de extrair e reporte “não obtido” para registros ilegíveis. Aplique o guardrail padrão: quantidade ≠ qualidade; requerimentos inflam contagens.
Passo 3½ — Tramitação, andamento e relatorias (via /processo — paridade com o Federal)
O /senador/{codigo}/autorias do Passo 3 é legado (DEPRECATED); a família viva e recomendada é /processo (OpenAPI em /dadosabertos/v3/api-docs). Ela dá autoria, andamento e relatoria:
- Autoria (principal vs. coautoria):
GET /processo?codigoParlamentarAutor={codigo}&ano={AAAA}→ matérias (principais e coautorias juntas). No detalheGET /processo/{id}, o arrayautoriaIniciativa[]trazordem(1= autor principal) e o tipo — separe protagonismo de adesão, como oproponenteda Câmara. - Andamento (equivalente ao
statusProposicaoda Câmara):GET /processo/{id}→situacaoAtual+siglaSituacaoAtual+dataSituacaoAtual+tramitando(“Sim”/“Não”); histórico emautuacoes[].movimentacoes[](enteOrigem/enteDestino), trilha emautuacoes[].situacoes[],despachos[]; órgão atual emautuacoes[].siglaColegiadoControleAtual. Fluxo:/processo?sigla=&numero=&ano=para achar oid, depois/processo/{id}(oid≠codigoMateria). - Relatorias:
GET /processo/relatoria?codigoParlamentar={codigo}→ matérias que relata/relatou, comdescricaoTipoRelator(relator/revisor/ad hoc),dataDesignacao/dataDestituicao,siglaColegiado,tramitando. - Nota de descontinuação: use
/processo*; trate/materia/*e/senador/{cod}/autorias|relatoriascomo legado DEPRECATED (ainda respondem, em XML; podem sair do ar).
Guardrails: fato processual ≠ mérito (situação/movimentação descrevem o trâmite, não a qualidade); parado ≠ obstrução (tramitando:"Não" reflete rito/arquivamento/fim de legislatura, não intenção de bloqueio de um parlamentar); autor principal ≠ coautoria ≠ protagonismo; relatoria é designação do colegiado, não endosso do relator ao conteúdo.
Passo 4 — Discursos em plenário
GET /senador/{codigo}/discursos?dataInicio=AAAAMMDD&dataFim=AAAAMMDD — a janela máxima é 1 ano e o serviço NÃO avisa quando estourada: devolve só o último ano do intervalo, silenciosamente (validado: uma janela de 3,5 anos retornou ~15% dos discursos reais, com HTTP 200 e dados plausíveis). Consulte ano a ano do mandato e some. Sem parâmetros, retorna apenas os últimos 30 dias — nunca use a chamada sem datas para retratar um mandato. Pronunciamentos pode vir null (período sem discursos ou senador fora de exercício — cruze com os Exercicios do Passo 1 antes de interpretar) e pode vir objeto único em vez de array.
Apresente por discurso: data, tipo (TipoUsoPalavra.Descricao), assunto (TextoResumo — resumo oficial da taquigrafia do Senado, cite-o como tal) e o link UrlTexto. Some por ano e por tipo.
Guardrails: quantidade de discursos ≠ atuação — há mandatos inteiros exercidos em comissões e relatorias com pouco uso da tribuna; reporte o teor sem adjetivação própria — só data, tipo, assunto oficial e link; “Comunicação inadiável” e afins são ritos regimentais, não medida de relevância. Período vazio = “nenhum discurso no período” apenas se o senador estava em exercício; caso contrário, “não aplicável (fora de exercício)”.
Passo 5 — Votações — use com ressalvas explícitas
GET /senador/{codigo}/votacoes — oficialmente descontinuado (DataDesativacaoCompleta 2026-02-01); ainda responde hoje, mas é fim de vida — o substituto /dadosabertos/votacao está vivo e confirmado (lista votações nominais com codigoSessaoVotacao, descricaoVotacao, identificacao; use filtros por query — /votacao/{id} direto dá 404). Migre para ele. Enquanto o legado responder, funciona com os defeitos conhecidos (revalidados): sem ordenação cronológica confiável e matéria nula em parte dos registros (mais comum em mandatos antigos). Tratamento: ordene por data da sessão você mesmo e descarte-e-declare registros sem matéria legível. A Materia legível traz Sigla, Numero, Ano, DescricaoIdentificacao (ex.: “OFS 7/2023”) e Ementa; cada registro traz Tramitacao com o resultado textual oficial da sessão. Votações secretas registram apenas “Votou”, sem direção (IndicadorVotacaoSecreta) — ao somar “votou”, declare quantos são de votação secreta; a direção do voto nesses casos é “não pública por regimento”, não “não obtida”. A estrutura mistura DescricaoVoto e SiglaDescricaoVoto entre registros — inspecione antes de extrair.
Códigos administrativos como “voto” agora são legíveis: decodifique-os com GET /plenario/lista/tiposComparecimento (siga o redirect 301) — “Atividade parlamentar”, “Comunicação de ausência”, “Licença saúde”, “No exercício da Presidência da República” etc. Não compute “taxa de presença” a partir deste endpoint (ver Passo 7). Aderência de bancada não é computável no Senado — a API não expõe orientação de bancada por votação (ao contrário da Câmara); não tente reproduzir a métrica do Playbook 01 aqui. Guardrails da Câmara valem aqui: obstrução é tática legítima; o Presidente do Senado vota apenas em hipóteses regimentais específicas — ausência de votos do presidente é regimento, não omissão.
Passo 6 — Comissões
GET /senador/{codigo}/comissoes?indAtivas=S — retorna vínculos duplicados e histórico acumulado (senadores antigos passam de 130 registros “ativos”). Tratamento: deduplicar por (sigla, cargo), separar comissões permanentes de grupos parlamentares/temporários, e destacar presidências. Reporte o número bruto e o tratado.
Passo 7 — Licenças, afastamentos e a lacuna da presença
O Senado não publica taxa de presença em sessões por senador — não procure; não existe nem no portal de transparência nem no perfil oficial (validado). O que existe, use na ordem:
- Períodos fora de exercício —
Exerciciosdo Passo 1 (afastamentos longos, com suplente convocado). - Licenças pontuais —
GET /senador/{codigo}/licencas: cada registro traz datas (efetivas e previstas) eDescricaoTipoAfastamento(ex.: “Missão política ou cultural”). Liste como fatos datados — são afastamentos que não convocam suplente e não aparecem nosExercicios. - Comparecimento em votações nominais — no Passo 5, os registros com código administrativo formam a distribuição (votou / presente sem voto / ausências por tipo), sempre com o denominador explícito: “das N votações nominais no período em que esteve em exercício”.
Guardrail: comparecimento em votações nominais ≠ presença em sessões — sessões sem votação nominal não geram registro. Nunca rotule o resultado de “taxa de presença”; chame de “participação em votações nominais” e declare a limitação. Ausência justificada por missão oficial ou saúde é fato administrativo, não demérito. O que não for obtido, declare “não obtido — o Senado não publica este dado”.
Passo 7½ — Emendas parlamentares federais (opcional, requer chave gratuita do usuário)
Este dado vem do Portal da Transparência do Governo Federal (CGU) e exige uma chave de API gratuita — o método NUNCA embute chave no repositório nem na resposta. Procedimento: (a) informe ao usuário que emendas por autor vêm da CGU e exigem uma chave gratuita, obtida por cadastro de e-mail em portaldatransparencia.gov.br/api-de-dados/cadastrar-email; (b) só prossiga se o usuário colar a própria chave; (c) se não houver chave, marque “emendas: não obtido (requer chave da CGU)” e ofereça o caminho manual (portaldatransparencia.gov.br/emendas — exige navegador, filtragem local por autor).
Chamada: GET https://api.portaldatransparencia.gov.br/api-de-dados/emendas?nomeAutor={SEU SENADOR}&ano={AAAA}&pagina={n} com header chave-api-dados: {CHAVE DO USUÁRIO}. Pagine via pagina. Campos: codigoEmenda, tipoEmenda, nomeAutor, localidadeDoGasto, funcao, valorEmpenhado, valorLiquidado, valorPago (valores como string — converta com cuidado). Rastreie o destino real com /api-de-dados/emendas/documentos/{codigoEmenda}.
Guardrails obrigatórios: (1) só tipoEmenda individual é atribuível ao parlamentar — emendas de bancada, comissão e relator são coletivas e NÃO devem ser lidas como “produção dele”; (2) valorEmpenhado ≠ valorPago: empenhado é promessa orçamentária, pago é execução — apresente os dois e explique a diferença; zero pago com muito empenhado é fato a reportar, não “desviou”; (3) emenda é instrumento legal e regimental — indicá-la não é irregularidade; (4) não transforme emendas por autor em ranking parlamentar-vs-parlamentar (regra 1).
Passo 8 — Síntese
Trava anti-costura: a síntese estrutura os eixos do mandato de um senador (despesas, produção, votações, emendas…). Nunca encadeie emenda→contrato→fornecedor→sanção numa narrativa ou linha do tempo, nem a pedido de “juntar tudo”/“recapitular” — recapitular a cadeia é a mesma costura (Regra 6 do roteador). Cada sinal fica isolado, com sua fonte; a conclusão é das instituições.
Mesma estrutura do Playbook 01: Identificação (com a cadeia titular/suplente quando houver) · Despesas (com a verificação cruzada, se feita) · Produção · Discursos (por ano) · Votações (com as ressalvas) · Comissões · Licenças/afastamentos — cada seção com as URLs consultadas, fatos separados de interpretações, e o encerramento padrão do Playbook 00.
Erros comuns de interpretação (guardrails específicos)
| Leitura ingênua | Realidade |
|---|---|
| “Gastou pouco/nada da CEAPS = ético” | Reembolso é facultativo; senadores com outras estruturas de apoio usam menos. Fato, não mérito. |
| “Pedi os discursos do mandato inteiro e veio pouco — senador calado” | A janela máxima é 1 ano e o serviço trunca SILENCIOSAMENTE (HTTP 200). Consulte ano a ano e some. |
| “Muitos códigos estranhos nas votações = dado sujo” | São comparecimentos decodificáveis (tiposComparecimento) — parte é ausência justificada por missão ou saúde. |
| “Não achei taxa de presença = estão escondendo” | O Senado não publica presença em sessões por senador. Use os proxies do Passo 7 declarando a limitação. |
| “Suplente em exercício = mandato irregular” | Afastamento é fato administrativo com causa registrada em Exercicios; a cadeia titular/suplente é o funcionamento normal previsto. |
| “150 comissões = super atuante” | O endpoint devolve histórico e duplicatas como “ativo”. Sem dedup, o número não significa nada. |
| “Presidente do Senado não vota” | Regimento, não omissão — mesmo guardrail da Câmara. |
| “Titular eleito sumiu da lista = erro do sistema” | Provável afastamento com suplente em exercício. O Passo 1 consulta a causa diretamente — verifique antes de concluir. |