The API's quirks¶
The ALEPE open data API is generated from an internal system and shows it. Each of the quirks below produced a wrong result before it was understood, and each is handled for you — but knowing they exist explains some of the shapes you will see in the data.
Two naming conventions at once¶
/servidores answers with NOME_LOTACAO; /parlamentares answers with
nomeParlamentar; /contratos mixes modalidade with vigenciaInicio. The
package normalises all of them to snake_case without translating the word, so
nome_lotacao and nome_parlamentar stay traceable to the field they came
from.
Two number encodings at once¶
Some fields arrive as Brazilian money strings, "1.234,56". Others arrive as
plain float-formatted strings: "119267.04" for a contract value, "2026.00"
for a year.
Reading either with a fixed locale corrupts the other. A Brazilian locale reads
"119267.04" as 11 926 704 — a contract inflated a hundredfold, silently and
plausibly. The parser decides per value instead: a comma always marks the
decimal, and a dot is a grouping mark only when it separates pure three-digit
groups.
Dates in three shapes¶
dd/mm/yyyy in the propositions, ISO in some fields, and serialised PHP
DateTime objects in others:
{"date": "2026-05-05 00:00:00.000000", "timezone_type": 3, "timezone": "America/Recife"}
All three come back as datetime.date.
Propositions are XML inside CSV¶
/proposicoes/{projetos,indicacoes,requerimentos} do not serve JSON. They serve
a CSV with a single column, and that column carries XML: one self-contained
fragment per proposition when listing, one full document when fetching a single
one. The package parses both into ordinary columns.
Free-text fields are HTML, and in /indicacoes they are double-encoded
(à for à). Markup and entities are stripped, so ementa is
plain readable text.
One very slow endpoint¶
/licitacoes takes 25–30 seconds to answer, and the service cuts its own query
off at 30 seconds. It therefore alternates between a 200 with the full payload
and a bare 500 at exactly the 30-second mark, depending on load. This is why
the default timeout is 60 seconds rather than the usual 30, and why the cache
matters more here than it looks.
Fields the service publishes empty¶
At the time of writing, /licitacoes returns valorEstimado, vencedor and
valorAdjudicado as null for every process, and /contratos fills
numeroContrato with the contractor's tax id rather than the contract number.
The package passes both through as published rather than guessing — a wrong
value invented by a client is worse than an honest gap.
The API blocks datacenter IPs¶
Requests from GitHub-hosted runners never complete: DNS resolves, but the TCP handshake to port 443 gets no answer at all. The test suite is therefore fully offline, running against fixtures that are verbatim samples of real responses. If you are automating on cloud infrastructure and seeing timeouts, this is probably why, and it is not something the package can work around.