# South Africa eTenders Opportunities Scraper (`automation-lab/south-africa-etenders-opportunities-scraper`) Actor

Search and export public South African National Treasury tender opportunities with buyer, province, deadlines, contacts, briefings, values, and documents.

- **URL**: https://apify.com/automation-lab/south-africa-etenders-opportunities-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.05 / 1,000 tender opportunities

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

## South Africa eTenders Opportunities Scraper

Search and export public procurement opportunities published by South Africa's National Treasury eTenders service.
The Actor reads the official OCDS JSON API and returns one normalized dataset row per tender release—ready for alerts, spreadsheets, CRM enrichment, and BI.

Use it to answer questions such as:

- Which Western Cape tenders are open or being planned?
- Which opportunities mention construction, security, software, or consulting?
- What closes before the bid team's next review meeting?
- Which buyer, contact, briefing, and tender-document details are available?

The Actor uses anonymous HTTP requests to the official API. It does not need a browser, login, proxy, or eTenders account.

### What this Actor does

1. Fetches OCDS releases for a configurable release-date range.
2. Follows the official API's pagination links.
3. Deduplicates releases by OCID and release ID.
4. Normalizes nested OCDS tender data into search-friendly fields.
5. Applies keyword, province, category, status, buyer, and closing-date filters.
6. Saves accepted tenders to the default Apify dataset.

V1 focuses on tender opportunities. It does not promise an awards-only dataset because many current source releases have empty award and contract arrays.

### Who is it for?

#### Suppliers and bid teams

Build a repeatable shortlist of relevant public opportunities, including deadlines, compulsory briefings, contacts, and documents.

#### Procurement consultants

Monitor multiple provinces, categories, or procuring entities and export consistent records for clients.

#### Market-intelligence teams

Load normalized tender signals into a warehouse or dashboard for buyer, category, and geographic analysis.

#### Automation builders

Schedule daily or weekly runs, then connect the dataset to Slack, email, Google Sheets, a CRM, or a webhook-driven workflow.

### Why use this Actor

- **Official source:** data comes from the South African National Treasury eTenders OCDS API.
- **Useful normalization:** important fields no longer require navigating deeply nested OCDS objects.
- **Targeted monitoring:** filter before records are saved and charged as results.
- **Document-ready:** include public tender document metadata and URLs when needed.
- **Integration-friendly:** every primary record is saved in the default dataset.
- **Low infrastructure overhead:** the Actor is HTTP-only and runs with 256 MB memory.
- **Transparent failure:** malformed input and exhausted upstream retries fail the run instead of returning misleading partial success.

### Extracted data

| Field | Meaning |
| --- | --- |
| `ocid`, `releaseId`, `releaseDate`, `releaseTags` | OCDS release identity and lifecycle metadata |
| `tenderId`, `title`, `description`, `status` | Tender reference, summary, and current source status |
| `buyerId`, `buyerName` | OCDS buyer identity |
| `procuringEntityId`, `procuringEntityName` | Entity conducting the procurement |
| `province`, `deliveryLocation` | Geographic fields published by eTenders |
| `category`, `mainProcurementCategory` | Source category and OCDS procurement category |
| `additionalProcurementCategories` | Additional OCDS category values |
| `procurementMethod`, `procurementMethodDetails` | Procurement procedure |
| `valueAmount`, `valueCurrency` | Published estimated value; may be zero or unavailable |
| `tenderStartDate`, `closingDate` | Opportunity period |
| `briefingRequired`, `briefingCompulsory` | Briefing-session flags |
| `briefingDate`, `briefingVenue` | Briefing logistics when published |
| `contactName`, `contactEmail`, `contactTelephone` | Public tender contact details |
| `documents`, `documentUrls` | Document metadata and public downloads |
| `sourceUrl` | Official single-release API URL |
| `scrapedAt` | UTC extraction timestamp |
| `raw` | Optional complete source release |

Nullable fields remain `null` when the publisher did not provide them. Arrays remain arrays, including when empty.

### Getting started

1. Open the Actor in Apify Console.
2. Keep the default 30-day release window or set `dateFrom` and `dateTo`.
3. Set `maxItems` to the maximum number of matching tenders you need.
4. Add optional filters such as `provinces`, `statuses`, or `keywords`.
5. Leave **Include documents** enabled if your workflow needs download links.
6. Click **Start**.
7. Open the **Tender opportunities** dataset view.
8. Export JSON, CSV, Excel, XML, or RSS, or consume the dataset through the API.

A useful first input is:

