Skip to content
Subsido

Matching

Matching a company

POST /v1/match evaluates every measure against what you know about one company and one project, and answers which plausibly fit, why, what is still unknown, and what each could be worth.

Who decides

A match is an indication based on the published conditions and the facts you provide. Only the competent authority decides who qualifies.

The request

curl -X POST "https://api.subsido.be/v1/match" \  -H "Authorization: Bearer sb_live_..." \  -H "Content-Type: application/json" \  -d '{"company":{"postcode":"9000","employees":12,"turnover_eur":1500000,"legal_form":"bv","nace":["62.010"]},"project":{"topics":["digitalisation","investment"],"budget_eur":25000,"planned_start":"2026-11-01"},"language":"en","limit":10}'
PropertyMeaning
companyWhat you know about the company. Every property is optional.
projectWhat the company wants support for. Every property is optional.
optionsWhich measures to consider. See below.
languagenl, fr or en (default): titles, summaries, rule labels and questions.
limitMatches to return, 1 to 100 (default 25). The count of all matches is in matched either way.

The body is strict: a property the API does not know, anywhere in it, or a value of the wrong type or outside its vocabulary, is 400 invalid_parameter naming it, so a misspelt turnover never silently turns into an unknown. A value that parses but cannot be right (a postcode outside Belgium, an enterprise number whose check digits fail, a negative amount) is 422 invalid_body with the property in details.field. Send Content-Type: application/json.

A fact you do not give is unknown, never assumed. That is the point: instead of a confident score built on guesses, the answer says which facts would settle each measure.

company

PropertyTypeMeaning
enterprise_numberstringThe KBO/BCE number in any usual form (BE0123.456.749, 0123 456 749, or the old nine digits). Validated with its mod-97 check and echoed back as 0123.456.749. An identifier only: no register is consulted, so it adds no facts.
postcodestringThe Belgian postcode of the seat or of the operating unit concerned. Decides the region and the province when you do not give them.
region, regionsstring, string[]Where the company has an establishment: flanders, brussels, wallonia. region is shorthand for a list of one; both may be given and are combined.
provincestringOne of the ten provinces (east_flanders, liege, ...). Brussels is in none.
sizestringmicro, small, medium or large. Derived from the figures below when absent.
employeesnumberStaff headcount in annual work units (FTE).
turnover_eur, balance_sheet_eurnumberThe last closed financial year’s annual turnover and balance sheet total.
nacestring[]The company’s NACE-BEL codes, with or without dots: 62.010, 62010, 62.01. Give at least the two-digit division.
legal_formstringThe abbreviation people type, in Dutch or French: bv/srl (and the old bvba/sprl), nv/sa, cv/sc, vof/snc, commv/scs, maatschap, eenmanszaak/entreprise individuelle, vzw/asbl, ivzw/aisbl, stichting/fondation, se, public, other. Case, dots and spaces are ignored.
applicant_typestringOne of companyself_employednon_profitpublic_bodyresearch_organisationindividualfarmersocial_enterprise Derived from the legal form when absent.
founded_ondateYYYY-MM-DD. Gives the company’s age.
age_yearsnumberThe age directly, when you do not have the date.
has_legal_personalitybooleanDerived from the legal form when absent: a sole proprietorship and a maatschap have none.
de_minimis_received_eurnumberDe minimis aid received over the last three years.
in_difficultybooleanWhether the company is an undertaking in difficulty in the EU state aid sense.

project

PropertyTypeMeaning
topicsstring[]What the project is about, as topic ids (digitalisation, energy_efficiency, ...; GET /v1/taxonomy lists them). Used for relevance, and to leave out measures about something else.
budget_eurnumberThe project’s cost. Used by budget rules and by the estimate.
startedbooleanWhether the project has started. Many schemes refuse costs made before the application.
planned_startdateGives started when you do not: a start on or before today means started.
regionstringWhere the project or investment takes place, when that is not simply where the company is.
cost_typesstring[]The costs to support: training, consultancy, equipment, software, personnel, ... (the eligible cost list).
duration_monthsnumberHow long the project lasts.
partnersnumberIndependent partners carrying out the project, the applicant included.

options

PropertyDefaultMeaning
statusesopen, continuous, forthcoming, unknownThe measure statuses to consider.
instrument_typesallOnly these instrument types (grant, loan, tax_deduction, ...).
include_not_eligiblefalseAlso return the measures a rule rules out, as not_eligible, with the rule that failed.
include_unrelatedfalseWith project topics given, a measure whose topics share nothing with them (not even a related topic) is left out, unless this is set. A measure with no topics at all is kept either way.

