# Denmark New Companies - CVR New Registrations & Leads (`scrapersdelight/cvr-new-companies-dk-scraper`) Actor

From $0.90 per 1,000 companies, no start fee. Newly registered Danish companies from the official CVR register, any date window: CVR number, name, start date, address, industry code, email, phone - plus the reklamebeskyttelse advertising-protection flag, so you can drop rows you may not market to.

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

## Pricing

$0.90 / 1,000 per company row 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

## Denmark New Companies — CVR New Registrations & Leads

Every company registered in Denmark in a date window you choose, straight from **CVR**
(Det Centrale Virksomhedsregister), the official business register run by Erhvervsstyrelsen.
Name, CVR number, registration date, legal form, status, full address, six-digit industry code,
email, phone — and the **reklamebeskyttelse** advertising-protection flag, which decides whether
you are allowed to market to the row at all.

**$0.90 per 1,000 companies. No run-start fee. Rows your filters remove are never delivered and
never charged.**

***

### What the data actually looks like

Counted on a **complete two-week census** of every new Danish company registered 2026-09-01 to
2026-09-14 — 2,544 distinct companies, not a sample — and re-confirmed on a live full-month run
of August 2026 (5,570 companies). Empty string, `null` and literal `"N/A"` all count as *not*
filled.

| field | fill, 2-week census (n=2,544) | fill, August 2026 (n=5,570) |
|---|---|---|
| `cvr`, `companyName`, `startDate` | **100%** | **100%** |
| `postalCode`, `city`, `fullAddress` | **100%** | **100%** |
| `companyForm`, `status`, `unitNumber` | **100%** | **100%** |
| `industryCode` + `industryText` | **100%** | **100%** |
| `streetAddress` | 100% | 99.87% |
| `advertisingProtected` | **100%** (a real boolean on every row) | **100%** |
| `email` | 57.78% | 54.99% |
| `phone` | 46.38% | 47.63% |
| **email or phone** | **67.73%** | **67.58%** |
| `careOfName` | 37.46% | 37.06% |
| `ceasedDate` | 1.10% | 2.05% |

`streetAddress` is null on 7 of the 5,570 August rows. They are Greenlandic addresses that publish
only a postcode and a town — there is no street to parse, so the field is null rather than
fabricated. `fixtures/region_greenland_2026-08.json` holds them.

#### Read this before you buy: the contact numbers above are an average of two very different things

Contact fill is almost entirely determined by **company form**. Counted on the 2026-09-08..14 week:

| company form | share of new companies | email | phone | advertising-protected | **marketable** |
|---|---|---|---|---|---|
| Anpartsselskab (ApS, private limited) | 472 of 1,015 | **12.3%** | 28.4% | 78.4% | **0.6%** |
| Aktieselskab (A/S, public limited) | 10 | **10.0%** | 10.0% | 80.0% | **0.0%** |
| Enkeltmandsvirksomhed (sole trader) | 270 | 92.6% | 54.4% | 78.1% | 21.5% |
| Personligt ejet Mindre Virksomhed | 135 | 90.4% | 58.5% | 73.3% | 23.0% |
| Frivillig forening (association) | 89 | 96.6% | 62.9% | 69.7% | 30.3% |
| Interessentskab (I/S) | 21 | 95.2% | 90.5% | 66.7% | 33.3% |

So: **if you filter to limited companies (ApS / A/S) you get ~12% email and almost no marketable
rows.** A verified live run over all of August, filtered to unprotected ApS and A/S with a contact
requirement, delivered **43 rows out of 5,570 registrations**. That is the honest shape of this
lane. If your buyer is "any newly registered Danish business", the numbers in the first table
apply; if your buyer is specifically "new limited companies with an email", this source cannot
give you volume, and no amount of engineering changes that — CVR simply does not publish one.

#### Advertising protection is the thing that matters, and it is not a minority

**77.48%** of new Danish companies carry `reklamebeskyttelse` — a registration under the Danish
CVR act asking that their register entry not be used for unsolicited marketing.

It is a **legal marker, not data suppression**. Protected companies publish an email at
essentially the same rate as unprotected ones (54.04% vs 52.54% on the measured week), so a raw
export looks like a perfectly good lead list and mostly is not one. Counted:

