Using the API
Rate limits and quotas
Three limits, each reported before you hit it: requests per second, requests per month, and match evaluations per month.
Per plan
| Developer | Pro | Business | Enterprise | |
|---|---|---|---|---|
| Requests per month | 10,000 | 100,000 | 500,000 | Unlimited |
| Match evaluations per monthOne company evaluated against every measure. | 100 | 1,000 | 10,000 | Unlimited |
| Requests per second | 5 | 15 | 40 | 150 |
| API keys | 2 | 3 | 5 | 50 |
| Rows per page | 100 | 200 | 200 | 500 |
| Companies per bulk match | Not included | Not included | 500 | 5,000 |
| Companies on watchlists | Not included | Not included | 5,000 | Unlimited |
| Webhook endpoints | Not included | 5 | 10 | 50 |
| Change feedGET /v1/changes | Included | Included | Included | Included |
| Versions of every measureGET /v1/subsidies/{id}/versions | Not included | Included | Included | Included |
| A measure as it stood on a date?as_of= | Not included | Included | Included | Included |
| Webhooks | Not included | Included | Included | Included |
| Bulk matchingPOST /v1/match/bulk | Not included | Not included | Included | Included |
| Watchlists | Not included | Not included | Included | Included |
| Whole-catalogue exportNDJSON | Not included | Not included | Included | Included |
| Redistribution rights (by contract) | Not included | Not included | Not included | Included |
Rendered from GET /v1/plans, the table the API enforces. Prices are on pricing.
An account without a plan can create a key, but that key answers 402 subscription_required on every route, before any limit is counted, until a plan is chosen in the dashboard.
Requests per second
Each account has a token bucket sized for its plan, shared by all its keys, with a burst of one second’s allowance: a handful of parallel requests followed by a pause is fine, a hot loop is not. Over it, the answer is 429 rate_limit_exceeded with Retry-After: 1. The rate limit is checked before the quota, so a client in a hot loop is told to slow down rather than that its month is spent. The routes that need no key are limited per client address instead.
Requests per month
Every request to a keyed route counts once, whatever it returns, the MCP endpoint and GET /v1/key included; a request without a valid key or without a plan, or refused by the rate limit or the quota itself, does not. Live and test keys count alike. The month is the UTC calendar month. When it is spent, the answer is 429 quota_exceeded with Retry-After set to the seconds until the next month begins. Enterprise has no monthly limit.
Match evaluations
Matching has its own monthly allowance, counted apart from requests. A match evaluation is one company evaluated against every measure:
| Call | Evaluations |
|---|---|
| POST /v1/match | 1 |
| POST /v1/match/bulk | One per company with valid facts; a company answered with its own error is not counted. |
| POST /v1/watchlists/{id}/companies | One per company accepted, added or replaced. |
| MCP match_company, explain_eligibility | 1 each. |
| Re-evaluating a watchlist when a measure changes | Nothing. Included in the plan. |
When the allowance is spent, matching answers 429 match_quota_exceeded (with details.limit and Retry-After), and everything else keeps working: you can still search and read measures. A bulk request or a watchlist upload that would go past the allowance is refused as a whole, and nothing of it is evaluated or counted. GET /v1/key reports match_evaluations_this_month.
Headers
Every response from a keyed route carries the monthly figures:
| Header | Meaning |
|---|---|
| RateLimit-Limit | Your plan’s monthly request quota. |
| RateLimit-Remaining | Requests left this month, after this one. It reaches 0 on the last request you are allowed. |
| RateLimit-Reset | Seconds until the quota resets, at the start of the next UTC month. |
| X-Quota-Limit, X-Quota-Remaining | The same two figures under a second name. |
curl -sI "https://api.subsido.be/v1/subsidies?limit=1" -H "Authorization: Bearer sb_live_..." | grep -i -E "ratelimit|quota"- An unlimited plan sends no
-Limitor-Remainingheader rather than a very large number;RateLimit-Resetis still sent. - The headers describe the monthly request quota, not the per-second limit and not match evaluations.
- Browsers can read them: the API exposes them to cross-origin JavaScript.
Other ceilings
Per request
| What | Limit |
|---|---|
| Rows per page | The plan’s max_page_size. See pagination. |
| Matches returned by POST /v1/match | limit, 1 to 100 (default 25). |
| Companies in POST /v1/match/bulk | The plan’s max_bulk_companies; above it, plan_required naming the plan that allows it. |
| Companies in one watchlist upload | 1,000. |
| Search text q | 200 characters. |
| Bulk export downloads | Two at a time across the service; a third waits (429, Retry-After: 5). |
Per account
| What | Limit |
|---|---|
| API keys | The plan’s api_keys. |
| Watchlists | 50. |
| Companies across all watchlists | The plan’s watchlist_companies. |
| Webhook endpoints | The plan’s webhook_endpoints. |
Need more?