What is derived

Facts you did not give are worked out from facts you did, conservatively, and every derivation is reported in profile.derived with the properties it came from. estimate: true marks one that rests on an assumption.

DerivedFromHow
company.regionscompany.postcodeA Belgian postcode determines its region. Only when you gave neither region nor regions.
company.provincecompany.postcodeAnd its province, except for Brussels, which has none. Only when you gave no province.
company.sizeemployees, turnover_eur, balance_sheet_eurThe EU SME definition, below. With a headcount alone, the headcount decides and estimate is true.
company.applicant_typecompany.legal_formbv, nv, cv, vof, commv, maatschap and se are a company; eenmanszaak is self-employed; vzw, ivzw and stichting are a non-profit; public is a public body. The French abbreviations map the same way.
company.has_legal_personalitycompany.legal_formFalse for eenmanszaak and maatschap, true for the other forms, unknown for other.
company.age_yearscompany.founded_onCompleted years on today’s Brussels date: founded 1 October 2019 is six years old on 27 September 2026, not seven. A date in the future is ignored with a warning.
project.startedproject.planned_startStarted when the planned start is today or earlier.
project.regionthe company’s regionsWhen the company is in exactly one region and you gave no project region. estimate is true: the project is assumed to be where the company is.

Size bands

Recommendation 2003/361/EC: a headcount ceiling and either the turnover or the balance-sheet ceiling. A company over a band’s financial ceilings moves up a band.

BandStaff (AWU)Turnoveror balance sheet
microfewer than 10at most €2mat most €2m
smallfewer than 50at most €10mat most €10m
mediumfewer than 250at most €50mat most €43m
largeeverything else

Partner and linked enterprises change the figures the definition uses, and the API cannot see them. That is one reason a match is “likely”, not “eligible”. Some measures (the Belgian tax shelter, for example) use the Belgian company code’s own size test instead; their rules then test the figures directly, so send the figures rather than only size.

The four statuses

Each measure’s rules are evaluated with three-valued logic (pass, fail, unknown; see eligibility rules), and the outcome, together with how good the measure’s rules are, gives the status:

match_statusExactly when
likely_eligibleEvery rule passed, and the measure’s rules are curated or extracted (rules_basis) with a confidence of at least 0.7. As strong as this API gets.
possibly_eligibleNo rule failed, and at least one could not be decided because a fact is missing. unknowns lists the facts that would decide it.
needs_reviewEvery rule passed, but the rules are only derived from structured fields, or their confidence is below 0.7: the conditions that decide are mostly prose that is not evaluated. Read the official page. A measure with no rules at all is here too.
not_eligibleA rule failed; reasons says which. Only returned with options.include_not_eligible.

Matches are sorted by status in that order, then by what can be applied for soonest (open, continuous, forthcoming, unknown, paused, budget exhausted, closed), then by score, then by the nearest deadline.

The response

