PNRR contracts: five public systems that do not talk

9/13/20267 min read
PNRR contracts: five public systems that do not talk

Direct answer: in Italy, answering «who won this PNRR contract, and with whose money» requires querying at least five separate public systems — OpenCUP, ANAC, SCP, OpenBDAP and the National State Aid Register — none of which exposes data in a way that lets you cross-reference it automatically with the others. Worse: for «ordinary» CIGs, which is precisely the category the large PNRR contracts fall into, the winning bidder's name is not present in the official ANAC API. This article documents every barrier, source by source, encountered while building a connector for OpenLegis.

TL;DR

  • OpenCUP has no API: it exposes one page per project, designed for a human with a browser. No search endpoint.
  • ANAC publishes a bulk file of roughly 3 million rows instead of a queryable search endpoint.
  • SCP and OpenBDAP are two separate systems, each with its own logic, covering different parts of the same lifecycle.
  • The National State Aid Register exists only as a massive XML dump, with a weak and unguaranteed link back to the CUP.
  • For «ordinary» CIGs — the category the large PNRR contracts fall into — the winning bidder is invisible in the official ANAC API: to find it you must go through SCP's «Esiti» (outcomes) section, a different source with a different key.
  • None of these systems was designed to be queried together with the others. The practical result: the chain funding → tender → winner → money actually paid does not close without manual work.

Why the question is simple and the answer is not

The starting question is the most ordinary one a citizen can ask: a PNRR project worth €864,000 in my town — who is carrying it out, and how much have they been paid so far?

On paper the data all exists, and it is all public. Every funded project has a CUP (unique project code). Every tender has a CIG (tender identification code). Every award has a winner and an amount. Every payment leaves an accounting trace.

The problem is not missing data. It is that each of these four steps lives in a different system, with a different data model, a different access key and a different idea of what «publishing» means.

The five sources, one by one

Source What it holds How you query it The real barrier
OpenCUP Funded project registry Web page per CUP No API. No programmable search
ANAC Tender and contract registry Bulk file (~3M rows) No search endpoint: all or nothing
SCP Tender outcomes, winners Separate portal Different key and data model from ANAC
OpenBDAP Accounting data, payments Separate portal Covers a different part of the lifecycle
State Aid Register Aid granted to companies Massive XML dump Weak, unguaranteed link to the CUP

Taken one at a time, none of these systems is scandalous. Taken together — which is the only way they are actually useful — they are a maze.

The gap that matters: the invisible winner

There is one technical detail worth more than all the others combined, and I only found it by integrating.

In ANAC's official API, for CIGs in «simplified» mode (small tenders) the winning bidder field is there. For CIGs in «ordinary» mode — the mode used for large contracts, meaning exactly the PNRR ones — that field is not exposed.

In plain terms: on precisely the contracts where the winner's name matters most, the official API does not tell you. To get it you have to go to a different portal (SCP's «Esiti» section), with a different key and a different search logic, and rebuild the link by hand.

This is not a typo in a file. It is a decision about which fields to expose, in which mode, in which system.

«Open» does not mean «queryable»

This pattern is not new — I have already documented it source by source across the whole Italian landscape: portals answering zero bytes to a program, official SPARQL endpoints returning an empty 200, broken TLS certificates on government domains.

With public contracts, though, the stakes are different. This is not a statistical dataset that happens to be convenient for a researcher: this is who gets public money, in the largest spending plan in the Republic's history. Fragmentation here is not a technical annoyance. It is a barrier to the one form of distributed oversight that open data is supposed to make possible.

If you are a journalist or an activist: what you can actually do

You do not need to write code to use what exists. You need to know what order to look in.

  1. Start from the CUP, not from the company name. The CUP is the only key that crosses several systems. You will find it on the municipal resolution or the funding decree.
  2. On OpenCUP you get the project registry entry: implementing body, funded amount, status.
  3. On ANAC you look for the linked CIGs. If the project is large, expect the winner to be missing.
  4. On SCP, «Esiti» section, you search the same CIG to find the actual winner.
  5. On OpenBDAP you check how much was actually disbursed — which almost never matches the awarded amount.

Every step you skip is a piece of the story you lose. And every step requires copying a code by hand from one portal to another, which is exactly why almost nobody follows it through to the end.

Neglect or design?

I do not have an answer, and I am wary of anyone who has one too quickly.

The neglect hypothesis is plausible and should not be dismissed: systems born in different eras, from different administrations, with different goals, none of which had «you must talk to the other four» as a requirement. This is the normal way public software accretes, everywhere in the world.

But the neglect hypothesis explains one detail poorly: why the winning bidder field is present in small tenders and disappears in large ones. That is not historical accretion. That is a behavioural difference inside the same system, deliberate at least in the sense that someone wrote it.

I am leaving the question open, because that is where it stands: the technical facts are verifiable, intentions are not. But the first step toward an answer is for the facts to be written down somewhere — which is what this article tries to do.

FAQ

Is there a single database of Italian public contracts?

No. There are several systems covering different phases — funding (OpenCUP), tender (ANAC), outcome (SCP), accounting (OpenBDAP), corporate aid (State Aid Register) — and none of them is designed to be cross-referenced automatically with the others.

Can I find out who won a PNRR contract straight from the ANAC API?

In most of the cases that matter, no. For CIGs in «ordinary» mode, which is the mode used for large contracts, the winning bidder is not exposed in the API. You have to retrieve it from SCP's «Esiti» section.

What is the CUP and why is it the right starting key?

The CUP (unique project code) identifies the funded project, not the individual tender. It is the only identifier that appears — in different forms — across several systems, which makes it the starting point that lets you follow a project through its phases.

Why is downloading ANAC's bulk file not enough?

Because it holds roughly three million rows of tender registry data, without outcomes, and without a direct, reliable link back to the upstream funding. It tells you a tender exists; it does not tell you who won it or which funds paid for it.


If you work with public data and need a reliable way to cross-reference it — or you are assessing whether a project like this is feasible in your context — let's talk. It is the same kind of work behind OpenLegis's knowledge graph of laws and public data.

Open DataCivic TechItalyData Engineering

Scritto da Giulio Garofalo