# SAM.gov Scraper — Federal Contract Opportunities (`khadinakbar/sam-gov-scraper`) Actor

Search public SAM.gov federal contract opportunities through the official API. Return solicitations, sources sought, awards, contacts, deadlines, set-asides, and direct SAM.gov links.

- **URL**: https://apify.com/khadinakbar/sam-gov-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Lead generation, MCP servers, Jobs
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 opportunity returneds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## SAM.gov Scraper — Federal Contract Opportunities

Search published U.S. federal contract opportunities through SAM.gov's official Opportunities Public API. Use it for capture, proposal, and business-development workflows that need structured solicitations, sources sought, special notices, and award notices instead of a brittle browser scrape.

Each dataset row is one validated opportunity with its title, solicitation number, notice type, agency, NAICS and classification codes, set-aside, dates, place of performance, public contracting contacts, award details when present, attachment URLs, and direct SAM.gov links.

### When to use it

Use this actor when a government contractor, capture team, proposal team, or AI agent needs a current shortlist of federal opportunities by keyword, NAICS code, set-aside, agency, location, notice type, posted date, or response deadline. It is especially suitable for scheduled bid monitoring because all results come from SAM.gov's paginated public API.

Do not use it to submit, edit, publish, or access restricted SAM.gov notices. It searches only published opportunities. It also does not download or OCR attachments; attachment URLs are returned where the official API provides them.

### No credentials required

The actor uses the public endpoint that powers SAM.gov search: `https://sam.gov/api/prod/opportunities/v2/search`. It does not need a SAM.gov account, personal API key, cookie, or proxy. The public gateway requires a non-empty compatibility query parameter, which the actor supplies internally without using a secret. The endpoint requires a posted-date range; this actor defaults to the last 30 days through today when dates are omitted.

### Quick start

Search recent cybersecurity solicitations and sources sought:

```json
{
  "query": "cybersecurity",
  "noticeTypes": ["o", "k", "r"],
  "naicsCode": "541512",
  "postedFrom": "2026-07-01",
  "postedTo": "2026-07-19",
  "maxResults": 100
}
```

Search small-business opportunities in Virginia:

```json
{
  "setAsideCode": "SBA",
  "state": "VA",
  "postedFrom": "2026-07-01",
  "postedTo": "2026-07-19",
  "maxResults": 250
}
```

### Inputs

| Field | Purpose |
| --- | --- |
| `query` | Matches the opportunity title through the official API. |
| `noticeTypes` | Optional SAM.gov codes: `o` solicitation, `k` combined synopsis, `p` presolicitation, `r` sources sought, `s` special notice, `a` award, `u` justification, `g` surplus sale, or `i` intent to bundle. |
| `naicsCode` | One 2–6 digit NAICS code, such as `541512`. |
| `setAsideCode` | One official code, such as `SBA`, `8A`, `HZC`, `SDVOSBC`, or `WOSB`. |
| `state` | Two-letter place-of-performance state or territory code. |
| `agency` | Official organization-name filter, such as `Department of Defense`. |
| `postedFrom`, `postedTo` | Inclusive posted-date range in `YYYY-MM-DD` or `MM/DD/YYYY`. SAM.gov permits at most one year. |
| `responseDueFrom`, `responseDueTo` | Optional inclusive deadline range; both must be supplied together. |
| `maxResults` | Hard cap of 1–10,000 dataset records and billable opportunity events. Defaults to 100. |

### Dataset fields

The default dataset has a stable, agent-friendly shape. `noticeId`, `title`, `samUrl`, `sourceUrl`, `contacts`, and `attachmentUrls` are always present. Fields that the official source omits are explicitly `null`, not silently removed.

`samUrl` is the public opportunity landing page. `sourceUrl` is the official API record URL when supplied. `contacts` contains public points of contact. `award` is populated only on award notices that include award data. `attachmentUrls` is a URL list, never a downloaded file.

| Field | Example | Downstream use |
| --- | --- | --- |
| `noticeId` | `ff826a59eac743c4a1a07ff5e0cf3e3a` | Stable deduplication key for a monitoring workflow. |
| `title`, `noticeType`, `active` | `Network modernization`, `Solicitation`, `true` | Bid/no-bid triage. |
| `agency`, `naicsCode`, `setAsideCode` | `Department of Defense`, `541512`, `SBA` | Fit scoring and routing to a capture owner. |
| `postedDate`, `responseDeadline` | `2026-07-18`, `2026-08-17T17:00:00-04:00` | Proposal-calendar prioritization. |
| `contacts` | `[{"name":"Ada Lovelace","email":"ada@example.gov"}]` | Public contracting contact handoff. |
| `samUrl`, `attachmentUrls` | Official SAM.gov URLs | Human review and proposal-document collection. |