{
  "matches": [
    {
      "subsidy_id": "federal:investeringsaftrek",
      "match_status": "likely_eligible",
      "confidence": 0.9,
      "relevance": 1,
      "score": 0.98,
      "reasons": [
        {
          "id": "applicant_type",
          "field": "company.applicant_type",
          "op": "in",
          "value": [
            "company",
            "self_employed",
            "farmer"
          ],
          "label": "Industrial, commercial or agricultural business, or liberal profession",
          "result": "pass",
          "actual": "company",
          "provenance": {
            "method": "curated",
            "source_url": "https://financien.belgium.be/nl/ondernemingen/vennootschapsbelasting/belastingvoordelen/investeringsaftrek",
            "source_section": "Wie kan de investeringsaftrek genieten?",
            "review_status": "verified",
            "reviewed_at": "2026-09-27",
            "note": null
          }
        }
      ],
      "unknowns": [],
      "matched_topics": [
        "digitalisation",
        "investment"
      ],
      "estimate": {
        "max_amount_eur": 10000,
        "rate_applied": 40,
        "basis": "€25,000 × 40%"
      },
      "subsidy": {
        "id": "federal:investeringsaftrek",
        "title": "Investment deduction",
        "summary": "Tax deduction from FOD Financiën for companies, self-employed people and farmers in Belgium. Covers 10% to 40% of eligible costs. Applications accepted at any time.",
        "status": "continuous",
        "instrument_type": "tax_deduction",
        "issuer": "FOD Financiën",
        "scope": "national",
        "regions": [],
        "topics": [
          "investment",
          "digitalisation",
          "energy_efficiency",
          "renewable_energy"
        ],
        "opens_at": null,
        "closes_at": null,
        "rolling": true,
        "budget_exhaustion_possible": false,
        "funding": {
          "rate_min": 10,
          "rate_max": 40,
          "amount_min": null,
          "amount_max": null,
          "annual_cap": null,
          "de_minimis": null
        },
        "rules_basis": "curated",
        "source": {
          "id": "curated_federal",
          "url": "https://financien.belgium.be/nl/ondernemingen/vennootschapsbelasting/belastingvoordelen/investeringsaftrek",
          "authority": "FOD Financiën",
          "last_checked_at": "2026-09-27T06:00:12+02:00",
          "freshness": "fresh"
        },
        "links": {
          "api": "https://api.subsido.be/v1/subsidies/federal:investeringsaftrek",
          "web": "https://subsido.be/en/grants/investeringsaftrek",
          "apply": "https://financien.belgium.be/nl/ondernemingen/vennootschapsbelasting/belastingvoordelen/investeringsaftrek"
        }
      }
    },
    {
      "subsidy_id": "federal:tax-shelter-start-up",
      "match_status": "possibly_eligible",
      "confidence": 0.9,
      "relevance": 0.25,
      "score": 0.515,
      "reasons": [
        {
          "id": "size",
          "field": "company.employees",
          "op": "lte",
          "value": 50,
          "label": "At most 50 employees (annual average)",
          "result": "pass",
          "actual": 12,
          "provenance": {
            "method": "curated",
            "source_url": "https://financien.belgium.be/nl/ondernemingen/tax-shelter-kleine-ondernemingen/startende-start-up",
            "source_section": "Art. 1:24 WVV",
            "review_status": "verified",
            "reviewed_at": "2026-09-27",
            "note": null
          }
        },
        {
          "id": "size_turnover_a",
          "field": "company.turnover_eur",
          "op": "lte",
          "value": 11250000,
          "label": "Annual turnover at most EUR 11,250,000 (excl. VAT)",
          "result": "pass",
          "actual": 1500000,
          "provenance": {
            "method": "curated",
            "source_url": "https://financien.belgium.be/nl/ondernemingen/tax-shelter-kleine-ondernemingen/startende-start-up",
            "source_section": "Art. 1:24 WVV",
            "review_status": "verified",
            "reviewed_at": "2026-09-27",
            "note": null
          }
        },
        {
          "id": "size_employees_b",
          "field": "company.employees",
          "op": "lte",
          "value": 50,
          "label": "At most 50 employees (annual average)",
          "result": "pass",
          "actual": 12,
          "provenance": {
            "method": "curated",
            "source_url": "https://financien.belgium.be/nl/ondernemingen/tax-shelter-kleine-ondernemingen/startende-start-up",
            "source_section": "Art. 1:24 WVV",
            "review_status": "verified",
            "reviewed_at": "2026-09-27",
            "note": null
          }
        },
        {
          "id": "size_balance_b",
          "field": "company.balance_sheet_eur",
          "op": "lte",
          "value": 6000000,
          "label": "Balance sheet total at most EUR 6,000,000",
          "result": "unknown",
          "actual": null,
          "provenance": {
            "method": "curated",
            "source_url": "https://financien.belgium.be/nl/ondernemingen/tax-shelter-kleine-ondernemingen/startende-start-up",
            "source_section": "Art. 1:24 WVV",
            "review_status": "verified",
            "reviewed_at": "2026-09-27",
            "note": null
          }
        },
        {
          "id": "size_turnover_c",
          "field": "company.turnover_eur",
          "op": "lte",
          "value": 11250000,
          "label": "Annual turnover at most EUR 11,250,000 (excl. VAT)",
          "result": "pass",
          "actual": 1500000,
          "provenance": {
            "method": "curated",
            "source_url": "https://financien.belgium.be/nl/ondernemingen/tax-shelter-kleine-ondernemingen/startende-start-up",
            "source_section": "Art. 1:24 WVV",
            "review_status": "verified",
            "reviewed_at": "2026-09-27",
            "note": null
          }
        },
        {
          "id": "size_balance_c",
          "field": "company.balance_sheet_eur",
          "op": "lte",
          "value": 6000000,
          "label": "Balance sheet total at most EUR 6,000,000",
          "result": "unknown",
          "actual": null,
          "provenance": {
            "method": "curated",
            "source_url": "https://financien.belgium.be/nl/ondernemingen/tax-shelter-kleine-ondernemingen/startende-start-up",
            "source_section": "Art. 1:24 WVV",
            "review_status": "verified",
            "reviewed_at": "2026-09-27",
            "note": null
          }
        },
        {
          "id": "age_max",
          "field": "company.age_years",
          "op": "lt",
          "value": 4,
          "label": "Within the first four years after incorporation",
          "result": "unknown",
          "actual": null,
          "provenance": {
            "method": "curated",
            "source_url": "https://financien.belgium.be/nl/ondernemingen/tax-shelter-kleine-ondernemingen/startende-start-up",
            "source_section": null,
            "review_status": "verified",
            "reviewed_at": "2026-09-27",
            "note": "Completed years: the fifth year after incorporation belongs to the scale-up regime."
          }
        }
      ],
      "unknowns": [
        {
          "field": "company.age_years",
          "request_path": "company.founded_on",
          "question": "When was the company founded?"
        }
      ],
      "matched_topics": [],
      "estimate": {
        "max_amount_eur": 11250,
        "rate_applied": 45,
        "basis": "€25,000 × 45%, capped at €500,000"
      },
      "subsidy": {
        "id": "federal:tax-shelter-start-up",
        "title": "Tax shelter for start-ups",
        "summary": "Tax credit from FOD Financiën for small companies in Belgium. Covers 30% to 45% of eligible costs, up to €500,000. Applications accepted at any time.",
        "status": "continuous",
        "instrument_type": "tax_credit",
        "issuer": "FOD Financiën",
        "scope": "national",
        "regions": [],
        "topics": [
          "starting_business",
          "financing"
        ],
        "opens_at": null,
        "closes_at": null,
        "rolling": true,
        "budget_exhaustion_possible": false,
        "funding": {
          "rate_min": 30,
          "rate_max": 45,
          "amount_min": null,
          "amount_max": 500000,
          "annual_cap": null,
          "de_minimis": null
        },
        "rules_basis": "curated",
        "source": {
          "id": "curated_federal",
          "url": "https://financien.belgium.be/nl/ondernemingen/tax-shelter-kleine-ondernemingen/startende-start-up",
          "authority": "FOD Financiën",
          "last_checked_at": "2026-09-27T06:00:12+02:00",
          "freshness": "fresh"
        },
        "links": {
          "api": "https://api.subsido.be/v1/subsidies/federal:tax-shelter-start-up",
          "web": "https://subsido.be/en/grants/tax-shelter-start-up",
          "apply": "https://financien.belgium.be/nl/ondernemingen/tax-shelter-kleine-ondernemingen/startende-start-up"
        }
      }
    }
  ],
  "matched": 2,
  "evaluated": 412,
  "profile": {
    "facts": {
      "company.applicant_type": "company",
      "company.employees": 12,
      "company.has_legal_personality": true,
      "company.legal_form": "bv",
      "company.nace": [
        "62010"
      ],
      "company.province": "east_flanders",
      "company.regions": [
        "flanders"
      ],
      "company.size": "small",
      "company.turnover_eur": 1500000,
      "project.budget_eur": 25000,
      "project.region": "flanders",
      "project.started": false,
      "project.topics": [
        "digitalisation",
        "investment"
      ]
    },
    "derived": [
      {
        "field": "company.regions",
        "value": [
          "flanders"
        ],
        "from": [
          "company.postcode"
        ],
        "estimate": false
      },
      {
        "field": "company.province",
        "value": "east_flanders",
        "from": [
          "company.postcode"
        ],
        "estimate": false
      },
      {
        "field": "company.size",
        "value": "small",
        "from": [
          "company.employees",
          "company.turnover_eur"
        ],
        "estimate": false
      },
      {
        "field": "company.applicant_type",
        "value": "company",
        "from": [
          "company.legal_form"
        ],
        "estimate": false
      },
      {
        "field": "company.has_legal_personality",
        "value": true,
        "from": [
          "company.legal_form"
        ],
        "estimate": false
      },
      {
        "field": "project.started",
        "value": false,
        "from": [
          "project.planned_start"
        ],
        "estimate": false
      },
      {
        "field": "project.region",
        "value": "flanders",
        "from": [
          "company.region"
        ],
        "estimate": true
      }
    ],
    "enterprise_number": null,
    "warnings": []
  },
  "missing_information": [
    {
      "field": "company.age_years",
      "request_path": "company.founded_on",
      "question": "When was the company founded?",
      "would_settle": 1
    }
  ],
  "language": "en",
  "disclaimer": "Independent service. Not affiliated with, endorsed by, or operated by any government or public authority. Eligibility and awards are decided by the competent authority.",
  "meta": {
    "request_id": "req_0192d3a4b5c67d8e9f0a1b2c3d4e5f61",
    "warnings": []
  }
}

