# UNGM Public Tenders — Search & Notice Export (`jpmarketdata/ungm-public-tender-search-export`) Actor

Export UNGM public tender notices by title keyword with native deadlines, business descriptions, categories and source links. Deduplicate across up to 3 queries.

- **URL**: https://apify.com/jpmarketdata/ungm-public-tender-search-export.md
- **Developed by:** [h ichi](https://apify.com/jpmarketdata) (community)
- **Categories:** Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.50 / 1,000 notice exporteds

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

## UNGM Public Tenders — Search & Notice Export

Turn 1–3 title keywords into a bounded list of public UNGM procurement notices with their complete source-published business Description. Schedule repeated intake or export the dataset to your procurement workflow.

**Price**: $0.0005 per unique delivered notice. No start, query, detail or summary fee.

### Input

`keywords` accepts 1–3 distinct title keywords, default `["medical"]`. `maxNoticesPerKeyword` accepts 1–30, default 30; `maxNotices` accepts 1–90, default 30. UNGM's source-active filter and native order define each search window, with fixed 15-row pages. The window does not represent all notices or an independently verified active market.

The Actor merges matched keywords by native notice ID, then selects unique notices fairly across queries. For example, three keywords with both caps at their maximum select up to 90 notices. A lower global cap still gives each query a turn before selecting further notices.

### Output

Each row includes the notice ID and detail URL, title, agency, notice type, reference, matched keywords, native publication and closing-date text, parsed publication date, closing time with the explicit GMT offset and UTC deadline when recognized, complete contact-screened business Description, native UNSPSC labels and safe source links.

`countries` contains the detail page's native beneficiary summary as one label. An exact “Multiple destinations” listing can have a nonempty expanded detail summary such as “Poland, Ukraine”; that whole text is retained without splitting country names. The native aggregate remains when the detail also uses it. This field does not enumerate the Countries tab. Nonaggregate listing/detail country mismatches fail. `unspscCodes` contains the notice's source-rendered classification-tree labels, including parents and descendants; no leaf-only or selected-only classification is inferred.

An intact section containing the exact native “No Description” placeholder preserves that value and records the notice ID in `COVERAGE.nativeDescriptionAbsentNoticeIds`. Missing sections and content that is empty after privacy screening fail. Short source-published descriptions are preserved; prose is never invented. Unknown closing-date or timezone components remain null; deadlines are never inferred from prose. Links are handoffs for the user and their destinations are never downloaded.

Free `COVERAGE` records query totals, visited pages, exhaustion or caps, count drift, deduplication and selected notices. `SUMMARY` records delivered rows and resource use. Overall zero matching notices is an explicit uncharged error; an empty individual query is recorded in coverage when other queries produce notices.

### Limits and failures

The run uses 256 MB and 300 seconds. It permits 110 HTTP requests, including robots, an anonymous public landing, at most six searches and 90 required details. Limits are 2 MiB wire and decoded per response, 256 KiB robots, 32 MiB cumulative decoded, 8 MiB staged JSON, 40000 markup tokens per HTML response and 60000 Description characters per notice. Acquisition has 270 seconds, delivery 20 seconds, and each request 20 seconds. Serial GET and anonymous POST share a minimum two seconds between request-start reservations per origin and respect longer source delays. Network setup can shift actual arrival times. A single public connection can reuse ordinary keepalive; this adds no parallel requests or retries.

All selected detail pages must validate before paid delivery. Source, session, structure, authentication, rate-limit, timeout and resource failures are explicit. A valid notice that exceeds a guard fails the run. Payment allowance must cover all staged notices; charged SDK delivery uses batches of 50. Already delivered charged rows can remain if later delivery fails. No login, proxy or browser is required. Public anonymous anti-CSRF tokens and permitted session cookies exist only in memory.

### Scope and attribution

This Actor completes bounded public UNGM tender intake. The wider buyer workflow's SAM.gov intake, supplier sourcing, document analysis, RFQ/email and bid submission require separate work. Buyer requests and same-use Store activity are observed; payments are unverified.

The parser reads the direct business Description section and excludes Contacts. It provides no contact-person fields and screens email, phone and secret patterns in business prose. Raw pages, cookies and anonymous tokens are not output or logged. Business organisation names remain useful procurement facts. Only public notice routes are requested; Scripts, UNUser/Documents, account and private portal routes are excluded. Source document links may still be shown as handoffs.

UNGM's terms restrict commercial redistribution. Preserve UNGM/source attribution and assess the terms for your use. The current Actor records these clauses and applies the repository's accepted DR-0007 policy.

# Actor input Schema

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

1–3 title keywords, 1–100 characters each. Searches source-active public notices; no complete platform or newest-first guarantee.

## `maxNoticesPerKeyword` (type: `integer`):

Source window cap per keyword, 1–30. Native pages contain up to 15 listings.

## `maxNotices` (type: `integer`):

Global cap on unique rich notice rows, 1–90. Fair round-robin selection and matched keyword attribution.

## Actor input object example

```json
{
  "keywords": [
    "medical"
  ],
  "maxNoticesPerKeyword": 30,
  "maxNotices": 30
}
```

# Actor output Schema

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

No description

## `coverage` (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("jpmarketdata/ungm-public-tender-search-export").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("jpmarketdata/ungm-public-tender-search-export").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 jpmarketdata/ungm-public-tender-search-export --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jpmarketdata/ungm-public-tender-search-export"
        }
    }
}
```

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/hDw7TXR1i8IuH84sD/builds/mJ5JockDqRnQaVvRG/openapi.json
