# SAM.gov Federal Bid Finder with Past Award Prices (`colinsabby/federal-bid-matcher`) Actor

Find new SAM.gov federal contract opportunities by NAICS, PSC, set-aside, state and keywords, with past award prices (median, range, top winners) from USAspending.

- **URL**: https://apify.com/colinsabby/federal-bid-matcher.md
- **Developed by:** [Colin Sabby](https://apify.com/colinsabby) (community)
- **Categories:** Business, Lead generation
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 results

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 Federal Bid Finder with Past Award Prices

Find new federal contract opportunities on SAM.gov that match your NAICS codes, PSC codes, set-asides, states, and keywords. Each opportunity comes with **past award prices** from USAspending.gov: how many similar contracts were awarded, the median, low and high amounts, and the top 3 winners. You can bid knowing the going rate.

Run it daily with **Only new or changed** turned on. Each run then returns only notices that are new or amended since the last run.

### What you get per opportunity

| Field | Meaning |
|---|---|
| `noticeId`, `title`, `solicitationNumber` | SAM.gov identifiers |
| `agency`, `office` | Buying agency and contracting office |
| `type`, `setAside` | Notice type (Solicitation, Sources Sought, …) and set-aside |
| `naics`, `psc` | Industry and product/service codes |
| `postedDate`, `responseDeadline` | When it was posted and when bids are due |
| `placeOfPerformance` | City, state and zip when SAM provides them |
| `samUrl` | Link to the notice on sam.gov |
| `attachmentsCount` | Number of attached files |
| `changedSinceLastRun` | True when this is an amendment of a notice you already got |
| `awardComps` | Past award prices (see below) |

Personal contact names, emails and phone numbers are **left out by default**. Turn on `includePointOfContact` to include them.

### Get your free SAM.gov key in 2 steps

1. Sign in at [sam.gov](https://sam.gov) and open **Account Details**.
2. Under **Public API Key**, reveal the key, confirm with the emailed code, and paste it into the **SAM.gov API key** field. That field is stored as a secret.

Personal keys without a SAM role allow about **10 requests a day**. That is plenty for a daily run with a few filters. Keys **expire after 90 days**, so regenerate yours in Account Details when it does. This Actor does not include a key, and you use your own.

### Example input

```json
{
  "samApiKey": "YOUR-SAM-PUBLIC-API-KEY",
  "naics": ["333120"],
  "setAside": ["SBA"],
  "placeOfPerformanceState": ["TX", "OK"],
  "postedWithinDays": 7,
  "onlyNew": true,
  "includeAwardComps": true,
  "maxResults": 100
}
```

Instead of codes, you can pick a plain-English **preset**: `heavy equipment`, `metal fabrication` or `janitorial`. Extra NAICS and PSC codes are added on top of the preset.

### Inputs

| Field | Default | Meaning |
|---|---|---|
| `samApiKey` | required | Your SAM.gov Public API Key (secret) |
| `preset` | none | Plain-English code bundle |
| `naics` | none | 2–6 digit NAICS codes |
| `psc` | none | 1–4 character PSC codes |
| `keywords` | none | Words searched in the notice title |
| `setAside` | none | SBA, 8A, WOSB, SDVOSBC, HZC, … |
| `placeOfPerformanceState` | none | Two-letter state codes |
| `postedWithinDays` | 7 | How far back to look (1–365) |
| `onlyNew` | true | Only new or changed notices since the last run |
| `includeAwardComps` | true | Add past award prices |
| `includePointOfContact` | false | Include contact name, email and phone |
| `maxResults` | 100 | Up to 5000 |

### What the award comps mean

For each notice we search USAspending.gov for contracts (award types A–D) with the **same 6-digit NAICS**, plus the same PSC when the notice has one, signed in the **last 3 years**.

- `count`, `medianUsd`, `minUsd`, `maxUsd`: computed from award amounts above $0.
- `topWinners`: the 3 companies with the largest total in that set.
- `sampled` / `sampleSize`: to keep runs fast, we read up to **3 pages (300) of the most recent awards**. When more exist, `sampled` is true and the median describes that recent sample, not every award.
- `{ "skipped": ... }`: the notice has no 6-digit NAICS, so no comps.
- `{ "error": ... }`: USAspending failed for that notice after retries. The notice is still returned.

Comps are a market reference, not a quote for the specific job.

### Limits

- Each filter combination (NAICS × PSC × state × set-aside) is one SAM request, and each request returns up to 1000 notices. A personal key's ~10 requests a day caps how many combinations you can run daily.
- SAM title search does not search the notice description.
- Award comps depend on USAspending.gov uptime and speed. A 1,000-notice run took between 1.5 and 8 minutes in our tests.
- Data comes from public U.S. government APIs. Check every detail on sam.gov before you bid.

# Actor input Schema

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

Public API key from SAM.gov: sign in, open Account Details, then Public API Key. Required. Stored as a secret. For a local npm start, SAM_API_KEY is used when this is blank. This Actor does not include a key. About 10 requests per day without a role and about 1,000 per day with a role (https://open.gsa.gov/api/entity-api/).

## `preset` (type: `string`):

Matches a notice if its NAICS or its PSC is in the preset. heavy equipment: NAICS 333120, 532412 and PSC 3805, 3810, 3820. metal fabrication: NAICS 332312, 332313, 332710 (no PSC). janitorial: NAICS 561720 and PSC S201. Sources are in the README. Extra naics and psc values are added to the preset.

## `naics` (type: `array`):

2–6 digit NAICS codes. Without a preset, a notice must match one of these and, when psc is also set, one of those PSC codes.

## `psc` (type: `array`):

Product or Service Codes, 1–4 letters or digits. Sent to SAM as ccode and to USAspending as psc_codes when the notice itself has a classification code.

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

Passed as the SAM title parameter. SAM search does not query the notice description.

## `setAside` (type: `array`):

Official typeOfSetAside codes: SBA, SBP, 8A, 8AN, HZC, HZS, SDVOSBC, SDVOSBS, WOSB, WOSBSS, EDWOSB, EDWOSBSS, LAS, IEE, ISBEE, BICiv, VSA, VSS.

## `placeOfPerformanceState` (type: `array`):

Two-letter state codes. A notice must match one of them.

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

Posted-date window ending today (UTC). SAM allows at most one year.

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

When on, a notice is emitted only if its solicitation (or notice id) was not seen last run, or its version changed. Seen notices are stored in the bid-matcher key-value store under SEEN_NOTICES.

## `includeAwardComps` (type: `boolean`):

Attach USAspending count, median, min, max, and top 3 winners. Notices with no NAICS get count 0 and null amounts.

## `lookbackYears` (type: `integer`):

How many years of contract awards (date signed) to use for comps.

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

Cap on notices kept after SAM results are merged, newest posted date first. Each SAM request uses limit 1000, then this cap keeps the newest.

## `includePointOfContact` (type: `boolean`):

Off by default. When on, each row gains pointOfContact with the primary contact name, email, and phone.

## Actor input object example

```json
{
  "naics": [
    "333120"
  ],
  "setAside": [
    "SBA"
  ],
  "placeOfPerformanceState": [
    "TX"
  ],
  "postedWithinDays": 7,
  "onlyNew": true,
  "includeAwardComps": true,
  "lookbackYears": 3,
  "maxResults": 100,
  "includePointOfContact": false
}
```

# Actor output Schema

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

Matching SAM.gov opportunities. Fields are described in the dataset schema.

# 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 = {
    "naics": [
        "333120"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("colinsabby/federal-bid-matcher").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 = { "naics": ["333120"] }

# Run the Actor and wait for it to finish
run = client.actor("colinsabby/federal-bid-matcher").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 '{
  "naics": [
    "333120"
  ]
}' |
apify call colinsabby/federal-bid-matcher --silent --output-dataset

```

## MCP server setup

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

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/kVU06jiISgHnOlThp/builds/CbhBieSTsitFHpqIc/openapi.json
