# Grants.gov API & SAM.gov Scraper — Federal Grants Feed (`owlabee/grants-gov-api`) Actor

Monitor federal grants and contract opportunities via the official Grants.gov and SAM.gov APIs, plus recent USAspending awards. Keyword search, normalized JSON, new/updated flags for scheduled runs and webhooks. Pay per opportunity record ($0.001).

- **URL**: https://apify.com/owlabee/grants-gov-api.md
- **Developed by:** [Owlabee](https://apify.com/owlabee) (community)
- **Categories:** Lead generation, News
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 opportunity records

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

## Grants.gov API & SAM.gov Scraper — Federal Grants Feed

![Grants.gov API & SAM.gov Scraper — Federal Grants Feed: banner with the main output fields](https://api.apify.com/v2/key-value-stores/r8pLvIribNPHYI9gX/records/gov-opportunity-feed-banner.png)

**Grants.gov API scraper and SAM.gov feed**: search federal grant opportunities on Grants.gov and contract opportunities on SAM.gov by keyword through the official APIs, plus recent USAspending awards, and get normalized JSON with new and updated flags. Schedule it with a webhook and it becomes a daily federal grants and RFP alert feed.

> **Renamed on 2026-11-07:** this Actor's address changed from `owlabee/gov-opportunity-feed` to `owlabee/grants-gov-api`. Saved tasks, schedules, webhooks and integrations keep working, because they point to the Actor's ID, which did not change. Calls by the old name no longer work, so please update anything that calls it by name: API URLs (`owlabee~grants-gov-api`), MCP tool lists (`owlabee/grants-gov-api`) and bookmarks.

### What it does

This Actor turns the official US federal opportunity APIs into one clean, keyword-filtered feed. It queries **Grants.gov** (federal grants, no key needed), **SAM.gov** (federal contract opportunities, free personal API key) and optionally **USAspending.gov** (who recently *won* similar grants and contracts), normalizes every record to the same field names, and flags what is **new or updated since your last run** so a daily schedule only emits changes.

It is built for grant writers, government-contracting business developers, SBIR/STTR applicants, nonprofits, universities, and anyone who wants an RFP alert feed without logging into three portals. Results land in an Apify dataset you can download as JSON, CSV or Excel, read over the API, push to a webhook, or query from an AI agent through the Apify MCP server.

Only official public APIs are used — no HTML scraping of sam.gov or grants.gov, no proxies, no login.

### Coverage

| Level | Jurisdiction | Official source | What it lists |
|---|---|---|---|
| Federal | United States | Grants.gov API | Federal grant opportunities (posted, forecasted, closed, archived) |
| Federal | United States | SAM.gov Get Opportunities API (free key) | Federal contract notices: solicitations, presolicitations, sources sought, awards |
| Federal | United States | USAspending.gov API (optional) | Recent federal grant and contract awards |
| Federal | United States | NIH RePORTER API (`nihReporter`) | Recent NIH research awards: recipient, amount, project dates, principal investigators (names), abstract |
| Federal | United States | NSF Award Search API (`nsfAwards`) | Recent NSF awards: recipient, obligated amount, program, principal investigator (name), abstract |
| Federal | United States | Federal Register API (`federalRegister`) | Notices matching "notice of funding opportunity" and your keyword, which often never reach a Grants.gov keyword search; the deadline stays in `datesText` as published |
| Local | City of Los Angeles, CA | data.lacity.org `hf3r-utnq` (RAMP Open Bid Opportunities) | Open bids with close dates and links to the RAMP notice |
| Local | New York City, NY | data.cityofnewyork.us `p8e4-uwuv` (Anticipated RFP) | School Construction Authority RFPs planned but not yet released, with estimated cost |
| Local | Montgomery County, MD | data.montgomerycountymd.gov `eeq6-nnwe` (Solicitations) | Active and closed county solicitations with issue and closing dates |
| Local | City of Mesa, AZ | data.mesaaz.gov `dfcn-ivuc` (Purchasing - Solicitations) | City solicitations (RFB, RFP, RFQ) and their status; no close date in the dataset |
| Local | Cook County, IL | datacatalog.cookcountyil.gov `ag43-fvd7` (Procurement - Intent to Execute) | Contracts about to be executed, with recommended vendor and amount (`noticeType: "intent-to-award"`) |
| State | State of Illinois | data.illinois.gov `6rb8-ntpm` (Future Solicitations) | Construction solicitations planned for a future bid date, with approximate cost |
| Local (all states) | Every US school and library in E-Rate (opt-in: `erate-470`) | datahub.usac.org `jp7a-89nd` + `39tn-hjzv` (FCC Form 470 and services requested) | Schools and libraries seeking bids for internet, Wi-Fi, network equipment and telecom; the bid window closes on the allowable contract date. Narrow by state with `sledStates` |
| State | State of Delaware (opt-in: `delaware`, `delaware-closed`) | data.delaware.gov `2hnj-zwix` (Open Bids), `yhim-4378` (Recently Closed Bids) | Every statewide open bid and recently closed bid, with deadlines, agency codes and UNSPSC codes |
| State | State of California (opt-in: `ca-grants`) | data.ca.gov California Grants Portal (CKAN datastore, updated daily) | Active and forecasted state grants: deadlines, available funds, eligible applicant types, geography (`noticeType: "grant"`) |
| State | State of New York (opt-in: `ny-sucf`) | data.ny.gov `vtxv-3j2b` (SUCF Advertised Procurements) | State University Construction Fund design and construction procurements, with due dates and estimated value ranges |
| State | State of Texas (opt-in: `txdot-lettings`) | data.texas.gov `qh8x-rm8r` (TxDOT Official and Unofficial Bid Items) | Highway lettings in the next 42 days, grouped into one record per project, with the bid opening date and the sealed engineer's estimate |
| State | State of Texas (opt-in: `txdot-bid-tabulations`) | data.texas.gov `de7b-7dna` (TxDOT Bid Tabulations) | Bids received in the last 24 months, one record per project with the apparent low bidder and bid total (`noticeType: "bid-tabulation"`; not an award) |
| Local | City of Baton Rouge and East Baton Rouge Parish, LA (opt-in: `baton-rouge`) | data.brla.gov `u9zk-8nix` (Bid Openings) | Bid openings with date and time, department, buyer and the bid-results page; `postedWithinDays` applies to the bid date |
| Local | Cook County, IL (opt-in: `cook-county-buying-plan`) | datacatalog.cookcountyil.gov `cbhc-xvrm` (Buying Plan) | Contracts the county plans to buy this year, with value range, term and the anticipated advertisement quarter (`noticeType: "forecast"`) |
| Local | San Diego County, CA (opt-in: `san-diego-county`) | data.sandiegocounty.gov `rrhp-9sw9` (Contracting Opportunities Forecast) | Contracts the county expects to post, with the anticipated posting date and a "good fit for small and local businesses" flag |
| Local | Montgomery County, MD (opt-in: `montgomery-md-awards`) | data.montgomerycountymd.gov `ecp6-b47r` (Proposed Awardees) | Proposed awardees per solicitation, with vendor and small-business flag (`noticeType: "intent-to-award"`) |
| Local | New York City, NY (opt-in: `nyc-mwbe-upcoming`) | data.cityofnewyork.us `ww83-bcks` (M/WBE Upcoming Procurements) | Small purchases set for M/WBE vendors this fiscal year, with NIGP codes in `classifications` |
| Local | City of Los Angeles, CA (opt-in: `la-city-awards`) | data.lacity.org `h8mw-iegk` (RAMP Awards) | Contract awards with vendor and amount (`noticeType: "award"`) |

State and local (SLED) coverage is the nineteen official open-data datasets above (eighteen read through the Socrata API, the California Grants Portal through its CKAN datastore API), with no login and no key; it is not a nationwide state and local bid feed, apart from E-Rate, which covers schools and libraries in every state. The first six were checked live on 2026-11-01 and the thirteen opt-in datasets on 2026-11-07. **An empty `sledJurisdictions` runs the original six datasets only, and always will:** datasets added on 2026-11-07 or later run only when you select them (or select `all`, which follows the catalog as it grows), so a saved input or schedule never starts running, and paying for, more searches. Checked and left out: New York City "Current RFP" (`bzjf-rmtp`, every listed due date had passed) and Ramsey County, MN (`iu7r-dzmj`, not updated since April 2024). Statewide e-procurement portals that need a login or page scraping (Cal eProcure, Texas SmartBuy, NY Contract Reporter) are not covered; the TxDOT, SUCF and Delaware datasets are those agencies' own open-data exports. Every record carries `jurisdiction` and `level` (`federal`, `state` or `local`), so one feed can be split by government level. Each state or local dataset and keyword is one search run, charged under the same `search-run` event as a federal source and keyword, and each record under the same per-record event.

To rank what the feed finds against your own organization, pass its items to [Grant Matching & RFP Bid/No-Bid Scorer (AI) — Grants.gov](https://apify.com/owlabee/grant-matching).

### Why this Actor

| | This Actor | Typical scraper in this category | Do it yourself |
|---|---|---|---|
| Inputs accepted | Keywords, one or both sources, Grants.gov statuses, a posting window, SAM.gov filters (NAICS, set-aside, state, notice type) and optional USAspending awards | Keywords or filters for a single portal | One API client per portal, written and kept current by you |
| Modes | A full feed, or monitor mode that emits only new or updated records with `isNew` and `isUpdated` flags, with an optional detail fetch for grants | A one-shot listing; change detection is left to you | A database of what you have already seen and a diff job |
| Output fields | One normalized shape across three sources: ids, title, agency, status, posted and close dates, url, plus grant details (award ceiling and floor, total funding, eligibilities, agency contact), SAM.gov notice fields (NAICS, set-aside, place of performance, points of contact) and award fields (recipient, amount) | The portal's own field names from one source | Whatever each API returns, mapped by you |
| Pricing unit | Per record saved, per grant detail fetched, and one small search-run charge per source and keyword; unchanged records in monitor mode cost nothing | Per record, sometimes a flat monthly fee | Your time and your rate-limit handling |
| Needs an API key or proxies | No proxies, no login; a free SAM.gov personal key only for SAM.gov | Often browser scraping behind proxies that breaks when the portal changes | A SAM.gov key and your own retry logic |
| Agent/MCP ready | Yes: pin link, `fetch-actor-details`, pay per run | Sometimes | You write the tool wrapper |
| Limits | Official APIs only: about two Grants.gov requests per second, the SAM.gov daily quota of your key, a one-year posting window; state and local bids, grants and awards from nineteen official open-data datasets only (see Coverage) | Varies by portal | Whatever the portals' quotas allow |

- Three official APIs, one record shape: a grant, a contract notice and an award share the same core fields, so one downstream pipeline reads them all.
- Monitor mode turns a daily schedule into a change feed, and you are charged only for what changed.
- The search-run charge is small and the per-record charge is per record saved, so a keyword that returns nothing costs almost nothing.
- Error items instead of failed runs: a source that is down or a key that is rejected produces one coded item and the other keywords still run.
- Points of contact, set-asides and NAICS codes come straight from the agency's own record, never from a scraped page.

### How to use

1. Enter your **Keywords** (one per line), choose **Sources** (Grants.gov is on by default; add SAM.gov and paste your free **SAM.gov API key**), and set **Posted within (days)**.
2. Optionally turn on **Fetch Grants.gov details** (award ceiling/floor, funding, eligibilities, description), **Include recent USAspending awards**, and **Only new or updated since last run** for scheduled monitoring with a **Webhook URL**.
3. Click **Start**. Records appear in the dataset as they are saved; schedule the Actor daily to get a change feed.

#### Quick start input

The same input the Store runs in its daily automated test, so it is cheap and always available; paste it into the JSON tab of the input form or send it as the body of an API or MCP call:

```json
{
  "keywords": [
    "small business"
  ],
  "sources": [
    "grantsGov"
  ],
  "oppStatuses": [
    "posted"
  ],
  "postedWithinDays": 14,
  "maxResults": 25,
  "fetchDetails": false,
  "includeRecentAwards": false,
  "onlyNewSinceLastRun": false
}
```

#### Ready-to-run inputs

Each block validates against the input schema. The key placeholder is a string you replace, never a real key in a README.

**A Grants.gov keyword feed with details, in monitor mode**

```json
{
  "keywords": [
    "rural broadband",
    "digital equity"
  ],
  "sources": [
    "grantsGov"
  ],
  "oppStatuses": [
    "posted",
    "forecasted"
  ],
  "postedWithinDays": 30,
  "maxResults": 200,
  "fetchDetails": true,
  "maxDetails": 100,
  "onlyNewSinceLastRun": true,
  "stateStoreName": "broadband-grants-state"
}
```

**A SAM.gov run for total small business set-asides under one NAICS code, with a webhook**

```json
{
  "keywords": [
    "cybersecurity"
  ],
  "sources": [
    "samGov"
  ],
  "samApiKey": "<YOUR_SAM_GOV_API_KEY>",
  "samFilters": {
    "naics": "541512",
    "setAside": "SBA",
    "state": "VA",
    "ptype": "o,k"
  },
  "postedWithinDays": 7,
  "maxResults": 100,
  "onlyNewSinceLastRun": true,
  "webhookUrl": "https://example.com/hooks/sam-gov-feed"
}
```

**Recent USAspending awards next to the open grants for a keyword**

```json
{
  "keywords": [
    "workforce development"
  ],
  "sources": [
    "grantsGov"
  ],
  "oppStatuses": [
    "posted"
  ],
  "postedWithinDays": 30,
  "maxResults": 100,
  "includeRecentAwards": true,
  "maxAwards": 50
}
```

**E-Rate bids from schools and libraries in two states, plus Delaware and TxDOT bids (opt-in state and local datasets)**

```json
{
  "keywords": [
    "wi-fi",
    "network"
  ],
  "sources": [
    "sled"
  ],
  "sledJurisdictions": [
    "erate-470",
    "delaware",
    "txdot-lettings"
  ],
  "sledStates": [
    "AZ",
    "CA"
  ],
  "postedWithinDays": 30,
  "maxResults": 300,
  "onlyNewSinceLastRun": true,
  "stateStoreName": "erate-wifi-state"
}
```

**Open California state grants for a program area**

```json
{
  "keywords": [
    "wildfire"
  ],
  "sources": [
    "sled"
  ],
  "sledJurisdictions": [
    "ca-grants"
  ],
  "maxResults": 100
}
```

### Input

| Field | Type | Required | Description |
|---|---|---|---|
| `keywords` | string\[] | yes | Search terms; each is searched in every enabled source |
| `sources` | string\[] | no | `grantsGov`, `samGov`, `sled` (state and local open-data bids and grants), `nihReporter`, `nsfAwards`, `federalRegister` (default `["grantsGov"]`) |
| `oppStatuses` | string\[] | no | Grants.gov statuses: `forecasted`, `posted`, `closed`, `archived` (default `["posted"]`) |
| `postedWithinDays` | integer | no | Only records posted in the last N days, 1–365 (default 30) |
| `maxResults` | integer | no | Cap on dataset items per run across all keywords and sources (default 500) |
| `fetchDetails` | boolean | no | Call Grants.gov `fetchOpportunity` for each emitted grant (default false) |
| `maxDetails` | integer | no | Cap on detail fetches per run (default 100) |
| `samApiKey` | string (secret) | for SAM.gov | Free personal SAM.gov public API key; SAM.gov is skipped when missing |
| `samFilters` | object | no | `{ "naics", "setAside", "state", "ptype" }` passed to SAM.gov as `ncode`, `typeOfSetAside`, `state`, `ptype` |
| `sledJurisdictions` | string\[] | no | State and local datasets to read when `sled` is on: `la-city`, `nyc-sca`, `montgomery-md`, `mesa-az`, `cook-county-il`, `illinois`, and opt-in `erate-470`, `delaware`, `delaware-closed`, `ca-grants`, `ny-sucf`, `txdot-lettings`, `txdot-bid-tabulations`, `baton-rouge`, `cook-county-buying-plan`, `san-diego-county`, `montgomery-md-awards`, `nyc-mwbe-upcoming`, `la-city-awards`; `all` = every dataset including future ones. Empty = the first six only (fixed) |
| `sledStates` | string\[] | no | Two-letter state codes that narrow national datasets (today `erate-470`); other datasets ignore it. Empty = every state |
| `socrataAppToken` | string (secret) | no | Optional free Socrata app token; only raises the open-data portals' rate limits, never required |
| `includeRecentAwards` | boolean | no | Add recent USAspending grant/contract awards for the keywords (default false) |
| `maxAwards` | integer | no | Cap on award records per keyword from USAspending, NIH RePORTER and NSF each (default 50) |
| `onlyNewSinceLastRun` | boolean | no | Monitor mode: emit only new/updated records, flagged `isNew` / `isUpdated` (default false) |
| `stateStoreName` | string | no | Named key-value store holding monitor snapshots (default `gov-opportunity-feed-state`) |
| `webhookUrl` | string | no | POST target for the run summary and emitted items |

### Output example

![Sample output of Grants.gov API & SAM.gov Scraper — Federal Grants Feed as a table: the dataset overview columns from the quick-start run](https://api.apify.com/v2/key-value-stores/r8pLvIribNPHYI9gX/records/gov-opportunity-feed-output.png)

Grants.gov opportunity (with `fetchDetails` on):

```json
{
  "source": "grantsGov",
  "recordType": "opportunity",
  "keyword": "small business",
  "opportunityId": "351083",
  "number": "SBA-OED-26-001",
  "title": "Small Business Development Centers Program",
  "agency": "Small Business Administration",
  "agencyCode": "SBA",
  "status": "posted",
  "docType": "synopsis",
  "postedDate": "2026-10-10",
  "closeDate": "2026-12-15",
  "lastUpdated": "2026-10-12T13:30:00.000Z",
  "assistanceListings": ["59.037"],
  "awardCeiling": null,
  "awardFloor": 0,
  "expectedAwards": 62,
  "estimatedTotalFunding": 125000000,
  "costSharing": true,
  "fundingCategories": ["Business and Commerce"],
  "fundingInstruments": ["Cooperative Agreement"],
  "eligibilities": ["Public and State controlled institutions of higher education"],
  "agencyContactName": "Jane Doe",
  "agencyContactEmail": "grants@sba.gov",
  "description": "The SBDC program provides counseling & training to small businesses. …",
  "url": "https://www.grants.gov/search-results-detail/351083",
  "detailsFetched": true,
  "isNew": true,
  "isUpdated": false,
  "jurisdiction": "United States",
  "level": "federal",
  "fetchedAt": "2026-10-16T12:00:00.000Z"
}
```

State and local bid (`sources: ["sled"]`, City of Los Angeles):

```json
{
  "source": "socrata",
  "recordType": "opportunity",
  "keyword": "services",
  "opportunityId": "la-city:232811",
  "title": "ANTISCALANT (PRETREAT PLUS 0100), MFR. KING LEE TECHNOLOGIES",
  "agency": "General Services",
  "status": "Open",
  "postedDate": "2026-10-30T21:33:30",
  "closeDate": "2026-11-05T19:00:00",
  "url": "https://www.rampla.org/s/opportunity-details?id=006Ql00000nrYTxIAM",
  "jurisdiction": "City of Los Angeles",
  "level": "local",
  "state": "CA",
  "dataset": "la-city",
  "datasetId": "data.lacity.org/hf3r-utnq",
  "datasetUrl": "https://data.lacity.org/d/hf3r-utnq",
  "noticeType": "bid",
  "solicitationNumber": "232811",
  "type": "RFQ - Request for Quote",
  "category": "Commodity",
  "description": null,
  "estimatedValue": null,
  "estimatedValueText": null,
  "contactName": null,
  "vendor": null,
  "location": null,
  "fetchedAt": "2026-11-01T12:00:00.000Z"
}
```

SAM.gov notices carry `noticeId`, `solicitationNumber`, `department` / `subTier` / `office`, `type`, `responseDeadLine`, `naicsCode`, `setAside`, `placeOfPerformance`, `pointOfContact[]` (names, emails and phones exactly as published by the agency), `uiLink` as `url`, and `descriptionUrl`. USAspending awards carry `awardId`, `recipientName`, `recipientUei`, `awardAmount`, `awardType`, `startDate` / `endDate` and a usaspending.gov `url`. State and local records carry `jurisdiction`, `level`, `state`, `country` (`US`), `dataset` (the key from `sledJurisdictions`), `datasetId`, `datasetUrl`, `noticeType` (`bid`, `forecast`, `intent-to-award`, `grant`, `bid-tabulation` or `award`), `solicitationNumber`, `type`, `category`, `estimatedValue` (a number when the dataset gives one) with the original `estimatedValueText`, `contactName`, `vendor` (Cook County intent to execute, Montgomery County proposed awardees, Los Angeles awards and TxDOT bid tabulations), `location`, `classifications` (`[{ scheme, code, description }]`: Delaware's UNSPSC codes, New York City's NIGP codes), `eligibilities` (California grants' eligible applicant types) and `deadlineText` (a deadline published as text, e.g. "Ongoing"); `url` is the notice link when the dataset has one, otherwise the dataset page. Their `source` is `socrata`, or `ckan` for the California Grants Portal. The datasets without a posting date (`nyc-sca`, `illinois`, `ca-grants`, `txdot-lettings`, `cook-county-buying-plan`, `san-diego-county`, `nyc-mwbe-upcoming`) return their current listing, so `postedWithinDays` does not apply to them; for `illinois`, `closeDate` is the estimated bid date, for `san-diego-county` the anticipated posting date, for `baton-rouge` the bid opening, for `erate-470` the allowable contract date (the end of the 28-day bid window), and for `txdot-lettings` the bid opening. E-Rate records take `state` and `jurisdiction` from the applicant (for example `"Sacramento, CA"`) and list the services requested in `type` and `category`. TxDOT records are one per project: `estimatedValue` is the sealed engineer's estimate for a letting and the apparent low bid for a tabulation. Every record shares `source`, `recordType`, `keyword`, `opportunityId`, `title`, `agency`, `status`, `postedDate`, `closeDate`, `url`, `jurisdiction`, `level` and `fetchedAt`.

NIH RePORTER and NSF records (`recordType: "award"`) carry `awardId` (NIH project number or NSF award id), `recipientName`, `recipientUei`, `recipientCity`, `recipientState` (also as `placeOfPerformanceState`), `awardAmount` (NIH: the fiscal-year award; NSF: funds obligated to date), `startDate`, `endDate`, `fiscalYear` (NIH), `program` (NIH activity code or NSF program), `assistanceListing`, `principalInvestigators` (names only, never contact details) and the abstract in `description`; `postedDate` is the award notice or award date. Federal Register records carry `documentNumber`, `documentType`, `action`, `agencies`, the abstract in `description`, `datesText` (the notice's DATES paragraph, where application deadlines are stated), `commentsCloseOn` and `pdfUrl`; `closeDate` is left empty because the deadline is free text.

Error items look like `{ "source": "samGov", "keyword": "…", "error": "SAM_AUTH_FAILED", "errorMessage": "…" }` and are charged at the opportunity rate, because the work to discover the problem was done.

If the output saves you time, a review on the Store page helps other buyers find this Actor; the Store invites you to leave one after you have run it a few times.

### Alerts and delivery

- **Schedules.** Create a schedule on the Actor page (Console → Schedules) with `onlyNewSinceLastRun: true`; a daily schedule with `postedWithinDays: 7` catches every new posting and emits only the changes. The first run is the baseline, later runs cost only the search runs plus the records that are new or updated.
- **The Actor's own `webhookUrl`.** When set, the Actor sends one POST at the end of the run with a JSON body of `actor`, `runId`, `produced` (records saved), `detailsFetched`, `keywords` (how many were searched), `sources`, `monitor` (true in monitor mode), `truncated` (units stopped by a time budget), `charges` (count per event), `limitReached`, `finishedAt`, then `items` (the emitted records themselves, up to 500) and `errors` (the error items). In monitor mode that payload is the alert: only new and updated records are in `items`. Delivery is attempted once and recorded as `webhookDelivered` on the `SUMMARY` record; it never fails the run.
- **Apify integrations.** The Integrations tab of the Actor page adds Actor webhooks on run events (succeeded, failed, timed out, aborted) with a payload template that can carry `{{resource.defaultDatasetId}}`, plus ready-made Slack, Make, Zapier, Google Sheets and email integrations that run on every finished run; in monitor mode an empty dataset means nothing changed, so set the receiving tool to skip empty runs.
- **API.** The latest finished run's items: `GET https://api.apify.com/v2/acts/owlabee~grants-gov-api/runs/last/dataset/items?status=SUCCEEDED&format=json` (`format=csv` for a spreadsheet, `fields=source,title,agency,postedDate,closeDate,setAside,naicsCode,url` for a short list); its summary: `GET https://api.apify.com/v2/acts/owlabee~grants-gov-api/runs/last/key-value-store/records/SUMMARY`. A specific run uses `GET https://api.apify.com/v2/actor-runs/<runId>/dataset/items`. All calls take your API token as `token` or a bearer header.

### Pricing

Pay per event. You only pay for what the Actor produces; set a **maximum cost per run** in the run options to cap spend.

| Event | Price | Notes |
|---|---|---|
| Opportunity record | $0.001 | Per dataset item: Grants.gov opportunity, SAM.gov notice, USAspending award, or error item |
| Opportunity detail | $0.002 | Per successful Grants.gov `fetchOpportunity` call (only with `fetchDetails`) |
| Search run | $0.004 | Once per source and keyword searched, whatever the number of pages, including searches that return nothing, only already-seen records in monitor mode, or an error |
| Actor start | $0.00005 | Apify platform event |

**Example:** 1,000 opportunities from one keyword on Grants.gov ≈ $1.00 + 1 search run $0.004 ≈ **$1.00**. 1,000 opportunities with details ≈ $3.00 + $0.004 ≈ $3.00. In monitor mode the first run is a baseline and is charged for every record it emits; later runs are charged only for new or updated records, plus the search run for each keyword.

Store pricing discounts: users on the Scale plan (Silver) pay 10% less per event, Business (Gold) 20% less.

### Limits and fair use

- Requests are rate-limited per host (≤ 2 req/s) with exponential backoff on 429/5xx.
- **SAM.gov quotas:** a personal, non-federal API key has a small daily request allowance. The Actor asks for up to 1,000 notices per request so one keyword normally costs one request; keep the keyword list short on SAM.gov schedules.
- `postedWithinDays` applies to the Grants.gov open date, the SAM.gov `postedFrom`/`postedTo` window (max 1 year) and the USAspending award start date.
- `maxResults` caps records *fetched* per run; in monitor mode unchanged records are not emitted, so the number of dataset items can be lower.
- Grants.gov OR-matches the words of a keyword ("small business" matches "small" or "business"); SAM.gov matches the notice title.
- **Time budget.** Each keyword on each source (a Grants.gov, SAM.gov or USAspending search plus its detail fetches) gets 10 minutes, and each keyword on each state or local dataset gets 2 minutes with a 15-second request deadline, and a unit that delivers no new records or details for 60 seconds is stopped. Records fetched before the stop are kept and charged as usual and the unit is listed under `truncated` in the `SUMMARY` record (`TIME_BUDGET`); a unit that produced nothing returns a charged error item (`TIME_BUDGET` or the source's error code). Requests time out after 20 seconds (30 for SAM.gov, NIH RePORTER, NSF and the Federal Register, 45 for USAspending) including retries, NIH and NSF requests are spaced at least one second apart, and `Retry-After` pauses are capped at 10 seconds. After two keywords in a row fail on the same source, the remaining keywords for that source are not requested and each gets one charged `SOURCE_UNAVAILABLE` error item. In `onlyNewSinceLastRun` mode, Grants.gov paging stops after two full pages that match the stored snapshot exactly.
- Memory: default run memory is 512 MB (256 MB is enough for typical runs, up to 1024 MB allowed).

### How to get a free SAM.gov API key

1. Create or sign in to an account at [sam.gov](https://sam.gov) (any individual can register; no entity registration is needed).
2. Open your profile → **Account Details**.
3. Under **Public API Key**, click **Request** (or **Regenerate**), enter your password, and copy the key shown.
4. Paste it into the **SAM.gov API key** field of this Actor. It is stored encrypted as a secret input and never written to logs.

Keys are personal and tied to the daily quota of your account type; federal-agency and entity-associated accounts get larger allowances.

### Related Actors

Other pay-per-event Actors from the same account, all limited-permission and agent-friendly:

- [Building Permits Scraper — Roofing & Construction Leads](https://apify.com/owlabee/building-permits-scraper) — city and county building permits for the same construction and infrastructure leads.
- [License Verification API — TDLR, DBPR, DORA, WA DOH, NPI](https://apify.com/owlabee/license-verification-api) — verify the professional licenses of bidders and awardees from official state records.
- [Hiring Signals & ATS Jobs Scraper — Greenhouse, Lever, Ashby](https://apify.com/owlabee/job-postings-api) — spot contractors staffing up after an award through their public job boards.

### Guide and code examples

- Guide: [Grants.gov API: Federal Grant Opportunities as JSON](https://owlabee.com/grants-gov-api/), covering the source, its fields and limits, and curl and MCP examples.
- Guide: [SAM.gov Contract Opportunities API Feed by Keyword](https://owlabee.com/sam-gov-contract-opportunities/), covering the source, its fields and limits, and curl and MCP examples.
- No-code recipe: [New Grants.gov Opportunities to Google Sheets with Zapier](https://owlabee.com/grants-gov-to-google-sheets-zapier/), step by step with Apify's official Zapier app and a ready input.
- Runnable examples (curl, Python, Node.js and an MCP config): [owlabee/owlabee on GitHub](https://github.com/owlabee/owlabee/tree/main/examples/grants-gov-api).

### Use from AI agents (MCP)

Pin this Actor in the Apify MCP server with one link: `https://mcp.apify.com?tools=owlabee/grants-gov-api`, or let the agent find it with the `search-actors` tool. It is pay-per-event with limited permissions, so agents can discover it, inspect the input schema with `fetch-actor-details` and pay per run through agentic payments. Prompts that map directly onto the input:

1. "Find federal grants posted in the last 14 days about rural broadband and tell me the close dates and award ceilings."
2. "Every morning, check SAM.gov for new total-small-business set-aside solicitations under NAICS 541512 in Virginia and send the new ones to my webhook."
3. "Who won federal grants or contracts mentioning 'workforce development' in the last 30 days, and which agencies currently have related opportunities open?"
4. "Which schools and libraries in Arizona posted E-Rate Form 470s for Wi-Fi this month, and when do their bid windows close?"

The agent receives the same dataset records shown in the output example above.

Copy this block to call the Actor through the Apify MCP server with the `call-actor` tool; the `input` is the quick-start input above, so it runs at the same low cost, and the tool returns the run's dataset items. Clients that want the schema first call `fetch-actor-details` with `owlabee/grants-gov-api`.

```json
{
  "tool": "call-actor",
  "arguments": {
    "actor": "owlabee/grants-gov-api",
    "input": {
      "keywords": [
        "small business"
      ],
      "sources": [
        "grantsGov"
      ],
      "oppStatuses": [
        "posted"
      ],
      "postedWithinDays": 14,
      "maxResults": 25,
      "fetchDetails": false,
      "includeRecentAwards": false,
      "onlyNewSinceLastRun": false
    }
  }
}
```

### FAQ

**Does this need proxies or a login?** No. Every source is an official public JSON API (the state and local datasets through the Socrata open-data API) that work from Apify's standard datacenter infrastructure. Only SAM.gov requires a (free) API key.

**How is cost controlled?** Set `maxResults`, `maxDetails` and `maxAwards`, plus the run's maximum total charge. The Actor charges each record the moment it is saved and stops cleanly when any limit is reached.

**How does "only new or updated" work?** For every source + keyword the Actor stores a compact fingerprint per opportunity in the named key-value store. On the next run, unseen ids are emitted with `isNew: true`; ids whose title, status, dates, set-aside or award fields changed are emitted with `isUpdated: true`; unchanged ones are skipped and not charged. Delete the store (or change `stateStoreName`) to reset.

**Can an AI agent use this?** Yes; see "Use from AI agents (MCP)" above for the pin link and example prompts. Schedules and webhooks work the same way from the Console or the API.

**What happens on errors?** A failing source/keyword produces one error item (`FETCH_FAILED`, `NIH_REPORTER_BAD_RESPONSE`, `NSF_BAD_RESPONSE`, `NSF_QUERY_FAILED`, `FEDERAL_REGISTER_BAD_RESPONSE`, `FEDERAL_REGISTER_QUERY_FAILED`, `SAM_AUTH_FAILED`, `SAM_RATE_LIMITED`, `SAM_HTTP_<status>`, `TIME_BUDGET`, `SOURCE_UNAVAILABLE`, and for state and local datasets `SOCRATA_HTTP_<status>`, `SOCRATA_RATE_LIMITED`, `SOCRATA_TOKEN_REJECTED`, `SOCRATA_QUERY_FAILED`, `CKAN_HTTP_<status>`, `CKAN_QUERY_FAILED`) instead of failing the run. Each state and local dataset counts as its own source, so one portal being down does not stop the others. A missing SAM.gov key skips that source with a log line.

**Why is `awardCeiling` null for some grants?** Grants.gov publishes "none" or leaves it empty when the agency did not set a ceiling; the Actor returns `null` rather than guessing.

**Will my saved state and local input start reading the new datasets?** No. An empty "State & local jurisdictions" list means the six datasets of 2026-11-01 and nothing else, so a saved input or schedule makes the same searches at the same cost. Select the new datasets by name, or `all`, to add them; each dataset and keyword is one search run.

**Can I try it for free?** Yes. The Apify free plan comes with monthly platform credit, and the quick-start input above costs a few cents per run, so you can test it on your own inputs before paying anything.

**How do I find this Actor again?** Bookmark it on the Store page (the bookmark icon next to the title); bookmarked Actors are listed in your Console, and the Store page shows new versions as they ship.

### Support

Questions, bugs or a source you'd like added? Open an issue on the Actor's **Issues** tab, or email jacob@owlabee.com.

### Changelog

- 2026-11-07 Three more federal sources, opt-in: `nihReporter` (NIH research awards), `nsfAwards` (NSF awards) and `federalRegister` (notices of funding opportunity, deadline kept as published text). NIH and NSF are capped per keyword by `maxAwards`, like USAspending. No key for any of them; same events and prices.
- 2026-11-07 State and local expansion, opt-in: E-Rate FCC Form 470 (every US school and library seeking telecom bids, with a new `sledStates` filter), Delaware open and recently closed bids (UNSPSC codes), the California Grants Portal, NY State University Construction Fund procurements, TxDOT lettings (one record per project), TxDOT bid tabulations (apparent low bidder), Baton Rouge bid openings, Cook County's buying plan, San Diego County's contracting forecast, Montgomery County proposed awardees, New York City M/WBE upcoming small purchases and Los Angeles RAMP awards. New record fields, additive: `country`, `classifications`, `eligibilities`, `deadlineText`, and `noticeType` values `grant`, `bid-tabulation` and `award`. An empty `sledJurisdictions` now means exactly the six 2026-11-01 datasets, fixed, so saved inputs keep the same searches and cost; the new datasets run only when selected, or with the new `all` alias. Same events and prices.
- 2026-11-07 Renamed from `owlabee/gov-opportunity-feed` to `owlabee/grants-gov-api` so the address matches what people search for. Input, output and pricing are unchanged; calls by Actor ID, saved tasks and schedules are unaffected. Calls to the old address no longer work; update API URLs and MCP tool lists.
- 2026-10-27 README: comparison table, ready-to-run inputs, alerts and delivery section, this changelog.
- 2026-11-01 State and local bids: `sled` source reading six official Socrata open-data datasets (City of Los Angeles, New York City School Construction Authority, Montgomery County MD, City of Mesa AZ, Cook County IL, State of Illinois), `sledJurisdictions` and optional `socrataAppToken` inputs, `jurisdiction` and `level` on every record. Uses the existing record and search-run events; federal defaults unchanged.
- 2026-10-25 Pricing round: a search-run event charged once per source and keyword (work-based, so empty searches carry their own small charge), pluralized event titles, Store discount tiers for the Scale and Business plans; Console rows confirmed 2026-10-26.
- 2026-10-23 Time budgets per keyword and source with charged `TIME_BUDGET` and `SOURCE_UNAVAILABLE` items, request deadlines that include retries, `Retry-After` pauses capped, monitor-mode paging stops after two unchanged pages; Store title now names Grants.gov and SAM.gov, SEO fields, quick-start input, the MCP section and a USAspending awards task example added; default run memory lowered from the platform default.
- 2026-10-17 Published on the Store; first charged-events check on the platform passed.
- 2026-10-16 First deploy.

### Legal

This Actor uses only the official public APIs of Grants.gov, SAM.gov and USAspending.gov; it does not scrape their websites. Use the data in compliance with each source's terms (SAM.gov data is subject to GSA's API terms of service and your own API key agreement) and applicable law. Points of contact are government employees' business contact details as published by the issuing agency. The Actor is not a consumer reporting agency and its output must not be used for employment, credit, insurance, housing or tenant screening decisions (FCRA).

# Actor input Schema

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

Search terms, one per line. Each keyword is searched in every enabled source. Grants.gov OR-matches the words of a keyword; SAM.gov matches the notice title. The prefilled value is the cheap example used by Apify's daily automated test.

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

Which official sources to query. Grants.gov needs no key. SAM.gov needs the free personal API key in "SAM.gov API key" below and is skipped (with a log line) when the key is missing. State & local reads official open-data bid, grant and award datasets (no login, no key); pick them under "State & local jurisdictions". NIH RePORTER and NSF awards return recent research awards (recipient, amount, principal investigators by name), capped per keyword by "Max awards per keyword"; Federal Register returns notices that match "notice of funding opportunity" plus the keyword, with the deadline as published text. None of them needs a key.

## `oppStatuses` (type: `array`):

Grants.gov statuses to include. "posted" = open for applications, "forecasted" = announced but not yet open.

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

Only opportunities posted in the last N days (1–365). For USAspending awards this is the award start-date window, for NIH the award notice date, for NSF the award date, for the Federal Register the publication date. State & local datasets without a posting date (nyc-sca, illinois, ca-grants, txdot-lettings, cook-county-buying-plan, san-diego-county, nyc-mwbe-upcoming) return their current listing.

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

Upper bound on dataset items across all keywords and sources per run (opportunities, awards and error items). Use together with the run's maximum cost to control spend.

## `fetchDetails` (type: `boolean`):

Call the Grants.gov fetchOpportunity endpoint for each emitted grant to add award ceiling/floor, estimated funding, expected awards, eligibilities, funding categories and the description. Each detail fetch is a separate paid event.

## `maxDetails` (type: `integer`):

Cap on Grants.gov detail fetches per run (only used when "Fetch Grants.gov details" is on).

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

Your free personal SAM.gov public API key (sam.gov → sign in → Account Details → Public API Key). Required only for the SAM.gov source. Stored encrypted and never logged.

## `samFilters` (type: `object`):

Optional SAM.gov filters: {"naics": "541511", "setAside": "SBA", "state": "VA", "ptype": "o"}. ptype codes: o = Solicitation, k = Combined Synopsis/Solicitation, p = Presolicitation, r = Sources Sought, s = Special Notice, a = Award Notice (comma-separate several). setAside codes: SBA, SBP, 8A, 8AN, HZC, HZS, SDVOSBC, SDVOSBS, WOSB, WOSBSS, EDWOSB, EDWOSBSS, LAS, IEE, ISBEE, BICiv, VSA, VSS.

## `sledJurisdictions` (type: `array`):

Which state and local datasets the "State & local" source reads. Empty = the original six (la-city, nyc-sca, montgomery-md, mesa-az, cook-county-il, illinois); that meaning is fixed, so a saved input never starts running, and paying for, datasets added later. Datasets added on 2026-11-07 run only when you pick them: erate-470 = E-Rate FCC Form 470, every US school and library seeking internet, Wi-Fi and telecom bids (narrow it with "States"); delaware = State of Delaware open bids, with UNSPSC codes; delaware-closed = Delaware recently closed bids; ca-grants = California Grants Portal, active and forecasted state grants with eligible applicants and amounts; ny-sucf = New York State University Construction Fund design and construction procurements; txdot-lettings = TxDOT highway lettings in the next 42 days, one record per project; txdot-bid-tabulations = TxDOT bid results of the last 24 months with the apparent low bidder; baton-rouge = City of Baton Rouge and East Baton Rouge Parish bid openings (the window applies to the bid date); cook-county-buying-plan = Cook County contracts planned for the year; san-diego-county = San Diego County contracting forecast; montgomery-md-awards = Montgomery County proposed awardees; nyc-mwbe-upcoming = New York City M/WBE upcoming small purchases with NIGP codes; la-city-awards = City of Los Angeles RAMP contract awards. `all` = every dataset, including ones added in future versions (the cost grows with them). Each dataset and keyword is one search run.

## `sledStates` (type: `array`):

Optional two-letter state codes, e.g. \["AZ", "CA"]. Narrows national datasets (today erate-470) to applicants in those states; datasets that cover one state or city are not affected. Empty = every state.

## `socrataAppToken` (type: `string`):

Optional free Socrata app token. It only raises the open-data portals' shared rate limits; the State & local source works without it. Stored encrypted and never logged.

## `includeRecentAwards` (type: `boolean`):

Also query USAspending.gov for grants and contracts recently awarded for the same keywords — useful to see who recently won similar awards. Each award is a dataset item charged at the opportunity rate.

## `maxAwards` (type: `integer`):

Cap on award records per keyword from each award source: USAspending (only used when "Include recent USAspending awards" is on), NIH RePORTER and NSF awards.

## `onlyNewSinceLastRun` (type: `boolean`):

Monitor mode for schedules: remember what was seen per source and keyword in the state store and emit only opportunities that are new or whose key fields changed, flagged with isNew / isUpdated. The first run is a baseline and emits (and charges for) everything.

## `stateStoreName` (type: `string`):

Named key-value store that holds the monitor snapshots. Use a different name per schedule if two schedules share keywords.

## `webhookUrl` (type: `string`):

If set, the Actor POSTs a JSON run summary plus the emitted items (max 500) to this URL when it finishes. Failures are logged, never fatal.

## Actor input object example

```json
{
  "keywords": [
    "small business"
  ],
  "sources": [
    "grantsGov"
  ],
  "oppStatuses": [
    "posted"
  ],
  "postedWithinDays": 14,
  "maxResults": 25,
  "fetchDetails": false,
  "maxDetails": 100,
  "samFilters": {},
  "sledJurisdictions": [],
  "sledStates": [],
  "includeRecentAwards": false,
  "maxAwards": 50,
  "onlyNewSinceLastRun": false,
  "stateStoreName": "gov-opportunity-feed-state"
}
```

# Actor output Schema

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

One item per grant, contract opportunity or award in the default dataset (source, title, agency, status, postedDate, closeDate, isNew, url; error items carry error and errorMessage). Fields are described in dataset_schema.json.

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

SUMMARY record in the run's default key-value store: sources queried, records produced, new/updated counts, charges and webhook delivery status, written when the run finishes.

# 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": [
        "small business"
    ],
    "sources": [
        "grantsGov"
    ],
    "oppStatuses": [
        "posted"
    ],
    "postedWithinDays": 14,
    "maxResults": 25,
    "fetchDetails": false,
    "includeRecentAwards": false,
    "onlyNewSinceLastRun": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("owlabee/grants-gov-api").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": ["small business"],
    "sources": ["grantsGov"],
    "oppStatuses": ["posted"],
    "postedWithinDays": 14,
    "maxResults": 25,
    "fetchDetails": False,
    "includeRecentAwards": False,
    "onlyNewSinceLastRun": False,
}

# Run the Actor and wait for it to finish
run = client.actor("owlabee/grants-gov-api").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": [
    "small business"
  ],
  "sources": [
    "grantsGov"
  ],
  "oppStatuses": [
    "posted"
  ],
  "postedWithinDays": 14,
  "maxResults": 25,
  "fetchDetails": false,
  "includeRecentAwards": false,
  "onlyNewSinceLastRun": false
}' |
apify call owlabee/grants-gov-api --silent --output-dataset

```

## MCP server setup

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

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/eXuDRKy3VKemb8R8g/builds/C0oAfpJax58BA3xfl/openapi.json
