# SAM.gov Contract Opportunities: Federal Bids by NAICS (`itayozer9/sam-gov-opportunities`) Actor

US federal contract opportunities from SAM.gov's official daily extract: solicitations, sources sought, presolicitations and award notices. Filter by keyword, NAICS, PSC, set-aside, agency, state, posted date and open deadline. Description text, only-new mode, contacts removed.

- **URL**: https://apify.com/itayozer9/sam-gov-opportunities.md
- **Developed by:** [Itay Ozer](https://apify.com/itayozer9) (community)
- **Categories:** Lead generation, Business, 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: Federal Bids by NAICS

Get US federal contract opportunities from SAM.gov as clean JSON: solicitations, combined synopses, sources sought, presolicitations, special notices and award notices. Filter by keyword, NAICS code, PSC code, set-aside, agency, state, posted date and open deadline, and get the description text of each notice.

Built for government contractors, bid and proposal teams, capture managers and agencies that track federal tenders, and for AI agents that need a small, predictable JSON feed of new bids.

The data comes from SAM.gov's official public Contract Opportunities extract (sam.gov Data Services), which the government rebuilds every day. That is the route SAM.gov's terms of use point to for bulk data, so there is no scraping of the website, no API key to request, no captchas and no proxy costs.

### What you get

For every opportunity:

- Notice id, SAM.gov link, title, solicitation number
- Notice type (Solicitation, Combined Synopsis/Solicitation, Sources Sought, Award Notice...) and the type of the original notice
- Posted date, response deadline (with its time zone), archive date
- Department, sub-tier agency, contracting office, CGAC, FPDS and office codes
- NAICS code, PSC (product and service) code
- Set-aside code and name (small business, 8(a), HUBZone, SDVOSB, WOSB...)
- Place of performance and contracting office location: city, state, zip, country
- Award details on award notices: number, date, amount in USD, awardee
- The notice description as plain text, with emails and phone numbers removed (SAM.gov's extract cuts descriptions at about 32,000 characters)
- The date of the SAM.gov extract the row comes from

Point-of-contact columns (names, emails, phones) are never returned, and emails and phone numbers are removed from titles and descriptions.

### Input

All fields are optional. With no filters you get the newest notices first.

| Field | Example | Notes |
|---|---|---|
| `keywords` | `cybersecurity, zero trust` | All words of a phrase must appear in the title, solicitation number or description. Commas separate alternatives |
| `naicsCodes` | `["5415", "236220"]` | Prefix match: `5415` covers 541511, 541512, 541519 |
| `pscCodes` | `["D3", "Z"]` | Prefix match on the product and service code |
| `setAsides` | `["SBA", "SDVOSBC"]` | Set-aside codes, see the list in the input form |
| `noticeTypes` | `["solicitation", "combined"]` | solicitation, combined, presolicitation, sources_sought, special_notice, award, justification, modification, surplus, bundle |
| `agency` | `veterans affairs` | Text in the department, agency or office name |
| `states` | `["VA", "MD", "DC"]` | Place of performance state |
| `postedWithinDays` | `7` | Notices posted in the last N days |
| `postedFrom` | `2026-10-01` | Notices posted on or after this date |
| `openOnly` | `true` | Only notices whose response deadline is today or later |
| `onlyNew` | `true` | Skip notices an earlier run with the same filters already returned |
| `descriptionMaxChars` | `2000` | Description length, 0 to leave it out. Default 2,000 |
| `maxItems` | `100` | 1 to 10,000, default 100. You pay only for notices returned |

Daily alert for IT services set aside for small business, open for bids:

```json
{
    "naicsCodes": ["5415"],
    "setAsides": ["SBA", "8A", "SDVOSBC", "WOSB", "HZC"],
    "noticeTypes": ["solicitation", "combined", "sources_sought"],
    "openOnly": true,
    "postedWithinDays": 3,
    "onlyNew": true,
    "maxItems": 500
}
```

Run it on a daily schedule: `onlyNew` makes each run return only notices you have not seen, and `postedWithinDays` keeps the run short.

### Output example

One dataset item per notice (description shortened here):

```json
{
    "noticeId": "ff9c886ead754999bbe7add4b0ad67e1",
    "url": "https://sam.gov/opp/ff9c886ead754999bbe7add4b0ad67e1/view",
    "title": "Pressure Seal V-Fold Mailer",
    "solicitationNumber": "041115-27-0002",
    "noticeType": "Solicitation",
    "baseNoticeType": "Solicitation",
    "postedAt": "2026-10-30T14:05:49",
    "responseDeadline": "2026-11-04T14:00:00-05:00",
    "archiveDate": "2026-11-19",
    "department": "COMMERCE, DEPARTMENT OF",
    "subTier": "US CENSUS BUREAU",
    "office": "DEPT OF COMMERCE CENSUS",
    "cgac": "013",
    "fpdsCode": "1323",
    "aacCode": "1333LB",
    "naicsCode": "322220",
    "pscCode": "7530",
    "setAsideCode": "SBA",
    "setAside": "Small Business Set Aside - Total",
    "placeOfPerformance": { "city": "Charlestown", "state": "IN", "zip": "47111", "country": "USA" },
    "officeLocation": { "city": "SUITLAND", "state": "MD", "zip": "20746", "country": "USA" },
    "award": null,
    "additionalInfoLink": null,
    "description": "The Government is currently reviewing vendor questions and coordinating responses with the requiring activity...",
    "dataAsOf": "2026-10-31T03:30:30.000Z"
}
```

On an award notice, `award` looks like this:

```json
{
    "number": "12-3J14-27-B-0001",
    "date": "2026-10-30",
    "amountUsd": 1784851.2,
    "awardee": "INN FOODS, INC. Watsonville CA USA",
    "awardeeWithheld": false
}
```

Fields SAM.gov leaves empty are `null`, never guessed.

### Pricing

You pay per notice returned, nothing per run beyond Apify's standard start fee:

| Event | Price | When |
|---|---|---|
| Opportunity | $0.002 | Every notice in your dataset |

Example: 1,000 notices cost $2.00. A daily alert that returns 30 new notices costs $0.06 a day.

The actor reads your run's maximum charge before it starts and returns only as many notices as that covers, so a run never goes over the limit you set.

### Limits

- Covers notices that are active on SAM.gov (about 72,000 on 2026-10-31). Archived notices are not in the extract.
- SAM.gov rebuilds the extract once a day (the 2026-10-31 file was published at 03:30 UTC), so notices posted today appear tomorrow. Every row carries `dataAsOf`.
- Attachments and the notice history are not included; follow `url` to the notice on SAM.gov.
- About 1 in 6 notices has no description in the extract (11,971 of 71,604 on 2026-10-31), so `description` is `null` for those.
- `postedAt` is given exactly as SAM.gov writes it, without a time zone.
- Email and phone removal works on common formats (703-555-0100, (703) 555-0100, 1-703-555-0100, +1 703 555 0100, +81 3-4545-0450). An unusual format can slip through.
- Results come newest posting date first (within one day, in SAM.gov's own order). Runs with a recent posted date or a small `maxItems` stop reading early and finish in seconds; a filter that matches only a few notices reads the whole file (about 10 seconds).

### FAQ

**Do I need a SAM.gov account or API key?** No. The extract is public.

**Is this allowed?** SAM.gov's terms say bulk data is offered through its APIs and the Data Services extracts, and prohibit scraping the website. This actor reads only the public extract. Federal government works are in the US public domain.

**Why are contact names, emails and phones missing?** They are personal details of government staff. The actor drops the contact columns and removes emails and phone numbers from descriptions. Use the SAM.gov link to reach the contracting office.

**Why is an awardee sometimes `null` with `awardeeWithheld: true`?** Two cases. When the awardee looks like a private person rather than an organization, the name and address are withheld for privacy. Award notices dated before 2022-04-04 may carry Dun & Bradstreet data that SAM.gov's terms restrict, so their awardee is withheld too. Amount, date and award number stay.

**How do I get only new bids every day?** Turn on `onlyNew` and schedule the actor daily. The memory of what you have seen lives in a storage in your own Apify account, separately for each set of filters.

**Can I use it from an AI agent or over the API?** Yes. Call the actor with a JSON input like the examples above and read the dataset items.

# Actor input Schema

## `keywords` (type: `string`):

Words that must all appear in the title, solicitation number or description. Separate alternatives with commas: "cybersecurity, zero trust" finds either. Leave empty for every notice.

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

Keep notices whose NAICS code starts with any of these. "5415" matches 541511, 541512 and so on.

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

Keep notices whose PSC (classification) code starts with any of these, for example "D3" for IT services or "Z" for construction and maintenance.

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

Keep notices with any of these set-asides. Empty keeps all, including notices with none.

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

Keep only these notice types. Empty keeps all.

## `agency` (type: `string`):

Text that must appear in the department, sub-tier agency or office name, for example "army", "veterans affairs" or "NASA".

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

2-letter state codes, for example VA, MD, DC. Notices without a place of performance are dropped when this is set.

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

Keep notices posted in the last N days. Recent-only runs are also the fastest: reading stops once older notices begin.

## `postedFrom` (type: `string`):

Keep notices posted on or after this date. If you also set "Posted within", the later of the two dates wins.

## `openOnly` (type: `boolean`):

Keep notices whose response deadline is today or later. Notices without a deadline (most award and special notices) are dropped.

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

Skip notices that an earlier run with the same filters already returned. Made for schedules: each run gives only what is new. The memory lives in a storage in your own account.

## `descriptionMaxChars` (type: `integer`):

Characters of the notice description to keep (emails and phone numbers removed). 0 leaves it out.

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

Most notices to return (1 to 10000), newest posted first. You pay only for notices returned.

## Actor input object example

```json
{
  "postedWithinDays": 7,
  "openOnly": false,
  "onlyNew": false,
  "descriptionMaxChars": 2000,
  "maxItems": 20
}
```

# Actor output Schema

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

One item per contract opportunity, newest posted first.

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

// Run the Actor and wait for it to finish
const run = await client.actor("itayozer9/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 = {
    "postedWithinDays": 7,
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("itayozer9/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 '{
  "postedWithinDays": 7,
  "maxItems": 20
}' |
apify call itayozer9/sam-gov-opportunities --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,itayozer9/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/rsVhbB5SotNakYeNW/builds/v0p6JzTW8rJdxUUuJ/openapi.json
