# Development Project Tenders & Procurement Notices Monitor (`abdulwhab95/development-tenders-monitor`) Actor

Invitations for bids, requests for expressions of interest and contract awards from the World Bank's open Procurement Notices dataset (CC BY 4.0) - filter by country (MENA included), notice type, method, keyword and dates; only new notices on a schedule. Not affiliated with the World Bank.

- **URL**: https://apify.com/abdulwhab95/development-tenders-monitor.md
- **Developed by:** [ABDULWAHAB NASER RASHED ALQARAWI](https://apify.com/abdulwhab95) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 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?

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

## Development Project Tenders & Procurement Notices Monitor

Invitations for bids, requests for expressions of interest and contract awards
on development projects financed by the World Bank, from the World Bank's
**open Procurement Notices dataset**. Filter by country, including the Middle
East and North Africa, and by notice type, procurement method, keyword and
date. Schedule it with `onlyNew` and each run returns only notices you have not
seen.

No API key, no login, no browser, no proxy. The data comes from the official
public API that the World Bank Data Catalog lists for this dataset.

> **Not affiliated with, sponsored or endorsed by the World Bank.** This Actor
> reads the World Bank's openly licensed data. See *Data source and license*
> below.

***

### What you get

One row per notice, **26 fields, every one always present**. Missing values
come back as `null`, never dropped.

| Field | Example |
|---|---|
| `title` | CONSULTANCY SERVICES FOR DETAILED DESIGN, TENDER ASSISTANCE OF SCADA SYSTEM… |
| `noticeType` | `Request for Expression of Interest` |
| `country` / `countryCode` | `Jordan` / `JO` |
| `borrowerAgency` | `Miyahuna Water Company` |
| `projectId` / `projectName` | `P176619` / `Jordan Water Sector Efficiency Project` |
| `procurementGroup` | `Consultant Services` |
| `procurementMethod` / `procurementMethodCode` | `Quality And Cost-Based Selection` / `QCBS` |
| `estimatedAmount` / `estimateCurrency` | `800000.0` / `USD` |
| `publishedAt` | `2026-09-01` |
| `deadline` | `2026-09-23T11:30` |
| `url` | `https://projects.worldbank.org/en/projects-operations/procurement-detail/OP00466105` |

Plus `noticeId`, `noticeStatus`, `region`, `bidReference`, `sectors`,
`language`, `noticeVersion`, `description`, `source`, `scrapedAt` and
`changeType`.

**Organizations only.** `borrowerAgency` is the implementing agency. Contact
persons' names, e-mail addresses and phone numbers are never copied into a row.
In `description` they are scrubbed out: e-mail addresses, phone-like numbers,
and the listed contact person's name. Contract award notices carry no
`description` at all, because their text lists bidders, and an individual
consultant is a person.

***

### Use it for

- **Tender alerts for contractors, suppliers and consultancies.** Schedule a
  daily run with `onlyNew`, filtered to your countries and procurement groups.
- **Open opportunities only.** Set `deadlineFrom` to `today`.
- **Market research.** See who wins contract awards, by country, method and
  sector.
- **MENA pipeline tracking** across Egypt, Jordan, Morocco, Lebanon, Tunisia,
  Iraq, Yemen, Djibouti, and West Bank and Gaza.

***

### Filters

| Input | What it does |
|---|---|
| `countryCodes` | World Bank country codes. Yemen is **RY** and West Bank and Gaza is **GZ**, not their ISO codes. |
| `regions` | MENA is `Mid East,North Africa,Afg,Pak`, which also covers Afghanistan and Pakistan. |
| `noticeTypes` | Invitation for Bids, Request for Expression of Interest, Contract Award, General Procurement Notice, Invitation for Prequalification. |
| `procurementGroups` | Goods (GO), Works (CW), Consultant services (CS), Non-consulting services (NC). |
| `procurementMethods` | Method codes: RFB, RFQ, QCBS, CQS, LCS, INDV, DIR and so on. |
| `keyword` | Full-text search of the notice. |
| `daysBack` / `publishedFrom` / `publishedTo` | Publication window. The default is the last 7 days. `0` means no date limit. |
| `deadlineFrom` / `deadlineTo` | Submission deadline window (`YYYY-MM-DD` or `today`). Notices without a deadline, such as awards, are left out when one is set. |
| `maxResults` | Stop after this many rows (up to 10,000). |

**The Gulf states have no notices.** The World Bank does not finance projects
in Saudi Arabia, Kuwait, the UAE, Qatar, Bahrain or Oman. A query for those six
codes returned 0 notices on 15 Sep 2026. Gulf firms bidding on MENA projects
should filter by the borrowing countries instead.

***

### Only new notices

Turn on `onlyNew` and schedule the Actor. Each run returns only notices not
delivered before (`changeType: NEW`), or re-published under a higher notice
version (`UPDATED`). The first run returns everything in the window as `NEW`.

The delivered notice ids live in a named key-value store in your account
(`stateStoreName`, default `worldbank-procurement-state`). Use a different name
for each separate monitor.

Only notices that were actually delivered are remembered. If a run stops at
your spending limit, or a page fails, the notices it did not deliver still
arrive as new next time.

***

### Measured (15 Sep 2026, local runs against the live API)

| Run | Requests | Time | Result |
|---|---|---|---|
| MENA, bids and EOIs, last 14 days, `onlyNew`, first run | 2 | 1.2 s | 40 notices, all `NEW` |
| The same run again | 2 | 1.1 s | **0 notices**, 40 already seen |
| 9 MENA countries, RFB and QCBS, `deadlineFrom: today`, no date limit | 16 | 25 s | 11 open notices from 1,474 scanned |

Requests go out at most one per second, 100 notices per request.

***

### Honest notes

**Deadlines are the borrower's local time.** The API gives the deadline date
and clock time with no time zone, so `deadline` is `2026-09-23T11:30` with no
offset. When the time is missing it is a date only. `publishedAt` is a date:
the dataset has no publication time.

**Some notice text has broken characters.** A few notices contain `�` where the
source already lost an accented letter or curly quote. It comes from the
dataset and is passed through unchanged.

**Date windows are applied by the Actor.** The API has no date-range filter.
Notices come newest first, so paging stops as soon as a page reaches notices
older than your window. A deadline filter with no publication window has to
scan every matching notice. It is capped at 20,000 notices per run, and the
status message says so if the cap is reached.

**Every filter is checked twice.** It is sent to the API and re-checked on each
notice, so a parameter the API ignores cannot slip unwanted rows into your
dataset.

**robots.txt is read first**, and the Actor only ever contacts
`search.worldbank.org`.

**Every run publishes a report** to the key-value store under `RUN_REPORT`:
requests, notices scanned, delivered, filtered out and already seen, and
whether the run was cut short.

***

### Data source and license

Data: **The World Bank: World Bank Procurement Notices:
search.worldbank.org/api/v2/procnotices**. It is provided under the
[Creative Commons Attribution 4.0 International License (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/),
subject to the World Bank's
[Terms of Use for Datasets](https://www.worldbank.org/ext/en/legal/terms-conditions/datasets).
Dataset catalog entry:
[World Bank Procurement Notices](https://datacatalog.worldbank.org/search/dataset/0037795/world-bank-procurement-notices).

Changes made: fields renamed and reformatted, HTML converted to plain text and
trimmed, and contact details removed. Every row carries this attribution in
`source`. If you share the data onward, the Dataset Terms ask you to keep the
same attribution. Linking to the terms above satisfies that.

This Actor and its author are not affiliated with the World Bank. Nothing here
implies the World Bank's sponsorship, approval or endorsement.

***

### Questions, or a filter that returns nothing?

Open an issue with your input.

# Actor input Schema

## `countryCodes` (type: `array`):

World Bank project country codes, one per line (for example EG Egypt, JO Jordan, MA Morocco, LB Lebanon, TN Tunisia, IQ Iraq, DJ Djibouti, RY Yemen, GZ West Bank and Gaza, PK Pakistan). Note Yemen is RY and West Bank and Gaza is GZ. Leave empty for all countries.

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

World Bank regions. MENA notices are under 'Mid East, North Africa, Afghanistan, Pakistan'.

## `noticeTypes` (type: `array`):

Leave empty for all types.

## `procurementGroups` (type: `array`):

Goods, works, consultant services or non-consulting services. Leave empty for all.

## `procurementMethods` (type: `array`):

Method codes, one per line - for example RFB (Request for Bids), RFQ (Request for Quotations), QCBS (Quality and Cost-Based Selection), CQS, LCS, INDV (Individual Consultant Selection), DIR (Direct Selection). Leave empty for all.

## `keyword` (type: `string`):

Full-text search across the notice, for example 'solar' or 'water'.

## `daysBack` (type: `integer`):

Used when 'Published from' is empty. 0 means no date limit (newest first, up to the result and scan caps).

## `publishedFrom` (type: `string`):

YYYY-MM-DD or 'today'. Overrides 'Published in the last N days'.

## `publishedTo` (type: `string`):

YYYY-MM-DD or 'today'.

## `deadlineFrom` (type: `string`):

YYYY-MM-DD or 'today'. Set 'today' to keep only notices still open for submissions. Notices without a deadline (awards) are left out when a deadline filter is set.

## `deadlineTo` (type: `string`):

YYYY-MM-DD or 'today'.

## `maxResults` (type: `integer`):

Stop after delivering this many notices.

## `includeDescription` (type: `boolean`):

Plain-text notice body (first 2,000 characters), with e-mail addresses, phone numbers and the contact person's name removed. Contract award notices never carry it, because their text lists bidders who may be individuals.

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

Deliver only notices not delivered before (changeType NEW), or re-published under a higher version (UPDATED). The first run delivers everything as NEW.

## `stateStoreName` (type: `string`):

Named key-value store that remembers delivered notice ids for 'Only new notices'. Use a different name for each separate monitor.

## Actor input object example

```json
{
  "countryCodes": [
    "EG",
    "JO",
    "MA"
  ],
  "daysBack": 7,
  "maxResults": 100,
  "includeDescription": true,
  "onlyNew": false,
  "stateStoreName": "worldbank-procurement-state"
}
```

# Actor output Schema

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

No description

## `runReport` (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 = {
    "countryCodes": [
        "EG",
        "JO",
        "MA"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("abdulwhab95/development-tenders-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 = { "countryCodes": [
        "EG",
        "JO",
        "MA",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("abdulwhab95/development-tenders-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 '{
  "countryCodes": [
    "EG",
    "JO",
    "MA"
  ]
}' |
apify call abdulwhab95/development-tenders-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abdulwhab95/development-tenders-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/SJ9E6pz9iOByeaz53/builds/K3PdUrlbs0ow5PdiF/openapi.json
