# Förderkatalog - German Federal Grants & R\&D Funding Data (`scrapersdelight/foerderkatalog-grants-scraper`) Actor

From $0.20 per 1,000 records, no start fee. Germany's official Förderkatalog register: 301,058 federal grants and research contracts with recipient, executing body, ministry, project title, municipality key, start/end dates and the euro amount. No contact data - the register publishes none.

- **URL**: https://apify.com/scrapersdelight/foerderkatalog-grants-scraper.md
- **Developed by:** [Scrapers Delight](https://apify.com/scrapersdelight) (community)
- **Categories:** Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.20 / 1,000 per grant record returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Förderkatalog — German federal grants & R\&D funding data

Germany's **Förderkatalog (FöKat)** is the federal government's statutory transparency register of
grants and research contracts. This Actor exports it as structured rows.

Every number below was counted on **2026-09-16** against the complete register, not sampled and not
estimated.

| Measured | |
|---|---|
| Records in the register | **301,058** |
| Records still running today | **40,784** |
| Distinct recipient organisations | **53,128** |
| Distinct executing bodies | **88,584** |
| Fields per record | **26 from the register + 15 derived** |
| Emails in the whole register | **0** |
| Phone numbers | **0** |
| Street addresses | **0** |

### Read this first: there is no contact data

This is the most important thing to know before you buy a run.

The Förderkatalog publishes **who got what money for which project, where** — by legal design. It is
not a contact directory, and it has no email, phone or street column in its schema at all.

I ran an email regex over all 301,058 records. It matched **11 times**. I read all 11 in context:

- `FDM@HAW.rlp`, `ODH@Bauhaus.MobilityLab`, `work4woman@www.de` — project acronyms inside a project
  **title**
- `rtteleg@leg-bw.deleg` — a corrupted organisation-name string

**Zero are contact fields.** A phone regex matched 4 rows; all four are machine model numbers or an
astronomical object id inside a title (`Kienzle 6000/6100/3000`, `eRASS J084850-420035`). A street
regex matched 220 rows; every one names the *building being renovated* inside a project title.

So this Actor **does not emit an email, phone or postal-address field**, and the store listing does
not claim one. Geography resolves to the municipality and the 8-digit Gemeindekennziffer, never to a
street.

What it *is* good for: an organisation name plus a municipality is an **enrichment seed**, and the
grant record itself is the intelligence — who is funded, by whom, for how much, and **when it runs
out**. Enrichment is a separate build, not this scrape.

### What one row is

One row is one **Förderkennzeichen** (federal grant number). Grant numbers are unique: 301,058
records carry 301,058 distinct numbers, so there is nothing to deduplicate and you are never charged
twice for the same grant.

#### Fields, with fill counted over the whole register

| Field | Fill | |
|---|---|---|
| `grantNumber` | 100.00% | Förderkennzeichen — unique, and the key back to the register page |
| `registerUrl` | 100.00% | Link to this record on foerderportal.bund.de |
| `ministry` | 100.00% | BMFTR / BMWE / BMUKN / BMV / BMLEH |
| `ministryUnit` | 99.99% | Referat inside the ministry |
| `projectAgency` | 100.00% | Projektträger administering the grant (PT-J, PT-DLR, PT-VDI…) |
| `projectAgencyUnit` | 93.00% | Arbeitseinheit inside the agency |
| `recipientName` | 100.00% | Zuwendungsempfänger — see the redaction note below |
| `recipientIsRedacted` | 100.00% | `true` on the 1.489% where the name is withheld by privacy law |
| `recipientMunicipality` / `recipientCity` | 99.98% / 99.97% | Official municipality, and the postal place name |
| `recipientState` | 99.79% | Bundesland |
| `recipientCountry` | 99.98% | 300,517 of 301,058 are Deutschland |
| `recipientMunicipalityKey` | 99.98% | 8-digit Gemeindekennziffer — the stable join key |
| `recipientStateKey` / `recipientDistrictKey` | 99.98% | First 2 and first 5 digits of that key |
| `executingBody` | 100.00% | Ausführende Stelle — the institute actually doing the work |
| `executingBodyIsRedacted` | 100.00% | `true` on 1.526% |
| `executing*` geography | 99.69–99.98% | Same shape as the recipient side |
| `projectTitle` | 100.00% | Thema des geförderten Vorhabens |
| `projectName` | **51.86%** | The short "Projekt" label. The one genuinely sparse column |
| `programmeCode` / `programmeName` | 100.00% / 99.57% | Leistungsplansystematik and its plain-text name |
| `fundingProfile` | 99.03% | Förderprofil |
| `fundingType` | 100.00% | Förderart |
| `startDate` / `endDate` | 100.00% | ISO. `startDateDe` / `endDateDe` keep the register's DD.MM.YYYY |
| `durationDays` / `daysUntilEnd` / `isRunning` | 100.00% | Derived from those dates |
| `fundingAmountEur` | 100.00% | Federal share as a number. 797 records carry a genuine `0` |
| `fundingAmountEurRaw` | 100.00% | The register's own `133.222,00` string, for audit |

A literal `"N/A"`, `"-"` or `""` is **not** counted as filled anywhere above.

#### The privacy redaction

German privacy law makes the register withhold the name when the funded party is a natural person.
It does that by publishing the sentence *"Keine Anzeige aufgrund datenschutzrechtlicher
Regelungen."* in the name column — so the column reads as 100% filled while some of its values are a
notice rather than a name.

Counted: **4,484 of 301,058 records (1.489%)** for the recipient, **4,593 (1.526%)** for the
executing body. Those grants are otherwise complete — amount, topic, ministry and municipality are
all there — so they are delivered and flagged with `recipientIsRedacted` /
`executingBodyIsRedacted` rather than quietly counted as a name.

### Filters

Everything the register's own Detailsuche can do, with the measured hit count for each example:

| Input | Example | Records (running projects) |
|---|---|---|
| `grantNumbers` | `13BDC%` | 40 |
| `recipientNames` | `Fraunhofer%` · `Helmholtz%` · both | 2,178 · 316 · 2,494 |
| `topicKeywords` | `Wasserstoff` (wrapped to `%Wasserstoff%`) | 941 |
| `ministries` | `BMWE` · `BMFTR` | 10,029 · 21,544 |
| `states` | `Bremen` · `Saarland` · both · `Thüringen` | 583 · 452 · 1,035 · 1,149 |
| `cities` | `Bremen` | 483 |
| `entityScope` | `Bremen` as recipient vs as executing body | 583 vs 788 |
| `startsOnOrAfter` | `01.01.2025` · `15.03.2025` | 19,666 · 17,025 |
| `endsOnOrBefore` | `31.12.2026` · `31.12.2027` | 15,507 · 26,972 |
| both dates | starts ≥ 01.01.2025 and ends ≤ 31.12.2027 | 7,450 |
| `minAmountEur` | `10000000` | 370 |
| `includeCompleted` | off vs on | 40,784 vs 301,058 |

Multiple values in one field are OR-ed; different fields are AND-ed. Verified arithmetically, twice:
Bremen 583 + Saarland 452 = 1,035 for both, and Fraunhofer% 2,178 + Helmholtz% 316 = 2,494.

#### The wildcard rule, which will bite you if you turn it off

The register matches these fields **whole**. `Fraunhofer` returns *nothing*; `Fraunhofer%` returns
2,178 — and the "nothing" arrives as HTTP 200 with a polite German *"keine Ergebnisse"*, which looks
exactly like a real empty result.

`autoWildcard` is on by default and wraps a plain term as `%term%`. It matters more than it sounds:
`Wasserstoff%` (a prefix search) matches 8 running projects, `%Wasserstoff%` matches 941. Values
picked from a drop-down (ministry, state, funding type) are always sent verbatim and never wrapped.

#### BMBF no longer exists

The 2025 ministry reorganisation renamed the research ministry. Grants that older sources label
**BMBF** are published here as **BMFTR**, and the literal string `BMBF` returns zero records. The
five ministries in the register today are BMFTR (193,892), BMWE (48,211), BMUKN (34,290), BMV
(16,036) and BMLEH (8,629) — which sum to exactly 301,058.

### How it works, and what it refuses to do

The register has a bulk CSV export that is not documented anywhere:
`SucheAction.do?actionMode=print&presentationType=csv`. It returns the **entire** result set of the
session's last search in one response — measured: the whole register came back as **190,101,939
bytes**, parsed to exactly 301,058 rows.

That makes the flow session-stateful and strictly serial: `GET` the search mask to be issued a
JSESSIONID → `POST` the Detailsuche → `GET` the export on the same cookie jar.

**The export is streamed, never buffered.** A 40,784-record / 26 MB uncapped run through this code
peaked at **23 MB of heap**. A capped run hangs up as soon as your cap is met, so `maxRecords=25`
really does read about 20 KB of a potentially 190 MB body.

#### Things that would silently ship a wrong answer, and what stops them

- **A body that dies mid-stream.** Nothing on this host sends `Content-Length` — every response is
  `Transfer-Encoding: chunked` — so a truncated body is indistinguishable from a complete one at the
  HTTP layer. Worse, on the register-wide search the hit count sits at byte **1,540,717 of
  1,588,610** (97% of the way in, behind a pager dropdown with 30,111 `<option>` elements), so a
  truncated page loses the count entirely and reads like "no results". Guards: the page must end in
  `</html>`, and the **parsed row count must reconcile against the hit count the register itself
  reported**. If it comes up short, the run **fails** rather than reporting a partial register as
  complete.
- **A stalled socket.** If the export delivers no bytes for 180s, the run fails with what it had read
  so far reported as incomplete.
- **UTF-8.** The site is ISO-8859-15 in *both* directions. Sending a search as UTF-8 returns a
  convincing empty result: `Thüringen` as `Th%C3%BCringen` → "keine Ergebnisse", as `Th%FCringen` →
  1,149 records. Reading a response as UTF-8 mangles the two markers that identify an empty result
  and a rejected input. Both directions are handled explicitly.
- **A `+` for a space.** `submitAction=Detailsuche+starten` makes the servlet miss its dispatch and
  return the **unfiltered** result set — 40,784 instead of Bremen's 583. A wrong answer that looks
  right. Spaces are always `%20`.
- **The Excel armour cliff.** Cells are wrapped as `="value"` — but only up to 254 characters.
  Measured: longest wrapped cell 254 chars, shortest bare cell 255. 18,007 cells are over the line.
  Stripping two leading and one trailing character unconditionally corrupts every one of them.
- **A session with no search.** The export URL answers HTTP 200, `text/plain`, 59 bytes of German
  error text. That is recognised as a transport failure, not an empty register.
- **A bad date.** The mask re-renders itself with an inline German message and HTTP 200 — no result
  list at all. Dates are validated before anything is sent, and the failure names the field.

#### Very large exports

Above 60,000 matching records an uncapped run splits the export on the first character of the
Förderkennzeichen, and pulls the chunks concurrently. That partition is **lossless** because
Förderkennzeichen is 100% filled — verified live: the 36 per-prefix hit counts summed to exactly
40,784, the same number the unpartitioned search reported. A bucket still over the threshold (only
`0`, which holds 166,411 records) is split again on the second character.

The Actor **re-runs that arithmetic every time** and refuses to use a split whose children do not sum
to the parent — which is not ceremony: 4 records start with `M ` (a space), so a second-character
split of the `M` bucket would drop them. That bucket is left whole instead.

### Honest limits

1. **No contact data.** Stated at the top, restated here. If you need emails, this register cannot
   give them to you at any price, and no scraper of it can.
2. **Geography stops at the municipality.** There is no street, no postcode, no coordinate.
3. **`projectName` is 51.86% filled** and skews modern — older records rarely carry one.
4. **The whole register is slow to pull.** Throughput on this host varies a lot: the same 26 MB
   export took 90s once and 158s another time; the 190 MB whole-register export took 294s on a quiet
   line and 947s when a second download shared it. A whole-register run is minutes, not seconds.
5. **I could not test Apify's own egress IPs from the build machine.** Measured from a plain
   Windows box with no proxy: HTTP 200 everywhere, no CAPTCHA, no user-agent gate, no rate limit
   (15 rapid sequential requests, all 200, flat ~1.25s), and the host serves no `robots.txt` at all
   (`/robots.txt` itself returns 403). The default is Apify's automatic proxy pool. If a
   whole-register pull fails on a short export, switch `proxyConfiguration` to `RESIDENTIAL`.
6. **A capped run is a sample, not a ranking.** Records arrive in the register's own order. Narrow
   the filters when you want a specific slice.
7. **The detail page adds nothing.** Checked on a real record: `SucheAction.do?actionMode=view` shows
   *less* than the CSV export (no Gemeindekennziffer, no Projekt) and carries no contact data either.
   The Actor does not fetch it; `registerUrl` just links to it.

### Pricing

**$0.20 per 1,000 records, no start fee.** You are charged once per record delivered to your
dataset. Records your filters exclude are never delivered and never charged, and a search that
matches nothing costs nothing. If the export comes back short of the count the register reported, the
run fails.

### Validating this build

```
node offline_validate.mjs
```

273 assertions, no network and no `node_modules`, against bytes captured from the live register on
2026-09-16 in `fixtures/` — including the 59-byte error document, the search mask the register
re-renders when it rejects a date, real rows whose cells are over the armour cliff, real rows with a
redacted recipient, and a 163,840-byte prefix of the real 1,588,610-byte register-wide result page,
which is what a body that dies mid-stream actually looks like.

### Source

Förderkatalog des Bundes (FöKat), <https://foerderportal.bund.de/foekat/>, site version 3.5.0.2 —
the federal government's statutory transparency register of grants and research contracts.

# Actor input Schema

## `grantNumbers` (type: `array`):

Grant reference numbers, e.g. "13BDC%" for the BMWE 13BDC programme line (40 running projects), or a complete number such as "13BDC40010" for one exact record. Several entries are OR-ed together. Grant numbers are unique: 301,058 records carry 301,058 distinct numbers.

## `recipientNames` (type: `array`):

Name of the funded organisation, or of the executing institute — whichever you selected under "Match names and places against". Measured: "Fraunhofer%" 2,178 running projects, "Helmholtz%" 316, and both together exactly 2,494. Several entries are OR-ed.

## `topicKeywords` (type: `array`):

Free text searched against the project title ("Thema des geförderten Vorhabens"). Measured: "Wasserstoff" wrapped to %Wasserstoff% matches 941 running projects, while the unwrapped prefix "Wasserstoff%" matches only 8 — the difference between a substring search and a starts-with search.

## `projectNames` (type: `array`):

The register's short "Projekt" label, which groups the sub-projects of one joint research project. This is the only sparse column in the register: 156,138 of 301,058 records (51.86%) carry one.

## `ministries` (type: `array`):

The federal ministry that paid. Counts are the whole register as of 2026-09-16 and sum to exactly 301,058. Note the 2025 ministry rename: research grants that older sources label BMBF are published here as BMFTR, and the literal string "BMBF" now returns zero records.

## `projectAgencies` (type: `array`):

The Projektträger that administers the grant on the ministry's behalf — "PT-J%", "PT-DLR%", "PT-VDI%", "PTKA%", "VDI/VDE%". Wildcards apply.

## `fundingTypes` (type: `array`):

All four values the register uses, with their whole-register counts. They sum to exactly 301,058.

## `programmeCodes` (type: `array`):

The federal programme-classification code, e.g. "B010%" or "ZMAN". Filled on 301,053 of 301,058 records. Wildcards apply.

## `states` (type: `array`):

The 16 states, exactly as the register's own pick-list spells them. Counts are whole-register recipient-side totals from 2026-09-16; 641 records carry no state. Several entries are OR-ed: measured, Bremen 583 + Saarland 452 running projects = 1,035 for both.

## `cities` (type: `array`):

Municipality name, e.g. "Bremen", "München%", "Garching%". Beware that the register spells the same place inconsistently ("Garching b.München" and "Garching b. München" both occur), so a wildcard is usually the right call. If you need a machine-stable geography, filter afterwards on the 8-digit recipientMunicipalityKey in the output.

## `countries` (type: `array`):

Whole country name as the register spells it in German. 300,517 of 301,058 records are "Deutschland"; the rest of the world totals about 500 records, led by Frankreich (64), Österreich (61), Belgien (55), Italien (55) and Israel (52).

## `entityScope` (type: `string`):

Every record names two organisations: the legal grant recipient and the institute that actually runs the project. They are often in different cities. The register's search applies the name, city, state and country filters to ONE of them at a time — measured: Bundesland=Bremen matches 583 running projects as recipient and 788 as executing body. Both organisations are always present in the output, whichever you pick.

## `startsOnOrAfter` (type: `string`):

German date, DD.MM.YYYY (ISO YYYY-MM-DD is accepted and converted). Filters on the project's start date. Measured: 01.01.2025 -> 19,666 running projects, 15.03.2025 -> 17,025. A malformed date makes the register re-render its search form with HTTP 200 and no result list at all, so this Actor validates it before sending and tells you which field is wrong.

## `endsOnOrBefore` (type: `string`):

German date, DD.MM.YYYY. Filters on the project's end date. Measured: 31.12.2026 -> 15,507 running projects, 31.12.2027 -> 26,972. Combined with the field above it becomes a containment window: starts after 01.01.2025 AND ends before 31.12.2027 -> 7,450. This is the field that finds projects about to expire.

## `minAmountEur` (type: `integer`):

Federal share in euros, whole numbers. Measured: 10,000,000 and up -> 370 running projects; 1,000,000 to 2,000,000 -> 2,857. Note that 797 records in the register carry a genuine 0,00 amount; those are delivered with fundingAmountEur = 0, not null.

## `maxAmountEur` (type: `integer`):

Federal share in euros, whole numbers.

## `includeCompleted` (type: `boolean`):

OFF (default): only projects still running — 40,784 records as of 2026-09-16. ON: the full historical register back to the 1960s — 301,058 records. Leave it off unless you want the archive; a prospecting list wants live projects.

## `jointProjectsOnly` (type: `boolean`):

The register's "Nur Projekte zeigen" switch — keep only records that belong to a named joint research project (a Verbundprojekt), which is the 51.86% of the register that carries a Projekt label.

## `autoWildcard` (type: `boolean`):

ON (default): a term you type with no % or \_ in it is sent as %term%, so it behaves like a search box. OFF: your terms are sent exactly as typed, which means the register matches them WHOLE. This switch exists because the register answers a missing wildcard with HTTP 200 and "keine Ergebnisse" — an empty result that looks exactly like a real one. Values picked from a drop-down (ministry, state, funding type) are always sent verbatim and are never wrapped.

## `maxRecords` (type: `integer`):

Hard cap on records delivered, and therefore on records charged. 0 means no cap. The register hands back the whole matching result set in one streamed response, and this Actor hangs up as soon as your cap is met, so a small cap really is a small run. Records arrive in the register's own order, so a capped run is a sample of your filter, not a ranked pick — narrow the filters when you want a specific slice.

## `exportConcurrency` (type: `integer`):

Only used when a single uncapped run would pull more than 60,000 records — the whole register is one uninterrupted 190 MB response, and a multi-megabyte body can die mid-stream while still reporting HTTP 200. Above that size the Actor splits the export on the first character of the Förderkennzeichen, which is a lossless partition (verified live: the 36 buckets summed to exactly the unpartitioned hit count) and refuses to use it on any run where that arithmetic does not reconcile. Set it to 1 to always use a single stream.

## `proxyConfiguration` (type: `object`):

Optional. foerderportal.bund.de has no anti-bot, no CAPTCHA, no user-agent gate and no rate limit — measured 2026-09-16: 15 rapid sequential requests all returned HTTP 200 in a flat ~1.25s, and the site serves no robots.txt at all. Datacenter is plenty. Switch to RESIDENTIAL if you pull the whole register in one stream and see the run fail on a short export.

## Actor input object example

```json
{
  "grantNumbers": [
    "13BDC%"
  ],
  "recipientNames": [],
  "topicKeywords": [],
  "projectNames": [],
  "ministries": [],
  "projectAgencies": [],
  "fundingTypes": [],
  "programmeCodes": [],
  "states": [],
  "cities": [],
  "countries": [],
  "entityScope": "recipient",
  "includeCompleted": false,
  "jointProjectsOnly": false,
  "autoWildcard": true,
  "maxRecords": 25,
  "exportConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per Förderkennzeichen: recipient organisation, executing body, both municipalities with their 8-digit municipality keys, ministry, project agency, project title, programme, runtime, days left and the federal amount in euros. No contact fields — the register publishes none.

## `runSummary` (type: `string`):

RUN\_SUMMARY: the hit count the register itself reported against the rows actually parsed and delivered, the per-field fill measured on this run, whether the export was split into partitions and how they reconciled, and the exact search that was sent.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "grantNumbers": [
        "13BDC%"
    ],
    "entityScope": "recipient",
    "includeCompleted": false,
    "autoWildcard": true,
    "maxRecords": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/foerderkatalog-grants-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "grantNumbers": ["13BDC%"],
    "entityScope": "recipient",
    "includeCompleted": False,
    "autoWildcard": True,
    "maxRecords": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/foerderkatalog-grants-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "grantNumbers": [
    "13BDC%"
  ],
  "entityScope": "recipient",
  "includeCompleted": false,
  "autoWildcard": true,
  "maxRecords": 25
}' |
apify call scrapersdelight/foerderkatalog-grants-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapersdelight/foerderkatalog-grants-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ZEgXHU0ztg5KXqF6I/builds/awKyonKjvefRz7S4m/openapi.json
