L logiover
business · May 22, 2026 · 6 min read

How to Scrape USASpending.gov Federal Contracts & Grants in 2026

Harvest authoritative US federal award data — contracts, grants, recipients, amounts and agencies — from the official USASpending.gov API at the scale of hundreds of thousands of records.

Every dollar the US federal government obligates — contracts, grants, loans, direct payments — is published, by law, on USASpending.gov. It’s the Treasury’s open-data portal and the single most authoritative source of who-got-paid-what in the federal market. The data is free and the API is documented. The catch is volume: a single fiscal year holds millions of award records, and the API is built for paginated retrieval, not bulk download. This guide covers how the USASpending POST API actually behaves and how to pull award data cleanly at scale.

What’s worth extracting

The USASpending award-search API returns one record per award action. Flattened, a usable record carries:

  • Award identity — the generated unique award ID (PIID for contracts, FAIN for grants), award type, and a link to the award detail page.
  • Recipient — recipient name, UEI/DUNS-era identifier, parent company, recipient location (state, country, congressional district).
  • Money — total obligated amount, current and potential award amount, and total outlays (what’s actually been disbursed vs. obligated).
  • Agency — awarding agency and sub-agency (e.g. Department of Defense / Department of the Army), and the funding agency where it differs.
  • Classification — award type (A/B/C/D for contract vehicles), description of the work, NAICS and PSC codes for contracts, CFDA program number for assistance.
  • Performance — period-of-performance start and end dates, action date, place of performance (state and country).

For business-development use you center on recipient, agency, amount and NAICS/PSC. For budget analytics you center on agency rollups, obligations vs. outlays, and time series on action date.

The API is open — the friction is shape and scale

USASpending doesn’t fight you with bots. It fights you with structure:

  • POST, not GET — the search endpoint takes a JSON filter body, not query strings. Filters nest (award type codes, time periods as date-range arrays, agency tier objects). Malformed filter bodies return a 422 with validation detail you have to read carefully.
  • Pagination depth — results page at up to 100 per request, and like most large APIs there’s a practical ceiling on how deep a single filter set will page before you must narrow. Pulling a full year means partitioning by month, agency or award type and stitching.
  • Obligated vs. outlay confusion — the API exposes several monetary fields that mean different things. Summing the wrong one produces numbers that don’t reconcile with published totals.
  • Transient errors under load — the endpoint returns intermittent 5xx during heavy queries; a long run without backoff-and-retry dies mid-pull.
  • Recipient identity drift — the same company appears under slightly different recipient names and identifiers across years (post-DUNS transition to UEI). De-duplication is on you.

Each is solvable; together they’re why a quick script becomes a project. A managed actor encapsulates the POST filter construction, the partitioning, the retry policy and the field normalization.

Run the USASpending.gov Federal Awards Scraper — official Treasury API, no key, automatic partitioning and backoff. Hundreds of thousands to millions of award records per run, flattened to clean rows.

How the query body works

A representative filter body for the award-search endpoint:

{
  "filters": {
    "award_type_codes": ["A", "B", "C", "D"],
    "time_period": [
      { "start_date": "2025-10-01", "end_date": "2026-09-30" }
    ],
    "agencies": [
      { "type": "awarding", "tier": "toptier", "name": "Department of Defense" }
    ],
    "keywords": ["cybersecurity"]
  },
  "fields": ["Award ID", "Recipient Name", "Award Amount", "Awarding Agency"],
  "page": 1,
  "limit": 100
}

To pull a whole fiscal year of DoD contracts you don’t run this once — you bucket the time_period into months (or split by sub-agency) so each filter set stays inside the page-depth ceiling, then merge. The scraper drives this partitioning from your high-level request.

Build it yourself vs. use a managed scraper

  • Roll your own — a day to a working single-filter script, then a long tail: building the POST bodies for every filter combination, partitioning to beat page depth, choosing the correct money field, retry-with-backoff, and recipient de-duplication. Plus re-checking the field list whenever USASpending revises its API version.
  • Managed actor — running in minutes, partitioning and retries handled, output flat. The award data is free, so pricing is essentially compute.

