# Government Tenders Scraper: SAM.gov & TED Europe (`scrapyx/government-tenders-scraper`) Actor

Scrapes US federal contract opportunities (SAM.gov) and EU public procurement notices (TED) into one unified schema. Search by keyword, NAICS or CPV code, or paste portal URLs. Full statements of work as clean Markdown for LLM use, ISO 8601 UTC deadlines, and buyer contact details.

- **URL**: https://apify.com/scrapyx/government-tenders-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** Automation, Lead generation, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 results

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.

- **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

## All-in-One Government Tenders & Procurement Scraper

Scrapes public procurement opportunities from **SAM.gov** (US federal contract
opportunities) and **TED — Tenders Electronic Daily** (EU public procurement)
and returns them in **one unified schema**.

Search by keyword, by industry code (NAICS for the US, CPV for the EU), or just
paste portal URLs — each one is routed to the right portal automatically. Every
row comes back with the same 46 fields, whichever side of the Atlantic it came
from.

Public data only. **No account, no login and no API key required** on either
portal.

### Why one Actor instead of two

The two portals have almost nothing in common mechanically: different ID
formats, different industry taxonomies, different date encodings, different
ways of expressing what a contract is worth — and TED publishes every title and
description in up to 24 languages at once.

They have exactly one thing in common: a public body saying what it intends to
buy.

If you sell to governments, you want **one table of live tenders**. Which
jurisdiction an opportunity happens to sit in is not something you chose, and
reconciling two ID schemes, two date formats and two industry taxonomies is the
genuinely hard part of the job. This Actor does that once, rather than handing
you the same problem twice.

### Why use this actor

- **No account, no login, no API key** on either portal
- **Full statements of work as clean Markdown** — ready to drop straight into an
  LLM prompt for bid/no-bid triage, requirement extraction or summarisation
- **Named procurement officers with real email addresses** — the contracting
  officer and their alternate, not a generic inbox
- **Every deadline as a true ISO 8601 UTC timestamp**, so US and EU tenders sort
  correctly against each other in one list
- **One identical schema across both portals** — no per-source branching in your
  pipeline
- Attachment listings, set-aside status, place of performance, estimated values
  and award winners
- Stable JSON output for pipelines, databases and spreadsheets; automatic
  retries; export to JSON/CSV/Excel

### How it works

1. You give it keywords, industry codes, or URLs pasted from either portal.
2. Each input is routed to the portal that can actually answer it — a NAICS code
   goes to SAM.gov, a CPV code goes to TED, keywords go to both.
3. It pages through every matching notice, then fetches each one in full to pull
   the complete statement of work, the contacts and the exact dates.
4. Every notice is folded into one schema, with descriptions converted to clean
   Markdown and all dates standardised to UTC.

No scrapers, browsers or blocks to babysit.

### What you can search

| Input | Goes to | Example |
| --- | --- | --- |
| `keywords` | Both | `["software development", "cyber security"]` |
| `naicsCodes` | SAM.gov | `["541511"]` (Custom Computer Programming) |
| `cpvCodes` | TED | `["72000000"]` (IT services) |
| `industryCodes` | Split automatically | `["541511", "72000000"]` |
| `noticeTypes` | Both, translated | `["solicitation", "award"]` |
| `setAsides` | SAM.gov | `["SBA", "8A", "SDVOSBC"]` |
| `pscCodes` | SAM.gov | `["7G21", "D302"]` |
| `buyerCountries` | TED | `["DEU", "FRA", "POL"]` |
| `placeOfPerformanceStates` | SAM.gov | `["VA", "CA"]` |
| `startUrls` | Routed by the URL | a search URL, a notice URL, or a bare ID |

**Mixed industry codes just work.** Put `541511` and `72000000` in one
`industryCodes` list and the NAICS code is sent to SAM.gov while the CPV code
goes to TED — neither is sent to the portal that cannot read it.

#### Supported URL and ID forms