Illustrative values. The Tax Shelter match shows the logic at work: its size test is “two of three criteria”, written as an any of three pairs. The first pair passed, so the unknown balance sheet in the other two does not matter and is not asked for; the company’s age is unknown and would decide, so it is.

FieldMeaning
matches[]Best first, at most limit.
matches[].subsidy_id, match_statusThe measure and the status above.
matches[].confidence0 to 1: how far the rules capture what decides eligibility for this measure (its eligibility.confidence).
matches[].relevance0 to 1: how well the measure’s topics fit the project’s. A shared topic counts fully, a related one (energy and energy efficiency, investment and financing) half. 0.5 when you gave no topics; 0.25 for a measure with no topics.
matches[].score0.5 × relevance + 0.3 × status weight (1, 0.7, 0.5, 0) + 0.2 × confidence, to three decimals. For ordering, not a probability.
matches[].reasons[]Every condition in the measure’s rule tree, in order: id, field, op, value, a label in your language, the result (pass, fail or unknown), the company’s actual fact (or null), and the rule’s provenance: where it was read, and how.
matches[].unknowns[]The facts that were unknown where knowing them could change the outcome: field, the request_path that supplies it, and the question to ask, in your language. Empty once the outcome is decided.
matches[].matched_topicsThe project topics the measure shares.
matches[].estimateSee below, or null.
matches[].subsidyWhat you need to show the measure without a second request: title, summary, status, instrument type, issuer name, scope, regions, topics, dates, funding, rules_basis, the source with its official URL and when it was last checked, and links (api, web, apply).
matchedHow many measures matched in all, before limit.
evaluatedHow many measures were evaluated.
profileThe facts evaluated (facts, keyed by rule field), what was derived and from what, the normalised enterprise_number, and warnings.
missing_information[]Across the returned matches, the missing facts that would settle the most of them, most first: field, request_path, question and would_settle (how many matches it appears in). Ask these, send the answers, and possibly_eligible turns into a decided status.
language, disclaimer, metaThe language used, the independence sentence, and the request id.

