# SAM.gov Contract Opportunities Feed: Official Data (`moo_iscool/sam-gov-opportunities`) Actor

New federal contract opportunities from SAM.gov's official public data file, with no scraping, API key or login. Filter by keyword, NAICS, PSC, set-aside, agency, state and deadline. Monitor mode returns only new notices and doesn't bill repeats. About 1 day behind sam.gov. $2 per 1,000.

- **URL**: https://apify.com/moo_iscool/sam-gov-opportunities.md
- **Developed by:** [moo_iscool](https://apify.com/moo_iscool) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

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

## SAM.gov Contract Opportunities Feed: Official Data

**New federal contract opportunities in your NAICS codes, every morning, without a SAM.gov API key.** This actor reads SAM.gov's official public Contract Opportunities data file (the daily CSV extract published for data.gov), filters it by keyword, NAICS, PSC, set-aside, agency, state, and deadline, and saves the matching notices as JSON, CSV, or Excel. It does not scrape the SAM.gov website and needs no login.

- **Who it's for:** proposal and capture teams watching a NAICS lane, set-aside, or agency; small businesses that want a daily govcon list without clicking through SAM.gov; analysts loading notices into a spreadsheet, CRM, or webhook.
- **Monitor mode:** with **Only new since last run**, a daily schedule returns only notices you haven't received yet, and repeats are not charged.
- **Price:** $2.00 per 1,000 opportunities saved, plus a small per-run start fee.

#### Quick example

Input (this is the prefilled form):

```json
{
  "keywords": ["cybersecurity", "software", "cloud"],
  "naicsCodes": ["5415"],
  "noticeTypes": ["Solicitation", "Combined Synopsis/Solicitation", "Sources Sought"],
  "postedWithinDays": 7,
  "maxResults": 50
}
```

Sample output rows (from a real run on 25 October 2026; a full record is shown further down):

| title | agency | NAICS | set-aside | deadline | type |
| --- | --- | --- | --- | --- | --- |
| DA01--RFI Action Only Healthcare Data Auditing Billing and C… | VETERANS AFFAIRS, DEPARTMENT OF | 541519 | – | 2026-11-06 | Sources Sought |
| Mortgage-Backed Securities Operations & Analytics (MBSOA) | HOUSING AND URBAN DEVELOPMENT, DEPARTMENT OF | 541512 | – | 2026-11-06 | Sources Sought |
| SILVAH software coding | AGRICULTURE, DEPARTMENT OF | 541511 | SBA | 2026-11-11 | Sources Sought |

#### Limits, up front

- **About one day behind sam.gov.** SAM.gov rebuilds the public file about once a day (usually around 03:30 UTC). A notice posted today appears in tomorrow's file.
- **No attachment or document links.** The public file does not include them. Each row has `samUrl`, which opens the notice page on sam.gov where files are posted.
- **Active notices only.** Archived notices are not in the file, so this is not a historical archive.
- Not affiliated with SAM.gov or GSA.

### How to get SAM.gov opportunities without an API key

The actor reads the official daily Contract Opportunities CSV that SAM.gov publishes for data.gov. It returns one dataset row per matching active notice. You do not need a SAM.gov API key, and the actor does not open or scrape the SAM.gov website.

The file is about 200 MB and lists active notices only. The actor streams it. When you set a posted-date window, it stops reading after 200 rows in a row that are older than that window. A 7-day search reads a few thousand rows, not the whole file, and typically finishes in seconds.

### Track new federal contracts by NAICS code

Only new since last run remembers the notice IDs already returned for a saved search. Those notices are not saved again, and they are not charged. The memory lives in the named key-value store `sam-gov-opportunities-state`. Named key-value stores stay until you delete them; Apify keeps named storage indefinitely on every plan, including the free plan.

### What data you get

Each result is one active notice. The extract has no attachment or document links. Open `samUrl` to see the notice on sam.gov, including any files posted there.

| Field | Meaning |
| --- | --- |
| noticeId | SAM.gov notice ID |
| title | Notice title |
| solicitationNumber | Solicitation number |
| noticeType | Notice type, such as Solicitation or Sources Sought |
| baseType | Base type from the file |
| agency | Department or independent agency |
| subTier | Sub-tier |
| office | Contracting office |
| agencyPath | Agency, sub-tier, and office joined with `>` |
| naicsCode | NAICS code |
| pscCode | Product or service code |
| setAsideCode | Set-aside code. `["SBA"]` becomes `SBA`. Blank, `[""]`, and `NONE` become null |
| setAside | Set-aside description. `NONE` is reported as `No set aside used` |
| postedDateTime | Posted timestamp as published |
| postedDate | Posted date, `YYYY-MM-DD` |
| responseDeadline | Deadline. A clock time keeps its timezone, such as `2026-10-26T06:00:00-04:00` |
| responseDeadlineDate | Deadline date, or null |
| daysLeft | Whole days until the deadline. Null when there is no deadline. Negative when it has passed |
| archiveDate | Archive date as published |
| placeOfPerformance | Street, city, state, ZIP, and country |
| award | Award number, date, amount as a number, and awardee, or null |
| primaryContact | Name, title, email, phone, and fax. Omitted when Include contacts is off |
| secondaryContact | Same shape as the primary contact. Omitted when Include contacts is off |
| officeAddress | Office city, state, ZIP, and country |
| link | Same address as `samUrl` |
| samUrl | Link from the file, or `https://sam.gov/workspace/contract/opp/<noticeId>/view` |
| additionalInfoLink | Extra link from the file, or null |
| description | Included only when you turn descriptions on. A blank description is null |
| source | `SAM.gov Contract Opportunities public extract` |
| extractDate | Last-Modified time of the CSV, in ISO format |
| scrapedAt | Time the run read the file, in ISO format |

Empty text fields are null.

### How to use

1. Set **Posted within days**. The usual value is `7`. Use `30` for about a month. Set it to `0` and leave **Posted since** empty to read the whole active file.
2. Add keywords, NAICS codes, notice types, or a set-aside. A set-aside entry can be a code such as `WOSB` or a label such as `Women-Owned`, `Small Business`, `SDVOSB`, `8(a)`, or `HUBZone`. Leave a list empty to skip that filter.
3. Set **Maximum results**. The actor stops once it has that many matches, or once it is past the posted-date window.
4. Run it and check the dataset. Turn **Include contacts** off if you do not want names, emails, and phone numbers.
5. For a daily feed, turn on **Only new since last run** and set a **Monitor name** for this search.

Give each saved search its own monitor name. The only-new memory is one list of notice IDs per name. If two searches share `default`, a notice returned by the first search is hidden from the second. The store is `sam-gov-opportunities-state`, and the key inside it is `SEEN_` plus the monitor name. The list keeps the most recent 200,000 notice IDs. Named key-value stores stay until you delete them; Apify keeps named storage indefinitely on every plan, including the free plan.

**Posted since** is the advanced date field. A value such as `2026-10-01` or `14 days` replaces **Posted within days**.

**Deadline after** accepts `today` or a date such as `2026-11-01`. `today` keeps deadlines after the start of today, US Eastern. Notices with no deadline stay in the results unless you turn on **Require response deadline**.

### Input example

```json
{
  "keywords": ["cybersecurity", "software", "cloud"],
  "naicsCodes": ["5415"],
  "noticeTypes": ["Solicitation", "Combined Synopsis/Solicitation", "Sources Sought"],
  "postedWithinDays": 7,
  "maxResults": 50,
  "includeContacts": true,
  "onlyNew": false
}
```

A notice matches if the title or the description contains `cybersecurity`, `software`, or `cloud`, the NAICS code starts with `5415`, the type is one of those three, and the notice was posted within the last 7 days. Description search is on by default. The description field itself is omitted until you set `includeDescription` to true.

### Output example

```json
{
  "noticeId": "4924a9998b8444c3ace265513047df72",
  "title": "SILVAH software coding",
  "solicitationNumber": "12760426Q0195",
  "noticeType": "Sources Sought",
  "baseType": "Sources Sought",
  "agency": "AGRICULTURE, DEPARTMENT OF",
  "subTier": "FOREST SERVICE",
  "office": "USDA FOREST SERVICE",
  "agencyPath": "AGRICULTURE, DEPARTMENT OF > FOREST SERVICE > USDA FOREST SERVICE",
  "naicsCode": "541511",
  "pscCode": "DA01",
  "setAsideCode": "SBA",
  "setAside": "Small Business Set Aside - Total",
  "postedDateTime": "2026-10-22 13:26:33",
  "postedDate": "2026-10-22",
  "responseDeadline": "2026-11-11T15:00:00-05:00",
  "responseDeadlineDate": "2026-11-11",
  "daysLeft": 17,
  "archiveDate": "2026-11-26",
  "placeOfPerformance": {
    "street": null,
    "city": "Parsons",
    "state": "WV",
    "zip": null,
    "country": "USA"
  },
  "award": null,
  "primaryContact": {
    "title": null,
    "name": "Brandon Newland",
    "email": "brandon.newland@usda.gov",
    "phone": null,
    "fax": null
  },
  "secondaryContact": null,
  "officeAddress": {
    "city": "Albuquerque",
    "state": "NM",
    "zip": "87102",
    "country": "USA"
  },
  "link": "https://sam.gov/workspace/contract/opp/4924a9998b8444c3ace265513047df72/view",
  "samUrl": "https://sam.gov/workspace/contract/opp/4924a9998b8444c3ace265513047df72/view",
  "additionalInfoLink": null,
  "source": "SAM.gov Contract Opportunities public extract",
  "extractDate": "2026-10-24T03:30:42.000Z",
  "scrapedAt": "2026-10-24T22:55:14.046Z"
}
```

This record came from the input example above. Description is omitted because include description is off. `daysLeft` was 17 on 24 October 2026.

### How much does it cost?

$2.00 per 1,000 opportunities ($0.002 each) plus a small per-run start fee. Notices you've already received in 'only new' mode are never charged.

You only pay for opportunities that are saved to the dataset. Notices the filters skip are not results. The start fee is a small flat charge for the run itself.

On a pay-per-event run the actor charges the `opportunity` event for each saved notice. It stops when your max charge limit is reached, and it says so in the log.

### Tips

Schedule the actor every day after 04:00 UTC. The public file is usually replaced around 03:30 UTC, so a same-day notice appears the next day. Pair the schedule with **Only new since last run** and a stable monitor name.

Use one monitor name per saved search. A NAICS 5415 search and a construction search should not share a name.

Leave descriptions off unless you need the text. Blank descriptions in the extract come back as `null`. Set `descriptionMaxLength` to 0 only when you want the full field.

Turn **Include contacts** on when you want the buyer's name and email. Turn it off when the dataset should stay smaller.

Apify can deliver the dataset to Google Sheets, a webhook, Make, or Zapier when the run succeeds. The default key-value store also gets a `SUMMARY` record with rows scanned, rows matched, rows saved, the file Last-Modified time, and the input that was used.

### FAQ

#### Is this legal, and where does the data come from?

The actor reads a public CSV that SAM.gov publishes for data.gov. It does not scrape the SAM.gov website, and it does not use the SAM.gov API. The notices are public contracting records. This actor is not a SAM.gov or GSA product, and it is not affiliated with either one.

#### Why is a notice missing?

The extract lists active notices only. Archived notices drop off when the file is rebuilt. A notice posted after the day's file was generated shows up in the next file, so the feed is about one day behind the sam.gov website.

A filter can hide it. Keyword, NAICS, set-aside, agency, state, posted date, and deadline are combined. Any keyword can match, but every filter you set has to match. **Only new since last run** hides notice IDs already returned for that monitor name.

The file has no attachment or document links. Open `samUrl` for the notice page.

#### Why is the description null?

Many rows in the public file have an empty Description column. Those results use `description: null`. The field is omitted entirely when **Include description** is off. Contact fields are omitted when **Include contacts** is off.

#### How often is the data updated?

SAM.gov rebuilds the public extract about once a day, usually around 03:30 UTC. Each run logs the Last-Modified header of the file it actually read. The same value is stored on every result as `extractDate` and in the run summary.

#### Is SAM.gov data free to use?

The Contract Opportunities extract is a public file that anyone can download from SAM.gov and data.gov without an account. You pay only for this actor's processing ($2.00 per 1,000 saved opportunities plus the start fee), not for the data itself.

#### Can I get the attachments?

No. The public extract has no attachment or resource links. Open `samUrl` on each row to see the notice and its files on sam.gov.

#### What does `postedDateTime` mean?

It is the posted timestamp exactly as written in the file. The file does not state a time zone. `postedDate` is the date part.

#### What happens if the download fails partway?

Rows saved before the failure stay in the dataset and count as results, and their notice IDs are remembered for only-new mode. The run then fails with an error message. Run it again to continue; already-sent notices are skipped in only-new mode.

### Support

Questions or a field that looks wrong? Open an issue on the actor page in Apify Console. Include the run ID and the input you used.

# Actor input Schema

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

Match notices whose title contains any of these phrases. Matching is case-insensitive. Each entry is one phrase, so "cloud computing" stays together. Description text is included when Search in description is on.

## `searchInDescription` (type: `boolean`):

Also match keywords in the notice description. Turn this off to match the title only.

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

Prefix match on the NAICS code. 5415 matches 541511, 541512, and any other code that starts with 5415. Leave empty to allow every NAICS code.

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

Prefix match on the classification code, also called the PSC or FSC code. R4 matches R425.

## `setAsideCodes` (type: `array`):

Keep notices with these set-asides. Each entry can be a code or a label, matched without case sensitivity. Codes: SBA, SBP, 8A, 8AN, HZC, HZS, SDVOSBC, SDVOSBS, WOSB, WOSBSS, EDWOSB, EDWOSBSS, VSA, VSS, ISBEE, IEE, LAS, BICiv, ESB, NONE. Labels such as Small Business, 8(a), HUBZone, SDVOSB, and Women-Owned are accepted. Leave empty to allow every set-aside, including notices with none.

## `smallBusinessOnly` (type: `boolean`):

Keep only notices that use a set-aside other than blank or NONE. You can combine this with specific set-aside codes.

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

Keep notices of these types. Leave empty to allow every type.

## `agencies` (type: `array`):

Case-insensitive substring match against the department, sub-tier, and contracting office. A notice matches if any entry is found in any of those three fields. Example: defense, veterans affairs.

## `states` (type: `array`):

Two-letter place-of-performance state codes, such as VA or TX. Matching is case-insensitive and uses the PopState column.

## `postedWithinDays` (type: `integer`):

Keep notices posted in the last this many days. 7 is one week. 30 is about a month. Set 0 to turn this field off. If Posted since is filled in, that field is used instead. Set this to 0 and leave Posted since empty to read the whole active file.

## `postedSince` (type: `string`):

Advanced posted-date filter. Use a date like 2026-10-01, or a window like 7 days, 24 hours, or 2 weeks. When this field is filled in, it replaces Posted within days. Leave it empty to use Posted within days. Posted timestamps in the file are treated as US Eastern. Clear both date fields to read the whole active file.

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

Keep notices whose response deadline is after this point. Use today, a date like 2026-11-01, or a window like 0 days. today means after the start of today, US Eastern. Notices with no deadline are kept unless Require response deadline is on. Leave empty to skip this filter.

## `responseDeadlineAfter` (type: `string`):

Same filter as Deadline after. Used only when Deadline after is empty. 0 days means still open as of now.

## `skipExpiredNotices` (type: `boolean`):

Skip notices whose parsed response deadline is earlier than the run start time. Notices with no deadline follow Require response deadline.

## `requireResponseDeadline` (type: `boolean`):

Drop notices that have no response deadline. By default those notices are kept.

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

Return only notice IDs this saved search has not returned before. Notices already returned are not saved again and are not charged. Use a different monitor name for each saved search.

## `monitorName` (type: `string`):

Name for the only-new memory of this saved search. Each saved search needs its own name. IDs are stored in the named key-value store sam-gov-opportunities-state, under SEEN\_ plus this name. Named key-value stores stay until you delete them, on every Apify plan, including the free plan. Letters, numbers, and ! - \_ . ' ( ) are kept. Other characters become underscores. If this is empty, State key is used.

## `stateKey` (type: `string`):

Another name for the only-new memory. Monitor name is used when both are filled in. The default name is default.

## `includeContacts` (type: `boolean`):

Include primary and secondary contact name, title, email, phone, and fax when the file has them. Turn this off to leave contact fields out of the dataset.

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

Add the notice description to each result. Many descriptions are blank, and those rows get description null. Descriptions can be long, so this is off by default.

## `descriptionMaxLength` (type: `integer`):

Maximum description length in characters when descriptions are included. Use 0 for the full text. A blank description is null.

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

Stop after this many notices have been saved. The download also stops once it is past your posted-date window.

## Actor input object example

```json
{
  "keywords": [
    "cybersecurity",
    "software",
    "cloud"
  ],
  "searchInDescription": true,
  "naicsCodes": [
    "5415"
  ],
  "setAsideCodes": [],
  "smallBusinessOnly": false,
  "noticeTypes": [
    "Solicitation",
    "Combined Synopsis/Solicitation",
    "Sources Sought"
  ],
  "postedWithinDays": 7,
  "postedSince": "",
  "deadlineAfter": "",
  "responseDeadlineAfter": "",
  "skipExpiredNotices": true,
  "requireResponseDeadline": false,
  "onlyNew": false,
  "monitorName": "",
  "stateKey": "",
  "includeContacts": true,
  "includeDescription": false,
  "descriptionMaxLength": 2000,
  "maxResults": 50
}
```

# Actor output Schema

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

Dataset with one row per matching SAM.gov notice.

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

JSON summary of the run: counts, stop reason, and input warnings.

# 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 = {
    "keywords": [
        "cybersecurity",
        "software",
        "cloud"
    ],
    "naicsCodes": [
        "5415"
    ],
    "noticeTypes": [
        "Solicitation",
        "Combined Synopsis/Solicitation",
        "Sources Sought"
    ],
    "postedWithinDays": 7,
    "onlyNew": false,
    "includeContacts": true,
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("moo_iscool/sam-gov-opportunities").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 = {
    "keywords": [
        "cybersecurity",
        "software",
        "cloud",
    ],
    "naicsCodes": ["5415"],
    "noticeTypes": [
        "Solicitation",
        "Combined Synopsis/Solicitation",
        "Sources Sought",
    ],
    "postedWithinDays": 7,
    "onlyNew": False,
    "includeContacts": True,
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("moo_iscool/sam-gov-opportunities").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 '{
  "keywords": [
    "cybersecurity",
    "software",
    "cloud"
  ],
  "naicsCodes": [
    "5415"
  ],
  "noticeTypes": [
    "Solicitation",
    "Combined Synopsis/Solicitation",
    "Sources Sought"
  ],
  "postedWithinDays": 7,
  "onlyNew": false,
  "includeContacts": true,
  "maxResults": 50
}' |
apify call moo_iscool/sam-gov-opportunities --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,moo_iscool/sam-gov-opportunities"
        }
    }
}
```

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/1QVJacRvh4FbLyWus/builds/wYYpkkS92rymeAV5h/openapi.json