```json
{
  "maxItems": 25,
  "includeDocuments": true,
  "includeRaw": false
}
````

### Input parameters

| Input | Type | Default | Description |
| --- | --- | --- | --- |
| `dateFrom` | string | 30 days ago | Earliest release date, `YYYY-MM-DD` |
| `dateTo` | string | run date | Latest release date, `YYYY-MM-DD` |
| `maxItems` | integer | `100` | Maximum saved results, from 1 to 10,000 |
| `keywords` | string\[] | none | Every keyword must occur in searchable tender text |
| `provinces` | string\[] | none | Match any listed province exactly, case-insensitive |
| `categories` | string\[] | none | Match any listed source category exactly |
| `statuses` | string\[] | none | Match any listed OCDS tender status |
| `buyer` | string | none | Text contained in buyer or procuring-entity name |
| `closingDateFrom` | string | none | Keep tenders closing on or after this date |
| `closingDateTo` | string | none | Keep tenders closing on or before this date |
| `includeDocuments` | boolean | `true` | Include document objects and URL list |
| `includeRaw` | boolean | `false` | Attach the complete source OCDS release |

Keyword matching is case-insensitive and uses tender reference, title, description, buyer, procuring entity, province, location, and category.
If you provide multiple keywords, all must match.
Province, category, and status arrays use “match any” behavior within each array.
Filters from different fields are combined with AND logic.

### Input examples

#### Active tenders in one province

```json
{
  "dateFrom": "2026-07-01",
  "dateTo": "2026-07-25",
  "provinces": ["Western Cape"],
  "statuses": ["active"],
  "maxItems": 100,
  "includeDocuments": true
}
```

#### Construction opportunities closing in a window

```json
{
  "keywords": ["construction"],
  "closingDateFrom": "2026-08-01",
  "closingDateTo": "2026-09-30",
  "maxItems": 250
}
```

#### Buyer-focused monitoring

```json
{
  "buyer": "Stellenbosch Municipality",
  "maxItems": 100,
  "includeDocuments": true,
  "includeRaw": false
}
```

### Output example

This abbreviated record reflects current source behavior observed during local validation:

```json
{
  "ocid": "ocds-9t57fa-163384",
  "releaseId": "ocds-9t57fa-163384-2026-07-25",
  "tenderId": "163384",
  "title": "BSM 126/26",
  "description": "UPGRADING OF 32 UNITS IN LA COLLINE, STELLENBOSCH",
  "status": "planning",
  "buyerName": "Stellenbosch Municipality",
  "province": "Western Cape",
  "category": "Construction",
  "procurementMethod": "open",
  "valueAmount": 0,
  "valueCurrency": "ZAR",
  "closingDate": "2026-08-24T11:00:00Z",
  "briefingCompulsory": true,
  "contactName": "Thabisa Manyingiza",
  "documentUrls": ["https://www.etenders.gov.za/home/Download?..."],
  "sourceUrl": "https://ocds-api.etenders.gov.za/api/OCDSReleases/release/ocds-9t57fa-163384"
}
```

Source values can change after publication. Treat zero values and nulls as source data, not as estimates made by the Actor.

### How much does it cost to scrape South Africa eTenders opportunities?

The Actor uses pay-per-event pricing:

- **$0.005 per run start**
- **$0.00010447 per saved tender on the Free tier**
- lower per-tender rates on higher Apify subscription tiers, down to **$0.000025437**

Only accepted, deduplicated tender rows are charged as item events. Rejected records and empty results are not charged as items.

Example Free-tier Actor charges:

| Results | Calculation | Actor charge |
| ---: | --- | ---: |
| 10 | $0.005 + 10 × $0.00010447 | $0.0060 |
| 100 | $0.005 + 100 × $0.00010447 | $0.0154 |
| 1,000 | $0.005 + 1,000 × $0.00010447 | $0.1095 |

Apify platform usage and subscription terms may also apply. Check the live Pricing tab before a large scheduled workflow.

### Scheduling and alerts

For a daily tender alert:

1. Create an Apify schedule.
2. Use a short rolling release window, such as the previous two days.
3. Add your keyword, province, buyer, or category filters.
4. Connect the run-finished webhook to your alerting service.
5. Store `ocid + releaseId` downstream to suppress repeat notifications across runs.

A rolling overlap helps capture late publication without pretending that the source is real-time.

### Integration patterns

#### CRM lead feed

Map buyer and procuring-entity fields to organizations, contact fields to public procurement contacts, and the OCID to an external stable key.

#### Bid calendar

Use `closingDate`, briefing fields, and document URLs to create review tasks and deadline reminders.

#### BI and market intelligence

Aggregate by province, buyer, category, method, or status. Preserve `releaseDate` and `scrapedAt` to distinguish source publication from extraction time.

#### Spreadsheet review

Export the `overview` view to CSV or Excel. Keep raw output disabled for a smaller file.

### API usage with cURL

Start a synchronous run and return dataset items:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~south-africa-etenders-opportunities-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"provinces":["Gauteng"],"maxItems":50,"includeDocuments":true}'
```

