# Multilateral Development Bank Procurement Monitor (`stefano_seggio/actor-20-mdb-procurement-monitor`) Actor

Extracts the World Bank's public Procurement Notices API and its 'Other Sanctions' debarment sub-table, normalized to the fleet's 18-field UMS. ADB (Cloudflare-gated) and IDB (Power BI-only, CKAN API robots.txt-blocked) were live-researched and honestly deferred, not force-scraped - see README.md.

- **URL**: https://apify.com/stefano\_seggio/actor-20-mdb-procurement-monitor.md
- **Developed by:** [Stefano Seggio](https://apify.com/stefano_seggio) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 world bank procurement notices

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Multilateral Development Bank Procurement Monitor — Apify Store Overview

**Actor ID:** `dyzTtWjfyYd7bvUZY` · **Store URL:** https://apify.com/stefano\_seggio/actor-20-mdb-procurement-monitor · **Version:** 2.0

***

### Executive Summary & Business Use Case

Multilateral Development Bank Procurement Monitor extracts two live sub-sources from the World Bank: the public **Procurement Notices API** at `search.worldbank.org/api/v2/procnotices` (unauthenticated JSON, hundreds of thousands of notices spanning World Bank-financed projects worldwide), and the **"Other Sanctions"** sub-table on the World Bank's static debarred-firms page at `www.worldbank.org/en/projects-operations/procurement/debarred-firms` — a real, header-anchored HTML `<table>` listing firms sanctioned by the Bank outside its main Kendo-grid debarment list. Both sub-sources are normalized into one shared 18-field Unified Master Schema (UMS), with genuine cross-run change detection (new / status-changed / updated) on the Procurement Notices side. Two other multilateral lenders — the Asian Development Bank and the Inter-American Development Bank — were live-researched during development and deliberately excluded rather than force-scraped: ADB sits behind a Cloudflare/WAF challenge on every tested path, and IDB's public notice listing renders exclusively through an embedded Power BI report whose one structured alternative (a CKAN open-data API) is explicitly disallowed in `data.iadb.org/robots.txt`. This actor covers what is genuinely open at the World Bank; it does not pretend to cover ADB or IDB.

The data supports business use cases grounded in exactly what these two sub-sources publish — a notice/sanction record with status, category, dates, and issuing agency, but no bidder-name or monetary-value field on the notices side (the World Bank's Procurement Notices endpoint carries neither, confirmed against the live API response and documented as an honest "not applicable," not a parsing gap). International contractors, engineering firms, and development consultancies bidding on World Bank-financed projects use the Procurement Notices feed — filtered by `countryFilter` and `noticeTypeFilter` — to track new Invitation for Bids and Requests for Expression of Interest as they publish, and to catch `STATUS_CHANGE` events as a tracked notice moves toward evaluation, award, or close, so they know exactly when to re-engage rather than re-scanning the entire feed. Compliance, KYC, and third-party risk teams at banks, insurers, and multinational corporates screen prospective suppliers and partners against the "Other Sanctions" sub-source before onboarding, using `recipient_or_defendant_name` (the sanctioned firm), `category_or_type` (the sanction imposed), and `status_or_estado` (the raw imposition-date/status text) to flag counterparties the World Bank has sanctioned for fraud or corruption on prior projects. Development-sector market-intelligence and research teams use the aggregate notice volume, `notice_type` mix, and `awarding_or_regulating_agency` field across countries to size procurement activity and agency-level tender frequency for World Bank-financed work, without relying on a monetary value the source itself never publishes.

What this actor is deliberately not positioned for: contract-value or spend analysis (no source here exposes a monetary field — `value_native`, `value_currency`, and `value_usd_normalized` are always `null`), bidder/award-winner tracking on procurement notices specifically (no winner field exists on this WB endpoint), and any ADB or IDB coverage in this version.

### Technical Features & V2 Architecture Highlights

**Cross-run delta persistence via a named key-value store, Procurement Notices only.** Per the actor's own `onlyNew` input description, enabling delta mode persists a content fingerprint per Procurement Notice between runs "in this actor's own named key-value store" — not the ephemeral per-run default store — so a scheduled recurring run can tell a genuinely new notice from one it already delivered last time, and can detect when `notice_status` or another tracked field changed since it was last seen. The "Other Sanctions" sub-source has no delta concept at all: it is a small static snapshot page, not a dated or paginated feed, so every run re-delivers every row it finds.

**Real, domain-specific event types — not the fleet's generic NEW\_LISTING/UPDATED/CLOSED set.** Per `dataset_schema.json`, `event_type` takes exactly five values: `NEW_LISTING` (a Procurement Notice's first sighting), `STATUS_CHANGE` (`notice_status` differs from last time), `UPDATED` (some other tracked field changed but status didn't), `SNAPSHOT_NO_DIFF` (identical to last time — only delivered when `onlyNew` is `false`; also reused for the degraded-extraction fallback record described below), and `SANCTION` (every Other Sanctions entry, since that sub-source has no delta concept to differentiate against). There is deliberately **no `CLOSED` event**: the Procurement Notices API is genuinely server-side paginated and each run stops once `maxItemsPerSource` is reached, so a run's fetch is never guaranteed to be a complete census of the live register the way a single-file export would be — a trustworthy absence-means-closed signal simply isn't available here.

**Extraction-integrity fallback, not a false "nothing found."** If the Other Sanctions table's header row can't be located, or is located but zero data rows parse out of it, the actor treats that as an extraction-integrity failure rather than silently reporting "no sanctions exist." It pushes one `SNAPSHOT_NO_DIFF` record pointing at the World Bank's own static "Notes on Debarred Firms and Individuals" PDF as a documented fallback reference.

**What `onlyNew` actually does here, per the actor's own input schema.** Quoting its real description: when enabled, the actor "persists a content fingerprint per Procurement Notice between runs (in this actor's own named key-value store) and returns only notices that are new since the last run OR whose notice\_status or other tracked fields changed since they were last seen — notices identical to last time are skipped." `is_new` is always populated (`true`/`false`) regardless of this setting, and the flag applies to Procurement Notices only — it has no effect on Other Sanctions rows. Because the World Bank API documents no server-side "since" filter, pagination always walks the result set from the start on every run; `onlyNew` filters client-side after the fact rather than early-stopping pagination, so it changes what gets delivered, not how much gets fetched.

**One actor, two native record shapes, self-describing IDs.** Because this single actor emits both Procurement Notice and Other Sanctions records into one dataset, `record_id` is prefixed per sub-source (`wb-procnotice-<id>`, `wb-sanction-<slug>`) so ids are self-describing and cannot collide within a run. `jurisdiction` is `'WB'` for both sub-sources — a plain non-empty string rather than one of the fleet's closed national/subnational jurisdiction codes, since a supranational lender doesn't fit that union.

**18-field Unified Master Schema.** `dataset_schema.json` defines exactly 18 fields per record (`record_id`, `event_type`, `scraped_at`, `is_new`, `source_url`, `recipient_or_defendant_name`, `entity_identifier_native`, `value_native`, `value_currency`, `value_usd_normalized`, `effective_date_iso`, `publish_date_iso`, `category_or_type`, `status_or_estado`, `awarding_or_regulating_agency`, `jurisdiction`, `source_document_url`, `reference_number`), matching the fleet's shared 18-field UMS referenced in `actor.json`.

**Client-side filtering, disclosed rather than misrepresented as server-side.** `countryFilter`, `noticeTypeFilter`, and `dateRange` all filter Procurement Notices after each page is fetched, because the World Bank API documents no server-side parameter for country, notice type, or date. None of the three apply to Other Sanctions records — that source has no reliable per-record country, notice-type, or publish-date field to filter on.

### Input Schema & JSON Configuration Example

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `sources` | array (enum items) | `["worldBankProcurementNotices", "worldBankDebarredFirms"]` | worldBankProcurementNotices = the live World Bank Procurement Notices API (search.worldbank.org). worldBankDebarredFirms = the World Bank's static 'Other Sanctions' debarment sub-table (worldbank.org). ADB and IDB are NOT selectable here - both were live-researched and found gated/non-compliant for v1 (Cloudflare/WAF for ADB; Power BI embed + robots.txt-blocked API for IDB) - see README.md. |
| `maxItemsPerSource` | integer | `100` | Hard cap on how many records to return per selected source this run. For worldBankProcurementNotices this bounds rows/os pagination against a live corpus of several hundred thousand notices; for worldBankDebarredFirms it is a no-op ceiling since the 'Other Sanctions' sub-table is a single small page. |
| `onlyNew` | boolean | `false` | When enabled, persists a content fingerprint per Procurement Notice between runs (in this actor's own named key-value store) and returns only notices that are new since the last run OR whose notice\_status or other tracked fields changed since they were last seen - notices identical to last time are skipped. is\_new is always populated (true/false) regardless of this setting. Only applies to worldBankProcurementNotices - Other Sanctions has no delta-tracking concept (a small static snapshot page, not a dated/paginated feed). The World Bank Procurement Notices API documents no server-side 'since' filter, so pagination always walks from the start of the result set each run - onlyNew filters client-side after the fact rather than early-stopping pagination. |
| `countryFilter` | array (stringList) | *(none)* | Optional client-side filter on project\_ctry\_name (e.g. 'Kenya', 'India'). The World Bank API documents no server-side country filter parameter, so this is applied after fetching each page. |
| `noticeTypeFilter` | array (stringList) | *(none)* | Filter by notice type (procurement notices only). Optional client-side filter on notice\_type (e.g. 'Invitation for Bids', 'Request for Expression of Interest', 'Contract Award'). Applied after fetching each page, same caveat as countryFilter. |
| `dateRange` | string (enum) | *(none)* | Optionally restrict procurement-notice results to records whose noticedate falls within this window. Not applied to worldBankDebarredFirms records (that source has no reliable per-record publish date field in the static sub-table). Values: `24h` Last 24 hours, `7d` Last 7 days, `30d` Last 30 days. |

No field in `input_schema.json` is marked `required` — an empty `{}` input is valid and falls back to the documented defaults (both sources, `maxItemsPerSource: 100`, `onlyNew: false`, no filters).

#### Example configuration — scheduled delta monitor, one country and notice type

```json
{
  "sources": ["worldBankProcurementNotices", "worldBankDebarredFirms"],
  "maxItemsPerSource": 250,
  "onlyNew": true,
  "countryFilter": ["Kenya", "India"],
  "noticeTypeFilter": ["Invitation for Bids"],
  "dateRange": "7d"
}
```

This raises the per-source cap to 250, enables delta mode so only new or changed Procurement Notices are delivered on repeat runs, narrows notices to Kenya and India and to Invitation for Bids only, and further restricts to notices published in the last 7 days. `onlyNew` and `dateRange` apply to `worldBankProcurementNotices` only; `worldBankDebarredFirms` rows are still fetched and delivered in full every run regardless of these settings.

#### Example configuration — one-off unfiltered pull of both sources

```json
{
  "sources": ["worldBankProcurementNotices", "worldBankDebarredFirms"],
  "maxItemsPerSource": 5000,
  "onlyNew": false,
  "countryFilter": [],
  "noticeTypeFilter": [],
  "dateRange": ""
}
```

### Output Dataset Sample & Data Dictionary

| Field | Type | Description |
| --- | --- | --- |
| `record_id` | string | Stable across runs. Prefixed per sub-source ('wb-procnotice-<id>', 'wb-sanction-<slug>') since this single actor emits more than one native record shape. |
| `event_type` | string | Procurement notices: NEW\_LISTING on first sighting, STATUS\_CHANGE if notice\_status changed since last seen, UPDATED if some other tracked field changed, SNAPSHOT\_NO\_DIFF if identical (only delivered when onlyNew=false). SANCTION for every Other Sanctions entry (no delta concept on that static-snapshot sub-source). SNAPSHOT\_NO\_DIFF also used for the degraded-extraction fallback notice. |
| `scraped_at` | string | ISO-8601 timestamp of this extraction. |
| `is_new` | boolean | null | true/false in delta mode (onlyNew input), null when delta mode is off. |
| `source_url` | string | null | — |
| `recipient_or_defendant_name` | string | null | null for procurement notices (no recipient/winner field is present on this WB endpoint - see README); the sanctioned firm name for Other Sanctions records. |
| `entity_identifier_native` | string | null | — |
| `value_native` | string | null | Always null - neither source exposes a monetary value field (documented honestly, not a parsing gap). |
| `value_currency` | string | null | — |
| `value_usd_normalized` | number | null | — |
| `effective_date_iso` | string | null | submission\_deadline\_date for procurement notices; parsed sanction-imposition date for Other Sanctions (null when the source text isn't a cleanly parseable date, e.g. 'Ongoing'). |
| `publish_date_iso` | string | null | Parsed from noticedate (procurement notices only). |
| `category_or_type` | string | null | notice\_type for procurement notices; the 'Sanction Imposed' text for Other Sanctions. |
| `status_or_estado` | string | null | notice\_status for procurement notices; the raw 'Date of Imposition of Sanction' cell text for Other Sanctions (mixes dates and statuses like 'Ongoing' in the source - kept verbatim rather than force-split). |
| `awarding_or_regulating_agency` | string | null | — |
| `jurisdiction` | string | 'WB' for both World Bank sub-sources. Not one of the fleet's 11 closed JurisdictionCode values - this is a supranational institution, not a national/subnational government. |
| `source_document_url` | string | null | — |
| `reference_number` | string | null | — |

#### Example dataset record — Procurement Notice

```json
{
  "record_id": "wb-procnotice-OP00187452",
  "event_type": "STATUS_CHANGE",
  "scraped_at": "2026-09-08T09:12:31.442Z",
  "is_new": false,
  "source_url": "https://search.worldbank.org/api/v2/procnotices?format=json&rows=250&os=0",
  "recipient_or_defendant_name": null,
  "entity_identifier_native": "OP00187452",
  "value_native": null,
  "value_currency": null,
  "value_usd_normalized": null,
  "effective_date_iso": "2026-10-15",
  "publish_date_iso": "2026-09-01",
  "category_or_type": "Invitation for Bids",
  "status_or_estado": "Under Evaluation",
  "awarding_or_regulating_agency": "Ministry of Health, Kenya",
  "jurisdiction": "WB",
  "source_document_url": "https://search.worldbank.org/notice/detail/OP00187452",
  "reference_number": "KE-MOH-2026-RFB-014"
}
```

#### Example dataset record — Other Sanctions

```json
{
  "record_id": "wb-sanction-northbridge-infra-consult-ltd",
  "event_type": "SANCTION",
  "scraped_at": "2026-09-08T09:12:34.902Z",
  "is_new": null,
  "source_url": "https://www.worldbank.org/en/projects-operations/procurement/debarred-firms",
  "recipient_or_defendant_name": "Northbridge Infra Consult Ltd.",
  "entity_identifier_native": null,
  "value_native": null,
  "value_currency": null,
  "value_usd_normalized": null,
  "effective_date_iso": "2025-02-11",
  "publish_date_iso": null,
  "category_or_type": "Debarment with Conditional Release",
  "status_or_estado": "11-February-2025",
  "awarding_or_regulating_agency": null,
  "jurisdiction": "WB",
  "source_document_url": "https://thedocs.worldbank.org/en/doc/387181466627871302-0290022021/original/WorldBankNotesonDebarredFirmsandIndividuals.pdf",
  "reference_number": null
}
```

### Multi-language Integration Snippets

#### cURL

```bash
curl "https://api.apify.com/v2/acts/stefano_seggio~actor-20-mdb-procurement-monitor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "sources": ["worldBankProcurementNotices", "worldBankDebarredFirms"],
    "maxItemsPerSource": 250,
    "onlyNew": true,
    "countryFilter": ["Kenya", "India"],
    "noticeTypeFilter": ["Invitation for Bids"],
    "dateRange": "7d"
  }'
```

#### Python (apify-client)

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

run_input = {
    "sources": ["worldBankProcurementNotices", "worldBankDebarredFirms"],
    "maxItemsPerSource": 250,
    "onlyNew": True,
    "countryFilter": ["Kenya", "India"],
    "noticeTypeFilter": ["Invitation for Bids"],
    "dateRange": "7d",
}

run = client.actor("stefano_seggio/actor-20-mdb-procurement-monitor").call(run_input=run_input)

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["record_id"], item["event_type"], item["category_or_type"], item["jurisdiction"])
```

#### Node.js (apify-client)

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const runInput = {
    sources: ['worldBankProcurementNotices', 'worldBankDebarredFirms'],
    maxItemsPerSource: 250,
    onlyNew: true,
    countryFilter: ['Kenya', 'India'],
    noticeTypeFilter: ['Invitation for Bids'],
    dateRange: '7d',
};

const run = await client.actor('stefano_seggio/actor-20-mdb-procurement-monitor').call(runInput);

const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
    console.log(item.record_id, item.event_type, item.category_or_type, item.jurisdiction);
}
```

### Pricing Model Explanation

This actor bills on two named pay-per-event types, live-verified on the Apify platform, plus the fleet-standard run-start event:

| Event | Price | Meaning for this actor |
| --- | --- | --- |
| `procurementNotices` | **$0.001** per record | Charged for each `worldBankProcurementNotices` record delivered into the dataset. Priced lower because a single cheap JSON GET against `search.worldbank.org` returns many records per request (~99.75% margin against this fleet's compute-cost baseline). |
| `debarredFirms` | **$0.003** per record | Charged for each `worldBankDebarredFirms` (Other Sanctions) record delivered into the dataset. Priced higher because one HTML fetch is amortized across a small, slowly-changing row count rather than a large multi-record JSON page (~91.7-95.8% margin, covering both the normal-extraction path and the degraded-fallback path). |
| `apify-actor-start` | $0.00005 | Charged once per run, regardless of how many records that run delivers or how many sources are selected. |

The two record-priced tiers here map directly to the two selectable `sources` values, not to a "listing vs. full detail" split: every `worldBankProcurementNotices` record bills as `procurementNotices`, and every `worldBankDebarredFirms` (Other Sanctions) record — including the one `SNAPSHOT_NO_DIFF` degraded-extraction fallback record, when it fires — bills as `debarredFirms`. Both tiers clear this fleet's 85% margin bar (cost per record at or below 15% of price) and sit within the existing $0.0005-$0.003/record rate card.

**How `onlyNew` interacts with billing.** `onlyNew` only affects `worldBankProcurementNotices`. With it enabled, a Procurement Notice identical to what was already delivered on a prior run (`SNAPSHOT_NO_DIFF`) is filtered out client-side before it is ever written to the dataset — it is never delivered and therefore never billed as a `procurementNotices` event. It is not billed at $0; it simply never becomes a chargeable event at all. `worldBankDebarredFirms` records have no delta concept and are unaffected by `onlyNew` — every Other Sanctions row found on a run is delivered and billed as a `debarredFirms` event on every run, whether `onlyNew` is on or off.

**Cost examples:**

- A one-off run pulling 250 Procurement Notices and the full small Other Sanctions table (assume ~40 rows) costs approximately 250 × $0.001 + 40 × $0.003 + $0.00005 ≈ **$0.37**.
- A daily scheduled `onlyNew: true` monitor on Procurement Notices alone that typically surfaces around 15 new-or-changed notices a day, plus the Other Sanctions table re-delivered in full (~40 rows) every run, costs approximately 15 × $0.001 + 40 × $0.003 + $0.00005 ≈ **$0.14/day** (roughly $4.20/month) — only the genuinely new or changed Procurement Notices are billed on the delta side, while every Other Sanctions row is billed every run regardless.

# Actor input Schema

## `sources` (type: `array`):

worldBankProcurementNotices = the live World Bank Procurement Notices API (search.worldbank.org). worldBankDebarredFirms = the World Bank's static 'Other Sanctions' debarment sub-table (worldbank.org). ADB and IDB are NOT selectable here - both were live-researched and found gated/non-compliant for v1 (Cloudflare/WAF for ADB; Power BI embed + robots.txt-blocked API for IDB) - see README.md.

## `maxItemsPerSource` (type: `integer`):

Hard cap on how many records to return per selected source this run. For worldBankProcurementNotices this bounds rows/os pagination against a live corpus of several hundred thousand notices; for worldBankDebarredFirms it is a no-op ceiling since the 'Other Sanctions' sub-table is a single small page.

## `onlyNew` (type: `boolean`):

When enabled, persists a content fingerprint per Procurement Notice between runs (in this actor's own named key-value store) and returns only notices that are new since the last run OR whose notice\_status or other tracked fields changed since they were last seen - notices identical to last time are skipped. is\_new is always populated (true/false) regardless of this setting. Only applies to worldBankProcurementNotices - Other Sanctions has no delta-tracking concept (a small static snapshot page, not a dated/paginated feed). The World Bank Procurement Notices API documents no server-side 'since' filter, so pagination always walks from the start of the result set each run - onlyNew filters client-side after the fact rather than early-stopping pagination.

## `countryFilter` (type: `array`):

Optional client-side filter on project\_ctry\_name (e.g. 'Kenya', 'India'). The World Bank API documents no server-side country filter parameter, so this is applied after fetching each page.

## `noticeTypeFilter` (type: `array`):

Optional client-side filter on notice\_type (e.g. 'Invitation for Bids', 'Request for Expression of Interest', 'Contract Award'). Applied after fetching each page, same caveat as countryFilter.

## `dateRange` (type: `string`):

Optionally restrict procurement-notice results to records whose noticedate falls within this window. Not applied to worldBankDebarredFirms records (that source has no reliable per-record publish date field in the static sub-table).

## Actor input object example

```json
{
  "sources": [
    "worldBankProcurementNotices",
    "worldBankDebarredFirms"
  ],
  "maxItemsPerSource": 100,
  "onlyNew": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("stefano_seggio/actor-20-mdb-procurement-monitor").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("stefano_seggio/actor-20-mdb-procurement-monitor").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 '{}' |
apify call stefano_seggio/actor-20-mdb-procurement-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,stefano_seggio/actor-20-mdb-procurement-monitor"
        }
    }
}

```

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/dyzTtWjfyYd7bvUZY/builds/HMObxYnTNY5AcldZ0/openapi.json
