# SAM.gov Scraper: federal contract opportunities and bid alerts (`bepolabs/sam-gov`) Actor

Search SAM.gov federal contract opportunities by keyword, NAICS, agency or set-aside: notice, deadline, agency, contacts and links as JSON or CSV. Costs 1.5 USD per 1,000 notices.

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

## Pricing

$0.12 / 1,000 notices

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

### 🏛️ What is SAM.gov Contract Opportunities?

Win more public work: SAM.gov Contract Opportunities turns every open federal contract solicitation into a tidy spreadsheet line, with names and emails of the people to call, place of performance, awards and attachments. No registration and no key needed. Turn on repeat mode and each morning only unseen listings arrive.

- **Daily bid alerts for contractors**: get new solicitations for your NAICS codes every morning in Slack, e-mail or a spreadsheet
- **Small business set-asides**: track only SBA, 8(a), SDVOSB, WOSB or HUBZone opportunities
- **Capture and BD pipelines**: feed opportunities with deadlines and contacts into your CRM or proposal tracker
- **Agency and market research**: see what the VA, the Army or NASA buys, how often, and under which codes
- **Consultants and bid-matching services**: run one alert per client with its own keywords and codes

![SAM.gov Contract Opportunities: US federal contract opportunities by keyword, NAICS, set-aside or agency, with deadlines, contacts and attachments.](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/sam-gov-hero.png)

#### ✨ Why use this Actor?

- ✅ **No account, no API key**: reads SAM.gov's official public daily extract of all active notices
- ✅ **One row per solicitation**: amendments are merged: the newest version is kept, older ids sit in earlierNoticeIds
- ✅ **Alert mode**: returns only notices you have not received before, per name; a day without news costs nothing
- ✅ **Deadlines made easy**: daysLeft on every row, open notices only by default, and a response-due date range
- ✅ **Attachments and contacts**: public files and links of each notice, plus primary and secondary contact with email and phone
- ✅ **Prefix codes**: NAICS 5415 covers every 5415xx entry, PSC 7A every 7A one

### 📦 What data can you get with SAM.gov Contract Opportunities?

| | | |
|---|---|---|
| 📄 Title and solicitation number | 🏷️ Notice type and base type | 🏛️ Agency, sub-tier and office |
| 📅 Posted date and response deadline | ⏳ Days left to respond | 🔢 NAICS and PSC code |
| 🎯 Set-aside code and name | 📍 Place of performance | 👤 Contacts: name, email, phone |
| 🏆 Award number, date, amount, awardee | 📎 Attachments and links | 📝 Full description and sam.gov link |

### 🚀 How to use SAM.gov Contract Opportunities

SAM.gov Contract Opportunities works in a few clicks, no coding needed:

