# World Bank Procurement Notices & Awards Scraper (`knotty_mistveil/world-bank-procurement-notices`) Actor

World Bank-financed tenders, EOIs and signed contract awards from the official projects.worldbank.org APIs: buyer contacts, deadlines, suppliers, US$ values.

- **URL**: https://apify.com/knotty\_mistveil/world-bank-procurement-notices.md
- **Developed by:** [Jason](https://apify.com/knotty_mistveil) (community)
- **Categories:** Business, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

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

## World Bank Procurement Notices & Awards Scraper

Pulls World Bank-financed procurement straight from the two official APIs behind
[projects.worldbank.org](https://projects.worldbank.org/en/projects-operations/procurement): the
**procurement notices** feed (invitations for bids, requests for expressions of interest, general
procurement notices, prequalifications and award notices, in 112 borrower countries and regional
programmes) and the **contract awards** feed (signed major contracts with the winning supplier, its
country and the value in US dollars). No API key, no login, no browser automation. You get one flat
JSON record per notice or contract, filtered by date window, country, notice type, procurement
category, method, keyword and submission deadline - including the buyer's own contact name, e-mail
and phone, and the complete advertisement as plain text.

This is the money side of every IBRD/IDA project: US$3.0 billion of contracts were signed in the
three months to 8 September 2026 alone, across 134 borrower countries and 151 supplier countries.

### What you get

Pick one `feed` per run; the two have different fields.

#### `feed: "notices"` - procurement notices

| Field | Description |
| --- | --- |
| `id` | World Bank notice id, e.g. `OP00446360` |
| `source` | `worldbank`, constant |
| `feed` | `notices`, constant |
| `url` | The notice page on projects.worldbank.org |
| `title` | Contract title (`bid_description`) |
| `noticeType` | `Invitation for Bids`, `Request for Expression of Interest`, `General Procurement Notice`, `Invitation for Prequalification`, `Contract Award` |
| `status` | `Published`, `Cancelled`, ... |
| `noticeDate` | Publication date, `YYYY-MM-DD` |
| `submissionDeadline` / `submissionDeadlineTime` | Bid or EOI closing date (`YYYY-MM-DD`) and the local clock time as published (`09:30`). `null` on award and general procurement notices |
| `country` / `countryCode` | Borrower country or regional programme, and its World Bank two-character code |
| `region` | World Bank region as the notices index spells it (`East Asia And Pacific`) |
| `projectId` / `projectName` / `projectUrl` | The financing project (`P162178`) and its page |
| `procurementGroup` / `procurementGroupCode` | `Goods` / `GO`, `Works` / `CW`, `Consultant Services` / `CS`, `Non-consulting Services` / `NC` |
| `procurementMethod` / `procurementMethodCode` | `Request for Bids` / `RFB`, `Quality And Cost-Based Selection` / `QCBS`, `Request for Quotations` / `RFQ`, ... |
| `bidReference` | The borrower's own reference, e.g. `YT-GS-4B` |
| `language` | Language the notice is written in |
| `contactName`, `contactEmail`, `contactOrganization`, `contactAddress`, `contactPhone`, `contactCountry`, `contactWebsite` | The buyer's published contact block (see the personal-data note below) |
| `noticeText` | The complete advertisement as plain text, HTML and entities decoded, capped at 20,000 characters. Switch it off with `includeNoticeText: false` |
| `fetchedAt` | ISO timestamp of the run |

#### `feed: "awards"` - signed contract awards

| Field | Description |
| --- | --- |
| `id` | World Bank contract id, e.g. `1896263` |
| `source` / `feed` | `worldbank` / `awards` |
| `url` | The contract page on projects.worldbank.org |
| `contractDescription` | What was bought |
| `supplierName` / `supplierCountry` | The winning supplier and its country (the first, for a joint venture) |
| `suppliers` | Every supplier as `{name, country, countryCode, amount}` - the shares add up to `amount` |
| `supplierCount` | How many suppliers share the contract |
| `contractReference` | The borrower's contract reference |
| `signingDate` / `noObjectionDate` | Contract signature date and the Bank's no-objection date, `YYYY-MM-DD` |
| `amount` / `currency` | Total contract amount as a number, and `USD` (the source publishes "Amount (US$)") |
| `procurementCategory` / `procurementCategoryCode` | `Works` / `CW`, `Goods` / `GO`, ... |
| `procurementMethod` | `Request for Bids`, `Individual Consultant Selection`, `Direct Selection`, ... |
| `projectId` / `projectName` / `projectUrl` | The financing project |
| `borrowerCountry` / `borrowerCountryCode` / `region` / `regionCode` | Where the contract is performed |
| `majorSectors` / `sectors` | Sector labels and `{code, name}` pairs |
| `reviewType` | `Prior` or `Post` World Bank review |
| `fiscalYear` | World Bank fiscal year of the award |
| `worldBankTaskTeamMember` | The Bank staff member on the project (published on the contract page) |
| `fetchedAt` | ISO timestamp of the run |

The dataset ships three views: **Overview** (works for either feed), **Notice contacts** (buyer,
contact, e-mail, phone, deadline) and **Award suppliers** (supplier, country, value, project).

### Input

| Input | Type | Default | Description |
| --- | --- | --- | --- |
| `feed` | string | `notices` | `notices` or `awards`. |
| `daysBack` | integer | `14` | Look-back window in days ending now, on `noticeDate` (notices) or `signingDate` (awards). Ignored when `dateFrom`/`dateTo` are set. |
| `dateFrom` | string | - | Start of the window, `YYYY-MM-DD` (inclusive). |
| `dateTo` | string | today | End of the window, `YYYY-MM-DD` (inclusive). |
| `countries` | string\[] | all | Borrower countries as ISO alpha-2 (`KE`), ISO alpha-3 (`KEN`) or a name fragment (`Kenya`, `congo`). |
| `noticeTypes` | string\[] | all | Notices feed only. `Invitation for Bids`, `Request for Expression of Interest`, `General Procurement Notice`, `Invitation for Prequalification`, `Contract Award`. The short forms `IFB`, `REOI`, `GPN` are accepted too. |
| `procurementGroups` | string\[] | all | `goods`, `works`, `consultants`, `non-consulting`. Works on both feeds. |
| `procurementMethods` | string\[] | all | Case-insensitive substrings matched against the method name and code: `RFB`, `Request for Bids`, `QCBS`, `Individual Consultant`. |
| `keywords` | string\[] | none | Full-text terms, ORed. Sent to the World Bank index, which matches them anywhere in the record, then narrowed by `keywordScope`. |
| `keywordScope` | string | `fields` | Where a keyword has to appear. `fields` keeps a record only when a term is in `title` / `projectName` / `bidReference` (notices) or `contractDescription` / `projectName` / `contractReference` (awards). `fulltext` keeps everything the index matched, advertisement body included. |
| `deadlineAfter` | string | - | Notices feed only. Keep only notices closing on or after this date. Set it to today to drop opportunities that have already closed; notices with no deadline are dropped. |
| `includeNoticeText` | boolean | `true` | Notices feed only. Include the full advertisement text (about 5 KB per notice). |
| `maxItems` | integer | `500` | Stop after this many records. You are charged per record, so this is also the cost cap. Records are newest-first, so a value below the window's volume drops the **oldest** records in it. |

Example - open tenders and consultant EOIs in East Africa, still accepting bids, with the buyer's e-mail:

```json
{
  "feed": "notices",
  "daysBack": 30,
  "countries": ["KE", "UG", "TZ", "ETH", "RW"],
  "noticeTypes": ["Invitation for Bids", "Request for Expression of Interest"],
  "deadlineAfter": "2026-09-08",
  "includeNoticeText": false,
  "maxItems": 300
}
```

Example - who is winning World Bank road and bridge works, worldwide, over the last quarter
(42 signed contracts on 8 September 2026):

```json
{ "feed": "awards", "daysBack": 90, "procurementGroups": ["works"], "keywords": ["road", "bridge"], "maxItems": 1000 }
```

Example - the complete unfiltered notice feed, scheduled daily (the overlapping window absorbs the
index's publication lag):

```json
{ "feed": "notices", "daysBack": 3, "maxItems": 800 }
```

An unknown `noticeTypes`, `procurementGroups` or `keywordScope` value, a malformed date or `dateFrom`
after `dateTo` ends the run immediately with the validation message as its status, before any request
is made.

**Where each filter is applied.** `countries` (when every value is a code), `noticeTypes`,
`procurementGroups` and `keywords` are sent to the World Bank index as query parameters. A country
**name** cannot be, so a list that mixes names and codes (`["KE", "Uganda"]`) is filtered locally
instead - the result is the same, the run just reads more pages. Every server-side filter is then
**re-checked locally** on the records that come back, so a facet the index stops honouring shows up
as a drop count in `SUMMARY.filteredOut` rather than as unfiltered records on your bill.
`procurementMethods`, `deadlineAfter`, `keywordScope` and the date window are only ever applied
locally. The `SUMMARY` record in the key-value store reports which filters ran where, the exact
`qterm` sent, and how many records each filter dropped.

**Keywords, and why `keywordScope` defaults to `fields`.** The World Bank index matches a keyword
anywhere in the record, and a notice record contains the entire advertisement - including the postal
addresses printed in it. A raw index search for `road` therefore returns *Procurement of Kitchen
Tools* because the bids go to "13, TNHB Complex, 100 Feet Road, Vadapalani". Measured on
8 September 2026: of the 134 notices the index matched for `road` in a 10-day window, only 14 (10%)
had the word in the title, project name or reference; the other 120 matched on the body text, mostly
street addresses. The default `keywordScope: "fields"` drops those 120 **before** they are charged
for, and the run log says how many it dropped and how to get them back. Set
`keywordScope: "fulltext"` when you genuinely want the wide match - for example to find every notice
that names a standard or a piece of equipment somewhere in its specification.

The two feeds also do not share a full-text query syntax (`OR` unions terms on the notices
endpoint, `|` on the awards endpoint, and each returns nonsense for the other's operator), so the
Actor builds the query string per feed. You just pass `keywords`.

### Output example

A real `notices` record from a live run on 2026-09-08, `noticeText` shortened:

```json
{
  "id": "OP00446360",
  "source": "worldbank",
  "feed": "notices",
  "url": "https://projects.worldbank.org/en/projects-operations/procurement-detail/OP00446360",
  "title": "Capacity Building for Digital Food Safety Supervision",
  "noticeType": "Invitation for Bids",
  "status": "Published",
  "noticeDate": "2026-09-05",
  "submissionDeadline": "2026-09-17",
  "submissionDeadlineTime": "09:30",
  "country": "China",
  "countryCode": "CN",
  "region": "East Asia And Pacific",
  "projectId": "P162178",
  "projectName": "China Food Safety Improvement Project",
  "projectUrl": "https://projects.worldbank.org/en/projects-operations/project-detail/P162178",
  "procurementGroup": "Goods",
  "procurementGroupCode": "GO",
  "procurementMethod": "Request for Proposals",
  "procurementMethodCode": "RFP",
  "bidReference": "YT-GS-4B",
  "language": "English",
  "contactName": "Wu Haotian",
  "contactEmail": "ytshb123@163.com",
  "contactOrganization": "Yantai Ocean Economic Research Institute",
  "contactAddress": "No.2, No.32, Yinhai Road, Laishan District, Yantai, Shandong Province, PRC",
  "contactPhone": "0535-6920098",
  "contactCountry": "China",
  "contactWebsite": null,
  "fetchedAt": "2026-09-08T02:26:04.529Z",
  "noticeText": "Invitation for Bids\nInformation Systems\n(Design, Supply and Installation)\nPurchaser: Yantai Marine Economic Research Institute\nProject: China Food (Shandong Yantai Aquatic Products) Safety Demonstration Project\nContract title: YT-GS-4B: Capacity Building for Digital Food Safety Supervision\nCountry: ..."
}
```

A real `awards` record from the same run:

```json
{
  "id": "1896263",
  "source": "worldbank",
  "feed": "awards",
  "url": "https://projects.worldbank.org/en/projects-operations/contractoverview/1896263",
  "contractDescription": "Construction of Yarmag New Road",
  "supplierName": "LONGJIAN ROAD & BRIDGE CO.LTD. (LRBC)",
  "supplierCountry": "China",
  "suppliers": [
    { "name": "LONGJIAN ROAD & BRIDGE CO.LTD. (LRBC)", "country": "China", "countryCode": "CN", "amount": 23594002.75 }
  ],
  "supplierCount": 1,
  "contractReference": "TYPE II - W3",
  "signingDate": "2026-08-14",
  "noObjectionDate": null,
  "amount": 23594002.75,
  "currency": "USD",
  "procurementCategory": "Works",
  "procurementCategoryCode": "CW",
  "procurementMethod": "Request for Bids",
  "projectId": "P174007",
  "projectName": "Ulaanbaatar Sustainable Urban Transport Project",
  "projectUrl": "https://projects.worldbank.org/en/projects-operations/project-detail/P174007",
  "borrowerCountry": "Mongolia",
  "borrowerCountryCode": "MN",
  "region": "East Asia and Pacific",
  "regionCode": "EAP",
  "majorSectors": ["Transportation"],
  "sectors": [{ "code": "TC", "name": "Urban Transport" }, { "code": "TF", "name": "PA Transportation" }],
  "reviewType": "Prior",
  "fiscalYear": null,
  "worldBankTaskTeamMember": "Edward Andrew Beukes",
  "fetchedAt": "2026-09-08T02:26:15.152Z"
}
```

Every run also writes a `SUMMARY` record to the key-value store: how many rows were scanned and kept,
how many each filter dropped, the resolved date window, the newest and oldest record delivered, and
`stopReason` - why paging ended (`windowExhausted`, `maxItems`, `offsetCeiling` or `unparseableDates`).
Anything other than `windowExhausted` means the window was not read to the end.

### Pricing

Pay per result: **US$0.003 per record delivered** (US$3 per 1,000 records). You are charged only for
records pushed to the dataset; a run that returns nothing costs nothing. Runs on the Apify free plan
are limited by the platform's free-tier usage allowance.

### Data source and licence

- Procurement notices: `GET https://search.worldbank.org/api/v2/procnotices?format=json&rows=200&os=0&srt=noticedate desc,id asc`
- Contract awards: `GET https://search.worldbank.org/api/contractdata?format=json&rows=200&os=0&srt=contr_sgn_date desc,id asc`
- Both are the public, key-free endpoints that the World Bank's own
  [Projects & Operations procurement pages](https://projects.worldbank.org/en/projects-operations/procurement)
  call. Records link back to `projects.worldbank.org/en/projects-operations/procurement-detail/{id}`,
  `.../contractoverview/{contractId}` and `.../project-detail/{projectId}`.
- Licence: the **World Bank Terms of Use for Datasets**,
  <https://www.worldbank.org/ext/en/legal/terms-conditions/datasets> (read 8 September 2026). That
  page states that the Bank's datasets are provided under a
  [Creative Commons Attribution 4.0 International licence (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/)
  with added terms, and CC BY 4.0 permits commercial reuse. It also sets the attribution format -
  *"The World Bank: Dataset name: Data source (if known)"* - so credit
  "The World Bank: Procurement Notices / Major Contract Awards" and link to the record.
  Note that the Bank's **general** Terms and Conditions
  (<https://www.worldbank.org/ext/en/legal/terms-conditions>, which is also where the older
  `/en/about/legal/terms-of-use-for-datasets` path now redirects) cover the Bank's website content
  and are more restrictive; the datasets page above is the one that governs these APIs.
- **Personal data.** Notices carry the buyer's own published contact block - `contactName`,
  `contactEmail`, `contactPhone`, `contactAddress` - because World Bank procurement rules require
  borrowers to publish a contact for bidders. Award records carry `worldBankTaskTeamMember`, the Bank
  staff member shown on the public contract page. These are real people. The World Bank publishes them
  lawfully as part of an open procurement process; using them afterwards, marketing in particular, is
  your responsibility under the GDPR, the borrower country's own rules and any applicable e-marketing
  law. They are published so that bidders can ask about that tender.

### Limits and freshness

All figures below were measured from this Actor against the live API on 8 September 2026.

- **Notice volumes.** 1,630 notices fell in the 14-day window ending 8 September 2026 - notice dates
  25 August to 6 September, the newest in the index. Per day that is **124 to 195 on a weekday** and
  **23 to 56 at a weekend**. The mix over that fortnight was
  75.6% contract-award notices, 13.2% requests for expression of interest, 10.8% invitations for bids,
  0.4% general procurement notices and 0.1% prequalifications, spread over 112 countries and regional
  programmes and four languages (English 1,105, French 370, Spanish 103, Portuguese 52). By category:
  Goods 584, Consultant Services 456, Works 399, Non-consulting Services 185.
- **Every open opportunity carries a contact.** All 398 non-award notices in that fortnight had a
  `contactEmail`, and 392 of them (98%) had a submission deadline. Award notices carry neither.
- **Award volumes.** 3,128 contracts had a signing date in the 90 days to 8 September 2026, worth
  US$3.0 billion in total (median US$56,820, largest US$260.9 million), across 134 borrower countries
  and 151 supplier countries; 176 of them were joint ventures with more than one supplier. The index
  is refreshed continuously, so counts for the same window move by a record or two between runs.
- **Freshness, and the lag you must plan for.** Notices reach the index one to two days after
  publication: at 02:00 UTC on Tuesday 8 September the newest notice date in the index was Sunday
  6 September. Contract awards lag much further, because a contract is loaded weeks after it is
  signed - only 103 contracts in the index had been signed in the previous 14 days, against 403 in the
  previous 30 and roughly 40 per day for dates three to four weeks old. **Use `daysBack` of 60-120 for
  awards**, and re-run an award window later if you need it complete.
- **Size `maxItems` to the window.** The default 500 is a sample, not an archive: an unfiltered 14-day
  notices run returns about 1,630 records, and an unfiltered 90-day awards run about 3,128. Because
  the feed is newest-first, a `maxItems` below the window's volume drops the oldest records and logs
  `limitReached: true` in the run summary.
- **Run time and page size.** Pages are 200 records (100 when `includeNoticeText` is on, because those
  pages are about 1 MB each) and are spaced 250 ms apart. Measured runs: 14 days of notices with full
  text = 1,630 records over 17 pages in 20-34 seconds; 90 days of awards = 3,128 records over 16 pages
  in 25-27 seconds. The spread is the endpoint's own latency, which varies with its load.
- **There is no date parameter on either endpoint** (checked 8 September 2026: `strdate`/`enddate` are
  silently ignored and a range expression returns HTTP 500). The Actor instead sorts newest-first and
  stops at the first record older than the window, so a long window costs proportionally more pages.
- **Keyword matching is the index's, then narrowed.** There is no field-scoped search parameter on
  either endpoint, so `keywords` are always sent as a whole-record `qterm` and the scoping happens on
  the records that come back. That means a keyword run reads (and pays nothing for) many more rows
  than it delivers, and it inherits the index's own tokenising: searching `roads` will not match a
  title that only says `Road`. The two endpoints union terms with different operators (`OR` on
  notices, `|` on awards) and each silently mis-answers the other's, so the Actor picks the right one
  per feed and records the exact string it sent in `SUMMARY.filters.qterm`.
- **Rate limits and flakiness.** The World Bank documents no rate limit and none was observed: 40
  back-to-back page requests in 34 seconds returned no `429`. The endpoint does, however,
  intermittently answer an **empty HTTP 500** when it is busy - measured on 8 September 2026 at
  anywhere between 0 and 30% of requests over batches of 30, with the same failure rate for filtered
  and unfiltered queries, so it is server load rather than anything in the query. Each page therefore
  gets up to eight attempts with exponential back-off (1 s, 2 s, 4 s ... capped at 30 s), which made
  those failures invisible in every measured run.
- **Paging depth, and how a truncated run announces itself.** The search back end refuses an offset
  beyond 100,000 records; the Actor stops with a warning if a window is wide enough to reach it and
  writes `stopReason: "offsetCeiling"`. A page on which no row's date can be parsed is not treated as
  the end of the window either - the Actor keeps paging through up to three such pages in a row,
  warns on each, and only then stops with `stopReason: "unparseableDates"`. A complete run always ends
  `windowExhausted` or `maxItems`.
- Records are de-duplicated by id within a run, so a notice that shifts position while the index is
  being refreshed cannot appear twice.
- Amounts are the borrower's US-dollar contract value and are never converted or adjusted. Dates are
  plain `YYYY-MM-DD`; `submissionDeadlineTime` is the local clock time at the submission address, as
  published, with no time zone attached.
- Regional programmes are filed under their own codes (`3E` Eastern and Southern Africa, `3W` Western
  and Central Africa, `8S` South Asia), so a `countries` filter will not return the multi-country
  programme that also covers that country. 225 of the 1,630 notices in the measured fortnight (14%)
  were regional, 181 of them Eastern and Southern Africa or Western and Central Africa.
- Some source records contain a U+FFFD replacement character where the World Bank's own editor mangled
  an accented character upstream. The Actor passes the text through as published rather than guessing.

### Use cases

- **Bid pipeline.** A daily feed of new invitations for bids and consultant EOIs in your countries and
  categories, with the buyer's e-mail and the closing date, so you can qualify and respond before the
  deadline. `deadlineAfter` keeps closed opportunities out of the list.
- **Competitor and market intelligence.** The awards feed shows who won what, for how much, in which
  sector and under which method - use it to size a market, track a rival across countries, or find the
  local partners who keep winning in a country you want to enter.
- **Project monitoring and compliance.** Archive every notice and contract for a project, a borrower
  or a sector with `dateFrom`/`dateTo`, and reconcile the two feeds through the shared `projectId`.

### Support

Open an issue on the Actor's Issues tab on Apify Store. Replies within 14 days. Bug reports that name
the run id and the input used are fixed fastest.

# Actor input Schema

## `feed` (type: `string`):

Which World Bank dataset to read. Procurement notices are the live opportunities and award notices published on projects.worldbank.org; contract awards are the signed major contracts, with the winning supplier and the US dollar value. The two feeds have different fields, so pick one per run.

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

Look-back window in days, ending now. Applied to the notice date on the notices feed and to the contract signing date on the awards feed. Ignored when Date from / Date to are set. Awards are loaded weeks after signature, so use 60-120 days for a useful awards run.

## `dateFrom` (type: `string`):

Start of the window, YYYY-MM-DD (inclusive). Overrides Days back.

## `dateTo` (type: `string`):

End of the window, YYYY-MM-DD (inclusive). Defaults to today.

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

Borrower countries. Accepts ISO alpha-2 ("KE"), ISO alpha-3 ("KEN") or a name fragment ("Kenya", "congo"). A name fragment is matched case-insensitively against the country name the World Bank publishes. Regional programmes are filed under their own codes (3E Eastern and Southern Africa, 3W Western and Central Africa, 8S South Asia), so a country filter does not return the multi-country programmes that also cover it. Empty = every country.

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

Notices feed only. Keep only these notice types. Empty = all types.

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

Keep only these categories. Works with both feeds.

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

Case-insensitive substrings matched against the method name and code: "RFB" or "Request for Bids", "RFQ", "QCBS", "Direct Selection", "Individual Consultant". A record is kept when any term matches. Empty = all methods.

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

Free-text terms, ORed. They are sent to the World Bank search index, which matches them anywhere in the record - including the full advertisement body and the postal addresses inside it. By default the results are then narrowed to records whose title, project name or reference actually contains a term; see Keyword scope. Empty = no keyword filter.

## `keywordScope` (type: `string`):

Where a keyword has to appear. "fields" (default) keeps a record only when a term is in the title, project name or reference number (notices) or the contract description, project name or reference (awards) - this is the setting you want for a bid pipeline, because the index alone also matches street addresses in the advertisement body, so a search for "road" would return kitchen tools sold at "100 Feet Road" and you would be charged for them. "fulltext" keeps everything the index matched, advertisement body included. Ignored when Keywords is empty.

## `deadlineAfter` (type: `string`):

Notices feed only. Keep only notices whose submission deadline falls on or after this date, YYYY-MM-DD - use today's date to drop opportunities that have already closed. Notices with no published deadline (award and general procurement notices) are dropped when this is set.

## `includeNoticeText` (type: `boolean`):

Notices feed only. Add the complete advertisement as plain text (field noticeText, truncated at 20,000 characters). Averages about 5 KB per notice; turn it off for a lean lead list.

## `maxItems` (type: `integer`):

Stop after this many records. You are charged per record delivered, so this is also the cost cap. Records come newest-first, so a value below the window's volume drops the OLDEST records in that window. Measured 8 September 2026: about 125-195 notices per weekday and 25-55 per weekend day, so an unfiltered 14-day notices run needs roughly 1,800.

## Actor input object example

```json
{
  "feed": "notices",
  "daysBack": 14,
  "countries": [],
  "noticeTypes": [],
  "procurementGroups": [],
  "procurementMethods": [],
  "keywords": [],
  "keywordScope": "fields",
  "includeNoticeText": true,
  "maxItems": 500
}
```

# Actor output Schema

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

All records returned by the run, one JSON object each. Append ?format=csv or ?format=xlsx to download a spreadsheet.

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

Counts, the date window used, the filters applied, how many rows each filter dropped and why paging stopped, written at the end of the run.

# 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 = {
    "feed": "notices",
    "daysBack": 14,
    "countries": [],
    "noticeTypes": [],
    "procurementGroups": [],
    "procurementMethods": [],
    "keywords": [],
    "keywordScope": "fields",
    "includeNoticeText": true,
    "maxItems": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("knotty_mistveil/world-bank-procurement-notices").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 = {
    "feed": "notices",
    "daysBack": 14,
    "countries": [],
    "noticeTypes": [],
    "procurementGroups": [],
    "procurementMethods": [],
    "keywords": [],
    "keywordScope": "fields",
    "includeNoticeText": True,
    "maxItems": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("knotty_mistveil/world-bank-procurement-notices").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 '{
  "feed": "notices",
  "daysBack": 14,
  "countries": [],
  "noticeTypes": [],
  "procurementGroups": [],
  "procurementMethods": [],
  "keywords": [],
  "keywordScope": "fields",
  "includeNoticeText": true,
  "maxItems": 500
}' |
apify call knotty_mistveil/world-bank-procurement-notices --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,knotty_mistveil/world-bank-procurement-notices"
        }
    }
}
```

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/OvAM4KYft7jg4czdF/builds/Qd0kv8xSN3XHBVnYy/openapi.json