For a one-time market-sizing query, a script is reasonable. For a contractor-intelligence feed that has to reconcile against published totals and refresh on a schedule, the partitioning and money-field correctness are exactly what you want someone else to maintain.

Schema design for downstream use

A clean per-award row:

{
  "award_id": "FA860126C0001",
  "award_type": "D",
  "recipient_name": "ACME DEFENSE SYSTEMS INC",
  "recipient_uei": "ABC123DEF456",
  "recipient_state": "VA",
  "recipient_district": "VA-11",
  "awarding_agency": "Department of Defense",
  "awarding_sub_agency": "Department of the Air Force",
  "naics_code": "541512",
  "psc_code": "D399",
  "description": "IT SERVICES - CLOUD MIGRATION",
  "total_obligated": 4250000.00,
  "total_outlay": 1180000.00,
  "potential_amount": 12000000.00,
  "period_start": "2026-01-15",
  "period_end": "2028-01-14",
  "action_date": "2026-01-10",
  "place_of_performance_state": "VA",
  "detail_url": "https://www.usaspending.gov/award/CONT_AWD_FA860126C0001",
  "scraped_at": "2026-05-22T11:00:00Z"
}

Schema choices worth making early:

  • Store total_obligated and total_outlay separately, and label them. Obligated is committed; outlay is paid. Mixing them is the most common reconciliation bug.
  • Keep the generated award_id as your key, and carry the recipient UEI so you can build a stable company dimension despite name drift.
  • Persist NAICS and PSC for contracts, CFDA for assistance. These codes are how the GovCon market is segmented; free-text description alone is unsearchable.
  • Record action_date distinct from period start. Time-series spending analysis runs on action date, not performance window.

Typical use cases

  • Government contractor capture planning — see who’s winning what, with which agency, at what value, in your NAICS — then target teaming partners and recompetes.
  • Federal budget and procurement analytics — agency and sub-agency spending rollups, obligations-vs-outlays trends, market sizing by code.
  • Grant tracking — surface new awards in cybersecurity, biotech, climate, AI or defense as they post.
  • B2B GovCon lead generation — federal awardees are pre-qualified prospects; segment them by agency, geography and dollar band.
  • Watchdog and investigative journalism — flag sole-source awards, unusual outlays, or contractor concentration in a district.
  • GovTech data feeds — power dashboards and alerting products with award-level data refreshed nightly.

The common thread is authoritativeness plus breadth. This is the official record; the value is having all of it, reconciled and current, rather than a partial pull that doesn’t tie to published totals.

Cost math for the managed approach

The award data is free and the API is HTTP-only — no proxy, no browser. So cost is compute. Even a multi-hundred-thousand-record pull lands in low double-digit dollars per month on a schedule. The real expense you’re avoiding is engineering time: building correct POST filter bodies, partitioning to beat page depth, and getting the obligated-vs-outlay distinction right so your numbers reconcile.

Common pitfalls

  • Summing the wrong money field — obligated, outlay, current and potential are different. Pick one deliberately and label it; don’t add across them.
  • Page-depth truncation — a broad filter silently stops paging at the ceiling. Partition by month or sub-agency and verify against the endpoint’s reported total count.
  • Recipient name drift — “ACME DEFENSE SYSTEMS INC” and “Acme Defense Systems, Inc.” are the same firm. De-dupe on UEI/parent, not name.
  • Award-type scope — contracts (A–D) and assistance (grants, loans) come back under different type codes with different fields. Decide your scope before you sum amounts.
  • Filter body validation — a 422 means your JSON filter is malformed, not that there’s no data. Read the validation message; nested tier/agency objects are strict.

Wrapping up

USASpending is the open, authoritative source of federal money flows. The challenge isn’t getting blocked — it’s beating page-depth limits, partitioning correctly, choosing the right monetary field, and de-duplicating recipients so your totals reconcile. For a single market-sizing query, the API docs suffice. For a contractor-intelligence or budget-analytics feed that has to be complete and current, let a managed actor carry the partitioning and normalization.

Open the USASpending scraper on Apify — filter by award type, date range, agency and keyword; full corpus via automatic partitioning. Schedule it for a refreshed federal-awards feed.

Related guides