For larger jobs, use the asynchronous run endpoint and poll the run status instead of holding one HTTP connection open.

### JavaScript API example

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/south-africa-etenders-opportunities-scraper').call({
    keywords: ['software'],
    statuses: ['active'],
    maxItems: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Python API example

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/south-africa-etenders-opportunities-scraper').call(
    run_input={
        'buyer': 'municipality',
        'maxItems': 100,
        'includeDocuments': True,
    }
)
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### MCP and AI agents

Add this Actor as an Apify MCP tool in Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/south-africa-etenders-opportunities-scraper"
```

#### Claude Desktop setup

Add this server object to Claude Desktop's MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/south-africa-etenders-opportunities-scraper"
    }
  }
}
```

#### Cursor setup

Add the same `apify` server URL under **Cursor Settings → MCP**, then enable the server for your workspace.

#### VS Code setup

Add the same HTTP MCP server URL to your VS Code MCP configuration and start it from the MCP servers panel.

Example prompts:

- “Find up to 50 active Gauteng tenders mentioning security and include document links.”
- “Export municipal construction opportunities closing next month.”
- “Create a table of buyer, tender reference, deadline, briefing date, contact, and source URL.”

Always review source documents before making a procurement decision.

### Limits and source behavior

- Coverage is limited to releases returned by the official eTenders OCDS API for the requested dates.
- Current releases may use statuses such as `active` or `planning`; values come from the publisher.
- A published value of zero does not mean the opportunity has no economic value.
- Contacts, briefings, locations, and documents can be missing.
- The source may revise a tender under the same OCID with a different release ID.
- `maxItems` limits accepted results, not pages inspected before filters match.
- A broad date range with selective filters can take longer because the Actor must inspect source pages.
- Temporary upstream failures are retried three times; persistent failure produces a failed Actor run.
- No proxy is used. If the government API is unavailable, changing proxy geography will not repair the source.

### Troubleshooting

#### The dataset is empty

Remove filters one at a time, confirm the release-date range contains published records, and check exact province/category/status spelling.
Remember that all keywords must match.

#### The run takes longer than expected

Reduce the release-date range, especially when combining it with a rare keyword or buyer filter. The Actor stops early when `maxItems` accepted records are reached.

#### A field is null or a value is zero

That is normally the value published in the OCDS release. Open `sourceUrl` and the tender documents to verify it.

#### I need awards or contracts

V1 is an opportunity scraper. Do not infer awards from empty source arrays. Use the optional `raw` object for source inspection, but an awards-only product is outside the current contract.

### Responsible use and legality

The Actor accesses public procurement records exposed by the National Treasury's open-data service.
Use the data in accordance with the source license, Apify's terms, and applicable law.
Contact information is published for procurement communication; do not use it for spam, harassment, or unrelated bulk marketing.
Verify deadlines, eligibility, compulsory briefings, and submission instructions in the official tender documents.
The Actor is an extraction tool and does not provide legal, procurement, or bidding advice.

### FAQ

#### Does it require an eTenders login?

No. The official OCDS API used by this Actor is public and anonymous.

#### Does it use a browser or proxy?

No. It uses direct HTTP JSON requests.

#### Can I filter by multiple provinces?

Yes. A tender may match any listed province. Other filter groups still combine with AND logic.

#### Can I save the original OCDS object?

Yes. Enable `includeRaw`. It increases dataset size, so normalized output is recommended for routine monitoring.

#### Are results real-time?

No real-time guarantee is made. Results reflect what the official API returns when the run executes.

#### How are duplicates handled?

Within a run, the Actor deduplicates by OCID plus release ID. A revised release can correctly appear as a distinct record.

### Related automation-lab Actors

