Funding API
Read access to the corpus this site is built on — calls from the EU Funding & Tenders Portal, CORDIS, Spain's BDNS and the BOE, normalised into one schema. The machine-readable contract is an OpenAPI 3.1 document; it is generated from the same constants the API validates against, so it never describes a parameter the endpoint would reject.
Two promises worth reading before you build on it
Only published calls are ever returned. Records withheld under the SNPSAP aviso legal — an organisation that is a natural person, for instance — are absent from every response, and there is no parameter to include them.
Nothing about a deadline is invented. deadline
is the closing day the source published. deadline_time is filled
in only when the source stated a time, and is null otherwise —
never midnight, because a midnight nobody published would sort and filter as
though somebody had. status is the status as it reads
today: a call whose stated deadline has passed is reported
closed even when its source still calls it open.
Getting started
No credential needed:
curl 'https://quiescence.eu/funding/api/v1/search?q=hydrogen&status=open&per_page=5'
With a key, for higher limits:
curl -H 'X-API-Key: fnd_…' \
'https://quiescence.eu/funding/api/v1/search?country=ES&sort=deadline'
Issue a key on your account page. It is
shown once: only a hash is stored, so it cannot be recovered or re-displayed
— if you lose one, revoke it and issue another. Send it as the
X-API-Key header and never as a query parameter, because URLs
reach access logs, Referer headers and browser history.
Tiers
| Tier | Per minute | Per day | How to get it |
|---|---|---|---|
anonymous |
60 | — | Send no credential. Limited by IP. |
basic |
120 | 1,000 | Any signed-in account can issue a key. |
pro |
600 | 25,000 | A key owned by an account with an active subscription. |
The tier is decided per request from the live subscription, not stored on the key — so an upgrade applies immediately and a lapse downgrades immediately. Anonymous callers have no daily quota on purpose: a daily cap on an IP is a cap on everyone behind one network, and the first people it would cut off are a university or a ministry.
Limits, and what to do when you hit them
Every response carries its own accounting:
X-API-Tier- The tier this request was served under.
X-RateLimit-Limit- Requests allowed per minute.
X-RateLimit-Remaining- Requests left in the current minute.
X-Quota-Limit- Daily allowance. Absent for anonymous callers, who have none.
X-Quota-Remaining- Calls left today, with this one already counted.
X-Quota-Reset- Seconds until the daily window rolls.
Both limits answer with 429 and a Retry-After
in seconds, which is authoritative — prefer it to your own backoff. The two
are distinguishable by the error field:
rate_limited means you are going too fast right now and
Retry-After is a few seconds; quota_exceeded means
the day's allowance is gone and Retry-After counts down to
00:00 UTC, when the window rolls.
Nothing resets a counter at that moment — tomorrow's calls are simply counted against tomorrow's date — so the reset needs no scheduled job and cannot be delayed by one failing.
Errors
Every error has the same shape. Branch on error, which is stable;
message is for humans and may change.
{"error": "quota_exceeded", "message": "Daily quota reached for this API key. It resets at 00:00 UTC."}
bad_request(400)- A parameter failed validation; the message names which.
invalid_key(401)- The key is not recognised — usually a truncated copy.
revoked_key(401)- The key was valid and has been revoked. Issue a new one.
subscription_required(403)- The endpoint is part of the paid plan.
rate_limited(429)- Too fast. Wait
Retry-Afterseconds. quota_exceeded(429)- Day's allowance used. Resets at 00:00 UTC.
Endpoints
GET /search
Parameters: q, country, status
(