How to Research a Federal Contractor
Updated
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.
Who this page is for: anyone trying to answer "who is this contractor, what have they won, and who do they compete with?" If you've ever been frustrated by the SAM.gov search UI, hit the USASpending rate limits, or been quoted $500+/month for a commercial database, this is for you.
What "federal contractor" actually means
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:
- Registered vs active. SAM.gov has roughly 880K registered entities. Only a fraction of those actively win contracts in any given year. "Federal contractor" in practice means "has won recent work," not just "is registered."
- Prime vs sub. Prime contractors hold the direct contract with the government. Subcontractors work for the prime. SAM.gov award notices cover primes only. Subcontractor relationships are visible in USASpending's sub-award data, which comes from FSRS reporting with a time lag.
- The individual case. Sole proprietors and 1099 consultants can register as entities too. In the data they look identical to small companies.
Where the data lives
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).
Find a company by name (and get its UEI)
"I know the company's name. I need their UEI to research them further."
Free SAM.gov web UI
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.
Free USASpending API
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.
GovCon API One GET, returns UEI plus aggregate stats
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 only ($39/mo).
Pull a contractor's award history
"I have their UEI. Show me every federal contract they've won."
Free USASpending API (full history back to 2008)
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.
Free SAM.gov UI
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.
GovCon API Direct paginated endpoint
# 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 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).
Identify a contractor's competitors
"Who else bids on the same kind of work as this company?"
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).
Free Manual USASpending workflow
- Pull the target's award history (query above). Note the top 3-5 NAICS codes they win in.
-
For each NAICS, query USASpending for top awardees in that code over a recent window:
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 } -
Intersect the recipient lists across NAICS codes. Overlap = candidate peers.
- Filter to recipients that also won from the same top agencies.
Takes 5-10 API calls plus local aggregation.
GovCon API Single call, ranked by overlap
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.
Find the incumbent on a re-compete
"A solicitation just dropped. Same scope as 2019. Who won it last time?"
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.
- Read the new solicitation. Note: contracting office, NAICS, PSC, solicitation number (sometimes echoes the prior number with a suffix like R6, R7), description keywords.
- On USASpending, search awards from the same contracting office with the same NAICS in the expected prior-period (typically 4-5 years earlier, matching the original period of performance).
- Narrow by description keywords. Sort by award amount if you expect a large award.
- The top result is almost always the incumbent. Verify by checking their recent activity: a live contractor will still be winning similar work; a dormant one has likely exited the space.
With our API, steps 2-4 compress into filtered calls against /api/v1/awards/search, but the workflow is the same.
Size a NAICS market by top awardees
"How big is federal spending in NAICS X, and who are the top recipients?"
Free USASpending category endpoint (best free option)
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.
GovCon API Top awards + automated profile lookups
# 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):
# /api/v1/companies/{uei}
Faster than USASpending for the top-N follow-up, because the company profile endpoint precomputes the aggregates.
Map an agency's top contractors
"Who does the Navy buy cybersecurity from? Ranked."
Free USASpending
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
}
GovCon API Same structure, cleaner filter API
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.
Due diligence on a contractor
"Should we acquire this company, or team with them on a proposal?"
The answer requires cross-referencing four things:
- Actual revenue. Total value of contracts they've won, verified against public records (not their pitch deck). USASpending or our awards endpoint gives this directly.
- Pipeline health. Are they winning now, or did their wins dry up a year ago? Compare last-12-months awards to last-90-days awards. A 4x drop in quarterly rate is a red flag.
- Customer concentration. If one agency is more than 70% of their revenue, they're fragile. That agency's contracting officer changing, or the program ending, tanks them.
- Exclusions / debarments. Check sam.gov/exclusions or our
/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.
GovCon API Single profile call returns every DD aggregate
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.
Sub-side revenue is in the same response on Pro. The profile now includes sub_revenue_total, top_paying_primes, and prime_revenue_share. For SMBs, sub income is often the larger half of federal revenue and a prime-only DD will lowball the target. For acquisition sizing or teaming-partner research where the candidate has a sub-vendor history, this is the missing field. See Subawards API guide for the underlying records.
Monitor a competitor over time
"Alert me when my competitors win a new contract."
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 API cheatsheet
USASpending is the authoritative free source for historical federal contract data. Non-obvious things to know before you burn a day on it:
- POST-based. Every search is a POST with a JSON filter body. No GET shortcuts.
- Field naming is inconsistent. Search endpoints want
"Award ID","Recipient Name","Recipient UEI"(capitalized, spaced) in thefieldsarray. Response keys echo that. Other endpoints userecipient_id,uei, etc. in lowercase snake_case. Read the example response before guessing. - Sort is required.
spending_by_awarddemands asortfield andorder("asc"/"desc"). Missing them returns a 400 with a list of allowed sort values. spending_by_awardreturns 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}/.- Pagination.
page(1-indexed) +limit, not offset. Max 100 per page. - Award type codes.
"A", "B", "C", "D"= contracts."02", "03", "04", "05"= grants. Filter withaward_type_codes. - Recipient resolution.
recipient_idis USASpending's hashed identifier (example:d41a6b8a-9d6a-0d28-7e24-989e31731aad-C), not UEI. Look up a recipient profile by UEI via/api/v2/recipient/. - Data lag. 2-4 weeks behind SAM.gov. Data path is SAM.gov -> FPDS -> USASpending. For anything newer, use SAM.gov directly.
- Coverage. Includes contract recipients that never appear in SAM.gov Award Notices (different reporting path). Measured against our SAM dataset (April 2026): 22,949 contractors exist in USASpending but not in SAM award notices; 4,840 appear in both.
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 profile
Matching 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.
GovCon API cheatsheet
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 ($39/mo) |
GET /api/v1/companies/{uei} |
Profile: totals, top NAICS, top agencies, recency | Pro ($39/mo) |
GET /api/v1/companies/{uei}/awards |
Paginated award history (same data as /awards/search?uei=X) | Pro ($39/mo) |
GET /api/v1/companies/{uei}/peers |
Similar companies ranked by NAICS + agency overlap | Pro ($39/mo) |
Rate limit: 1,000 requests/hour across the whole API (Developer and Pro). Authentication is a Bearer token in the Authorization header.
Glossary
UEI (Unique Entity Identifier)
The 12-character alphanumeric ID the federal government assigns to every registered contractor. Replaced DUNS in 2022. Shows up as award_uei_sam in SAM data, recipient_uei in USASpending.
CAGE code Commercial and Government Entity code. 5 characters. Assigned by DLA. Used alongside UEI in contracting. Still relevant for DoD.
DUNS Legacy Dun & Bradstreet identifier. Deprecated for federal use in 2022. If you see a DUNS in old research, look up the current UEI via SAM.gov.
NAICS code 6-digit industry classification. 541512 ="Computer Systems Design Services", 236220 ="Commercial and Institutional Building Construction", etc. Each federal contract is tagged with one primary NAICS.
PSC (Product Service Code) Federal-specific classification, more granular than NAICS. 4-character code. Example: D302 ="IT and Telecom - Systems Development". Used heavily in DoD contracting.
Set-aside Contract restricted to a specific small-business category. SBA = total small business. SDVOSBC = Service-Disabled Veteran-Owned Small Business. WOSB = Women-Owned Small Business. 8(a) = Economically Disadvantaged Small Business. HUBZone = Historically Underutilized Business Zone.
Award Notice The notice type SAM.gov publishes when a contract has been awarded. Our data and HigherGov pull from here. Contains awardee UEI, amount, date, but minimal additional context.
Solicitation number The procuring agency's ID for a specific solicitation. Not globally unique. Example: FA8620-25-R-0009.
Award number The specific contract identifier after award. Also not globally unique across agencies. Example: FA8620-25-C-0012.
Prime vs sub Prime = direct contract holder with the government. Sub = works for the prime. SAM.gov award feeds cover primes only. Sub-award data (from FSRS reporting) is available in USASpending.
FAQ
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?
Yes, on Pro. The /subawards endpoints carry FFATA sub-award reporting: search, single report, and prime-to-sub / sub-to-prime lookups, plus sub-award blocks on the awards, companies, entities, and exclusions endpoints. Sub-award data comes from FSRS, where prime contractors self-report, so accuracy varies. That is an upstream quirk, passed through as-is rather than cleaned.
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 /pricing. For everything else, USASpending and SAM.gov will get you there with more effort.