# US Federal Contracts & Grants — SAM.gov + USAspending (`vhsgreed/us-federal-contracts`) Actor

Official US federal procurement data in one run: SAM.gov contract opportunities (RFPs, solicitations, sources sought, award notices), USAspending.gov award history, and Grants.gov funding opportunities. Filter by keyword, NAICS, agency, set-aside, place of performance and response deadline.

- **URL**: https://apify.com/vhsgreed/us-federal-contracts.md
- **Developed by:** [Karl Sundström](https://apify.com/vhsgreed) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.95 / 1,000 record scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## US Federal Contracts & Grants

**Official US federal procurement data — contract opportunities, awards, and grants — from SAM.gov, USAspending.gov and Grants.gov. No scraping.**

This actor pulls the same authoritative feeds that the multi-thousand-dollar GovCon platforms resell, and hands you clean, provenance-tagged JSON: SAM.gov contract opportunities (RFPs, solicitations, combined synopses, sources sought, award notices), USAspending.gov award history, and Grants.gov funding opportunities — filterable by keyword, NAICS, agency, set-aside, place of performance and response deadline.

It is the US-market counterpart to `eu-ted-tenders-api-fresh`: same buyer, same workflow, new continent.

### Why this one

- **Official sources only.** GSA's own `open.gsa.gov` APIs and the free SAM.gov daily bulk extract, USAspending (Treasury), Grants.gov (HHS). There is no anti-bot wall to fight and no ToS grey area — this is published government data, designed to be consumed programmatically.
- **The no-key path is the *rich* path.** SAM.gov's Data Services publishes a nightly full snapshot of active notices (~230 MB, no key, no registration) that carries the **full description text** and a public opportunity link — fields the rate-limited API returns only as a URL.
- **Cleaner than the current market.** Existing actors mostly dump the raw API payload. This one normalises to a stable, flat schema, stamps every record with `source`, `source_url`, `fetched_at` and `actor_version`, and never fabricates a missing value.
- **Built for the real constraint.** SAM.gov keys are personal and rate-limited, so the actor is designed for incremental, scoped pulls — not naive full-table dumps that hit the daily cap in one run.

### Input

| Field | Type | Notes |
|---|---|---|
| `sources` | array | `sam.gov`, `usaspending.gov`, `grants.gov` (default `["usaspending.gov", "grants.gov"]` — see *Prefilled default* below) |
| `samApiKey` | secret | Optional. Your personal SAM.gov public API key. Omit to use the free bulk CSV (no key). |
| `useBulkCsv` | boolean | Stream the free official daily Contract Opportunities CSV (~230 MB, no key) when no API key is set. Off by default. |
| `keywords` | array | Narrow free-text terms (title/description/solicitation match) |
| `naicsCodes` | array | NAICS codes (also passed to the USAspending award search) |
| `agencies` | array | Department/subtier names (one per request) |
| `setAsides` | array | Official GSA set-aside codes: `SBA`, `SBP`, `8A`, `8AN`, `HZC`, `HZS`, `SDVOSBC`, `SDVOSBS`, `WOSB`, `WOSBSS`, `EDWOSB`, `EDWOSBSS`, `LAS`, `IEE`, `ISBEE`, `BICiv`, `VSA`, `VSS`. SAM.gov takes **one** per request, so each code is run as a separate scoped request. |
| `procurementTypes` | array | `o` solicitation, `k` combined synopsis, `p` pre-solicitation, `r` sources sought, `s` special notice, `a` award, `u` justification (J\&A), `g` sale of surplus property, `i` intent to bundle. (`f` and `l` are retired upstream.) |
| `placeOfPerformanceState` | string | Two-letter state code(s) (e.g. `VA` or `VA,MD`) |
| `postedFrom` / `postedTo` | string | `YYYY-MM-DD`; auto-chunked to SAM.gov's 1-year window; also bounds the USAspending period |
| `responseDeadlineFrom` / `responseDeadlineTo` | string | `YYYY-MM-DD` |
| `maxRecords` | integer | Hard cap across all sources, split evenly between them (default 200) |
| `maxApiRequests` | integer | Safety budget (default 9 — fits a 10/day personal SAM.gov key) |
| `includeFullText` | boolean | Fetch full notice descriptions on the API path (costs 1 request per notice); ignored on the bulk-CSV path, which already includes full text |

#### Prefilled default — designed to pass a 5-minute, secret-free QA run

The **prefilled input** deliberately uses the two **keyless, small, fast** sources —
`sources: ["usaspending.gov", "grants.gov"]` with `maxRecords: 200` — so a run:

- needs **no API key** (both sources are unauthenticated), and
- **does not touch the ~230 MB bulk CSV** (that download only happens when you explicitly
  pick `sam.gov` *and* set `useBulkCsv: true`).

A measured prefilled run returns ~200 records (100 awards + 100 grants) in **under 4 seconds**
using the default 9-request budget. Selecting `sam.gov` without a key and without `useBulkCsv`
logs a clear message and is skipped rather than silently downloading 230 MB.

#### Example

```json
{
  "sources": ["sam.gov", "usaspending.gov"],
  "useBulkCsv": true,
  "keywords": ["cybersecurity", "zero trust"],
  "naicsCodes": ["541512"],
  "setAsides": ["SBA", "SDVOSBC"],
  "procurementTypes": ["o", "k", "r"],
  "responseDeadlineFrom": "2026-09-01",
  "maxRecords": 1500
}
```

The above uses the **no-key bulk CSV** path for SAM.gov (set `useBulkCsv: true`, leave
`samApiKey` empty). To use the live API instead, provide `samApiKey` and set `maxApiRequests`
within your key's daily quota.

### Output

One dataset record per opportunity / award / grant. Contract-opportunity record (abridged):

```json
{
  "record_type": "contract_opportunity",
  "notice_id": "abc123def456",
  "solicitation_number": "W91QUZ-26-R-0001",
  "title": "Zero Trust Architecture Support Services",
  "opportunity_type": "Solicitation",
  "posted_date": "2026-09-10 14:00:00",
  "response_deadline": "2026-10-15 16:00:00",
  "agency": "DEPT OF DEFENSE.ARMY",
  "naics_code": "541512",
  "classification_code": "R408",
  "set_aside": "Total Small Business",
  "set_aside_code": "SBA",
  "place_of_performance_state": "VA",
  "place_of_performance_zip": "22060",
  "award_number": null,
  "award_amount": null,
  "awardee_name": null,
  "description_url": "https://api.sam.gov/prod/opportunities/v1/noticedesc?...",
  "attachment_links": ["https://.../SOW.pdf"],
  "source": "sam.gov",
  "source_url": "https://sam.gov/opp/abc123def456/view",
  "fetched_at": "2026-09-27T10:00:00Z",
  "actor_version": "0.1.0"
}
```

Award records (`record_type: "award"`) carry `award_id`, `recipient_name`, `award_amount`, `awarding_agency`, dates and NAICS. Grant records (`record_type: "grant"`) carry `opportunity_number`, `agency`, funding ceilings/floors, `response_deadline`, contact details and CFDA numbers.

### Pricing

Pay-per-event: **run start $0.004** + **$0.0009 per record** (tiers down to $0.0004 at Diamond). *(Final, 2026-09-27.)*

A typical 1,500-record run costs **$0.004 + 1,500 × $0.0009 ≈ $1.35**. Market for the same dataset (Apify store API, 2026-09-27): the closest paid competitors charge $0.001 (`jungle_synthesizer`, 169 users — our named leader, which we sit 10% under), $0.0025 (`scrapesage`) and $0.003 (`fortuitous_pirate`) per record. The run-volume leader, `automation-lab`, charges a $0.000115 commodity floor with only 12 users; we deliberately do **not** chase that floor (see `PLAN.md` §5).

### Responsible use

- This actor consumes **official, public** data via documented APIs and the free SAM.gov bulk extract. Still run it considerately.
- **Honour your own SAM.gov key's daily quota.** Keys are personal to your account (default 10 requests/day for a non-federal personal key; 1,000/day once role-backed). Set `maxApiRequests` within your budget; the actor will not exceed it.
- SAM.gov `includeFullText` and attachment downloads cost extra upstream requests — leave them off unless you need them.
- Some fields (contracting-officer names, grant contact names/emails) can be personal data. Do not use them for unsolicited marketing, and check your own obligations under GDPR/CCPA before republishing.
- Respect the upstream services' own terms. We publish a tool; how you run it is your choice.

### Development

```bash
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt        # apify~=4.0, httpx~=0.28, pytest
pytest -q                              # 22 tests, no network, no API key
python -m src.main                     # local run (reads local input.json)
```

`pytest` output for this draft: **22 passed** (streaming CSV parser incl. quoted multi-line
descriptions, filters, normalisation, pagination, request-budget hard stop, 429 handling,
and a check that API keys never appear in error messages).

Note: `requirements.txt` pins `apify~=4.0` (not the older `~=1.7`) because pay-per-event
billing via `Actor.charge` does not exist in the 1.x SDK.

# Actor input Schema

## `sources` (type: `array`):

Which official sources to pull from in this run. SAM.gov = contract opportunities; USAspending = award history / actual spend; Grants.gov = funding opportunities. The prefilled default uses the two keyless sources so a run needs no API key and finishes in seconds. Allowed values: sam.gov, usaspending.gov, grants.gov.

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

Your personal SAM.gov public API key (SAM.gov → Account Details). Required only for live keyword-scoped pulls via the Get Opportunities API. Leave empty to use the free daily bulk CSV (enable 'Use bulk CSV' below) instead, which needs no key. Keys are personal to your account; the default budget is 10 requests/day for a non-federal personal key with no SAM role.

## `useBulkCsv` (type: `boolean`):

When true and no SAM.gov API key is set, stream the official daily Contract Opportunities CSV (~230 MB, no key, no registration). It carries the full description text and a public opportunity link for free, but the file is large — set a small 'Max records' to stop early. Leave this OFF for a fast prefilled run.

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

Free-text terms matched (case-insensitive, any-of) against opportunity title / description / solicitation number. Keep narrow for SAM.gov — its rate limits make broad pulls a design constraint.

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

NAICS codes to filter on (e.g. 541512). Also used for the USAspending award search.

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

Filter by associated organization name (department or subtier), e.g. "Department of Defense". SAM.gov accepts a single organization name per request, so each value is a separate scoped request counted against 'Max upstream API requests'.

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

Small-business set-aside codes. SAM.gov accepts ONE set-aside value per request, so each code you add is executed as a separate scoped request (counted against maxApiRequests). Values are the official GSA Set-Aside codes (open.gsa.gov get-opportunities-public-api). Allowed values: SBA, SBP, 8A, 8AN, HZC, HZS, SDVOSBC, SDVOSBS, WOSB, WOSBSS, EDWOSB, EDWOSBSS, LAS, IEE, ISBEE, BICiv, VSA, VSS.

## `procurementTypes` (type: `array`):

o=Solicitation, k=Combined Synopsis/Solicitation, p=Pre-solicitation, r=Sources Sought, s=Special Notice, a=Award Notice, u=Justification (J\&A), g=Sale of Surplus Property, i=Intent to Bundle Requirements (DoD-funded). Retired upstream: f=Foreign Government Standard, l=Fair Opportunity/Limited Sources — use u instead. Allowed values: o, k, p, r, s, a, u, g, i.

## `placeOfPerformanceState` (type: `string`):

Two-letter US state code(s) (e.g. VA, or "VA,MD"). Optional. Matched against the notice place-of-performance state.

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

Start of the posted-date window. SAM.gov allows at most a 1-year window per request; the actor chunks longer windows automatically. Also bounds the USAspending time period.

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

End of the posted-date window. Defaults to today when omitted.

## `responseDeadlineFrom` (type: `string`):

Only return opportunities whose response deadline is on/after this date. Records with no deadline are excluded when this filter is set.

## `responseDeadlineTo` (type: `string`):

Only return opportunities whose response deadline is on/before this date.

## `maxRecords` (type: `integer`):

Hard cap on records pushed to the dataset across all sources. Split evenly between the selected sources. Keep it modest for SAM.gov runs (its API quota is the real constraint); a small value also makes the bulk-CSV path stop early.

## `maxApiRequests` (type: `integer`):

Safety budget for outbound requests in this run. Keeps the actor inside a personal SAM.gov daily quota (default 10/day). SAM.gov returns no rate-limit headers, so this hard cap is the only guard.

## `includeFullText` (type: `boolean`):

If true, fetches each SAM.gov notice's full description — this costs one extra API request per notice and is usually unaffordable on a personal key. Listing description URLs is always free. Ignored on the bulk-CSV path, which already includes full text.

## Actor input object example

```json
{
  "sources": [
    "usaspending.gov",
    "grants.gov"
  ],
  "useBulkCsv": false,
  "keywords": [],
  "naicsCodes": [],
  "agencies": [],
  "setAsides": [],
  "procurementTypes": [],
  "maxRecords": 200,
  "maxApiRequests": 9,
  "includeFullText": false
}
```

# Actor output Schema

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

Dataset of opportunities, awards and grants.

## `resultsJson` (type: `string`):

Full dataset items as raw JSON.

## `runView` (type: `string`):

Inspect this run, its logs and storages in Apify Console.

# 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 = {
    "sources": [
        "usaspending.gov",
        "grants.gov"
    ],
    "useBulkCsv": false,
    "maxRecords": 200,
    "maxApiRequests": 9
};

// Run the Actor and wait for it to finish
const run = await client.actor("vhsgreed/us-federal-contracts").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 = {
    "sources": [
        "usaspending.gov",
        "grants.gov",
    ],
    "useBulkCsv": False,
    "maxRecords": 200,
    "maxApiRequests": 9,
}

# Run the Actor and wait for it to finish
run = client.actor("vhsgreed/us-federal-contracts").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 '{
  "sources": [
    "usaspending.gov",
    "grants.gov"
  ],
  "useBulkCsv": false,
  "maxRecords": 200,
  "maxApiRequests": 9
}' |
apify call vhsgreed/us-federal-contracts --silent --output-dataset

```

## MCP server setup

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

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/CsDkYegIHCmx451bc/builds/1kj81HbhxOt55bYHc/openapi.json
