# Insolvency & Bankruptcy Watch (`mikee368/insolvency-bankruptcy-watch`) Actor

Watch official insolvency publications for companies and sole traders in NL, the UK, France and the US, and return only new matches. Personal insolvencies are excluded.

- **URL**: https://apify.com/mikee368/insolvency-bankruptcy-watch.md
- **Developed by:** [Mike Berckmoes](https://apify.com/mikee368) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 watched entities

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

Watch official insolvency publications for **companies and sole traders** and return only **new** matches. The Netherlands, the United Kingdom, France and the United States each have one adapter. Germany and Norway are listed and left unsupported, with the reason.

This Actor is a **screening aid, not legal advice**. Confirm the publication before you rely on it. Consumer insolvencies are excluded.

Supplier Risk Monitor can call the same check without this Actor:

```python
from my_actor.check import check_insolvency
```

`check_insolvency` does not charge and does not write the key-value store. The caller keeps `remember` (publication ids only) and decides which matches are new.

### What does Insolvency & Bankruptcy Watch do?

1. You pass companies (`name`, `number`, `country`) and/or keywords, plus the countries to check.
2. Each supported adapter reads its official source for publications on or after the saved watermark (or `lookbackDays` on the first run).
3. A register number or an exact normalised name is a firm match. A partial name or a keyword is `possibleMatch: true` with `verifyNote` **possible match, verify**.
4. The first run stores publication ids in the named store `insolvency-bankruptcy-watch-state` (`seen-<monitorId>`, `meta-<monitorId>`) and returns no rows unless **Include baseline** is on. Later runs return only ids that were not stored. State holds ids, country, source and a personal flag. It does not hold names, birth dates or addresses. Personal ids are dropped after 90 days.

### Country coverage

| Country | Source | Coverage | Terms |
|---|---|---|---|
| NL | Centraal Insolventieregister `searchUndertaking` + `getCase` | Supported when you supply your free CIR subscription (`cirUsername`, `cirApiSecret`) | Trade-information use. Delete case data within six months after the proceeding ends. The natural-person operation is never called. |
| GB | The Gazette insolvency notice feed | Supported. Corporate notice codes 24xx only | Open Government Licence v3. Personal data is outside that licence. Fair use: identifiable user agent, robots.txt, at most 5 requests / 10 seconds, and on the platform only **21:00–07:00 UK**. Schedule overnight. |
| FR | BODACC annonces commerciales | Supported. Collective proceedings that carry a SIREN. A natural person's name is withheld unless **Include personal names** is on | Licence Ouverte 2.0. No key. |
| US | SEC EDGAR Form 8-K item 1.03 | Supported for a numeric CIK | Free EDGAR fair-access rules (declared user agent, under 5 requests/second here). **PACER is paid ($0.10/page) and is not called.** Item 1.03 is not a national bankruptcy docket. |
| DE | insolvenzbekanntmachungen.de | **Unsupported.** No request is made | Official FAQ item 13: no download interface. Automation is limited to one named-debtor lookup (Einzelabruf), which is not a feed of new proceedings. The InsBekV further restricts consumer notices. |
| NO | Brønnøysund Konkursregisteret | **Unsupported.** No request is made | No anonymous open feed. The JSON service needs a legal basis for national identity numbers. XML announcements are a signed SFTP subscription. |

Czech ISIR and Estonia Ametlikud Teadaanded publish insolvency notices, and the e-Justice interconnection portal exists. They are not wired: ISIR returns full debtor files including consumers, and the others had no verified open bulk feed when this Actor was written. Add a module under `my_actor/sources/` and register it in `ADAPTERS`.

### Why use it?

- One schedule covers the supported countries. Unsupported countries come back with a reason and are not charged.
- Daily runs that see the same publication finish without a `new-match` charge.
- `maxEntities` (default 25) is named in the run status message.
- The run is pinned to **256 MB**.

### What data can it extract?

| Field | Meaning |
|---|---|
| `source` | `UK_GAZETTE`, `NL_CIR`, `FR_BODACC` or `US_EDGAR` |
| `name` / `registrationNumber` | Business name and company number, SIREN, KvK or CIK when the source published one |
| `entityKind` | `company` or `sole-trader` |
| `matchConfidence` | 1 register number, 0.96 exact name, lower for a possible match |
| `possibleMatch` / `verifyNote` | `true` and `possible match, verify` when the hit is not exact |
| `eventType` | `baseline` (uncharged) or `new-match` (charged) |
| `charged` | `true` only on a `new-match` row |
| `disclaimer` | Repeated on every row |

Practitioner names, given names, birth dates, addresses and EINs are not copied.

### How to watch a company

1. Add companies. Use `GB` (or `UK`), `NL`, `FR` or `US`. `DE` and `NO` return the unsupported reason.
2. For the Netherlands, paste your free CIR username and password. Without them, NL is skipped and not charged.
3. Leave **Include baseline** off so the first run only seeds state. Turn it on when you want that first window as uncharged rows.
4. Schedule UK runs between 21:00 and 07:00 UK time. A platform run outside that window skips the Gazette and does not charge those GB entities.
5. Optional **Webhook URL** receives one JSON digest when there is at least one new match.

### How much does it cost?

Pay per event. The live price is `.actor/pricing.json`.

| Event | Price | When |
|---|---|---|
| `watched-entity` | **$0.003** | One company, sole trader, or keyword actually checked on a supported source |
| `new-match` | **$0.03** | One new business publication after the baseline |

Apify keeps 20% and then deducts platform usage. Compute is priced at the FREE tier, **$0.20 per CU** (1 GB for one hour). This Actor pins 256 MB (0.25 GB) and a 120 second timeout. Two key-value writes are $0.05 per thousand.

Worst small run: 1 entity, 0 matches, held for the full 120 seconds.

- Compute `0.25 * 120/3600 * 0.20` = **$0.001667**. Two state writes = **$0.0001**. Platform total **$0.001767**.
- Event revenue $0.003. Publisher share after 20% = **$0.0024**.
- Profit **about $0.00063**.

Five entities and no match in 60 seconds keep about **$0.011**. One entity plus one new match, even at the full 120 seconds, keeps about **$0.025** (the match also writes one dataset row at $0.005 per thousand). A run with no companies and no keywords exits before any charge. The local offline suite does not produce a platform invoice; the one-entity harness wall time is in **Local check** below.

### Input

```json
{
  "entities": [
    {"name": "Example Holdings Ltd", "number": "12345678", "country": "GB"}
  ],
  "keywords": ["Example Holdings"],
  "countries": ["GB", "FR", "NL", "US"],
  "monitorId": "default",
  "lookbackDays": 7,
  "includeBaseline": false,
  "includePersonalNames": false,
  "maxEntities": 25,
  "maxMatches": 25,
  "webhookUrl": "https://example.com/hook",
  "cirUsername": "YOUR_CIR_USER",
  "cirApiSecret": "YOUR_CIR_PASSWORD"
}
```

### Output

```json
{
  "source": "UK_GAZETTE",
  "country": "GB",
  "name": "EXAMPLE HOLDINGS LTD",
  "matchedOn": "register-number",
  "matchConfidence": 1,
  "possibleMatch": false,
  "eventType": "new-match",
  "charged": true
}
```

A partial name comes back with `"possibleMatch": true` and `"verifyNote": "possible match, verify"`.

### Tips

- One `monitorId` per schedule. **Reset monitor state** drops seen ids for that id.
- Keywords are possible matches. Prefer a register number when you have one.
- A US watch needs a CIK in `number`. There is no ticker map, and PACER is not a fallback.

### FAQ, disclaimers and support

Official notices can name people. This Actor keeps business names and register numbers and drops consumer proceedings (Gazette 25xx, CIR natural persons with no KvK and no trade name, BODACC rows with no SIREN). A BODACC row with a SIREN but no company form (SAS, SARL, SA, and the other forms in the parser) is treated as a natural person: the SIREN is kept and the name is omitted unless **Include personal names** is on. It is not a credit rating.

A repeated CIR case file is reused from the named store for 24 hours. Gazette, BODACC and EDGAR feeds are remembered only inside the current run, so the next schedule still sees a new publication.

Personal data is protected by the GDPR in the European Union and by other laws elsewhere. Use the rows when you have a legitimate reason to screen a business you already hold. CIR terms require you to delete case data within six months after the proceeding ends. If you are unsure, ask your lawyers.

Questions and bugs belong on the **Issues** tab. Programmatic runs use the **API** tab.

### Sources and terms

- Netherlands CIR webservice: free subscription, `searchUndertaking` and `getCase` only. https://www.rechtspraak.nl/registers/webservice-centraal-insolventieregister
- The Gazette insolvency feed, Open Government Licence, fair-use window 21:00–07:00 UK. https://www.thegazette.co.uk/fair-use-policy
- BODACC / DILA, Licence Ouverte 2.0. No key.
- SEC EDGAR submissions, free. PACER is not used.
- Germany and Norway: documented as unsupported above. No HTTP call.

### Local check

Offline suite: `python3 tests/harness.py suite actors/insolvency-bankruptcy-watch` (18/18) plus `python3 -m unittest tests.test_unit` (29 tests). The one-entity Gazette baseline (R1) took **2.6s** wall time in that harness. That is local replay time, not a platform invoice. The price above uses the 120 second timeout.

# Actor input Schema

## `entities` (type: `array`):

Objects with name, number (company number, SIREN, KvK or CIK) and country (NL, GB, FR, US, DE, NO). DE and NO are reported as unsupported and are not fetched. UK is accepted as GB.

## `keywords` (type: `array`):

Optional words that mark a publication as a possible match when no register number or exact name hits. Keywords shorter than 4 characters are ignored. A keyword match is flagged possible match, verify.

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

Adapters to run: NL, GB, FR, US, plus DE and NO (unsupported, with the reason). Leave empty to use each company's country. Keywords without companies search the supported countries.

## `monitorId` (type: `string`):

Separate named-store state (seen-<monitorId> and meta-<monitorId>) when one Actor has two schedules.

## `lookbackDays` (type: `integer`):

How far back the first run, or a run with no saved watermark, asks each source. Later runs start at the previous run's date. State still drops ids already seen.

## `includeBaseline` (type: `boolean`):

Off by default. The first run only stores publication ids. Turn this on to also write that first window as uncharged baseline rows.

## `includePersonalNames` (type: `boolean`):

Off by default. A BODACC natural person (no company form such as SAS or SARL) is returned with the SIREN only. Turn this on to copy that person's name into the row. You are the controller for that name.

## `maxEntities` (type: `integer`):

Per-run cap. Extra companies are left for a later run and counted in the status message.

## `maxMatches` (type: `integer`):

Cap on matched rows. Unmatched publications are still remembered. Matches over the cap are left for the next run.

## `webhookUrl` (type: `string`):

Optional https URL on port 443. The host is resolved once and the connection uses that address. Private, loopback, link-local and metadata addresses are rejected, including on a redirect. When the run has at least one charged new match, one JSON digest is posted. Baseline runs and empty runs do not call it.

## `resetState` (type: `boolean`):

Drop seen publication ids and the watermark for this monitorId. The next result is a new baseline.

## `cirUsername` (type: `string`):

Username from the CIR abonnementenportaal. Not logged.

## `cirApiSecret` (type: `string`):

Password for the CIR webservice. Sent as a WS-Security username token. Not logged and not written to the dataset or the run summary.

## Actor input object example

```json
{
  "entities": [
    {
      "name": "Example Holdings Ltd",
      "number": "12345678",
      "country": "GB"
    }
  ],
  "keywords": [
    "Example Holdings"
  ],
  "countries": [
    "GB",
    "FR",
    "NL",
    "US"
  ],
  "monitorId": "default",
  "lookbackDays": 7,
  "includeBaseline": false,
  "includePersonalNames": false,
  "maxEntities": 25,
  "maxMatches": 25,
  "resetState": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset with one row per new or baseline match

## `summary` (type: `string`):

Counts, source notes and the screening disclaimer

# 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 = {
    "entities": [
        {
            "name": "Example Holdings Ltd",
            "number": "12345678",
            "country": "GB"
        }
    ],
    "keywords": [
        "Example Holdings"
    ],
    "countries": [
        "GB",
        "FR",
        "NL",
        "US"
    ],
    "monitorId": "default"
};

// Run the Actor and wait for it to finish
const run = await client.actor("mikee368/insolvency-bankruptcy-watch").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 = {
    "entities": [{
            "name": "Example Holdings Ltd",
            "number": "12345678",
            "country": "GB",
        }],
    "keywords": ["Example Holdings"],
    "countries": [
        "GB",
        "FR",
        "NL",
        "US",
    ],
    "monitorId": "default",
}

# Run the Actor and wait for it to finish
run = client.actor("mikee368/insolvency-bankruptcy-watch").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 '{
  "entities": [
    {
      "name": "Example Holdings Ltd",
      "number": "12345678",
      "country": "GB"
    }
  ],
  "keywords": [
    "Example Holdings"
  ],
  "countries": [
    "GB",
    "FR",
    "NL",
    "US"
  ],
  "monitorId": "default"
}' |
apify call mikee368/insolvency-bankruptcy-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mikee368/insolvency-bankruptcy-watch"
        }
    }
}
```

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/apGg7hAr3bTDqMkAV/builds/OBIK35K7aViZuts11/openapi.json
