A working reference for researchers, BD people, proposal writers, and capture managers. Covers where federal contractor data actually lives (SAM.gov, USASpending, FPDS), how to find a company by name or UEI, how to pull their award history, and how to identify their competitors. Every workflow below is documented with both a free public-source approach and an automated API approach.
A federal contractor is a company (or individual) that holds an active contract with a US federal agency. They're registered in SAM.gov, they have a 12-character UEI (Unique Entity Identifier), and they've won at least one solicitation posted through the federal acquisition process.
Three subtle distinctions matter:
Four authoritative public sources. Knowing which to use for what saves hours.
| Source | What it has | Access | Use for |
|---|---|---|---|
| SAM.gov | Registrations, active solicitations, Award Notices, exclusions (debarments) | Web UI + public API (rate-limited, 1,000/day for registered users) | Current opportunities, UEI lookup, exclusion screening |
| USASpending.gov | All federal spending (contracts, grants, loans, sub-awards), back to 2008 | Web UI + JSON API (POST-based, free, no key) | Historical contract research, sub-award tracking, bulk data |
| FPDS-NG | Federal Procurement Data System (the underlying source USASpending queries) | Web UI + ATOM feed (clunky) | Raw transaction data, modifications, task orders |
| GovCon API | SAM opportunities + awards, aggregated with a faster search API. This site. | REST API, $0-$39/mo | Programmatic access, peer analysis, faster lookups |
Rule of thumb. If the question is "what's happening right now?", use SAM.gov. If the question is "what happened historically?", use USASpending. If you need programmatic access at speed, use an API (ours or USASpending's).
Go to sam.gov/search, select "Entity Information" in the dropdown, type the company name. UEI is on the entity card. Works for any registered entity, whether they've won contracts or not.
Search awardees via POST /api/v2/search/spending_by_award/. Two gotchas: field names are capitalized and spaced ("Recipient UEI" not recipient_uei), and sort + order are required.
curl -X POST "https://api.usaspending.gov/api/v2/search/spending_by_award/" \
-H "Content-Type: application/json" \
-d '{
"filters": {
"recipient_search_text": ["Lockheed Martin"],
"award_type_codes": ["A", "B", "C", "D"],
"time_period": [{"start_date":"2022-01-01","end_date":"2026-12-31"}]
},
"fields": ["Award ID", "Recipient Name", "Recipient UEI", "Award Amount"],
"sort": "Award Amount",
"order": "desc",
"limit": 10
}'
Returns contract awards matching the name. Recipient UEI is the value you want.
curl -H "Authorization: Bearer $KEY" \
"https://govconapi.com/api/v1/companies/search?q=Lockheed&limit=5"
Response shape:
{
"query": "Lockheed",
"count": 5,
"pagination": {"limit": 5, "offset": 0, "total": 37, "has_next": true},
"results": [
{
"uei": "H11HD5VHGHN3",
"name": "Lockheed Martin Corporation",
"total_awards": 16,
"total_value": 26800000.0,
"last_award_date": "2026-03-10"
},
...
]
}
One call gives you UEI, canonical name, total awards, total dollars, and the last win date. Paginate with offset when pagination.has_next is true. Pro Bundle only ($39/mo).
Two-step workflow because spending_by_award returns hollow data (NAICS, PIID, obligation, date_signed come back NULL; a known API quirk).
Step 1. Get paginated award summaries, each with a generated_internal_id:
curl -X POST "https://api.usaspending.gov/api/v2/search/spending_by_award/" \
-H "Content-Type: application/json" \
-d '{
"filters": {
"recipient_search_text": ["Lockheed Martin"],
"award_type_codes": ["A","B","C","D"],
"time_period": [{"start_date":"2008-01-01","end_date":"2026-12-31"}]
},
"fields": ["Award ID","Recipient Name","Recipient UEI","Award Amount","Start Date","Awarding Agency"],
"sort": "Award Amount",
"order": "desc",
"page": 1, "limit": 100
}'
Step 2. For full detail (NAICS, PSC, obligation, extent competed, business categories, parent company), fetch each award individually:
curl "https://api.usaspending.gov/api/v2/awards/CONT_AWD_DEAC0494AL85000_8900_-NONE-_-NONE-/"
The detail endpoint returns 28 top-level fields plus latest_transaction_contract_data with 69 contract fields (NAICS hierarchy, type of contract pricing, extent competed, set-aside type, etc.). Slow: ~1.5-2 seconds per call in April 2026 testing, and parallelism doesn't speed it up.
Note on lag: USASpending trails SAM.gov by 2-4 weeks because data flows SAM.gov -> FPDS -> USASpending. For anything newer, SAM.gov is the authoritative source.
sam.gov does not expose a full award history per entity in its search UI. You'd filter Contract Opportunities by notice type "Award Notice" plus the company UEI, but this only covers post-2024 SAM notices, not the full historical record.
# Developer tier (free filter on any UEI):
curl -H "Authorization: Bearer $KEY" \
"https://govconapi.com/api/v1/awards/search?uei=XX2WFHJEFB45&sort_by=award_date&limit=100"
# Pro Bundle convenience URL (same data):
curl -H "Authorization: Bearer $KEY" \
"https://govconapi.com/api/v1/companies/XX2WFHJEFB45/awards?limit=100&sort=date"
Response shape:
{
"uei": "XX2WFHJEFB45",
"pagination": {"limit": 100, "offset": 0, "total": 842, "has_next": true},
"sort": "date",
"data": [
{
"notice_id": "abc123...",
"solicitation_number": "SPE7M525R0012",
"title": "Replenishment parts for F-16 landing gear",
"award_number": "SPE7M525C0042",
"award_date": "2026-03-10",
"award_amount": 487200.0,
"agency": "DEPT OF DEFENSE",
"naics": "336413",
"psc": "1680",
"posted_date": "2026-03-11",
"response_deadline": null,
"performance_state_code": "OK",
"performance_city_name": "OKLAHOMA CITY"
},
...
]
}
Our dataset starts Q4 2024. For earlier history, USASpending is the correct source (match on award_number = piid).
This question has no direct answer in any public tool. "Competitor" requires joining two inferences: shared NAICS codes (similar type of work) and shared agencies (similar customers).
POST /api/v2/search/spending_by_category/recipient/
{
"filters": {
"naics_codes": {"require": ["541512"]},
"time_period": [{"start_date":"2023-01-01","end_date":"2026-12-31"}]
},
"limit": 50
}
Takes 5-10 API calls plus local aggregation.
curl -H "Authorization: Bearer $KEY" \
"https://govconapi.com/api/v1/companies/XX2WFHJEFB45/peers?limit=10"
Response shape:
{
"uei": "XX2WFHJEFB45",
"target": {"naics_count": 12, "agency_count": 7},
"count": 10,
"peers": [
{
"uei": "H11HD5VHGHN3",
"name": "LOCKHEED MARTIN CORPORATION",
"total_awards": 16,
"total_value": 26800000.0,
"naics_overlap": 6,
"agency_overlap": 1,
"similarity_score": 19
},
...
]
}
similarity_score = naics_overlap * 3 + agency_overlap. NAICS is weighted 3x because same-industry signals direct competition; shared customers are a weaker signal.
This is a workflow, not a single query. The trick is matching the new solicitation to a prior award by scope, agency, and contract vehicle.
With our API, steps 2-4 compress into filtered calls against /api/v1/awards/search, but the workflow is the same.
curl -X POST "https://api.usaspending.gov/api/v2/search/spending_by_category/recipient/" \
-H "Content-Type: application/json" \
-d '{
"filters": {
"naics_codes": {"require": ["541512"]},
"time_period": [{"start_date":"2024-01-01","end_date":"2026-12-31"}]
},
"limit": 20
}'
Returns top recipients by obligated dollars. Use spending_by_category/naics/ to get aggregate market size per NAICS.
# Get top 20 award records in the NAICS
curl -H "Authorization: Bearer $KEY" \
"https://govconapi.com/api/v1/awards/search?naics=541512&sort_by=award_amount&limit=20"
# Then profile each awardee in a loop (Pro Bundle):
# /api/v1/companies/{uei}
Faster than USASpending for the top-N follow-up, because the company profile endpoint precomputes the aggregates.
POST /api/v2/search/spending_by_category/recipient/
{
"filters": {
"agencies": [{"type":"awarding","tier":"toptier","name":"Department of the Navy"}],
"naics_codes": {"require": ["541512"]},
"time_period": [{"start_date":"2024-01-01","end_date":"2026-12-31"}]
},
"limit": 20
}
curl -H "Authorization: Bearer $KEY" \
"https://govconapi.com/api/v1/awards/search?agency=navy&naics=541512&awarded_after=2024-01-01&sort_by=award_amount&limit=100"
Aggregate by award_uei_sam client-side, or chain to the company profile endpoint for each top UEI.
The answer requires cross-referencing four things:
/api/v1/exclusions/search. If the principals appear on any exclusion list, that's a deal-killer.None of this requires paid tools. USASpending plus SAM.gov exclusions is enough for thorough DD; our API just collapses the cross-reference into one call.
curl -H "Authorization: Bearer $KEY" \
"https://govconapi.com/api/v1/companies/XX2WFHJEFB45"
Response shape:
{
"uei": "XX2WFHJEFB45",
"name": "KAMPI COMPONENTS CO INC",
"primary_city": "BROOKLYN",
"primary_state": "NY",
"total_awards": 842,
"total_value": 223500000.0,
"avg_value": 265440.0,
"first_award_date": "2024-11-04",
"last_award_date": "2026-04-18",
"awards_last_90d": 47,
"awards_last_12mo": 312,
"top_naics": [
{"naics": "332710", "awards": 198, "value": 52400000.0},
{"naics": "332999", "awards": 112, "value": 31100000.0},
...
],
"top_agencies": [
{"agency": "DEPT OF DEFENSE", "awards": 601, "value": 168200000.0},
{"agency": "DEPT OF VETERANS AFFAIRS", "awards": 84, "value": 19400000.0},
...
]
}
Pipeline health is awards_last_90d * 4 vs awards_last_12mo. Concentration risk is top_agencies[0].value / total_value. Acquisition sizing is total_value against their claimed revenue, assuming federal is the whole book (or a known share).
For business categories (Small Business, WOSB, HUBZone, 8(a), SDVOSB), parent company, or total obligation vs award ceiling, fall through to USASpending's /awards/{generated_internal_id}/ detail endpoint. We don't surface those fields yet.
SAM.gov has a "Follow" button for notices but not for entities. You can't subscribe to "every award Company X wins." You have to build it.
Simple cron pattern that works against any API:
import requests, json
from pathlib import Path
COMPETITORS = ["UEI_A", "UEI_B", "UEI_C"]
STATE_FILE = Path("state.json")
state = json.loads(STATE_FILE.read_text()) if STATE_FILE.exists() else {}
for uei in COMPETITORS:
# Using our API; same pattern works with USASpending's spending_by_award
r = requests.get(
f"https://govconapi.com/api/v1/companies/{uei}/awards",
headers={"Authorization": f"Bearer {API_KEY}"},
params={"limit": 20, "sort": "date"},
)
awards = r.json().get("data", [])
since = state.get(uei, "2000-01-01")
new_wins = [a for a in awards if a["award_date"] and a["award_date"] > since]
if new_wins:
notify(uei, new_wins)
state[uei] = max(a["award_date"] for a in new_wins)
STATE_FILE.write_text(json.dumps(state))
Run daily on any free server. Swap the URL for USASpending if you prefer the free path; the logic is identical.
USASpending is the authoritative free source for historical federal contract data. Non-obvious things to know before you burn a day on it:
"Award ID", "Recipient Name", "Recipient UEI" (capitalized, spaced) in the fields array. Response keys echo that. Other endpoints use recipient_id, uei, etc. in lowercase snake_case. Read the example response before guessing.spending_by_award demands a sort field and order ("asc"/"desc"). Missing them returns a 400 with a list of allowed sort values.spending_by_award returns hollow data. NAICS, PIID, total obligation, date signed, award type, solicitation identifier all come back NULL from this endpoint. Known API limitation, not a script bug. For the real fields, fetch each award by ID from /awards/{generated_internal_id}/.page (1-indexed) + limit, not offset. Max 100 per page."A","B","C","D" = contracts. "02","03","04","05" = grants. Filter with award_type_codes.recipient_id is USASpending's hashed identifier (example: d41a6b8a-9d6a-0d28-7e24-989e31731aad-C), not UEI. Look up a recipient profile by UEI via /api/v2/recipient/.Most useful endpoints for contractor research:
POST /api/v2/search/spending_by_award/ - award-level list (thin fields; use for pagination)GET /api/v2/awards/{generated_internal_id}/ - full award detail (NAICS, PSC, business categories, extent competed, 69 contract fields)POST /api/v2/search/spending_by_category/recipient/ - aggregated by recipient (top awardees in a NAICS, agency, etc.)POST /api/v2/search/spending_by_category/naics/ - aggregated by NAICS (market sizing)POST /api/v2/search/spending_by_transaction/ - transaction-level (unlike spending_by_award, this one actually returns NAICS in the results)POST /api/v2/download/awards/ - async bulk export, up to 500,000 records per job, returns a download URL when readyGET /api/v2/recipient/{recipient_id}/ - recipient profileMatching SAM to USASpending. Use award_number (SAM) = piid (USASpending). Do not try to match on solicitation_identifier; it's NULL in spending_by_award results.
Full docs: api.usaspending.gov.
Four endpoints specific to contractor research. See the full API docs for everything else.
| Method & path | What it returns | Tier |
|---|---|---|
GET /api/v1/awards/search?uei=... | All awards for a UEI | Developer ($19) |
GET /api/v1/companies/search?q=... | Distinct awardees by name/UEI prefix with aggregates | Pro Bundle ($39) |
GET /api/v1/companies/{uei} | Profile: totals, top NAICS, top agencies, recency | Pro Bundle ($39) |
GET /api/v1/companies/{uei}/awards | Paginated award history (same data as /awards/search?uei=X) | Pro Bundle ($39) |
GET /api/v1/companies/{uei}/peers | Similar companies ranked by NAICS + agency overlap | Pro Bundle ($39) |
Rate limit: 1,000 requests/hour across the whole API (Developer and Pro). Authentication is a Bearer token in the Authorization header.
award_uei_sam in SAM data, recipient_uei in USASpending.How is a federal contractor different from a federal grant recipient?
Contract = the government buys something from you. Grant = the government gives you money to do something (research, services to a population). Different legal frameworks, different data feeds. USASpending covers both; SAM.gov Award Notices are contracts only.
How do I find a contractor's annual revenue?
Federal revenue specifically: sum their awards in USASpending for the fiscal year. Total revenue (including commercial): not public unless they're a public company. ZoomInfo and similar private-sector tools have approximations but they're often wrong.
Why does the same company appear under different names?
Reorgs, acquisitions, abbreviations, capitalization inconsistencies. "LOCKHEED MARTIN CORPORATION" and "Lockheed Martin Corp." and "LOCKHEED MARTIN CORP" may all be the same UEI. UEI is the stable identifier; name variations are noise.
Can I find who bid on a solicitation but lost?
No. Losing bidders are not public. Only the winning award is announced. You can infer likely bidders by looking at who regularly wins similar NAICS + agency combinations.
How do I verify a contractor's small-business status?
SAM.gov entity registration page. Look at their SBA certifications and self-representations. The relevant fields are "SBA Certifications" (8(a), HUBZone, etc.) and "Representations and Certifications." This is self-reported but audited.
Is there a free API that replaces HigherGov?
No single free API covers everything HigherGov does (opportunity tracking plus award history plus document enrichment plus alerting). USASpending replaces the award history piece. SAM.gov replaces the opportunity piece. Document enrichment (OCR, keyword extraction on solicitation PDFs) is where HigherGov genuinely adds value and free alternatives don't exist.
What if I just need to check one or two companies occasionally?
USASpending's web UI is free and fine for occasional manual lookups. Our API makes sense when you're doing this at volume, or when you need peer analysis that isn't available elsewhere.
Can I see subcontracts?
Via USASpending's sub-award search. Subcontractor data comes from FSRS reporting and has quirks (prime contractors self-report; accuracy varies). Our API does not currently include sub-award data.
How fresh is each source?
SAM.gov: real-time for opportunities, usually same-day for award notices. USASpending: 2-4 weeks behind SAM.gov (data flows SAM.gov to FPDS to USASpending). Our API: within 24 hours of SAM.gov publication (hourly ingestion).
Why does a company show up in USASpending but not in SAM award notices (or vice versa)?
Different reporting paths. SAM.gov Award Notices are what contracting officers publish on the opportunity feed. USASpending pulls from FPDS, which captures more contract actions (modifications, task orders under IDIQs, micro-purchases above $10K threshold reporting, etc.) but with a 2-4 week lag. In our April 2026 measurement, 22,949 contractors appear in USASpending without a matching SAM Award Notice, and 6,286 SAM-only contractors have no matching USASpending record (mostly recent, still inside the propagation window). For complete coverage, you need both.
If you want to automate the workflows on this page against our API, the relevant endpoints are listed in the cheatsheet above. Pricing at govconapi.com/#pricing. For everything else, USASpending and SAM.gov will get you there with more effort.
Last updated: April 2026 · API reference · Questions