Example persisted record:

```json
{
  "noticeId": "ff826a59eac743c4a1a07ff5e0cf3e3a",
  "title": "Network modernization services",
  "noticeType": "Solicitation",
  "postedDate": "2026-07-18",
  "responseDeadline": "2026-08-17T17:00:00-04:00",
  "naicsCode": "541512",
  "setAsideCode": "SBA",
  "agency": "DEPARTMENT OF DEFENSE",
  "contacts": [{ "name": "Ada Lovelace", "title": "Contracting Officer", "email": "ada@example.gov", "phone": null }],
  "attachmentUrls": [],
  "samUrl": "https://sam.gov/opp/ff826a59eac743c4a1a07ff5e0cf3e3a/view",
  "sourceUrl": "https://api.sam.gov/opportunities/v2/search?noticeid=ff826a59eac743c4a1a07ff5e0cf3e3a"
}
```

### Workflow: from search to bid queue

1. Schedule a daily query for one NAICS, agency, or set-aside and use a narrow posted-date range.
2. Deduplicate records by `noticeId`; retain a record when its deadline, notice type, or title makes it a potential fit.
3. Rank candidates by your capabilities and response deadline, then open `samUrl` to review the official notice and any supplied attachments.
4. Assign a capture owner from the public `contacts` data. A row is a discovery signal, not a bid recommendation.

For a reliable pagination workflow, use `maxResults` as the run's total cap. The actor requests the official API in pages of up to 100 records and stops when it has reached the cap or the source has no more results.

### Run outcomes

Every terminal path writes `OUTPUT` and `RUN_SUMMARY` in the default key-value store:

- `COMPLETE`: all fetched pages were processed successfully.
- `PARTIAL`: useful opportunities were returned, but a page failed, a source record was malformed, or the event-charge limit was reached.
- `VALID_EMPTY`: the official API completed normally but had no matching opportunities.
- `INVALID_INPUT`: a filter or date range needs correction; the run succeeds so automation can inspect the diagnostic.
- `UPSTREAM_FAILED`: the official API returned no usable data for a valid request; the run fails honestly.

### Pricing

This actor uses Pay per Event plus Apify platform usage.

- Actor start: $0.00005 per configured GB.
- Opportunity returned: $0.0035 for each validated dataset record.

The actor caps opportunity charges at `maxResults`, reports the maximum event cost at startup, and returns only records that have passed basic shape validation. Platform compute and storage usage are additional and charged by Apify separately.

For example, a run capped at 100 returned opportunities has a maximum event charge of `$0.35005` (100 × `$0.0035` plus one 512 MB start event charged as one GB). If SAM.gov returns 12 opportunities, the event charge is `$0.04205`, plus Apify platform usage.

### API and AI-agent use

After you deploy this private actor, call `sam-gov-scraper` through the Apify API with an input such as:

```bash
curl -X POST 'https://api.apify.com/v2/acts/khadinakbar~sam-gov-scraper/runs?token=YOUR_APIFY_TOKEN' \
  -H 'content-type: application/json' \
  -d '{"query":"cybersecurity","noticeTypes":["o","r"],"postedFrom":"2026-07-01","postedTo":"2026-07-19","maxResults":25}'
```

For an AI agent, use this actor to identify federal opportunities matching a clearly stated capability or NAICS code. Do not use it for entity registration, award-spending history, restricted notices, or document extraction. The agent should treat `VALID_EMPTY` as a completed search, surface `INVALID_INPUT` or `CONFIG_ERROR` to its operator, and continue with returned records for `PARTIAL`.

### Scheduling guidance

For a daily monitoring feed, use a narrow posted range such as yesterday through today, a stable filter set, and `maxResults` sized to your workflow. To capture revisions as well as new notices, schedule one search per relevant NAICS or agency rather than relying on an unbounded broad query.

### Source and limitations

The actor queries SAM.gov's documented Opportunities Public API. API availability, returned fields, and rate limits are controlled by SAM.gov. The public API returns the latest active version of an opportunity; it is not an archive of every historical revision. The actor intentionally makes no claim that a published notice is a viable bid, complete solicitation package, or contract award guarantee.