| Portal | Search URL | Single notice |
| --- | --- | --- |
| **SAM.gov** | `https://sam.gov/search/?index=opp&naics=541511` | `https://sam.gov/opp/<32-char-id>/view` |
| **TED** | `https://ted.europa.eu/en/search/result?...` | `https://ted.europa.eu/en/notice/547033-2026/html` |

Bare IDs work too: a 32-character SAM.gov notice ID, or a TED publication number
like `547033-2026`. So does the shorthand `sam:<id>` / `ted:<id>`.

### Input

```json
{
  "sources": ["sam", "ted"],
  "keywords": ["software development"],
  "industryCodes": ["541511", "72000000"],
  "noticeTypes": ["solicitation"],
  "activeOnly": true,
  "publishedWithinDays": 30,
  "deadlineWithinDays": 45,
  "includeDescription": true,
  "includeAttachments": true,
  "maxItemsPerQuery": 200,
  "tedLanguage": "eng",
  "tedScope": "ALL",
  "samSort": "-modifiedDate",
  "maxConcurrency": 6,
  "minRequestInterval": "0.15",
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

| Field | Type | Description |
| --- | --- | --- |
| `sources` | array | Which portals to search: `sam`, `ted`, or both. Pasted URLs always go to the portal they name. |
| `startUrls` | array | SAM.gov / TED search or notice URLs, or bare notice IDs. |
| `keywords` | array | Free-text terms, combined with OR. Searched on both portals. |
| `industryCodes` | array | Mixed NAICS and CPV codes; split automatically by shape. |
| `naicsCodes` | array | US industry codes. SAM.gov only. |
| `cpvCodes` | array | EU Common Procurement Vocabulary codes. TED only. |
| `noticeTypes` | array | `solicitation`, `presolicitation`, `sources-sought`, `award`, `special-notice`, `justification`, `modification`, `surplus-sale`. Translated into each portal's own codes. |
| `activeOnly` | boolean | Restrict SAM.gov to notices still open. Default `true`. |
| `publishedWithinDays` | integer | Only notices published in the last N days. `0` disables. |
| `deadlineWithinDays` | integer | Only notices closing within the next N days. `0` disables. |
| `setAsides` | array | US small-business set-aside codes. SAM.gov only. |
| `pscCodes` | array | US Product Service Codes. SAM.gov only. |
| `organizationIds` | array | Restrict to a buying agency. SAM.gov only. |
| `placeOfPerformanceStates` | array | Two-letter US state codes. SAM.gov only. |
| `placeOfPerformanceCountries` | array | Three-letter country codes. SAM.gov only. |
| `buyerCountries` | array | Three-letter country codes of the EU buyer. TED only. |
| `tedExpertQuery` | string | A raw TED expert-search expression, replacing every other TED filter. |
| `includeDescription` | boolean | Fetch full statements of work. **Strongly recommended** — see Notes. Default `true`. |
| `includeAttachments` | boolean | Also list solicitation attachments. SAM.gov only. Default `false`. |
| `includeRawUpstream` | boolean | Attach each portal's original record under `rawUpstream`. Default `false`. |
| `maxItemsPerQuery` | integer | Cap per portal per query. `0` means no cap. Default `200`. |
| `tedScope` | string | `ALL`, `ACTIVE`, or `LATEST`. |
| `tedLanguage` | string | Preferred language for TED titles and descriptions. |
| `tedOnlyLatestVersions` | boolean | One row per notice rather than every revision. Default `true`. |
| `samSort` | string | Result ordering for SAM.gov. |
| `samPageSize` | integer | Notices per SAM.gov request. Default `100`. |
| `maxConcurrency` | integer | Total simultaneous requests. Default `6`. |
| `minRequestInterval` | string | Seconds between request starts. Default `0.15`. |
| `proxyConfiguration` | object | Residential proxy recommended. |

### Output

Three record types share the dataset, told apart by `recordType`:
`TENDER` (one per notice), `SEARCH_SUMMARY` (one per query) and `ERROR`.

#### A US tender (SAM.gov)

```json
{
  "_input": "criteria:SAM.gov",
  "_source": "SAM.gov-api",
  "_scrapedAt": "2026-08-21T20:12:15Z",
  "recordType": "TENDER",
  "tenderId": "ab5de2004b3a4549819300908e5f3ee1",
  "source": "SAM.gov",
  "sourceJurisdiction": "US",
  "title": "Request for Solutions (RFS): Autonomous Coding (AC) and Automated Appeals & Denials Management (ADM)",
  "agency": "DEFENSE HEALTH AGENCY",
  "agencyDepartment": "DEPT OF DEFENSE",
  "agencyPath": ["DEPT OF DEFENSE", "DEFENSE HEALTH AGENCY (DHA)", "DEFENSE HEALTH AGENCY"],
  "procurementType": "Solicitation",
  "procurementTypeCode": "o",
  "procedureType": null,
  "contractNature": null,
  "deadlineDate": "2026-08-28T14:00:00Z",
  "deadlineDateRaw": "2026-08-28T10:00:00-04:00",
  "deadlineDatePrecision": "datetime",
  "deadlineDatesAllLots": [],
  "deadlineTimeZone": "America/New_York",
  "publishedDate": "2026-08-21T15:19:04Z",
  "lastModifiedDate": "2026-08-21T15:19:04Z",
  "archiveDate": "2026-09-27T00:00:00Z",
  "estimatedValue": null,
  "estimatedValueCurrency": null,
  "estimatedValueBasis": null,
  "url": "https://sam.gov/opp/ab5de2004b3a4549819300908e5f3ee1/view",
  "descriptionMarkdown": "August 21, 2026: Responses to submitted questions are now available in the attached document, 'ACADM Phase 1 QA 082126'.\n\n**Request for Solutions (RFS): Autonomous Coding (AC) and Automated Appeals & Denials Management (ADM)**\n\n**Opportunity Overview**\n\nThe Defense Healthcare Management Systems Modernization (DHMSM) Program Management Office … ",
  "descriptionTruncated": false,
  "descriptionSource": "detail",
  "industryCodeSystem": "NAICS",
  "industryCodes": ["541511"],
  "classificationCode": "DA01",
  "setAside": null,
  "setAsideLabel": null,
  "solicitationNumber": "HT0038RFSACADM",
  "noticeStatus": "open",
  "isActive": true,
  "isCanceled": false,
  "buyerCountry": "USA",
  "placeOfPerformance": {
    "city": "Rosslyn", "state": "Virginia", "stateCode": "VA",
    "country": "UNITED STATES", "countryCode": "USA", "zip": null
  },
  "contacts": [
    { "name": "Sharjeel Javaid", "title": null, "email": "sharjeel.j.javaid.civ@health.mil", "phone": null, "fax": null, "type": "primary" },
    { "name": "Dominique Brown", "title": null, "email": "dominique.u.brown.civ@health.mil", "phone": null, "fax": null, "type": "secondary" }
  ],
  "submissionUrl": null,
  "attachments": [
    { "name": "ACADM Phase 1 QA 082126.pdf", "type": "file", "mimeType": ".pdf", "sizeBytes": 217079, "accessLevel": "public", "postedDate": "2026-08-21T15:19:04Z", "url": "https://sam.gov/api/prod/opps/v3/opportunities/resources/files/5aa0ab25da0f424d91318cf10ecfb981/download" }
  ],
  "awardee": null,
  "language": "eng"
}
```

#### An EU tender (TED)

```json
{
  "_input": "criteria:TED",
  "_source": "TED-api",
  "_scrapedAt": "2026-08-21T20:12:14Z",
  "recordType": "TENDER",
  "tenderId": "506441-2026",
  "source": "TED",
  "sourceJurisdiction": "EU",
  "title": "Zakup in poraba impulzov za telefonsko številko 080 2002 za potrebe Enotnega kontaktnega centra",
  "agency": "MINISTRSTVO ZA NOTRANJE ZADEVE IN JAVNO UPRAVO",
  "agencyDepartment": null,
  "agencyPath": [],
  "procurementType": "Contract notice",
  "procurementTypeCode": "cn-standard",
  "procedureType": "Open",
  "contractNature": "Services",
  "deadlineDate": "2026-08-24T09:00:00Z",
  "deadlineDateRaw": "2026-08-24T11:00:00+02:00",
  "deadlineDatePrecision": "datetime",
  "deadlineDatesAllLots": ["2026-08-24T00:00:00Z"],
  "deadlineTimeZone": null,
  "publishedDate": "2026-07-22T00:00:00Z",
  "lastModifiedDate": "2026-07-21T00:00:00Z",
  "archiveDate": null,
  "estimatedValue": null,
  "estimatedValueCurrency": null,
  "estimatedValueBasis": null,
  "url": "https://ted.europa.eu/en/notice/-/detail/506441-2026",
  "descriptionMarkdown": "Zakup in poraba impulzov za telefonsko številko 080 2002 za potrebe Enotnega kontaktnega centra",
  "descriptionTruncated": false,
  "descriptionSource": "search-row",
  "industryCodeSystem": "CPV",
  "industryCodes": ["64200000"],
  "classificationCode": "64200000",
  "setAside": null,
  "setAsideLabel": null,
  "solicitationNumber": "77d80d06-21c9-4f08-8846-e0da4b6702d4",
  "noticeStatus": "open",
  "isActive": true,
  "isCanceled": false,
  "buyerCountry": "SVN",
  "placeOfPerformance": {
    "city": "Ljubljana", "state": null, "stateCode": null,
    "country": null, "countryCode": "SVN", "zip": null, "allCountryCodes": ["SVN"]
  },
  "contacts": [
    { "name": "MINISTRSTVO ZA NOTRANJE ZADEVE IN JAVNO UPRAVO", "title": null, "email": "gp.mnz@gov.si", "phone": "01 428 40 00", "website": "https://www.gov.si/drzavni-organi/ministrstva/ministrstvo-za-notranje-zadeve-in-javno-upravo", "city": "Ljubljana", "country": "SVN", "type": "buyer" }
  ],
  "submissionUrl": "https://ejn.gov.si/ponudba/pages/aktualno/aktualno_jnc_podrobno.xhtml?zadevaId=77151",
  "attachments": [],
  "awardee": null,
  "language": "slv"
}
```

#### Tender fields

| Field | Type | Description |
| --- | --- | --- |
| `tenderId` | string | SAM.gov notice ID, or TED publication number. |
| `source` | string | `SAM.gov` or `TED`. |
| `sourceJurisdiction` | string | `US` or `EU`. |
| `title` | string | The procurement title. |
| `agency` | string | The buying entity — the specific office, not just the parent department. |
| `agencyDepartment` | string | Top-level department (SAM.gov). |
| `agencyPath` | array | Full agency hierarchy, department down to buying office. |
| `procurementType` | string | Readable notice type, e.g. `Solicitation`, `Contract notice`, `Award Notice`. |
| `procurementTypeCode` | string | The portal's own code. |
| `procedureType` | string | `Open`, `Restricted`, `Competitive dialogue`… (TED). |
| `contractNature` | string | `Works`, `Services` or `Supplies` (TED). |
| `deadlineDate` | string | **Response deadline as ISO 8601 UTC.** Multi-lot EU notices report the earliest. |
| `deadlineDateRaw` | string | The deadline as the portal published it, in local time with offset. |
| `deadlineDatePrecision` | string | `datetime` when a real time was published, `date` when only a day was, `none` when no deadline exists. |
| `deadlineDatesAllLots` | array | Every per-lot deadline, for multi-lot EU notices. |
| `deadlineTimeZone` | string | Named timezone, where the portal gives one. |
| `publishedDate` | string | Publication date, ISO 8601 UTC. |
| `lastModifiedDate` | string | Last update, ISO 8601 UTC. |
| `archiveDate` | string | When the notice auto-archives (SAM.gov). |
| `estimatedValue` | number | Contract value where published. |
| `estimatedValueCurrency` | string | ISO currency code. |
| `estimatedValueBasis` | string | Where the number came from — a procedure estimate, an awarded total, or a sum of per-lot estimates. |
| `url` | string | Public link to the notice. |
| `descriptionMarkdown` | string | **The full statement of work, as clean Markdown.** |
| `descriptionTruncated` | boolean | `true` only if you disabled full descriptions and the text was clipped. |
| `descriptionSource` | string | Whether the text came from the full notice or the list row. |
| `industryCodeSystem` | string | `NAICS` or `CPV`. |
| `industryCodes` | array | Industry codes in that system. |
| `classificationCode` | string | PSC code (US) or main CPV code (EU). |
| `setAside` / `setAsideLabel` | string | Small-business set-aside code and its full name (US). |
| `solicitationNumber` | string | The buyer's own reference number. |
| `noticeStatus` | string | `open`, `closed`, `awarded`, `archived` or `cancelled` — one vocabulary for both portals. |
| `isActive` | boolean | Still accepting responses (deadline-aware). |
| `isCanceled` | boolean | Withdrawn by the buyer. |
| `buyerCountry` | string | Three-letter country code. |
| `placeOfPerformance` | object | Where the work happens: city, state, country, postcode. |
| `contacts` | array | Procurement officers: name, email, phone, role. |
| `submissionUrl` | string | Direct link to the bidding portal, where published. |
| `attachments` | array | Solicitation documents: name, type, size, download link. |
| `awardee` | object | Winner name, unique entity ID, award number and date, on award notices. |
| `language` | string | Language the title and description are in. |

#### Search summary

One per query, so you always know whether you got everything:

```json
{
  "recordType": "SEARCH_SUMMARY",
  "source": "SAM.gov",
  "queryLabel": "SAM.gov[keywords=cyber security]",
  "totalMatchingUpstream": 2237,
  "returnedCount": 3,
  "pagesFetched": 1,
  "requestsMade": 4,
  "filtersApplied": { "keywords": ["cyber security"], "activeOnly": true, "deadlineWithinDays": 45 },
  "descriptionsFetched": true,
  "attachmentsFetched": false,
  "resultWindowCapped": false,
  "maxItemsPerQuery": 3,
  "completeness": "capped-by-maxItemsPerQuery",
  "notes": []
}
```

`completeness` is one of `complete`, `partial`, `capped-by-maxItemsPerQuery` or
`capped-by-upstream-window`, and `filtersApplied` shows exactly which filters
actually took effect — so a small result set is never ambiguous.

### Notes & limits

- **Leave `includeDescription` on.** SAM.gov's result rows carry only the first
  250 characters of the statement of work. Turning it off makes runs faster and
  cheaper, but the descriptions are clipped — and the Actor tells you so, via
  `descriptionTruncated` on the row and a note on the summary.
- **SAM.gov returns at most 10,000 notices per query.** That is the portal's own
  limit, not the Actor's. When a query matches more, the run stops cleanly at
  10,000 and sets `resultWindowCapped: true` with the real total in
  `totalMatchingUpstream`. Split the query — by industry code, notice type or
  date window — to reach the rest. **TED has no such limit.**
- **A search that names only EU codes will not search SAM.gov** (and vice
  versa), because the portal cannot filter on the other side's taxonomy and
  would otherwise return its entire notice corpus narrowed only by date. You get
  an explicit `ERROR` row explaining what to add, instead of thousands of
  irrelevant rows.
- **Estimated values are frequently absent on US notices.** SAM.gov publishes a
  value only on award notices; open solicitations have no such field. This is
  the portal's behaviour, not a gap in extraction.
- **TED notices may not be in English.** Titles and descriptions are resolved to
  your preferred language, then English, then whatever the notice actually has —
  a national-only notice keeps its original language rather than coming back
  blank. The `language` field always tells you which you got.
- Date-only fields keep their calendar date rather than being shifted by a
  timezone, so a notice TED published on 22 July reports 22 July.
- Residential proxy is recommended for scheduled runs.

# Actor input Schema

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

Which government procurement portals to query when you use the keyword/code filters below. SAM.gov covers US federal contract opportunities; TED covers EU public procurement. Pasted URLs always go to the portal they name, whatever is selected here.

## `startUrls` (type: `array`):

Paste SAM.gov or TED URLs and each is routed automatically: a search URL (sam.gov/search/?index=opp&...) becomes a query, an opportunity URL (sam.gov/opp/<id>/view) or TED notice URL fetches that one notice. Bare ids also work: a 32-hex SAM id, or a TED publication number like 547033-2026.

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

Free-text terms, for example "Software Development" or "Construction". Terms are combined with OR, so one run can cover a whole capability list. Searched full-text on both portals.

## `industryCodes` (type: `array`):

One list for both taxonomies. Codes are split by shape and sent only to the portal that understands them: 8 digits is a CPV code (TED), 2-6 digits is a NAICS code (SAM.gov). Use the two dedicated fields below if you want to be explicit.

## `naicsCodes` (type: `array`):

US industry codes, for example 541511 (Custom Computer Programming Services). Only sent to SAM.gov. Overrides anything matched from the mixed list above.

## `cpvCodes` (type: `array`):

EU Common Procurement Vocabulary codes, for example 72000000 (IT services) or 45000000 (Construction work). Only sent to TED. Overrides anything matched from the mixed list above.

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

One unified vocabulary, translated into each portal's own codes. Concepts a portal does not have (there is no EU equivalent of Sources Sought) are simply not sent to it rather than faked. Leave empty for all types.

## `activeOnly` (type: `boolean`):

Restrict SAM.gov to notices that are still open. Cuts SAM's corpus from roughly 5.6 million to about 51,000, so leaving this on is usually what you want.

## `publishedWithinDays` (type: `integer`):

Only notices published in this window. 0 disables the filter. Also the single most effective way to stay under SAM.gov's hard 10,000-record result window on a broad query.

## `deadlineWithinDays` (type: `integer`):

Only notices whose response deadline falls between today and N days from now. 0 disables the filter. Useful for a bid-desk queue of what is actually closing soon.

## `setAsides` (type: `array`):

US small-business set-aside filters, for example SBA (Total Small Business), 8A, HZC (HUBZone), SDVOSBC, WOSB. An unrecognised code is refused rather than silently ignored.

## `pscCodes` (type: `array`):

US Product Service Codes, for example 7G21 or D302. Complements NAICS with a what-is-being-bought view.

## `organizationIds` (type: `array`):

SAM.gov internal organization ids to restrict the buying agency, for example 100000000 for the Department of Defense. Found in the organizationHierarchy of any result row.

## `placeOfPerformanceStates` (type: `array`):

Two-letter US state codes, for example VA or CA. Filters on where the work happens, not where the agency sits.

## `placeOfPerformanceCountries` (type: `array`):

Three-letter country codes, for example USA or DEU. Useful for finding overseas US federal work.

## `buyerCountries` (type: `array`):

Three-letter ISO country codes of the EU buying authority, for example DEU, FRA, POL. Only sent to TED.

## `tedExpertQuery` (type: `string`):

A raw TED expert-search expression, passed straight through and replacing every other TED filter. Build and test one at ted.europa.eu/en/search/expert-search. Example: classification-cpv IN (72000000) AND publication-date>=today(-30)

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

Strongly recommended. SAM.gov's search rows carry only the FIRST 250 CHARACTERS of the statement of work, so the full scope, contacts and dates need one extra request per notice. On TED this costs no extra requests at all -- it widens the field set instead.

## `includeAttachments` (type: `boolean`):

Adds one more request per notice to list solicitation attachments (name, type, size, download URL). File contents are not downloaded.

## `includeRawUpstream` (type: `boolean`):

Attach each portal's original JSON under rawUpstream, for fields the unified schema does not carry. Off by default because it roughly triples row size.

## `maxItemsPerQuery` (type: `integer`):

Cap on notices returned per portal per query. 0 means no cap. Note that SAM.gov cannot return more than 10,000 for any single query no matter what you set here -- narrow the query and run it in slices instead.

## `tedScope` (type: `string`):

ALL searches every notice ever published, ACTIVE only currently open ones, LATEST only the newest OJ S release.

## `tedLanguage` (type: `string`):

TED publishes titles and descriptions in up to 24 languages at once. One is resolved per field before output, falling back to English and then to whatever the notice actually has, so a national-only notice still keeps its title.

## `tedOnlyLatestVersions` (type: `boolean`):

TED republishes corrected notices under the same identifier. On, you get one row per notice; off, you also get its superseded versions.

## `samSort` (type: `string`):

Ordering for SAM.gov results. Validated in code because SAM silently ignores an unknown sort key and answers 200 with its default ordering.

## `samPageSize` (type: `integer`):

Notices fetched per SAM.gov search request. Larger pages mean fewer search calls but a bigger burst of detail requests behind them.

## `maxConcurrency` (type: `integer`):

Upper bound on total in-flight requests across every query, including SAM.gov's per-notice detail fetches.

## `minRequestInterval` (type: `string`):

Paces request starts without holding a worker. TED rate-limits at roughly 10 requests/second, so this -- not concurrency -- is the honest speed control. Lower it only if you are hitting SAM.gov alone.

## `proxyConfiguration` (type: `object`):

Residential proxy by default. Neither API blocks by fingerprint, but a cloud run shares datacenter egress with every other Apify actor and TED rate-limits by IP, so a shared exit address would spend the run retrying.

## Actor input object example

```json
{
  "sources": [
    "sam",
    "ted"
  ],
  "startUrls": [],
  "keywords": [
    "software development"
  ],
  "industryCodes": [],
  "naicsCodes": [],
  "cpvCodes": [],
  "noticeTypes": [],
  "activeOnly": true,
  "publishedWithinDays": 0,
  "deadlineWithinDays": 0,
  "setAsides": [],
  "pscCodes": [],
  "organizationIds": [],
  "placeOfPerformanceStates": [],
  "placeOfPerformanceCountries": [],
  "buyerCountries": [],
  "tedExpertQuery": "",
  "includeDescription": true,
  "includeAttachments": false,
  "includeRawUpstream": false,
  "maxItemsPerQuery": 200,
  "tedScope": "ALL",
  "tedLanguage": "eng",
  "tedOnlyLatestVersions": true,
  "samSort": "-modifiedDate",
  "samPageSize": 100,
  "maxConcurrency": 6,
  "minRequestInterval": "0.15",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# 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 = {
    "sources": [
        "sam",
        "ted"
    ],
    "startUrls": [],
    "keywords": [
        "software development"
    ],
    "industryCodes": [],
    "naicsCodes": [],
    "cpvCodes": [],
    "noticeTypes": [],
    "setAsides": [],
    "pscCodes": [],
    "organizationIds": [],
    "placeOfPerformanceStates": [],
    "placeOfPerformanceCountries": [],
    "buyerCountries": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/government-tenders-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 = {
    "sources": [
        "sam",
        "ted",
    ],
    "startUrls": [],
    "keywords": ["software development"],
    "industryCodes": [],
    "naicsCodes": [],
    "cpvCodes": [],
    "noticeTypes": [],
    "setAsides": [],
    "pscCodes": [],
    "organizationIds": [],
    "placeOfPerformanceStates": [],
    "placeOfPerformanceCountries": [],
    "buyerCountries": [],
}

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/government-tenders-scraper").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 '{
  "sources": [
    "sam",
    "ted"
  ],
  "startUrls": [],
  "keywords": [
    "software development"
  ],
  "industryCodes": [],
  "naicsCodes": [],
  "cpvCodes": [],
  "noticeTypes": [],
  "setAsides": [],
  "pscCodes": [],
  "organizationIds": [],
  "placeOfPerformanceStates": [],
  "placeOfPerformanceCountries": [],
  "buyerCountries": []
}' |
apify call scrapyx/government-tenders-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/government-tenders-scraper"
        }
    }
}

```

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/XSSlkNH1Zd8NoHsts/builds/mdWOOX14wzMOt0ysN/openapi.json