Unknown into pass

request_path is the property to send, which is not always the rule’s field: an age rule on company.age_years asks for company.founded_on, and a region rule on company.regions asks for company.region. Build the follow-up form from missing_information, send the same request with the new facts, and the unknowns become passes or failures.

The estimate

Arithmetic on the published figures, indicative only:

  • The rate is the highest tier in funding.rates for the company’s size, or funding.rate_max when no tier names that size.
  • The cap is the lower of funding.amount_max and funding.annual_cap.
  • With a project budget and a rate: budget × rate, capped. Otherwise, when there is a cap: the cap, as the maximum amount. Otherwise null.
  • basis says the sum in words, in your language (€25,000 × 40%, capped at €7,500). For a tax measure the figure is the size of the advantage the rate describes, not a payment.

What a match costs

Each POST /v1/match is one request and one match evaluation, whatever the number of measures evaluated. A request refused for invalid facts is not counted as an evaluation. Match evaluations have their own monthly allowance, so you can keep reading measures after it is spent; see rate limits and quotas.

Bulk matching

Business and abovePOST /v1/match/bulk needs the bulk_match capability.

Many companies in one request: up to 500 on Business and 5,000 on Enterprise. Each has your own reference (1 to 200 characters, unique in the request), echoed back.

{
  "companies": [
    {
      "reference": "client-0042",
      "company": {
        "postcode": "2000",
        "employees": 4,
        "legal_form": "bv"
      },
      "project": {
        "topics": [
          "energy_efficiency"
        ]
      }
    },
    {
      "reference": "client-0043",
      "company": {
        "postcode": "4000",
        "nace": [
          "47.110"
        ]
      }
    }
  ],
  "options": {
    "statuses": [
      "open",
      "continuous"
    ]
  },
  "language": "fr",
  "limit_per_company": 10
}

The answer is { results, evaluated, language, disclaimer, meta }, one result per company in request order: { reference, matches, matched, missing_information, error }. A company whose facts are invalid gets its own error ({ code, message, details }) and empty matches, and is not counted; the others are one evaluation each. limit_per_company is 1 to 100 (default 10). The whole request is refused with match_quota_exceeded when its valid companies would take you past your allowance, and with plan_required when it has more companies than your plan allows in one request.

To match the same companies again whenever a measure changes, put them on a watchlist instead: re-evaluation is included.