# Bid Scout: SAM.gov Federal Bids Digest (`datapenguin/sam-gov-opportunities-digest`) Actor

New federal bids from SAM.gov, filtered for your trade by keyword, NAICS code, set-aside, state or agency. Run it daily to see only what's new, and send results to Excel, Sheets, Slack or email. No SAM.gov account or API key. Not affiliated with the U.S. government.

- **URL**: https://apify.com/datapenguin/sam-gov-opportunities-digest.md
- **Developed by:** [Data Penguin](https://apify.com/datapenguin) (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 $50.00 / 1,000 digests

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

### Find new federal bids for your trade without checking SAM.gov every day

Bid Scout reads the public SAM.gov Contract Opportunities data and gives you a short list of new federal bids that fit what you do. Filter by keyword, NAICS code, set-aside, state or agency. Run it once, or put it on a schedule and get only the notices that are new or amended since the last run.

There is no SAM.gov account to set up and no API key to request. Fill in a few filters, press Start, and read the results in your browser, in Excel or in a spreadsheet.

It is built for small contractors and subcontractors looking for federal work (janitorial, landscaping, facilities, construction, security, IT and similar trades), for proposal staff who want a daily list per NAICS code, for consultants who track federal buying for several clients, and for anyone who needs SAM.gov opportunity data as JSON, CSV or Excel.

#### How to use it

1. Click **Try for free** and open the **Input** tab.
2. Enter what you do. For example, a keyword like `janitorial`, a NAICS code like `5617`, a set-aside and a state. Leave anything you don't need empty.
3. Click **Start**. A run takes about 10 to 60 seconds. The **Output** tab shows the table, and the run's key-value store has a readable digest (`DIGEST_MD`).

To get a list every morning, turn on **Only new or updated since last run**, give the search a name in **State key**, and add an Apify Schedule.

#### Example inputs

Paste any of these into the Input tab (switch to the JSON view). The notes under each one come from a test in late October 2026, and your results will differ from day to day.

**Small-business janitorial work in Texas**

```json
{
    "keywords": ["janitorial", "custodial"],
    "setAsides": ["SBA"],
    "states": ["TX"],
    "postedWithinDays": 30,
    "maxItems": 25
}
```

This returned 2 open notices, including a sources-sought notice for an Amarillo field office. Without the `setAsides` line it returned 15.

**Construction bids in Florida**

```json
{
    "naicsCodes": ["23"],
    "states": ["FL"],
    "postedWithinDays": 14,
    "minDaysToDeadline": 5,
    "maxItems": 25
}
```

The code `23` matches every construction NAICS code. `minDaysToDeadline` hides notices that close too soon to respond to.

**Landscaping and grounds work for small and veteran-owned businesses**

```json
{
    "naicsCodes": ["561730"],
    "keywords": ["grounds maintenance", "landscaping", "mowing"],
    "setAsides": ["SBA", "SDVOSBC"],
    "postedWithinDays": 14,
    "maxItems": 25
}
```

**Roofing, HVAC and plumbing at VA and Army Corps offices**

```json
{
    "keywords": ["roofing", "HVAC", "plumbing", "painting"],
    "agencies": ["veterans affairs", "army corps"],
    "postedWithinDays": 14,
    "maxItems": 50
}
```

**Who is winning contracts in your trade**

```json
{
    "naicsCodes": ["5617"],
    "noticeTypes": ["Award Notice"],
    "postedWithinDays": 30,
    "maxItems": 50
}
```

#### Running it on a schedule

Save your input as a task and create a Schedule that runs it. The data file refreshes overnight, so a run after 6 AM Eastern works well. Use **Only new or updated since last run** with a different **State key** for each saved search, so each one remembers what it already sent you.

From the **Integrations** tab you can send results to Slack, Gmail, Google Sheets, Zapier, Make or your own webhook. Every run also saves an email-ready HTML digest (`DIGEST_HTML`) and a plain-text digest (`DIGEST_TXT`) in its key-value store, and each result has a one-line `digestLine` that works as an email subject or chat message.

Agencies post every amendment as a separate notice. Bid Scout shows the latest version of each solicitation once and tells you how many versions it replaced, and an amended notice is marked **updated** so it doesn't slip past you.

#### What each result contains

Title, notice type, solicitation number, agency and office, posted date, response deadline and days left, NAICS and product/service codes, set-aside, place of performance and a direct link to the notice on SAM.gov. You can also include the contracting officer's contact details as published in the notice, the description text, and a relevance score used for sorting.

A digest entry looks like this:

```
### S--AMARILLO FIELD OFFICE JANITORIAL SERVICES
- Type: Sources Sought · Solicitation #: 140LL027Q0008
- Agency: INTERIOR, DEPARTMENT OF THE › DEPARTMENTAL OFFICES › BLM CONTRACTING ACTIVITY
- Posted: 2026-10-23 · Due: 2026-10-28 (1 day)
- NAICS: 561720 · Set-aside: Small Business Set Aside - Total · Place: Amarillo, TX
- Link: https://sam.gov/workspace/contract/opp/55310392f07642a7840173a58e854adb/view
```

And a data item, shortened:

```json
{
    "title": "S--AMARILLO FIELD OFFICE JANITORIAL SERVICES",
    "solicitationNumber": "140LL027Q0008",
    "type": "Sources Sought",
    "postedDate": "2026-10-23",
    "responseDeadline": "2026-10-28T09:00:00-06:00",
    "daysToDeadline": 1,
    "agency": "INTERIOR, DEPARTMENT OF THE",
    "naicsCode": "561720",
    "setAside": "Small Business Set Aside - Total",
    "placeOfPerformance": { "city": "Amarillo", "state": "TX", "zip": "79101" },
    "url": "https://sam.gov/workspace/contract/opp/55310392f07642a7840173a58e854adb/view",
    "relevanceScore": 5
}
```

#### Pricing

You pay per use. There is no monthly fee.

| What | Price |
| --- | --- |
| A digest, once per run that finds at least one notice | $0.05 |
| Each notice returned | $0.0015 ($1.50 per 1,000) |
| Starting a run | $0.00005 |

A daily run that returns 5 new notices costs $0.05 plus 5 x $0.0015, about $0.06, which comes to roughly $1.75 over a month of daily matches. A run that finds nothing costs only the start fee. A weekly run returning about 20 notices costs around $0.08.

To set a hard limit, use **Maximum cost per run** in the run options. Bid Scout stops returning results when it reaches your limit. Apify's free plan includes some usage credit each month, so you can try it before paying anything.

#### Questions

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

No. Bid Scout never signs in to SAM.gov and doesn't use a key.

##### Where does the data come from, and how fresh is it?

From the public Contract Opportunities data file that the U.S. General Services Administration publishes at sam.gov/data-services. The file refreshes overnight, so a notice posted today usually appears tomorrow. If you run it daily, set **Posted within the last (days)** to at least 2 or 3.

##### SAM.gov has saved searches with email alerts. Why use this?

SAM.gov's alerts are free and work well for a search or two. Bid Scout helps when you want several searches at once, results in a spreadsheet or Slack, filters like days left to respond, or the data as CSV, Excel or JSON. Some people use both.

##### Does it include attachments or the statement of work?

No, attachments are not in the data file. Each result links to the notice on SAM.gov, where you can download them.

##### How do I find my NAICS code?

It's the industry code you picked when you registered on SAM.gov. You can enter fewer digits to cast a wider net: `5617` covers all building and grounds services, and `23` covers all construction.

##### Why did I get no results?

Your filters may be too narrow. Try fewer keywords, drop the set-aside, raise **Posted within the last (days)**, or remove the state. If **Only new or updated since last run** is on, notices you already received under the same State key are hidden on purpose.

##### Why did the state filter miss a notice?

It matches the place of performance, or the issuing office's state when no place is listed. Some notices list neither, so adding a keyword filter helps.

##### Can I use the contact details?

They are the business contact details the contracting officer published in the notice. Turn them off with `"includeContacts": false` if you don't need them.

##### Something is wrong or missing. Where do I report it?

Open a thread in the **Issues** tab. Bug reports and requests are welcome there.

#### All input fields

| Field | What it does |
| --- | --- |
| `keywords`, `excludeKeywords`, `keywordMatch` | Words or phrases in the title or description, matching any or all |
| `naicsCodes`, `pscCodes` | Industry and product/service codes, matched by prefix (`5617` matches `561720`) |
| `noticeTypes` | Defaults to notices you can still respond to. Add `Award Notice` to see winners |
| `setAsides` | Small business, 8(a), HUBZone, service-disabled veteran-owned, women-owned and more |
| `agencies`, `states` | Part of an agency or office name, and two-letter state codes |
| `postedWithinDays`, `hideExpired`, `minDaysToDeadline` | Date limits |
| `collapseAmendments` | On by default. One entry per solicitation, latest version only |
| `onlyNew`, `stateKey` | Return each notice once per saved search, and again if it is amended |
| `sortBy`, `maxItems` | Order and number of results |
| `includeDescription`, `includeContacts` | Turn the heavier fields on or off |

#### Good to know

- The source is the SAM.gov Contract Opportunities public data file, published by the U.S. General Services Administration.
- Award notices dated before 2022-04-04 can contain third-party data that SAM.gov doesn't allow in bulk use, so the awardee name is left out of those.
- This is an independent tool. It is not affiliated with, endorsed by or sponsored by the U.S. government, the General Services Administration or SAM.gov. Data can be up to a day old or incomplete, so confirm requirements and deadlines on SAM.gov before you bid. This is not legal or procurement advice.

# Changelog

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

# Actor input Schema

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

Words or phrases to look for in the title or description, such as janitorial or grounds maintenance. Leave empty to skip keyword filtering.

## `keywordMatch` (type: `string`):

Choose whether a notice must contain any one of your keywords or all of them.

## `excludeKeywords` (type: `array`):

Skip notices that mention any of these words in the title or description.

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

Industry codes. Enter a full six-digit code like 561720, or just the first digits to cover a group: 5617 matches every code that starts with 5617, and 23 matches all construction. Leave empty for any.

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

Federal product and service codes, such as S201. The first characters work too (S2). Leave empty for any.

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

Which kinds of notices to include. The default list covers notices you can still respond to. Add Award Notice to see who won.

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

Only show notices reserved for these programs, for example small business or service-disabled veteran-owned. Leave empty for any.

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

Part of a department, agency or office name, such as veterans affairs or army corps. Not case sensitive.

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

Two-letter state codes, such as TX or CA. Matches the place of performance, or the issuing office's state when no place is listed.

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

How far back to look. The data file updates overnight, so use at least 2 or 3 days if you run this every day.

## `hideExpired` (type: `boolean`):

Notices with no deadline, such as sources sought, are always kept.

## `minDaysToDeadline` (type: `integer`):

Skip notices that close sooner than this. For example, 5 hides anything due within five days.

## `collapseAmendments` (type: `boolean`):

Agencies post every amendment as its own notice. When this is on, you see only the latest version of each solicitation, with a count of the versions it replaced.

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

Remembers what you already received under your State key, so a daily schedule shows each notice once. A notice that gets amended shows up again.

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

A name for this saved search. Use a different key for each search you schedule, so each one keeps its own history.

## `sortBy` (type: `string`):

The order used before results are cut off at Max results.

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

The most results to return. You are charged per result, so this also caps what a run can cost.

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

Add the notice's description to each result.

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

Longer descriptions are cut off at this length.

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

Name, email and phone exactly as published in the notice.

## Actor input object example

```json
{
  "keywords": [
    "janitorial",
    "landscaping"
  ],
  "keywordMatch": "any",
  "noticeTypes": [
    "Solicitation",
    "Combined Synopsis/Solicitation",
    "Presolicitation",
    "Sources Sought",
    "Special Notice"
  ],
  "postedWithinDays": 30,
  "hideExpired": true,
  "minDaysToDeadline": 0,
  "collapseAmendments": true,
  "onlyNew": false,
  "stateKey": "default",
  "sortBy": "relevance",
  "maxItems": 25,
  "includeDescription": true,
  "descriptionMaxChars": 1500,
  "includeContacts": true
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `digest` (type: `string`):

No description

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

No description

## `digestHtml` (type: `string`):

No description

## `digestText` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [
        "janitorial",
        "landscaping"
    ],
    "postedWithinDays": 30,
    "maxItems": 25
};

// Run the Actor and wait for it to finish
const run = await client.actor("datapenguin/sam-gov-opportunities-digest").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": [
        "janitorial",
        "landscaping",
    ],
    "postedWithinDays": 30,
    "maxItems": 25,
}

# Run the Actor and wait for it to finish
run = client.actor("datapenguin/sam-gov-opportunities-digest").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": [
    "janitorial",
    "landscaping"
  ],
  "postedWithinDays": 30,
  "maxItems": 25
}' |
apify call datapenguin/sam-gov-opportunities-digest --silent --output-dataset

```

## MCP server setup

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

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/s6vTRoqb8egk0dnaL/builds/91s54mH4ac2R2C8SY/openapi.json