- 2,544 new companies over two weeks
- 1,971 (77.48%) advertising-protected
- 573 (22.52%) not protected
- of those 573, **331 publish an email or a phone**
- → **13.01% of all new Danish companies are both lawfully marketable and reachable** — roughly
  26 a day, about 9,500 a year

Set **Advertising-protected companies → Exclude** and the register itself filters them out: they
are never fetched, never delivered and never charged. That filter was verified exact — on
2026-09-01 it returned 147 rows against a day total of 681, and exactly 147 of those 681 rows
carry `reklameBeskyttet: false`.

***

### How much data is there

Measured from the register's own counts on 2026-09-16:

| window | new companies |
|---|---|
| a weekday | 142 – 226 |
| a weekend day | 43 – 54 |
| the 1st of a month | 661 – 681 |
| 1 January 2026 | 1,716 |
| one week | 1,015 – 1,600 |
| August 2026 | 5,570 |
| 2026 year to date (to 16 Sept) | 50,943 |

The whole register holds 2,269,054 companies; this Actor is scoped to **new registrations in a
date window**, which is the part with a buyer.

***

### The two traps this Actor exists to survive

#### 1. A single query silently returns at most 3,000 rows

Ask the gateway for August 2026 and it answers **HTTP 200**, an envelope reading `total: 5570`,
and exactly **3,000 rows**. No error, no flag, no short-page signal. 2,570 companies are simply
not there. Pinned to the exact row (`fixtures/cap_month_offset*.json`):

```
offset 0     -> 1 row,  total 5570
offset 2999  -> 1 row,  total 5570
offset 3000  -> 0 rows, total 0     <- HTTP 200; past the ceiling even `total` lies
```

This Actor **slices the window** until every query sits under the ceiling, fetches each slice in
one request, and floor-asserts the rows it got against the register's own count for that same
response. Verified end to end on the exact window that breaks: August 2026 came back as
2,760 + 2,810 = **5,570 rows, 5,570 distinct CVRs**, in 6 requests and 41 seconds.

If a single day ever exceeds 3,000 (the busiest measured was 1 January at 1,716), it is partitioned
by company form and then by region — both verified to be exact partitions, summing to the day's own
total with nothing double-counted and nothing missing.

#### 2. Paging this gateway loses rows

The obvious escape from the ceiling is to page. It does not work. Two `size=1000` pages of the same
1,015-row week, captured seconds apart, returned 1,000 + 15 = 1,015 raw rows — apparently complete —
but only **1,009 distinct CVRs**. Six rows are byte-identical duplicates across the page boundary,
so by pigeonhole six other companies never came back at all. At HTTP 200, with `total` still reading
1,015.

**This Actor never pages.** Every slice is sized to come back whole in one request.

#### And a third: the order the register returns rows in is not random

The gateway returns company-registry entities (ApS, A/S, branches) first and personally-owned ones
(sole traders, associations) after. Because contact fill differs so sharply between those groups,
"the first N rows" is a systematically contact-poor sample — measured on the 1,015-row week, rows
0-250 carry 16.8% email against the week's own 53.69%. A local run capped at 50 rows delivered 3
emails where the week's rate predicts 27.

So every slice is **sorted by registration date, then CVR, before the cap is applied**. A capped
run is a chronological prefix of your window, not an arbitrary stratum — and two runs of the same
window return rows in the same order, so a diff between them means something. After the fix the
same 50-row run delivered 35 contactable rows.

***

### Access: this Actor requires the Apify UNBLOCKER proxy group

`datacvr.virk.dk` sits behind a Cloudflare managed challenge. Measured 2026-09-16, every one of
these got **HTTP 403 with zero cookies ever issued**:

- plain HTTP with a real Chrome user agent
- Playwright Chromium, headed, three navigations
- a **real installed Chrome** on a persistent profile, headed, 3 × 75 s of waiting
- Apify **RESIDENTIAL**, two distinct genuine Danish IPs
- Apify datacenter IPs

Apify Proxy with `groups=UNBLOCKER` returns **HTTP 200** and issues the session cookie. That is the
only route found, and the input schema pins it as the default. Good news for cost: a plain HTTP
client works through it — no browser is needed — so this Actor runs on the small Node image at
512 MB rather than a 4 GB Chromium one.