As of July 19, 2026, the implementation targets SAM.gov's live public search endpoint at `https://sam.gov/api/prod/opportunities/v2/search`. Re-check the official API documentation and search behavior before changing filters or source fields.

### Troubleshooting and responsible use

If `INVALID_INPUT` reports a date-range issue, use dates no more than one year apart and provide both response-deadline bounds. If the actor returns `VALID_EMPTY`, broaden the date range, remove a filter, or choose a different notice type rather than retrying the identical request. If it returns `UPSTREAM_FAILED`, retry later after checking the public SAM.gov search page; the endpoint may be unavailable or have changed.

Use returned public data only for lawful procurement research and follow the governing solicitation and SAM.gov requirements. Verify all material details on the official notice before making a business, proposal, contact, or compliance decision.

# Actor input Schema

## `query` (type: `string`):

Use this to search words in the SAM.gov opportunity title, for example cybersecurity or cloud migration. It defaults to no keyword so filters can return all matching opportunities. This is not a full-text search of attached solicitation documents.

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

Use this to limit results to published SAM.gov notice-type codes. Select values such as o for Solicitation, k for Combined Synopsis/Solicitation, r for Sources Sought, or a for Award Notice. It defaults to all supported types. This is not a contract award category.

## `naicsCode` (type: `string`):

Use this to filter opportunities by one 2-to-6-digit NAICS industry code, for example 541512. It is optional and the official API accepts one code per request. This is not a PSC or a free-text industry name.

## `setAsideCode` (type: `string`):

Use this to filter by one SAM.gov set-aside code, for example SBA, 8A, HZC, or SDVOSBC. It is optional and should use the official short code. This is not a description such as 'small business'.

## `state` (type: `string`):

Use this to filter the work location by a two-letter state or territory code, for example VA. It is optional and maps to SAM.gov's place-of-performance filter. This is not the contracting agency's state.

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

Use this to filter by the SAM.gov organization name, for example Department of Defense. It is optional and supports the official organization-name field. This is not a contracting officer's name.

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

Use this to set the first posted date as YYYY-MM-DD or MM/DD/YYYY, for example 2026-07-01. It defaults to 30 days ago and SAM.gov permits at most one year per search. This is not a response deadline.

## `postedTo` (type: `string`):

Use this to set the last posted date as YYYY-MM-DD or MM/DD/YYYY, for example 2026-07-19. It defaults to today and must not precede posted from. This is not an archive date.

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

Use this with response deadline to include only opportunities whose response date is on or after this date. Use YYYY-MM-DD or MM/DD/YYYY, for example 2026-07-20. Both deadline fields are required together. This is not a posted-date filter.

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

Use this with response deadline from to include only opportunities whose response date is on or before this date. Use YYYY-MM-DD or MM/DD/YYYY, for example 2026-08-31. Both deadline fields are required together. This is not an award date.

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

Use this to cap validated SAM.gov opportunity records written to the dataset. Enter an integer from 1 through 10000, for example 100. It defaults to 100 and prevents charges beyond this number of returned opportunities. This is not an API page count.

## Actor input object example

```json
{
  "query": "cybersecurity",
  "noticeTypes": [
    "o",
    "k",
    "r"
  ],
  "naicsCode": "541512",
  "setAsideCode": "SBA",
  "state": "VA",
  "agency": "Department of Defense",
  "postedFrom": "2026-07-01",
  "postedTo": "2026-07-19",
  "responseDueFrom": "2026-07-20",
  "responseDueTo": "2026-08-31",
  "maxResults": 100
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `output` (type: `string`):

No description

## `summary` (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 = {
    "query": "cybersecurity",
    "noticeTypes": [
        "o",
        "k",
        "r"
    ],
    "postedFrom": "2026-07-01",
    "postedTo": "2026-07-19",
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/sam-gov-scraper").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 = {
    "query": "cybersecurity",
    "noticeTypes": [
        "o",
        "k",
        "r",
    ],
    "postedFrom": "2026-07-01",
    "postedTo": "2026-07-19",
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/sam-gov-scraper").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 '{
  "query": "cybersecurity",
  "noticeTypes": [
    "o",
    "k",
    "r"
  ],
  "postedFrom": "2026-07-01",
  "postedTo": "2026-07-19",
  "maxResults": 100
}' |
apify call khadinakbar/sam-gov-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/SZC3tSm0Rhoc9KRzO/builds/QpL5bZcYcnsQBSsdM/openapi.json