1. [Create a free Apify account](https://console.apify.com/sign-up) (the free plan includes 5 USD of monthly credit).
2. Open [SAM.gov Contract Opportunities](https://apify.com/bepolabs/sam-gov) and click **Try for free**.
3. Enter your keywords, NAICS codes, set-asides or agencies, and how many days back to search. Switch on alert mode for a daily schedule.
4. Click **Start** and wait for the run to finish (most runs take seconds).
5. Download your data as JSON, CSV, Excel, XML or HTML, or send it straight to Google Sheets, Make, Zapier or your AI agent.

![How SAM.gov Contract Opportunities works](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/sam-gov-workflow.png)

### ⬇️ Input

Every filter is optional; combine as many as you like. With none set you get the newest open notices of the last 7 days.

##### Codes and prefixes

NAICS and PSC codes match as prefixes: `5415` finds 541511, 541512, 541519 and the rest. Set-asides take abbreviations (`SBA`, `8A`, `SDVOSBC`, `WOSB`, `HZC`) or words of the name.

##### Deadlines

`openOnly` (default on) drops notices whose deadline has passed. Set `responseDueFrom` and `responseDueTo` (YYYY-MM-DD) to get, for example, only bids due in the next two weeks.

##### Daily alerts

Turn on `onlyNew`, pick an alert name and add a daily schedule. Each run returns only notices that no earlier run with it returned, so a day with nothing new is free.

| Field | Type | What it does | Default |
|---|---|---|---|
| **Keywords** (`keywords`) | array | Any of these words in the title, solicitation number or description (case-insensitive). | `["software"]` |
| **NAICS codes** (`naicsCodes`) | array | NAICS codes or prefixes, e.g. | `["5415"]` |
| **PSC codes** (`pscCodes`) | array | Product and service codes or prefixes, e.g. |  |
| **Set-asides** (`setAsides`) | array | Set-aside codes (SBA, 8A, SDVOSBC, WOSB, HZC) or words of the set-aside name. |  |
| **Notice types** (`noticeTypes`) | array | Solicitation, Combined Synopsis/Solicitation, Presolicitation, Sources Sought, Special Notice, Award Notice, Justification, Sale of Surplus Property, Intent to Bundle Requirements (DoD-Funded). |  |
| **Agencies** (`agencies`) | array | Words of the department, sub-tier or office, e.g. |  |
| **Place of performance states** (`states`) | array | Two-letter state codes, e.g. |  |
| **Posted within (days)** (`postedWithinDays`) | integer | Only notices posted in the last N days. | `7` |
| **Only open notices** (`openOnly`) | boolean | Drop notices whose response deadline has passed (notices without a deadline stay). | `true` |
| **Response due from** (`responseDueFrom`) | string | Only notices whose response deadline is on or after this day (YYYY-MM-DD, UTC). |  |
| **Response due to** (`responseDueTo`) | string | Only notices whose response deadline is on or before this day (YYYY-MM-DD, UTC, the whole day counts). |  |
| **Merge amendments** (`mergeAmendments`) | boolean | One row per solicitation number: the newest notice, older notice ids in earlierNoticeIds. | `true` |
| **Alert mode: only new notices** (`onlyNew`) | boolean | Return only notices not returned by an earlier run with the same alert name. | `false` |
| **Alert name** (`alertName`) | string | Separates several alerts (letters, digits, dashes). | `"default"` |
| **Max results** (`maxResults`) | integer | Maximum number of contract opportunities returned (1 to 10,000), newest posted first. | `200` |
| **Include description** (`includeDescription`) | boolean | The full notice text (median about 800 characters). | `true` |
| **Include attachments** (`includeAttachments`) | boolean | Per notice the public attachments and links (name, URL, type), as listed under Attachments/Links on sam.gov. | `true` |

![SAM.gov Contract Opportunities input form](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/sam-gov-input.png)

#### Input example

```json
{
    "naicsCodes": [
        "5415"
    ],
    "noticeTypes": [
        "Solicitation",
        "Combined Synopsis/Solicitation",
        "Sources Sought",
        "Presolicitation"
    ],
    "postedWithinDays": 7,
    "maxResults": 100
}
```

### ⬆️ Output

Every solicitation becomes one row, newest first. The run summary in the key-value store (`OUTPUT`) counts the notices in the extract, the matches and the amendments merged.

![SAM.gov Contract Opportunities output table](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/sam-gov-output.png)

#### Output example

One row of the dataset (NASA, description shortened, 2 of 3 attachments shown):

```json
{
    "noticeId": "56d2fe81e3b1488b8a6938021756a553",
    "title": "COD FARO FOCUS I.1 3D LASER SCANNER",
    "solicitationNumber": "80NSSC27947229Q",
    "type": "Combined Synopsis/Solicitation",
    "baseType": "Combined Synopsis/Solicitation",
    "agency": "NATIONAL AERONAUTICS AND SPACE ADMINISTRATION",
    "subTier": "NATIONAL AERONAUTICS AND SPACE ADMINISTRATION",
    "office": "NASA SHARED SERVICES CENTER",
    "postedDate": "2026-10-15T13:44:32.000Z",
    "responseDeadline": "2026-10-22T07:00:00-05:00",
    "daysLeft": 6,
    "naicsCode": "541519",
    "pscCode": "7A20",
    "setAsideCode": "SBA",
    "setAside": "Small Business Set Aside - Total",
    "placeOfPerformance": {
        "city": "Hampton",
        "state": "VA",
        "zip": "23681",
        "country": "USA"
    },
    "award": null,
    "primaryContact": {
        "name": "Shanna Patterson",
        "title": null,
        "email": "shanna.l.patterson@nasa.gov",
        "phone": null
    },
    "secondaryContact": {
        "name": "Bobbie Young",
        "title": null,
        "email": "bobbie.j.young@nasa.gov",
        "phone": null
    },
    "link": "https://sam.gov/workspace/contract/opp/56d2fe81e3b1488b8a6938021756a553/view",
    "additionalInfoLink": null,
    "description": "** THIS IS A BRAND NAME REQUIREMENT ** for COD FARO FOCUS I.1 3D LASER SCANNER ** AUTHORIZED RESELLERS ONLY ** ...",
    "earlierNoticeIds": [],
    "attachments": [
        {
            "name": "SATPC0043053 Tab 06 BNJ..pdf",
            "url": "https://sam.gov/api/prod/opps/v3/opportunities/resources/files/4126c454c31742cd854c2076fb4a7709/download",
            "type": "file",
            "postedDate": "2026-10-15T17:44:32.004+00:00",
            "sizeBytes": 145486
        },
        {
            "name": "SATPC0043053 Tab 04 4 SOW..pdf",
            "url": "https://sam.gov/api/prod/opps/v3/opportunities/resources/files/cff8ffb3ab8349a6be8a741c23be2a2f/download",
            "type": "file",
            "postedDate": "2026-10-15T17:44:32.004+00:00",
            "sizeBytes": 141909
        }
    ]
}
```

#### How fresh is the data?

The Actor streams SAM.gov's public daily extract of all active contract opportunities (71,196 notices in our test run on 2026-10-16) and keeps only the matches. The data is as fresh as that snapshot, which SAM.gov rebuilds once a day; archived ones are not in it. If GSA ever moves or renames that file, the run fails with a clear message instead of returning blanks.

View the results as a table or JSON in the Output tab and download them as JSON, CSV, Excel, XML, HTML or RSS, all fields or only those you pick.

### 💰 How much does SAM.gov Contract Opportunities cost?

SAM.gov Contract Opportunities is priced **per event**: **1.5 USD per 1,000 notices** (0.0015 USD each), with no monthly rental. Each saved row is one charge. No start fee applies, so an alert run that finds only old listings costs zero.

| You get | You pay |
|---|---|
| 100 notices | 0.15 USD |
| 1,000 notices | 1.5 USD |
| 10,000 notices | 15 USD |
| 100,000 notices | 150 USD |

💡 Apify's free plan gives you 5 USD of credit every month, enough for about **3,333 notices** at no cost. Set a spending limit per run and the Actor stops there.

### ⚖️ SAM.gov Contract Opportunities vs. the alternatives

| | SAM.gov Contract Opportunities | SAM.gov website search | Official SAM.gov API |
|---|---|---|---|
| **No account or API key** | ✅ | ✅ for searching | ❌ personal key |
| **Request limit** | ✅ none | ✅ none | ❌ 10 a day without a SAM.gov role |
| **Amendments merged into one row** | ✅ | ❌ | ❌ |
| **Only new notices since the last run** | ✅ alert mode | ❌ check by hand | ❌ build it yourself |
| **Export to CSV, Excel, Sheets, CRM** | ✅ | ❌ copy by hand | ❌ build it yourself |

### 🔌 Integrations, API and MCP

#### Connect SAM.gov Contract Opportunities to your AI agent (MCP)

Give Claude, ChatGPT, Cursor or any MCP client direct access to SAM.gov Contract Opportunities through the [Apify MCP server](https://mcp.apify.com). Add this URL to its settings:

```text
https://mcp.apify.com/?actors=bepolabs/sam-gov
```

For Claude Desktop, add it under `mcpServers` in `claude_desktop_config.json`:

```json
{
    "mcpServers": {
        "sam-gov": {
            "command": "npx",
            "args": [
                "-y",
                "@apify/actors-mcp-server",
                "--actors",
                "bepolabs/sam-gov"
            ],
            "env": {
                "APIFY_TOKEN": "<your Apify API token>"
            }
        }
    }
}
```

Then ask: *"Find open SAM.gov small business set-aside opportunities for NAICS 541512 posted this week and list the ones due in the next 10 days."*

#### Run it from your code

Python (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("bepolabs/sam-gov").call(run_input={"naicsCodes":["5415"],"noticeTypes":["Solicitation","Combined Synopsis/Solicitation","Sources Sought","Presolicitation"],"postedWithinDays":7,"maxResults":100})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

JavaScript (`npm install apify-client`):

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('bepolabs/sam-gov').call({"naicsCodes":["5415"],"noticeTypes":["Solicitation","Combined Synopsis/Solicitation","Sources Sought","Presolicitation"],"postedWithinDays":7,"maxResults":100});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### No-code integrations

Send results to **Google Sheets, Slack, Airtable, HubSpot, Make, Zapier, n8n** and more from the Integrations tab, start runs on a **schedule**, or trigger your own endpoint with a **webhook** when a run finishes. The [Apify API](https://docs.apify.com/api/v2) gives you full control over runs and datasets.

### ❓ FAQ

##### Do I need a SAM.gov account or API key?

No. The Actor reads the public daily extract GSA publishes for download. You need a SAM.gov registration only to bid, not to search.

##### Why are there fewer rows than on sam.gov?

Amendments are merged into one row per solicitation, notices with a passed deadline are dropped (turn off `openOnly` to keep them), and only the `postedWithinDays` window is searched.

##### Can I get a daily e-mail or Slack alert?

Yes: turn on alert mode, name it and add a daily schedule; connect the Slack, e-mail, Make, Zapier or n8n integration to receive the new notices.

##### Does it include attachments?

Yes: `attachments` lists every public file and link of a notice with its name and URL; those URLs download without a SAM.gov account. Sign-in-only documents are left out. Turn off `includeAttachments` for a shorter run.

##### How long does a run take?

One to a few minutes (about three in our test run): most of it is streaming the extract (about 200 MB), plus one quick request per returned notice for its attachments.

##### Are award notices included?

Yes: choose the type Award Notice; the `award` field then carries the number, date, amount and awardee as far as the listing gives them.

##### Is it legal to use SAM.gov Contract Opportunities?

Yes. The extract is released by GSA for open download without an account or key, and contract opportunity data is a work of the US government and in the public domain (17 U.S.C. 105). Contact names and emails are published by the agencies on each notice for vendors to reach them; use them for that purpose and respect anti-spam laws.

##### What if something is missing or does not work?

Open an issue on the **Issues** tab; we read each one and reply. Feature requests are welcome too.

### 💬 Your feedback

Tell us what SAM.gov Contract Opportunities should add on the **Issues** tab or leave a review; your notes decide what we work on next.

### 🔗 Related Actors

| Actor | What it does |
|---|---|
| 🏛️ [UK Tenders](https://apify.com/bepolabs/uk-tenders) | UK public contracts from Contracts Finder and Find a Tender by keyword, CPV, value, region and deadline, with daily alerts. |
| 🏛️ [US Federal Grants Finder](https://apify.com/bepolabs/us-grants) | Grants.gov opportunities by keyword, agency or CFDA number, with award amounts, deadlines, eligibility and contacts. |
| 🩺 [NPI Registry Lookup](https://apify.com/bepolabs/npi-registry) | US doctors, nurses, clinics and pharmacies from the official CMS NPI Registry, by specialty, name, NPI or place. |
| 🌦️ [US Weather Forecast](https://apify.com/bepolabs/us-weather) | Official National Weather Service forecasts, hourly and 7-day, plus active weather alerts for any US point or state. |
| 📧 [Email Verifier](https://apify.com/bepolabs/email-dns-check) | Bulk email validation over DNS: valid, risky or invalid per address, with the reasons, a score, a typo fix, throwaway and shared-inbox flags. |
| 📞 [Phone Number Validator](https://apify.com/bepolabs/phone-validator) | Bulk phone number validation offline: valid or not, E.164 format, country and line type (mobile, fixed line, VoIP) for every number. |
| 🧾 [EU VAT Number Validator](https://apify.com/bepolabs/vat-validation) | Check thousands of EU VAT numbers against the official VIES service: valid or not, company name and address. |
| 💼 [ATS Jobs](https://apify.com/bepolabs/ats-jobs) | Every open job from company career boards on Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee in one deduped feed. |

# Changelog

This Actor's version history is a separate document: https://apify.com/bepolabs/sam-gov/changelog.md

# Actor input Schema

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

Any of these words in the title, solicitation number or description (case-insensitive). Empty = all.

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

NAICS codes or prefixes, e.g. 5415 (all computer systems design) or 541512. Empty = all.

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

Product and service codes or prefixes, e.g. 7A or D3. Empty = all.

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

Set-aside codes (SBA, 8A, SDVOSBC, WOSB, HZC) or words of the set-aside name. Empty = all.

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

Solicitation, Combined Synopsis/Solicitation, Presolicitation, Sources Sought, Special Notice, Award Notice, Justification, Sale of Surplus Property, Intent to Bundle Requirements (DoD-Funded). Empty = all.

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

Words of the department, sub-tier or office, e.g. veterans affairs, army, NASA. Empty = all.

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

Two-letter state codes, e.g. VA, TX. Many notices leave the state empty, so this filter drops those.

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

Only notices posted in the last N days.

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

Drop notices whose response deadline has passed (notices without a deadline stay).

## `responseDueFrom` (type: `string`):

Only notices whose response deadline is on or after this day (YYYY-MM-DD, UTC). With a due date set, notices without a deadline are left out.

## `responseDueTo` (type: `string`):

Only notices whose response deadline is on or before this day (YYYY-MM-DD, UTC, the whole day counts).

## `mergeAmendments` (type: `boolean`):

One row per solicitation number: the newest notice, older notice ids in earlierNoticeIds.

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

Return only notices not returned by an earlier run with the same alert name. Schedule it daily; a run with nothing new costs nothing.

## `alertName` (type: `string`):

Separates several alerts (letters, digits, dashes).

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

Maximum number of contract opportunities returned (1 to 10,000), newest posted first.

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

The full notice text (median about 800 characters).

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

Per notice the public attachments and links (name, URL, type), as listed under Attachments/Links on sam.gov. One extra request per returned notice.

## Actor input object example

```json
{
  "keywords": [
    "software"
  ],
  "naicsCodes": [
    "5415"
  ],
  "postedWithinDays": 7,
  "openOnly": true,
  "mergeAmendments": true,
  "onlyNew": false,
  "alertName": "default",
  "maxResults": 200,
  "includeDescription": true,
  "includeAttachments": true
}
```

# Actor output Schema

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

Dataset items, one row per result, in the overview table view.

# 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": [
        "software"
    ],
    "naicsCodes": [
        "5415"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("bepolabs/sam-gov").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": ["software"],
    "naicsCodes": ["5415"],
}

# Run the Actor and wait for it to finish
run = client.actor("bepolabs/sam-gov").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": [
    "software"
  ],
  "naicsCodes": [
    "5415"
  ]
}' |
apify call bepolabs/sam-gov --silent --output-dataset

```

## MCP server setup

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

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/KWnWFqejXcX4jFnY7/builds/wLRFOHZNBLWxBWNw2/openapi.json