**UNBLOCKER usage is billed to your Apify account separately from this Actor's per-row price.** A
full month of 5,570 companies cost 6 requests and 3.43 MB.

`robots.txt` at datacvr.virk.dk declares `Crawl-delay: 10` and does **not** disallow `/gateway` or
`/soegeresultater`. This Actor runs at most 4 requests in flight; ten back-to-back calls with no
delay at all returned 200 every time, with no throttling observed, but the crawl-delay is the site's
stated preference and heavy use should respect it.

***

### Fields

| field | notes |
|---|---|
| `cvr` | the 8-digit CVR number, the Danish company identifier |
| `companyName` | current registered name |
| `startDate` | official registration date, ISO |
| `startDateInRequestedWindow` | see below — the date filter is not perfectly exact |
| `companyForm` | legal form, verbatim Danish (`Anpartsselskab`, `Enkeltmandsvirksomhed`, …) |
| `status` | verbatim from the register — **see the caveat below** |
| `ceasedDate`, `isCeased` | set for companies already closed again; 1-2% of a new-company window |
| `careOfName` | the `c/o` line, when there is one |
| `streetAddress`, `postalCode`, `city` | parsed out of the register's single multi-line address string |
| `fullAddress` | the whole address on ONE line, commas not newlines, so CSV/XLSX stay one row per company |
| `addressLineCount` | how many lines the source address had (2, 3 or 4) |
| `industryCode`, `industryText` | six-digit Danish DB07/NACE code and its Danish description |
| `email`, `phone`, `hasContact` | exactly what the company filed; verbatim, never normalised |
| `advertisingProtected` | `true` = reklamebeskyttelse registered. **Never** guessed: a missing flag stays `null` |
| `marketableLead` | `advertisingProtected === false && hasContact` |
| `unitNumber` | the register's internal `enhedsnummer` |
| `cvrUrl` | link to the company's page on datacvr.virk.dk |
| `scrapedAt` | run timestamp, ISO |

#### Fields that are NOT here, and why

- **There is no website field.** The source does not publish one anywhere, and there is no way to
  derive it honestly. It is not offered.
- **No extra contact data from the company detail page.** The obvious enrichment — fetch
  `/gateway/virksomhed/hentVirksomhed` per company — was tested on 42 companies (30 + 12). Its
  `stamdata` object has no `email` and no `telefon` key **at all**: 0/30 and 0/12, including for
  companies whose search row carried both. Contact data lives only in the search row. That is also
  why this Actor is cheap: one request returns up to 3,000 complete lead rows with no per-company
  follow-up.
- `reg` (null on all 2,544 rows), `harPseudoCvr` (false on all), the three `highlight*` search-UI
  flags and `visNavnPostfix` are dropped — they are empty or constant, not data.

#### Two honest caveats about individual fields

**`status` mixes two vocabularies inside a single response.** One 1,015-row payload contained 492
rows reading `NORMAL` and 514 reading `Aktiv`, both meaning an active company, plus `Ophørt`,
`UDENRETSVIRKNING` and `OPLØSTEFTERSPALTNING`. It is passed through verbatim rather than
normalised into a guess. For "is this company still alive", use `isCeased` / `ceasedDate`: on the
measured week `ophoersDato` was filled for exactly the 8 rows whose status read `Ophørt`.

**The date filter is not perfectly exact.** Querying 2026-01-02 returned 253 rows, 3 of which carry
a `startDato` in a different month (June, August and April 2026). It is rare — zero exceptions on
the September week, 2 of 5,570 across August — but it is real, so every row carries
`startDateInRequestedWindow` and `RUN_SUMMARY` counts them. Filter on it if you need a strict feed.

***

### Input

Everything is optional. With an empty input the Actor returns the last 7 days, capped at 1,000 rows.

- **Last N days** — a rolling window counted back from today *in Denmark*, including today. This is
  the setting for a scheduled daily or weekly feed: nothing to edit. Fill it in and it wins; clear
  it to use exact dates.
- **Registered from / to** — exact ISO dates, inclusive. Any length of window: the Actor slices it.
- **Advertising-protected companies** — `include` (default, every row flagged) / `exclude`
  (marketing-safe rows only, filtered by the register itself) / `only`.
- **Only companies with…** — any / email or phone / email / phone.
- **Company form, Region, Municipality, Industry code, Company status** — all optional, all
  validated against the register's own live vocabulary before the run starts.
