# SAM.gov Scraper: Federal Contract Opportunities Monitor (`fedsignals/federal-opportunities-monitor`) Actor

Returns new SAM.gov federal contract opportunities as clean rows: title, notice type, agency, NAICS/PSC, set-aside, deadline, days left and link. Filter by category, set-aside, agency, state or keyword; only new notices on scheduled runs. No API key.

- **URL**: https://apify.com/fedsignals/federal-opportunities-monitor.md
- **Developed by:** [FedSignals Data](https://apify.com/fedsignals) (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.50 / 1,000 opportunity notice delivereds

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 Scraper: Federal Contract Opportunities Monitor

Get every new federal contract opportunity from SAM.gov as clean, categorized data. The Actor covers solicitations, presolicitations, sources-sought notices and combined synopses from **all agencies**. Filter by plain-English category, agency, set-aside, state, NAICS/PSC or keyword. Run it daily on a schedule, and incremental mode returns **only notices you have not seen yet**.

You don't need a SAM.gov API key, so there are no 10-requests-per-day limits. The Actor reads the official public SAM.gov Contract Opportunities extract.

### What you get

- **Human-readable categories**: each notice is tagged with one of 16 groups, mapped from its PSC and NAICS codes: IT & Cyber, Telecom, Construction, Facilities & Maintenance, Security & Guard Services, Medical & Health, Defense & Aerospace, Research & Development, Professional Services, Architecture & Engineering, Education & Training, Logistics & Transportation, Energy & Environment, Food & Lodging, Equipment & Supplies, Other.
- Department, sub-tier and office.
- Set-aside, as a code plus a label.
- NAICS and PSC.
- Place of performance.
- Response deadline and **days until deadline**.
- **Award notices with winners**: awardee name and address, award amount, number and date.
- **Solicitation-number lookup**: every notice for a solicitation (original, amendments, award) with `solicitationNumbers`.
- A public SAM.gov link, an attachments-page link, and direct attachment download links if you add your own SAM.gov API key.
- A trimmed description.
- **Incremental mode**: the Actor remembers notice IDs in a named key-value store, so scheduled runs only return (and only charge for) new notices. `baselineOnFirstRun` makes the first run a free baseline, and `pushRunSummary` adds a free summary row for webhooks.
- Contact names, emails and phones are **off by default**. They are opt-in with `includeContacts`.

### Example input

```json
{
  "daysBack": 3,
  "categories": ["IT & Cyber"],
  "setAsides": ["small business"],
  "noticeTypes": ["Solicitation", "Combined Synopsis/Solicitation", "Sources Sought"],
  "minDaysToDeadline": 5,
  "onlyNew": true,
  "maxItems": 500
}
```

Set-aside groups: `small business`, `8(a)`, `hubzone`, `sdvosb`, `wosb`, `veteran-owned`, `indian`, `ied`. You can also use raw SAM codes such as `SBA` or `SDVOSBC`.

### Example output

```json
{
  "noticeId": "56e57b68bdf74e2482af682c2e1df81b",
  "title": "Online management support software for SDS",
  "noticeType": "Solicitation",
  "postedDate": "2026-10-27",
  "responseDeadline": "2026-11-06T17:00:00-08:00",
  "daysUntilDeadline": 9,
  "category": "IT & Cyber",
  "pscCode": "7A20",
  "naicsCode": "513210",
  "department": "INTERIOR, DEPARTMENT OF THE",
  "subTier": "DEPARTMENTAL OFFICES",
  "office": "BLM CONTRACTING ACTIVITY",
  "setAsideCode": "SBA",
  "setAside": "Small Business Set Aside - Total",
  "url": "https://sam.gov/opp/56e57b68bdf74e2482af682c2e1df81b/view",
  "attachmentsPageUrl": "https://sam.gov/opp/56e57b68bdf74e2482af682c2e1df81b/view#attachments-links"
}
```

A real 3-day, all-agency run on Oct 28, 2026 returned 1,884 open notices. Agencies: DoD 1,471, VA 138. Categories: Equipment & Supplies 841, Defense & Aerospace 232, Facilities 229 and so on.

### Use cases

- Small businesses and GovCon consultants: a daily feed of new bids in your categories and set-asides.
- Capture and BD teams: route notices into a CRM, Slack or a spreadsheet (via Apify integrations or webhooks).
- Market researchers: track how many notices each agency or category posts over time.

### Data source and terms

The data is the official **SAM.gov Contract Opportunities public data extract** published by the U.S. General Services Administration. It is U.S. government information and is not subject to copyright in the U.S. Always confirm details and amendments on the official notice before bidding. Categories are this Actor's own grouping of PSC/NAICS codes. Notices without codes are labeled "Other".

### Scheduling

Create a Task with your filters and schedule it **daily**, for example 7:00 AM ET. SAM.gov refreshes the extract overnight. Keep `onlyNew: true` and `daysBack: 3` so weekends and late postings are covered without duplicates. Give each saved Task its own `stateKey` if you run several with the same filters.

### How much does it cost?

Pay per event: you pay only for the events below plus Apify's $0.00005 run-start fee. Platform compute is included in the price.

- **$2.50 per 1,000 notices** ($0.0025 per notice delivered).
- **$0.01 per alert run**, charged only when a run delivers at least one new notice.

Real examples from our test runs:

- **Quick-start input** (10 IT & Cyber notices): 10 × $0.0025 + $0.01 alert-run fee = **about $0.035**.
- **IT & Cyber small-business set-asides, last 7 days**: 18 notices in our Oct 28 test = 18 × $0.0025 + $0.01 = **about $0.055**.
- **Everything from all agencies for 3 days**: 1,884 notices in our Oct 28 test = **about $4.72**. Use categories, set-asides and `maxItems` to stay small.
- A run that finds no new notices pays no alert fee and no notice fees, only Apify's tiny start fee.

Use `maxItems` and Apify's per-run spending limit to cap spend; the Actor stops cleanly when the limit is reached.

### Limits

- The public extract updates once a day, so this is a daily feed, not real-time.
- Attachment files are not downloaded. Direct attachment links need your own SAM.gov API key; without one, use `attachmentsPageUrl`.
- `awardeeName` is split from SAM.gov's combined awardee text at the street number, so a few names may be cut or include part of the address.
- Categories are a best-effort mapping. Notices without PSC/NAICS codes are labelled Other, and Equipment & Supplies is dominated by DLA spare-parts notices.

### FAQ

**Do I need a SAM.gov API key?**\
No. The Actor reads the public SAM.gov Contract Opportunities data extract, so there is no key and no 10-requests-per-day limit. A key is optional and only adds direct attachment download links (`samApiKey`).

**How fresh is the data?**\
SAM.gov refreshes the public extract once a day, overnight. Notices posted today usually appear in the next day's run.

**How do I get only new bids every day?**\
Save a Task with your filters, turn on `onlyNew`, keep `daysBack` at 3 and schedule it daily. Each run returns only notices you haven't received yet.

**Can I get contact details?**\
Yes, turn on `includeContacts` to add the primary point of contact published on the notice. It is off by default.

**Does it cover award notices?**\
Yes. Set `noticeTypes` to `Award Notice` to see who won: `awardeeName`, `awardeeAddress`, `awardAmount`, `awardNumber` and `awardDate` are filled when SAM.gov publishes them. The dataset has an Award notices view.

**Can I look up one solicitation number?**\
Yes. Put it in `solicitationNumbers` and set `daysBack` to cover its history (for example 90). You get every notice for it: the original, amendments and the award notice. Other filters are ignored in lookup mode.

**Where are the attachments?**\
Every notice has `attachmentsPageUrl`, the public SAM.gov page section listing its files. For direct download links in `resourceLinks`, add your own free SAM.gov API key in `samApiKey` (one request covers up to 1,000 notices).

**My first scheduled run returned hundreds of old notices. How do I avoid that?**\
Turn on `baselineOnFirstRun` with `onlyNew`. The first run marks everything currently matching as seen, returns nothing and charges nothing; from then on you get only new notices.

**How do I trigger a webhook or Zap with the result?**\
Turn on `pushRunSummary` to add one free `run-summary` row with counts and the run link at the end of the dataset. The same summary is always saved as `SUMMARY` in the key-value store.

**Why is a notice in the wrong category?**\
Categories are our own grouping of PSC and NAICS codes. Use `pscPrefixes` or `naicsPrefixes` for exact control.

### Reliability

Measured on Apify as of Oct 29, 2026: 3 of 3 of our own test runs succeeded (100%), with a median run time of 4 seconds (longest 4 s) on small test inputs. It is a small sample from a new Actor; we will update it as runs accumulate. Local tests: a 3-day all-agency run read 2,603 notices and returned 1,884 in about 10 seconds; the incremental rerun returned 0 duplicates.

### Use it from AI agents (MCP)

Add this Actor as a tool in Claude Desktop, Cursor or any MCP client through the Apify MCP server:

```json
{
  "mcpServers": {
    "federal-opportunities-monitor": {
      "url": "https://mcp.apify.com?tools=fedsignals/federal-opportunities-monitor",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

### Use it from code (API)

One call runs the Actor and returns the dataset items. `maxTotalChargeUsd` caps what the run can charge.

Python:

```python
import requests

items = requests.post(
    "https://api.apify.com/v2/acts/fedsignals~federal-opportunities-monitor/run-sync-get-dataset-items",
    params={"maxTotalChargeUsd": 1},
    headers={"Authorization": "Bearer YOUR_APIFY_TOKEN"},
    json={"daysBack": 5, "categories": ["IT & Cyber"], "onlyNew": False, "maxItems": 10},
    timeout=300,
).json()
print(len(items), "items")
```

JavaScript (Node 18+):

```js
const res = await fetch(
  "https://api.apify.com/v2/acts/fedsignals~federal-opportunities-monitor/run-sync-get-dataset-items?maxTotalChargeUsd=1",
  {
    method: "POST",
    headers: { Authorization: "Bearer YOUR_APIFY_TOKEN", "Content-Type": "application/json" },
    body: JSON.stringify({"daysBack": 5, "categories": ["IT & Cyber"], "onlyNew": false, "maxItems": 10}),
  }
);
const items = await res.json();
console.log(items.length, "items");
```

### Related FedSignals Actors

- [Expiring Federal Contracts: Recompete Finder (USAspending)](https://apify.com/fedsignals/federal-recompete-finder): federal contracts expiring soon, with incumbents
- [USAspending Scraper: Federal Spending Trends by Category](https://apify.com/fedsignals/federal-spending-signals): where federal contract spending is growing
- [SEC Form D Scraper: New Startup Funding Rounds](https://apify.com/fedsignals/sec-form-d-monitor): new private funding rounds from SEC Form D filings
- [Building Permits Scraper: New Construction Leads by City](https://apify.com/fedsignals/building-permits-monitor): new building permits as construction leads

### Feedback

Found a bug or need a filter or source? Open an issue on the Issues tab or email **fedsignals.alerts@gmail.com**.

This Actor is not affiliated with or endorsed by GSA or SAM.gov.

# Actor input Schema

## `daysBack` (type: `integer`):

Returns notices posted within the last N days. Use 1-3 for a daily schedule, up to 30 for a backfill.

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

Returns only these SAM.gov notice types. Empty = all types.

## `categories` (type: `array`):

Returns only notices in these plain-English category groups (mapped from PSC, then NAICS). Empty = all categories.

## `naicsPrefixes` (type: `array`):

e.g. 5415, 236220. Empty = all.

## `pscPrefixes` (type: `array`):

e.g. D3, Y1, 65. Empty = all.

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

Matches department, sub-tier or office text, e.g. VETERANS AFFAIRS, ARMY. Empty = all agencies.

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

Returns only notices with these set-asides. Groups: small business, 8(a), hubzone, sdvosb, wosb, veteran-owned, indian, ied; or raw SAM codes such as SBA or SDVOSBC. Empty = any, including no set-aside.

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

2-letter codes, e.g. CO, TX. Empty = anywhere.

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

Match in title or description (case-insensitive).

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

Drop notices containing any of these.

## `solicitationNumbers` (type: `array`):

Returns every notice (all types, including amendments and award notices) whose solicitation or award number matches, ignoring the other filters. Set Days back to cover the solicitation's history, for example 90 (up to 365); each extra month adds roughly 15-30 seconds of download. Dashes and spaces are ignored.

## `samApiKey` (type: `string`):

Returns attachment download links (`resourceLinks`) and the awardee's UEI when set. Uses SAM.gov's official Get Opportunities API with your own free key from SAM.gov Account Details (non-federal keys allow about 10 requests a day). Without a key every notice still has `attachmentsPageUrl`, the public page where attachments are listed.

## `samApiMaxRequests` (type: `integer`):

Returns attachment links for up to 1,000 notices per request (only used with a SAM.gov API key). Keep at 1 on a daily schedule to stay inside SAM.gov's daily key limit.

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

Skip notices marked inactive.

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

Skip notices whose response deadline is sooner than this. 0 drops past deadlines.

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

On: returns only notices not delivered by an earlier run with the same filters (memory in a named key-value store). Turn on for scheduled runs; off returns everything that matches.

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

Optional. Separate incremental memory per saved task. Defaults to a hash of your filters.

## `baselineOnFirstRun` (type: `boolean`):

Returns nothing on the first incremental run: marks every notice currently matching your filters as already seen, so the next scheduled run alerts only on genuinely new notices. Free. Needs Only new on.

## `pushRunSummary` (type: `boolean`):

Returns one extra free row at the end with `recordType: "run-summary"` (counts, window, run link), so a webhook or Zapier step can read the run result from the dataset. The same summary is always saved as SUMMARY in the key-value store.

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

Adds the primary point of contact (name, email, phone) published on the notice. Off by default.

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

Truncate description text; 0 omits it.

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

Maximum notices returned (and charged) per run.

## `userAgent` (type: `string`):

Contact string sent to SAM.gov.

## Actor input object example

```json
{
  "daysBack": 5,
  "noticeTypes": [
    "Solicitation",
    "Combined Synopsis/Solicitation",
    "Presolicitation",
    "Sources Sought"
  ],
  "categories": [
    "IT & Cyber"
  ],
  "naicsPrefixes": [],
  "pscPrefixes": [],
  "agencies": [],
  "setAsides": [],
  "placeOfPerformanceStates": [],
  "keywords": [],
  "excludeKeywords": [],
  "samApiMaxRequests": 1,
  "activeOnly": true,
  "minDaysToDeadline": 0,
  "onlyNew": true,
  "baselineOnFirstRun": false,
  "pushRunSummary": false,
  "includeContacts": false,
  "descriptionMaxChars": 1000,
  "maxItems": 10
}
```

# Actor output Schema

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

New SAM.gov contract opportunity notices. One item per row; field definitions are in the dataset schema.

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

JSON summary of the run (counts scanned, pushed and skipped).

# 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 = {
    "daysBack": 5,
    "categories": [
        "IT & Cyber"
    ],
    "onlyNew": false,
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("fedsignals/federal-opportunities-monitor").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 = {
    "daysBack": 5,
    "categories": ["IT & Cyber"],
    "onlyNew": False,
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("fedsignals/federal-opportunities-monitor").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 '{
  "daysBack": 5,
  "categories": [
    "IT & Cyber"
  ],
  "onlyNew": false,
  "maxItems": 10
}' |
apify call fedsignals/federal-opportunities-monitor --silent --output-dataset

```

## MCP server setup

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

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/bILTNTVITwQ8BjG1L/builds/6GFT69qRbebEqjRAW/openapi.json
