Colombian public procurement, four questions deep
SECOP II publishes every public contract in Colombia. This is a read-only view over a daily ELT pipeline that lands it in BigQuery, models it with dbt, and serves four questions through a FastAPI service on Cloud Run.
One thing to carry into every page: these figures describe what entities reported, not what they did. A missing value is a missing report, and it is not a zero. Wherever a number was not reported this site draws it as a hatched gap rather than filling it in — because a confident zero is a wrong answer where no answer exists.
The pipeline
Every stage runs daily, orchestrated by Airflow. Nothing on this site is precomputed at build time.
01
Socrata API
SECOP II, daily extract
02
GCS
raw landing
03
BigQuery
secop_raw
04
dbt
staging → marts
05
FastAPI
Cloud Run
06
Next.js
this site
Rows loaded by the API
- dim_entidad
- 5.621
- agg_entidad_modalidad
- 55.234
- agg_entidad_ejecucion
- 3.511
Read live from /health, never hardcoded — the marts are a full daily rebuild and these drift. This container loaded them at 22/08/2026, 9:52 a. m. Bogotá time.
How to read a gap
The most important convention on this site.
A hatched block means not reported. It never means zero, and it never means low. It appears for every null value, every contract that recorded no value, the unknown supplier, and every entity with no median.
Solid blue is a reported figure. The texture, not the colour, is what distinguishes the two — so it survives greyscale, printing, and colour vision deficiency.
Amounts are Colombian pesos, compacted on the long scale: M is a million and B is a billón, 10¹². Entity, sector and modality names are Spanish because the source data is.
National context, 2024
Contracts signed
950.670
across 3.442 entities
Signed in Nov–Dec
110.731
two months of the twelve
Nov–Dec share, by count
11,6 %
below the 16,7 % those two months are by time
Nov–Dec share, by value
28,3 %
the year-end effect is in contract size, not volume
Observed, not expected. These are the figures each entity's own Nov–Dec share has to be read against — never one against the other, since count and value answer different questions.
Why 2024? It is the most recent year whose values have actually landed. 2025 currently reports a Nov–Dec value share of 4,1 % — late value reporting rather than a real change, and the API's completeness flag does not catch it, because that year's contract count share is normal at 12,1 %. Every year is selectable on year-end rush.
The four questions
Q1 · direct contracting
How much is awarded without competition?
The share of an entity's contracting awarded directly rather than competitively, by count and by value.
The catch: direct contracting is 78 % of all Colombian contracts, so a high rate is normal. The signal is deviation from peers. Both rates are published because they diverge — 90 % of contracts and 1 % of the money is a different story from the reverse.
Q2 · supplier concentration
Who did the money actually go to?
For one entity in one year: its largest suppliers, and how concentrated its spending was.
The catch: concentration without size is meaningless — 100 % across one supplier and two contracts is noise. This is also the only page that queries the fact table live, at about 163 MiB per entity, so the list you pick from is served from memory instead.
Q3 · year-end rush
How much is signed in the last two months?
The share of an entity's yearly contracting signed in November and December, against the national figure for the same year.
The catch: an entity's figure means nothing without the national one beside it, and the count share and the value share answer different questions.
Q4 · coverage and execution
Do finished contracts record what was paid?
Of an entity's finished contracts, the share recording any payment — and among those, the median paid-to-contracted ratio.
The catch: ranking by the median alone measures reporting discipline, not execution. An entity that never reports looks identical to one that never executed.