- [Singapore GeBIZ Tender Opportunities Scraper](https://apify.com/automation-lab/singapore-gebiz-tender-opportunities-scraper) — Singapore procurement opportunities.
- [World Bank Procurement Notices Scraper](https://apify.com/automation-lab/world-bank-procurement-notices-scraper) — global World Bank notices.
- [UK Find a Tender Scraper](https://apify.com/automation-lab/uk-find-a-tender-scraper) — UK procurement notices.
- [Spain Public Tenders Scraper](https://apify.com/automation-lab/spain-public-tenders-scraper) — Spanish public tender discovery.

Combine country-specific Actors only when your workflow genuinely needs each source; fields and procurement rules differ by publisher.

### Support

For reproducible help, include the Actor run URL, sanitized input, expected behavior, and one relevant OCID or tender reference.
Do not post private bid material or credentials in a public issue.

# Actor input Schema

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

Earliest release date to fetch, in YYYY-MM-DD format. Defaults to 30 days before the run.

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

Latest release date to fetch, in YYYY-MM-DD format. Defaults to the run date.

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

Maximum number of matching tender records to save.

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

Require every keyword to appear somewhere in the tender reference, title, description, buyer, province, location, or category. Matching is case-insensitive.

## `provinces` (type: `array`):

Keep tenders in any listed province, using case-insensitive exact matching (for example, Gauteng or Western Cape).

## `categories` (type: `array`):

Keep tenders in any listed source category, using case-insensitive exact matching.

## `statuses` (type: `array`):

Keep tenders in any listed OCDS status, such as active or planning.

## `buyer` (type: `string`):

Case-insensitive text contained in the buyer or procuring entity name.

## `closingDateFrom` (type: `string`):

Keep tenders closing on or after this YYYY-MM-DD date.

## `closingDateTo` (type: `string`):

Keep tenders closing on or before this YYYY-MM-DD date.

## `includeDocuments` (type: `boolean`):

Include tender document metadata and public download URLs.

## `includeRaw` (type: `boolean`):

Attach the complete source release under raw. Leave disabled for smaller, integration-friendly records.

## Actor input object example

```json
{
  "maxItems": 20,
  "keywords": [],
  "includeDocuments": true,
  "includeRaw": false
}
```

# Actor output Schema

## `overview` (type: `string`):

Open the default dataset table containing accepted, deduplicated tender opportunity records.

# 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 = {
    "maxItems": 20,
    "keywords": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/south-africa-etenders-opportunities-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "maxItems": 20,
    "keywords": [],
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/south-africa-etenders-opportunities-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "maxItems": 20,
  "keywords": []
}' |
apify call automation-lab/south-africa-etenders-opportunities-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=automation-lab/south-africa-etenders-opportunities-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "South Africa eTenders Opportunities Scraper",
        "description": "Search and export public South African National Treasury tender opportunities with buyer, province, deadlines, contacts, briefings, values, and documents.",
        "version": "0.1",
        "x-build-id": "LvweMkFOJGtEqlcsp"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/automation-lab~south-africa-etenders-opportunities-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-automation-lab-south-africa-etenders-opportunities-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/automation-lab~south-africa-etenders-opportunities-scraper/runs": {
            "post": {
                "operationId": "runs-sync-automation-lab-south-africa-etenders-opportunities-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/automation-lab~south-africa-etenders-opportunities-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-automation-lab-south-africa-etenders-opportunities-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "dateFrom": {
                        "title": "Release date from",
                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                        "type": "string",
                        "description": "Earliest release date to fetch, in YYYY-MM-DD format. Defaults to 30 days before the run."
                    },
                    "dateTo": {
                        "title": "Release date to",
                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                        "type": "string",
                        "description": "Latest release date to fetch, in YYYY-MM-DD format. Defaults to the run date."
                    },
                    "maxItems": {
                        "title": "Maximum tenders",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Maximum number of matching tender records to save.",
                        "default": 100
                    },
                    "keywords": {
                        "title": "Keywords",
                        "type": "array",
                        "description": "Require every keyword to appear somewhere in the tender reference, title, description, buyer, province, location, or category. Matching is case-insensitive.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "provinces": {
                        "title": "Provinces",
                        "type": "array",
                        "description": "Keep tenders in any listed province, using case-insensitive exact matching (for example, Gauteng or Western Cape).",
                        "items": {
                            "type": "string"
                        }
                    },
                    "categories": {
                        "title": "Tender categories",
                        "type": "array",
                        "description": "Keep tenders in any listed source category, using case-insensitive exact matching.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "statuses": {
                        "title": "Tender statuses",
                        "type": "array",
                        "description": "Keep tenders in any listed OCDS status, such as active or planning.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "buyer": {
                        "title": "Buyer or procuring entity",
                        "type": "string",
                        "description": "Case-insensitive text contained in the buyer or procuring entity name."
                    },
                    "closingDateFrom": {
                        "title": "Closing date from",
                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                        "type": "string",
                        "description": "Keep tenders closing on or after this YYYY-MM-DD date."
                    },
                    "closingDateTo": {
                        "title": "Closing date to",
                        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                        "type": "string",
                        "description": "Keep tenders closing on or before this YYYY-MM-DD date."
                    },
                    "includeDocuments": {
                        "title": "Include documents",
                        "type": "boolean",
                        "description": "Include tender document metadata and public download URLs.",
                        "default": true
                    },
                    "includeRaw": {
                        "title": "Include raw OCDS release",
                        "type": "boolean",
                        "description": "Attach the complete source release under raw. Leave disabled for smaller, integration-friendly records.",
                        "default": false
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