- **Maximum companies** — default 1,000. 0 means no cap.
- **Proxy** — leave on Apify Proxy + UNBLOCKER.

#### Why the filters are validated before the run

Because on this gateway a wrong filter value does not produce an error:

| mistake | what the gateway does |
|---|---|
| `virksomhedsform: ["Aktieselskab"]` (the name, not the kode) | HTTP 200, **0 rows** |
| `kommune: ["København"]` (the name, not the kode) | HTTP 200, **the UNFILTERED result** — the filter silently vanishes and you are charged for rows you asked to exclude |
| `branchekode: "6421"` (a prefix of a 6-digit code) | HTTP 200, **0 rows** — a prefix is not treated as a prefix |
| `virksomhedsstatus: ["NORMAL"]` (a value rows actually contain) | HTTP 200, **0 rows** |
| dates as `01/09/2026` | HTTP 200, **0 rows** |

Every one of those is byte-for-byte identical to a genuine "nothing was registered". The Actor
refuses them up front with a message naming the valid values, and nothing is charged.

***

### Output: `RUN_SUMMARY`

Written to the key-value store on every run. It reconciles the register's own count for each slice
against the rows actually read and delivered, reports contact fill counted **on that run**, and
keeps three kinds of nothing apart, because merging them is how a blocked run gets mistaken for a
quiet week:

- `emptySlices` — dates the register itself says hold no registrations. A real answer.
- `excluded` — rows your filters removed. Fetched, never delivered, **never charged**.
- `unreachableSlices` — slices that could not be read. The companies in them are **missing**. If a
  quarter or more of the planned slices land here, the run fails rather than reporting a short
  dataset as complete.

`delivered` always equals `charged`.

***

### Billing

Pay per event, one event: **`company-scraped`, $0.0009 per company row delivered.**

- No run-start fee. A run that matches nothing costs nothing.
- Excluding advertising-protected companies is applied *by the register*, so those rows are never
  fetched and never charged.
- A contact requirement drops rows before delivery, so they are never charged.
- Rows are pushed with the charge event attached, so what is delivered is exactly what is billed
  and your own charge cap is respected row by row.

Measured cost to run: a 7-day, 669-row window is **1 request and 11 seconds**; all of August —
5,570 companies — is **6 requests, 3.43 MB and 41 seconds** at 512 MB.

***

### Source and licence

Det Centrale Virksomhedsregister (CVR), Erhvervsstyrelsen, via
`https://datacvr.virk.dk/gateway/soeg/fritekst`. CVR is public data published by the Danish
Business Authority. **Advertising protection is a legal restriction on how a row may be used, not a
restriction on access** — which is exactly why it ships as a first-class field with a filter rather
than being quietly dropped. If you are marketing into Denmark, filter on it.

A cleaner long-term route exists and is not used here: Erhvervsstyrelsen's official CVR
distribution API at `distribution.virk.dk/cvr-permanent/_search` sits behind plain HTTP Basic auth
with no Cloudflare in front of it, and credentials are issued free on application. Moving to it
would remove the UNBLOCKER dependency entirely.

Validate the parser against the captured bytes with `node offline_validate.mjs` — 249 assertions,
no network, no node\_modules.

# Actor input Schema

## `lastDays` (type: `integer`):

Companies registered in the last N days, counted back from today in Denmark and including today. 1 = today only, 7 = the past week, 30 = the past month. Best for a scheduled daily or weekly lead feed: no dates to edit. Leave this EMPTY to use the exact date fields below instead.

## `startDateFrom` (type: `string`):

First registration date to include, ISO format, e.g. 2026-09-01. Used only when "Last N days" is empty. Note: the register takes ISO dates only - a DD/MM/YYYY value comes back as HTTP 200 with zero results, which looks exactly like a quiet week, so this Actor stops with an error instead of delivering an empty dataset.

## `startDateTo` (type: `string`):

Last registration date to include, ISO format, e.g. 2026-09-30. Inclusive. Any window works, however long: the register silently caps a single query at 3,000 rows, so this Actor splits the window into slices that each stay under the cap and reconciles every slice against the register's own count.

## `advertisingProtection` (type: `string`):

Include: every company, each row carrying advertisingProtected true/false. Exclude: only companies WITHOUT advertising protection - applied by the register itself, so protected companies are never fetched, never delivered and never charged (verified exact: on 2026-09-01 the filter returned 147 rows and the unfiltered day held 681, of which exactly 147 were unprotected). Only: the inverse, for compliance and suppression-list work.

## `contactRequirement` (type: `string`):

Contact fill is what it is: the register publishes what each company filed. Pairing "An email or a phone" with "Exclude advertising-protected" gives the marketing-safe, reachable slice - 13.01% of all new companies on the two weeks measured, roughly 26 a day.

## `companyForms` (type: `array`):

Legal form. Pick ApS and A/S for real limited companies; leave empty for everything, including sole traders and associations. Multiple values are OR-ed.

## `regions` (type: `array`):

Danish administrative region. Measured split of 2026-09-01 (681 companies): Hovedstaden 256, Midtjylland 151, Syddanmark 115, Sjælland 84, Nordjylland 57, Greenland 18. Multiple values are OR-ed.

## `municipalities` (type: `array`):

Finer than region. Measured on 2026-09-01: København 102 of the day's 681, Aarhus 44. Multiple values are OR-ed.

## `industryCode` (type: `string`):

One six-digit Danish industry code (DB07/NACE), e.g. 642120 for non-financial holding companies or 620100 for computer programming. It must be all six digits: the register does NOT treat a shorter code as a prefix - measured, "642120" returned 83 companies and "6421" returned zero with no error, so this Actor refuses a partial code rather than delivering a silent empty result.

## `companyStatuses` (type: `array`):

The register's own status keys. "aktive" is the useful one - on 2026-09-01 it returned 668 of the day's 681, with 13 already ceased. Leave empty for all. Careful: these are the register's filter keys, not the values that appear in the status column of the output (which are Danish display labels such as NORMAL, Aktiv and Ophørt).

## `maxCompanies` (type: `integer`):

Stop after this many rows have been delivered. 0 means no cap - the whole window, however large. Denmark registers about 200 companies a day, 1,000-1,600 a week and roughly 5,600 a month, so a month with no cap delivers and charges for about 5,600 rows.

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

datacvr.virk.dk sits behind a Cloudflare managed challenge. Measured 2026-09-16: plain HTTP, Playwright Chromium, a real headed Chrome on a persistent profile for 225 seconds, two genuine Danish residential IPs and Apify datacenter IPs ALL got HTTP 403 with zero cookies ever issued. Only Apify Proxy with the UNBLOCKER group returns HTTP 200. Leave this exactly as it is unless you know better; anything else will simply fail. UNBLOCKER usage is billed to your Apify account separately from this Actor's per-row price.

## Actor input object example

```json
{
  "lastDays": 7,
  "advertisingProtection": "include",
  "contactRequirement": "any",
  "companyForms": [],
  "regions": [],
  "municipalities": [],
  "companyStatuses": [],
  "maxCompanies": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "UNBLOCKER"
    ]
  }
}
```

# Actor output Schema

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

One row per company registered in your date window: CVR number, name, registration date, legal form, status, address, six-digit industry code, email, phone, and the reklamebeskyttelse advertising-protection flag with a derived marketableLead boolean.

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

RUN\_SUMMARY: how the date window was sliced to stay under the register's silent 3,000-row ceiling, what the register said each slice held against what was actually read, rows delivered and charged, contact fill counted on this run, and the three kinds of nothing kept apart - empty days, rows your filters excluded, and slices that could not be read.

# 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 = {
    "lastDays": 7,
    "advertisingProtection": "include",
    "contactRequirement": "any",
    "maxCompanies": 50,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "UNBLOCKER"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/cvr-new-companies-dk-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 = {
    "lastDays": 7,
    "advertisingProtection": "include",
    "contactRequirement": "any",
    "maxCompanies": 50,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["UNBLOCKER"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/cvr-new-companies-dk-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 '{
  "lastDays": 7,
  "advertisingProtection": "include",
  "contactRequirement": "any",
  "maxCompanies": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "UNBLOCKER"
    ]
  }
}' |
apify call scrapersdelight/cvr-new-companies-dk-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapersdelight/cvr-new-companies-dk-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/hfLsmwiLTbKrRqx7f/builds/staX0rHOaRhqGUUNL/openapi.json
