Federal contracts API for developers. Clean JSON: federal opportunities, FPDS prime contracts, SAM Award Notices, federal subawards, the SAM entity registry (~873K registered firms), exclusions, contracting-officer contacts, and full notice descriptions.
All example counts and response values in this documentation are illustrative. Use /api/stats or /meta for current numbers.
Endpoints
Response source attribution (universal)
Every /api/v1/* response carries a top-level _sources array naming where the data came from. Endpoints that compose multiple sources list each one (so a Pro /companies/{uei} call that returns both subaward and FPDS enrichment carries ["sam_entities", "sam_opportunities", "usaspending_ffata", "usaspending_fpds"]). Customers reading _sources know exactly what to verify upstream when something looks off, without consulting per-endpoint documentation.
In the response examples throughout this guide, _sources and _report_url are sometimes elided for brevity. _sources is omitted when the value is the obvious single-source case for that endpoint (e.g. ["sam_opportunities"] on opportunities responses); _report_url is omitted because its value is a unique signed link per request and any literal example value would be misleading. Assume both fields are present on every authenticated /api/v1/* response unless an example explicitly omits them. The /api/v1/federal-hierarchy/* reference-data endpoints are the exception: they currently do not carry _sources.
| Identifier | Meaning |
sam_opportunities | sam.gov contract notices (the opportunities table) — serves /opportunities/*, /awards/*, /delta |
sam_entities | sam.gov entity registry — serves /entities/* and the base data on /companies/{uei} |
sam_exclusions | SAM exclusions extract — serves /exclusions/* |
usaspending_fpds | FPDS prime contract transactions from USAspending — serves /contracts/* and FPDS enrichment blocks on other endpoints |
usaspending_ffata | FFATA Section 2 subaward records from USAspending — serves /subawards/* and subaward enrichment blocks on other endpoints |
usaspending_fabs | Financial-assistance (grant) award transactions from USAspending — serves /grants/* |
derived_duns_uei_crosswalk | FFATA-derived crosswalk used by the public DUNS↔UEI lookup |
derived_vendor_risk | Computed signal stack served by /vendor-risk/* |
Reporting a wrong response (universal)
Every /api/v1/* response also carries a top-level _report_url. Open it in a browser and you land on a one-textarea form pre-filled with the call you just made (method, path, query, your email, request timestamp). Type what you expected versus what you actually got, hit Send, and it emails the team. No portal login, no support-form hop. The signed link is valid for 24 hours.
The token is bound to the customer who generated it. Don't paste a response containing _report_url into a public Slack, GitHub issue, or gist, since anyone holding the link can submit one report under your email while it's valid.
Pro enrichment fields (universal pattern)
Several Pro-tier responses include enrichment blocks that compose FPDS prime contract activity and FFATA subaward activity for a single UEI. The same shapes appear in multiple places, so the field reference is given once here and cross-linked from each endpoint section.
- Per-recipient FPDS aggregates on
/companies/{uei} and /entities/{uei}: fpds_obligated_total (float, net federal action obligation summed across all prime contract transactions in the FY2025-onward window (since 2024-10-01)), fpds_distinct_contracts (int, distinct contract_award_unique_key), fpds_transaction_count (int, every base award and modification), fpds_first_action_date and fpds_latest_action_date (ISO date, activity bounds). On /companies/{uei} only: fpds_top_naics (array of up to 5 objects, each {code, description, transaction_count, value}, sorted desc by value) and fpds_top_agencies (array of up to 5 objects, each {name, transaction_count, value}, awarding sub-agency by total $). Each top_* object also carries a deprecated n field with the same value as transaction_count; new code should read transaction_count.
- Per-recipient FFATA subaward aggregates on
/companies/{uei}, /entities/{uei}: sub_revenue_total (float, total FFATA dollars received as a sub), top_paying_primes (array of up to 10 objects, each {uei, name, total, subaward_count}). On /companies/{uei} only: prime_revenue_share (float, FPDS prime obligations / (FPDS prime + sub revenue) ratio).
contract_exposure block on /vendor-risk/{uei}: {fpds_obligated_total, fpds_distinct_contracts, fpds_transaction_count, fpds_first_action_date, fpds_latest_action_date, top_agencies: [{name, value, transaction_count}], window_days}. Descriptive only; not part of triage rules.
subaward_exposure block on /vendor-risk/{uei}: {as_prime: {total_paid_to_subs, distinct_sub_vendors, subaward_count, first_subaward_date, last_subaward_date, top_subs: [{uei, name, total, subaward_count}]}, as_sub: {total_received_from_primes, distinct_primes, subaward_count, first_subaward_date, last_subaward_date, top_primes: [{uei, name, total, subaward_count}]}, window_days}. Both sides of the FFATA flow.
recent_contract_actions block on /exclusions/{uei_sam}: {lookback_days, total_obligated_recent, transaction_count, distinct_contracts, distinct_agencies, most_recent_action_date, most_recent_action_amount, most_recent_awarding_agency, most_recent_piid, top_paying_agencies: [{name, value, transaction_count}]}. The compliance question: is this excluded UEI still receiving direct prime contract obligations?
recent_sub_payments block on /exclusions/{uei_sam}: {lookback_days, total_received, subaward_count, distinct_primes, most_recent_subaward_date, most_recent_subaward_amount, most_recent_paying_prime: {uei, name}, top_paying_primes: [{uei, name, total, subaward_count}]}. The "are clean primes still paying this excluded vendor as a sub?" question.
All blocks are silently omitted on Free / Developer keys; Pro callers (contacts_access=true) receive them inline so they don't need a second round-trip. The blocks always return the zero shape (empty arrays, zero counts) when no records exist for the UEI in the window, so client code can safely read fields without per-call None checks.
Search federal contract notices with filters. Returns paginated results.
At least one meaningful filter is required.
Provide at least one filter parameter (e.g.
naics,
keywords,
state,
date_from,
agency). Filter values must be meaningful:
keywords: minimum 3 characters
naics, psc, state, set_aside, notice_type, agency, location, solicitation_number, naics_multiple: minimum 2 characters
date_from, date_to, posted_after, due_before, due_after: full date format YYYY-MM-DD
value_min, value_max, has_attachments: any valid value
Parameters like
limit,
offset, and
sort_by do not count as filters. Requests without a valid filter return
400. For full-database sync, use
/api/v1/opportunities/delta: pass a timestamp, get only what changed since.
Basic filters (all plans)
naics – Single NAICS code (e.g. 541330)
psc – Product Service Code (e.g. D302)
state – State code (e.g. CA, TX) or full name (e.g. California)
keywords – Full-text search across title, agency name, and contract description. Also matches solicitation number. Hyphenated terms (e.g. fluorine-free) are handled automatically. Results are ranked by relevance to title and agency by default (descriptions still participate in matching but not in ranking, since they include standard regulatory clause text that would otherwise dilute results).
notice_type – Filter by notice type (e.g. Solicitation, Award Notice, Presolicitation)
solicitation_number – Exact solicitation number (e.g. W52P1J-25-R-0001)
limit – Results per page (default 20, max: Free=50, Developer=1000)
offset – Pagination offset (default 0)
fields – Comma-separated response fields to return. notice_id always included. Example: fields=notice_id,title,naics,posted_date. See Response Shaping.
active_only – true / false. When true, returns only currently-open notices (those whose archive date is in the future). Echoed in filters_applied when set so a client can confirm the filter applied. Computed as archive_date_detailed > today; the stored active field is always "Yes" by design and is not what this filter reads.
Concepts to know before you integrate. These are assumptions the data makes that are not obvious from the field names; they cause the most integration mistakes.
notice_id vs solicitation_number. One procurement (one solicitation_number) moves through a lifecycle: Sources Sought → Presolicitation → Solicitation → amendments → Award Notice. Every stage and every amendment is a separate notice_id (a new 32-char hex). One solicitation maps to many notice_ids. To count unique procurements, dedupe on solicitation_number (falling back to notice_id when null). To walk a procurement's lifecycle, filter by solicitation_number=....
- Three different date fields.
posted_date is a calendar date (no time). response_deadline is a timezone-aware timestamp (the bid deadline; precision varies by source). archive_date_detailed is a future calendar date (when the notice will be archived). Filters map to these: date_from / date_to / posted_after filter posted_date; due_after / due_before filter response_deadline; active_only reads archive_date_detailed.
active is always "Yes". The stored active field is a constant by design ("never archived" is a product feature). Do not filter on it. Use active_only=true to get currently-open notices.
description_text is tri-state. Real description text, the literal sentinel "NO_DESCRIPTION_AVAILABLE" (the notice has no description in the source), or null (description not yet retrieved). Handle all three.
set_aside_type "none" is tri-state too: "", "NONE", or null all mean unrestricted. A real code (SDVOSBC, 8A, WOSB, HZC, SBA, etc.) means restricted. Majority of set-asides are SBA.
- Combined notices are common. "Combined Synopsis/Solicitation" is roughly a third of opportunities. When pulling bidding opportunities, query both
notice_type=Solicitation and notice_type=Combined%20Synopsis/Solicitation to catch everything.
- Award amounts only on Award Notices.
award_amount, awardee_name, award_date, and related fields are populated only when notice_type=Award Notice. Solicitations and Sources Sought do not have these fields.
notice_type valid values (exact case-insensitive match): Solicitation, Combined Synopsis/Solicitation, Presolicitation, Sources Sought, Award Notice, Justification, Special Notice, Sale of Surplus Property, Modification, Intent to Bundle Requirements (DoD-Funded). Solicitation does NOT match Presolicitation.
Undocumented aliases. Four parameter aliases are accepted for forgiveness: q and keyword map to keywords; posted_from maps to date_from; posted_to maps to date_to. Canonical names win if both forms are sent.
naics + naics_multiple: if both are sent, naics_multiple wins and the single naics is silently dropped. Pick one. A 1-digit or 7+ digit value returns 400; a 2-5 digit prefix returns 400 with the "must be 6-digit" message; a well-formed but nonexistent 6-digit code returns 200 with total=0 (an empty result can mean "bad code," not "no opportunities").
Date, location, amount, and agency filters
agency – Agency name (partial match, e.g. defense)
set_aside – Set-aside type (e.g. SBA, 8(a), SDVOSB)
posted_after – Posted after date (YYYY-MM-DD format)
due_before – Response deadline before date (YYYY-MM-DD format)
due_after – Response deadline after date (YYYY-MM-DD format). Use due_after=<today> to return only open opportunities.
value_min – Minimum award value in dollars (only for Award Notice records)
value_max – Maximum award value in dollars (only for Award Notice records)
location – Performance location (city or state)
date_from – Posted date from (YYYY-MM-DD format)
date_to – Posted date to (YYYY-MM-DD format)
sort_by – Sort field. Valid: posted_date (default when no keywords), due_date (maps to response_deadline), award_amount, title, agency, relevance. Invalid value returns 400 with the valid list (no silent fallback). When keywords is set and sort_by is omitted, results default to relevance (best title and agency matches first); pass sort_by=posted_date to override.
sort_order – asc or desc (default desc). Ignored when sort_by=relevance. NULLs sort first on asc, last on desc. Results are tie-broken by notice_id so pagination is stable.
naics_multiple – Comma-separated NAICS codes for multiple search
has_attachments – Filter by attachment availability: true or false
format – json (default) or csv. csv returns this same filtered result set as a CSV download (honoring fields), with all 59 columns by default. Requires the Developer plan, same as /export.csv.
Response
{
"data": [
{
"notice_id": "abc123def456",
"title": "IT Services Contract",
"agency": "Department of Defense",
"posted_date": "2025-11-01",
"response_deadline": "2025-12-15T17:00:00+00:00",
"naics": ["541330"],
"set_aside_type": "Small Business",
"solicitation_number": "W52P1J-25-R-0001",
"description_text": "Full contract requirements...",
"award_amount": 1500000.00,
"awardee_name": "Tech Solutions Inc",
"contact_name": "John Smith",
"contact_email": "[email protected]",
"sam_url": "https://sam.gov/opp/...",
"performance_city_name": "Washington",
"performance_state_code": "DC",
"_additional": "59 fields total per record"
}
],
"pagination": {
"limit": 20,
"offset": 0,
"total": 98,
"total_is_estimate": false,
"has_next": true
},
"filters_applied": {
"naics": "541330",
"state": "CA",
"date_from": "2024-05-27"
},
"window": {
"plan_window_days": 730,
"earliest_searchable": "2024-05-27",
"clamped": true,
"reason": "No date filter was sent; results are limited to your plan window (last 730 days, since 2024-05-27). Pass date_from within the window, or see https://govconapi.com/enterprise for deeper history."
}
}
Total count is capped at 10,000. On broad searches, pagination.total stops at 10000 and the response sets "total_is_estimate": true (read it as "10,000+"). Exact counts on very broad full-text matches are expensive, so the count short-circuits past 10,001. Page forward with has_next; do not compute the last page from total when total_is_estimate is true. The other list endpoints (awards, companies, entities, exclusions) return an exact total.
The window block shown in the response example is always present on this endpoint. It surfaces the plan history window applied to your query; see Search Window above for the full field-by-field explanation and clamp semantics.
Examples
NAICS + state:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?naics=541330&state=CA&limit=10"
NAICS 541330 (engineering services) in California returns 98 results
Agency filter:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?agency=defense&limit=20"
Department of Defense returns 149,706 results
Paid plans - High-value awards:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?notice_type=Award%20Notice&value_min=1000000&sort_by=award_amount"
Note: value_min only works with Award Notice records (completed contracts)
Paid plans - Multiple NAICS codes:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?naics_multiple=541330,541511&limit=10"
Paid plans - Only opportunities with attachments:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?has_attachments=true&limit=20"
Not all opportunities have attachments – check resource_links_array in the response.
GET /api/agency-crosswalk No Auth Required
Free agency name standardization utility. Returns mappings between agency variants and canonical names, with department hierarchy and USASpending codes.
Data: Generated fresh from current contract database. Includes 2,000+ agency mappings with confidence scores.
Response Format
{
"data": [
{
"raw_agency_text": "Dept. of Defense",
"canonical_agency": "Department of Defense",
"canonical_acronym": "DOD",
"department": "Department of Defense",
"department_acronym": "9700",
"fh_level": "sub_tier",
"usaspending_toptier_code": "097",
"confidence": 0.95,
"source": "federal_register",
"frequency": 1250,
"first_seen": "2025-08-07",
"last_seen": "2025-11-21"
}
],
"count": 2000,
"message": "Free agency name standardization utility - updated weekly"
}
Example
curl "https://govconapi.com/api/agency-crosswalk"
GET /api/v1/opportunities/{notice_id} Requires Auth
Fetch one complete opportunity by its 32-character notice_id. Use it when you already hold a notice_id (from search results, a sam.gov URL, or your own store) and want the full record.
Not subject to the history window. Unlike /opportunities/search, ID lookups return notices of any age, so this is the way to retrieve an old notice you already have the id for. Plan-window clamping does not apply here.
Parameters
notice_id (path) — a 32-character hex string (regex ^[a-f0-9]{32}$, case-insensitive). Example: 00016e91148440e0b80537f6362f45ea.
No query parameters are accepted; field projection via ?fields= is not available on this endpoint (the full record is always returned).
notice_id is NOT the same as solicitation_number.
notice_id: a 32-character hex UUID like 002518857671489eb8688df91a64ecfb. This is the path parameter this endpoint accepts.
solicitation_number: a human-readable contract identifier like N0003925R4014 or W52P1J-25-R-0001. The same solicitation_number can appear on multiple notice rows (every amendment is its own notice).
If you have a solicitation_number and want the matching notice(s), use the search endpoint instead:
GET /api/v1/opportunities/search?solicitation_number=N0003925R4014
Calling /api/v1/opportunities/<solicitation_number> returns a structured 400 with a hint_url pointing at the search endpoint (see Errors below).
Response Format
The record is wrapped under opportunity, with two metadata fields alongside it:
{
"opportunity": {
"notice_id": "00016e91148440e0b80537f6362f45ea",
"title": "FILTER ASSEMBLY,ELE",
"notice_type": "Solicitation",
"solicitation_number": "SPRMM126Q...",
"agency": "DEPT OF DEFENSE.DEFENSE LOGISTICS AGENCY.DLA MARITIME...",
"naics": ["334419"],
"psc": ["5915"],
"posted_date": "2026-05-22",
"response_deadline": "2026-06-22T20:30:00+00:00",
"description_text": null,
"...": "all 59 opportunity fields, same shape as /opportunities/search data[]"
},
"has_raw_data": true,
"last_updated": "2026-05-22T..."
}
opportunity — the same 59-field record returned by search. Reminders from the search domain primer: naics / psc are arrays; description_text is tri-state (real text / "NO_DESCRIPTION_AVAILABLE" / null); active is always "Yes" by design; set_aside_type "none" is tri-state.
has_raw_data — true if the original SAM payload is retained for this notice (available for notices ingested through the live pipeline; older backfilled rows may be false).
last_updated — when this notice last changed in our database. Same value /opportunities/delta sorts and filters on.
Errors
- 400 — path is not 32-char hex (e.g. a solicitation number passed by mistake). Returns a structured body with a
hint_url pointing to the search endpoint so the caller can recover programmatically.
- 404 — well-formed id, no such notice in our database. Body:
{"detail": "Opportunity not found"}.
- 429 — rate limit exceeded.
Sample 400 body when a solicitation number is passed instead of a notice_id:
{
"detail": {
"error": "invalid_notice_id",
"message": "'36C24926R0057' is not a valid notice_id. notice_id is a 32-character hex string (example: 002518857671489eb8688df91a64ecfb). If '36C24926R0057' is a solicitation_number, use the search endpoint instead.",
"hint_url": "/api/v1/opportunities/search?solicitation_number=36C24926R0057",
"docs": "https://govconapi.com/api-guide#notice-id-vs-solicitation-number"
}
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/00016e91148440e0b80537f6362f45ea"
Note: description_text: null does not mean "no description exists." It means enrichment has not run for this notice yet (rare on notices older than a day). Re-fetch later, or check the live description_url.
Worked example: an EPA Region 1 procurement (real)
Calling GET /api/v1/opportunities/0035baae11ef4760b1157425704b23c2 returns the EPA Region 1 Contracting Office's notice "H--Proficiency Testing (PT) Samples" for the New England Regional Laboratory at North Chelmsford, MA. Live response excerpt (verified 2026-06-02):
{
"opportunity": {
"notice_id": "0035baae11ef4760b1157425704b23c2",
"title": "H--Proficiency Testing (PT) Samples ",
"notice_type": "Combined Synopsis/Solicitation",
"agency": "ENVIRONMENTAL PROTECTION AGENCY.ENVIRONMENTAL PROTECTION AGENCY.REGION 1 CONTRACTING OFFICE",
"naics": ["325199"],
"psc": ["H268"],
"posted_date": "2026-04-10",
"response_deadline": "2026-04-21T16:00:00+00:00",
"solicitation_number": "68HE0126Q0009",
"contact_name": "Williams, Brandon",
"contact_email": "
[email protected]",
"contact_phone": "617-918-1965",
"performance_street_address": "NE Regional Laboratory",
"performance_city_name": "North Chelmsford",
"performance_state_code": "MA",
"performance_zip": "01863",
"archive_date_detailed": "2026-05-06",
"active": "Yes",
"...": "39 additional fields per opportunity"
},
"has_raw_data": true,
"last_updated": "2026-04-12T14:04:38.552010+00:00",
"_sources": ["sam_opportunities"]
}
One detail call delivers the procurement context (agency hierarchy, NAICS, PSC, solicitation number), the awarding officer (name, email, phone), the place of performance (lab address), the lifecycle markers (posted_date, response_deadline, archive_date_detailed), and the SAM last_updated stamp. Per the active column is "Yes" by design rule, "active": "Yes" here even though the notice has archived; the canonical "is it currently open" answer is archive_date_detailed compared against today.
GET /api/v1/opportunities/{notice_id}/attachments Requires Auth
Return the downloadable attachment URLs (solicitation PDFs, drawings, statements of work, amendments) for one notice. URLs are direct SAM.gov download links you can hand to a browser or HTTP client; we do not proxy them.
Parameters
notice_id (path) — same 32-character hex rule as /opportunities/{notice_id}. A solicitation number returns the same structured 400 with a hint_url.
No query parameters are accepted.
Response
{
"notice_id": "002b2fe0c9bd4af9809196504715c3e1",
"title": "Mobile Subscription Services for U.S. Embassy Singapore",
"attachment_count": 3,
"attachments": [
"https://sam.gov/.../download"
]
}
attachment_count — length of attachments. Often 0; many notices carry their documents as external links or have no files at all.
attachments — array of canonical SAM.gov download URLs. Same data as resource_links_array on the main opportunity record. An empty array ([]) is returned when a notice has none.
This is the same data the search filter has_attachments reads, so the two stay consistent: has_attachments=true on search selects notices where this array is non-empty.
Finding notices that have attachments
There is no list endpoint; look them up per notice. Filter search first, then fetch attachments for each id:
# 1) find notices that have files, in your space
"https://govconapi.com/api/v1/opportunities/search?has_attachments=true&naics=541512&limit=50"
# 2) for each result.notice_id:
"https://govconapi.com/api/v1/opportunities/{notice_id}/attachments"
Downloading the files
Each URL is a SAM.gov "front-door" link. When a client follows it, SAM 303-redirects to a short-lived signed S3 URL and the file streams from there. Three practical notes:
- Use
GET with redirect-follow, not HEAD. AWS pre-signed URLs scope the signature to the GET method; a HEAD against the resolved S3 URL returns 403.
- Do not cache the resolved S3 URL. The signature has a very short expiry. Re-hit the SAM URL each time you need the file.
- Allow
*.s3.amazonaws.com through proxies / firewalls. If a corporate proxy blocks S3, the redirect lands on a host that fails to load.
Errors
- 400 — path is not 32-char hex (e.g. a solicitation number). Structured body with
hint_url to the search endpoint, same shape as /opportunities/{notice_id}.
- 404 — well-formed id, no such notice. Body:
{"detail": "Opportunity not found"}. A notice that exists but has no files returns 200 with attachment_count: 0, not 404.
- 429 — rate limit exceeded.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/002b2fe0c9bd4af9809196504715c3e1/attachments"
When a file URL returns "BAD_REQUEST: The resource has been deleted". SAM occasionally removes individual files after publication (a contracting officer pulls or replaces them in an amendment). The notice's attachment list still references the URL until the next refresh of our copy, so a previously-working URL can stop working. The error comes from SAM directly, not our endpoint; the same file is unreachable from sam.gov for the same reason. If you suspect a file is missing, re-fetch this endpoint to see if our copy has updated.
Some notices' documents are not on SAM at all. A subset of solicitations (notably DLA / NAVSUP NSN parts buys) reference Technical Data Packages hosted in DoD systems like cFolders or NECO that require JCP (Joint Certification Program) certification. Our endpoint correctly returns attachment_count: 0 in that case; the documents exist but are not in the SAM extract.
Freshness: the array is rebuilt periodically from the source; a brand-new notice may briefly show 0 before its files are picked up, even when SAM already has them.
GET /api/v1/stats Requires Auth
Get comprehensive database statistics including total records, recent activity, unique agencies and NAICS codes.
Response
{
"database_stats": {
"total_opportunities": 199016,
"recent_opportunities": 7874,
"unique_agencies": 2224,
"unique_naics_codes": 1095,
"total_exclusions": 163314,
"active_exclusions": 163306,
"last_updated": "2026-04-04T02:01:11.019038+00:00"
},
"data_freshness": {
"last_collection": "2026-04-04T02:01:11.019038+00:00",
"collection_frequency": "Daily at 2:00 AM UTC"
}
}
Note: All values shown are examples. Use the endpoint to get current statistics.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/stats"
GET /api/stats No Auth Required
Public statistics endpoint for landing page. Returns real-time counts computed from database.
Response
{
"total_notices": 199016,
"currently_open": 14701,
"award_records": 47103,
"full_descriptions": 167770,
"with_attachments": 63327,
"total_exclusions": 163314,
"coverage": {
"descriptions": "84.3%",
"attachments": "31.8%"
}
}
Note: All values shown are examples. Use the endpoint to get current statistics.
Field Descriptions
total_notices - Total contract notices in database (all types, never archived)
currently_open - Notices still accepting bids (deadline > now, not yet awarded)
award_records - Notices with award information (winner, amount, date)
full_descriptions - Notices with complete extracted requirement text from SAM.gov
Example
curl "https://govconapi.com/api/stats"
GET /api/v1/me Requires Auth
Get information about your API key: plan, entitlements, current rate-limit state, and your effective historical search window. A good first authenticated call to confirm your key works (it requires no other parameters).
Response
{
"plan": "developer",
"contacts_access": false,
"email": "
[email protected]",
"rate_limit_remaining": 980,
"rate_limit": 1000,
"historical_window_days": 365,
"historical_earliest_allowed": "2025-05-28",
"docs_url": "https://govconapi.com/api-guide"
}
plan / contacts_access — your tier and whether Pro Contacts/Companies/Vendor-Risk features are enabled.
rate_limit / rate_limit_remaining — your hourly ceiling and what's left this window (also returned as X-RateLimit-Limit / X-RateLimit-Remaining headers on every response).
historical_window_days / historical_earliest_allowed — the effective search window applied to /opportunities/search, /awards/search, and /export.csv.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/me"
GET /api/v1/contracts/search Requires Auth
Search federal prime contract transactions. Every base award and every modification is one row, sourced from the federal procurement system of record (FPDS) for award types A, B, C, and D. Coverage today is FY2025 + FY2026 (action dates from October 2024 onward).
Parameters
At least one of uei, parent_uei, piid, parent_piid, agency, or naics is required. Unknown parameters return 400.
uei — recipient UEI, 12 characters, exact match (case-insensitive).
parent_uei — recipient parent UEI for corporate roll-up across subsidiaries.
piid — Procurement Instrument Identifier, exact match.
parent_piid — parent vehicle (IDV) PIID.
agency — awarding agency name substring, case-insensitive. defense matches every DoD sub-agency.
naics — exactly 6 digits.
award_type_code — one of A (BPA Call), B (Purchase Order), C (Delivery Order), D (Definitive Contract). Not a substantive filter on its own; combine with one of the above.
date_from / date_to — YYYY-MM-DD bounds on action_date. Older dates are soft-clamped to the coverage floor; the clamp is surfaced in the window block.
amount_min / amount_max — bounds on federal_action_obligation. 0 is honored. Accepts value_min / value_max as aliases.
sort_by — one of action_date (default), federal_action_obligation, current_total_value_of_award, recipient_name.
sort_order — asc or desc (default).
limit — 1 to 250, default 50.
offset — pagination offset.
fields — lean (default, 26 fields), expanded (57 fields), full (every column), or a comma-separated list.
Response
Standard list envelope: data, pagination, filters_applied, window, and _sources. pagination.total is exact (no estimate cap). Each row in data is one FPDS transaction. _sources is ["usaspending_fpds"].
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/contracts/search?uei=CKV2L9GZKJK3&naics=541512&agency=defense&limit=50"
GET /api/v1/contracts/{piid} Requires Auth
Single contract by PIID. Returns the latest transaction (the contract block, 26 lean fields by default) plus a transaction_rollup sibling that aggregates obligations, ceiling, distinct recipients, and action-date bounds across every transaction under that PIID. Pro responses also include a subaward_rollup sibling.
Parameters
piid (path) — Procurement Instrument Identifier, upper-cased server-side.
fields — lean / expanded / full / comma list, applies to the contract block. transaction_rollup is fixed shape.
Response
{
"contract": { /* 26 lean fields, latest transaction */ },
"transaction_rollup": {
"transaction_count": 52,
"total_obligated": 162360657.45,
"max_current_total_value": 392556695.66,
"max_potential_total_value": 504348015.85,
"latest_current_total_value": 392556695.66, /* alias for max_current_total_value */
"latest_potential_total_value": 504348015.85, /* alias for max_potential_total_value */
"first_action_date": "2024-10-11",
"latest_action_date": "2026-02-27",
"distinct_recipient_ueis": 1
},
"_sources": ["usaspending_fpds"]
}
Reading the numbers
The example above is the live shape for Deloitte's $392M Army task order under PIID W56JSR23F0062. Two customer-actionable signals are in the rollup directly: transaction_count: 52 over a 16-month action-date span says the prime has cycled 52 mods (active, well-managed contract). max_current_total_value and latest_current_total_value agree at $392.56M (current ceiling matches the all-time peak, scope stable). max_potential_total_value at $504.35M agrees with latest_potential_total_value at the same number, but when these two differ in a live response, that is a scope-reduction signal worth chasing in a recompete play (a previous mod set a higher ceiling than the current one). Customers tracking ceilings over time read both pairs and compare.
Errors
- 404 — no contract with that PIID in the coverage window.
- 429 — rate limit exceeded.
Subaward enrichment Pro
On Pro keys, the response includes an additional subaward_rollup sibling summarizing the FFATA subaward footprint flowing from this prime contract: sub count, total subcontracted, share of the prime obligation, distinct sub-vendor count, first and last subaward dates, plus up to 5 named top_subs. The PIID join into the subaward layer is dense within the FY2025+ window: roughly 88% of subaward filings match a prime contract row, and 98% of in-scope contracts that have subaward activity see a populated block. _sources extends to ["usaspending_fpds", "usaspending_ffata"] when the block fires. For UEI-keyed reverse lookups across every contract a recipient holds, use /api/v1/companies/{uei}/subawards.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/contracts/W56JSR23F0062"
GET /api/v1/contracts/{piid}/modifications Requires Auth
Full transaction history for one PIID, oldest action first. Every row is a single FPDS action: base award, exercised options, supplemental agreements, partial terminations, administrative cleanup. Use this to reconstruct what happened on a contract over its life.
Not date-windowed. When you ask for one PIID's history, you get the full history we carry, regardless of the search-time coverage window.
Parameters
piid (path) — Procurement Instrument Identifier.
limit — 1 to 500, default 100. Higher cap than search because modification trails are bounded.
offset — pagination offset.
fields — same options as search.
Response
Returns piid, data (ASC-ordered by action_date then modification_number), pagination, and _sources. 404 when no transactions exist for the PIID.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/contracts/W56JSR23F0062/modifications?limit=500"
GET /api/v1/grants/search Requires Auth
Search federal financial-assistance award transactions: block grants, formula grants, project grants, and cooperative agreements (assistance types 02-05), sourced from USAspending. This is the grant side of federal spending, money to states, universities, hospitals, nonprofits, tribes, and local governments, distinct from the contract (FPDS) side. Every base award and every modification is one row. Coverage today is FY2025 + FY2026 (action dates from October 2024 onward).
Parameters
At least one of uei, parent_uei, fain, agency, cfda, recipient_name, recipient_state, or funding_opportunity is required. recipient_type and assistance_type_code are refinements and do not satisfy the requirement on their own. Unknown parameters return 400.
uei — recipient UEI, 12 characters, exact match. The same UEI joins into contracts and companies, so one organization's grants and contracts line up.
parent_uei — recipient parent UEI for corporate roll-up.
fain — Federal Award ID Number, exact match. Not unique across recipients/years; to pull one specific award use the detail endpoint with the award key.
agency — awarding agency name substring, case-insensitive.
cfda — CFDA / Assistance Listing number, exact (e.g. 93.778).
assistance_type_code — 02 (Block grant), 03 (Formula grant), 04 (Project grant), 05 (Cooperative agreement). Refinement only.
recipient_name — recipient name substring, case-insensitive (minimum 3 characters).
recipient_state — recipient state: 2-letter code (exact) or full name (prefix).
recipient_type — plain-language recipient bucket: higher_education, nonprofit, state_government, local_government, school_district, tribal, small_business, for_profit, individual. Refinement only.
funding_opportunity — funding-opportunity (NOFO) number, exact.
date_from / date_to — YYYY-MM-DD bounds on action_date. Older dates are soft-clamped to the coverage floor (surfaced in the window block).
amount_min / amount_max — bounds on federal_action_obligation. 0 is honored. Accepts value_min / value_max as aliases.
sort_by — one of action_date (default), federal_action_obligation, total_obligated_amount, recipient_name.
sort_order — asc or desc (default).
limit — 1 to 250, default 50.
offset — pagination offset.
fields — lean (default, 24 fields), expanded (~50 fields), full (every column), or a comma-separated list.
Two amounts, two meanings (read this)
Each row carries both federal_action_obligation (what this transaction obligated, sum it to total a recipient, program, or window) and total_obligated_amount (the award's lifetime cumulative, repeated on every transaction of that award, never sum it across rows). Conflating them is the most common grant-data mistake. De-obligations carry a negative federal_action_obligation; summing nets them out correctly, so do not filter negatives away.
Response
Standard list envelope: data, pagination, filters_applied, window, and _sources (["usaspending_fabs"]). pagination.total is exact. Each row is one transaction.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/grants/search?recipient_type=higher_education&recipient_state=CA&agency=Health&assistance_type_code=04&limit=50"
GET /api/v1/grants/{award_key} Requires Auth
Single grant award by assistance_award_unique_key (the unambiguous award id that also appears in the USAspending permalink, e.g. ASST_NON_4683DRCAP00000001_070). Returns the latest transaction (the grant block, lean fields by default) plus a transaction_rollup sibling aggregating obligations, outlays, program count, and action-date bounds across every transaction under that award. Use the award key, not the FAIN, since a FAIN can recur across recipients and years.
Response
{
"grant": { /* latest transaction, lean fields */ },
"transaction_rollup": {
"transaction_count": 1409,
"total_obligated": 312276899.65,
"award_total_obligated_amount": 403698397.09,
"award_total_outlayed": 264256562.26,
"first_action_date": "2024-10-04",
"latest_action_date": "2026-05-22",
"distinct_programs": 1
},
"_sources": ["usaspending_fabs"]
}
Reading the numbers
The example is the live shape for a California FEMA disaster-recovery grant (CFDA 97.036). transaction_rollup.total_obligated ($312.3M) is the sum of federal_action_obligation across this award's 1,409 transactions in our coverage window; award_total_obligated_amount ($403.7M) is the award's lifetime cumulative carried verbatim from USAspending, so the roughly $91M gap is obligation that predates our FY2025+ coverage; award_total_outlayed ($264.3M) is money actually disbursed. To answer "how much has this grant obligated to date," read the award figure; to answer "how much landed in my window," read the rollup sum.
Errors
- 404 — no award with that key.
- 429 — rate limit exceeded.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/grants/ASST_NON_4683DRCAP00000001_070"
GET /api/v1/grants/{award_key}/modifications Requires Auth
Full transaction history for one award, oldest action first. Every row is a single assistance action: the base obligation, added funding, de-obligations, administrative corrections. Not date-windowed, when you ask for one award's history you get the full history we carry.
Parameters
award_key (path) — the assistance_award_unique_key.
limit — 1 to 500, default 100. Higher cap than search because one award can carry hundreds of modifications.
offset — pagination offset.
fields — same options as search.
Response
Returns award_key, data (ASC by action_date then modification_number), pagination, and _sources. 404 when no transactions exist for the award.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/grants/ASST_NON_4683DRCAP00000001_070/modifications?limit=500"
GET /api/v1/companies/{uei}/grants Requires Auth
Every grant a recipient received, by UEI, plus a summary and its top programs. The reverse lookup over /grants/search for one recipient.
Response
Returns uei, a summary (total obligated, distinct awards, distinct programs, distinct agencies, first/last action date, and a top_programs CFDA breakdown ranked by dollars), then the standard data / pagination / filters_applied / window / _sources. summary.total_obligated sums federal_action_obligation, so a program whose only in-window action was a de-obligation shows a negative total and the sum is the net.
Parameters
uei (path) — recipient UEI.
date_from / date_to, sort_by, sort_order, limit, offset, fields — same as search.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/companies/RFKGNHR7ZH37/grants?limit=50"
GET /api/v1/grant-opportunities/search Requires Auth
Search federal grant opportunities (grants.gov notices of funding opportunity), the open funding you can still apply for, the forward-looking counterpart to grant awards. The full corpus is searchable (open, forecasted, closed, archived); status is derived live from the dates, so the default search returns the actionable set (open + forecasted) and "open" means open today, not a stale flag.
Parameters
Open + forecasted is browseable without a filter; reaching into closed, archived, or all requires at least one of keywords, agency, or cfda. Unknown parameters return 400.
keywords — full-text over title + description.
agency — awarding agency code or name substring, case-insensitive.
cfda — CFDA / Assistance Listing number, exact, array-contains (e.g. 93.213). The same number joins to /grant-programs/{cfda} and to grant awards.
eligibility — plain-language applicant bucket: for_profit, small_business, nonprofit, government, tribal, higher_education, individual, unrestricted. Resolved to grants.gov applicant-type codes; the ambiguous "Others (see text)" code is excluded from the for-profit/small-business buckets.
funding_category — category-of-funding-activity code (e.g. ST science/technology, HL health, ED education); array-contains.
funding_instrument — G (grant), CA (cooperative agreement), PC (procurement contract), O (other).
status — open, forecasted, closed, archived, or all. Default: open + forecasted. Derived live from post_date / close_date / archive_date.
date_from / date_to — YYYY-MM-DD bounds on close_date (the deadline axis).
posted_after / posted_before — YYYY-MM-DD bounds on post_date.
value_min / value_max — award-range overlap: value_min matches award_ceiling, value_max matches award_floor. 0 honored. Accepts amount_min / amount_max as aliases.
sort_by — close_date (default), post_date, award_ceiling, opportunity_title, last_updated_date.
sort_order — asc (default; soonest deadline first) or desc.
limit — 1 to 250, default 50. offset — pagination offset.
fields — lean (default), expanded, full, or a comma-separated list.
Response
Standard list envelope: data, pagination (exact total), filters_applied (echoes the effective status), and _sources (["grants_gov"]). No window block, this surface is not date-windowed. Each row carries a derived status; a null close_date is a rolling deadline (treated as open), not missing data; a notice has no recipient (there is no winner until it is awarded).
{
"data": [
{
"opportunity_id": "279638",
"opportunity_title": "Renewable Energy Systems and Energy Efficiency Improvements Program",
"agency_code": "USDA-RBCS",
"agency_name": "Rural Business-Cooperative Service",
"status": "open",
"post_date": "2015-10-13",
"close_date": null, /* rolling deadline */
"eligible_applicants":["11","23","25"], /* 23 = small business */
"cfda_numbers": ["10.868"],
"funding_instrument_type": ["G"],
"award_floor": 1500.0, "award_ceiling": 500000.0,
"expected_number_of_awards": 1000
}
],
"pagination": { "limit": 1, "offset": 0, "total": 448, "total_is_estimate": false, "has_next": true },
"filters_applied": { "status": "open", "eligibility": "small_business", "sort_by": "close_date", "sort_order": "asc" },
"_sources": ["grants_gov"]
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/grant-opportunities/search?status=open&eligibility=small_business&sort_by=close_date&sort_order=asc&limit=50"
GET /api/v1/grant-opportunities/{opportunity_id} Requires Auth
The full notice by opportunity_id: title, agency, eligibility, award range, funding instrument, dates, the agency point of contact, the description, and the CFDA program(s). On Pro keys the response also carries a program_intel block inline (the same data as /grant-programs/{cfda}), so one call tells you both what the notice is and whether the program is worth pursuing; on non-Pro keys that block is a short {"locked": true} stub with no award data.
Response
A flat opportunity object plus the program_intel sibling and _sources (["grants_gov"], or ["grants_gov","usaspending_fabs"] when the program intel joins award history). 404 on an unknown id; not date-windowed.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/grant-opportunities/357328"
GET /api/v1/grant-programs/{cfda} Pro
Program competitive intelligence: for a CFDA program, who has historically won it, whether it is a genuine open competition or wired to a few incumbents, and the realistic award size, joined from the federal grant-award record on the same program number. This answers the question a notice never does, "is this worth a proposal?", before you write one. Pair it with /grant-opportunities/search?cfda=... to see what is open under the program now.
Response
Returns cfda, a program_intel block, the open_opportunity_count currently open under the program, and _sources (["grants_gov","usaspending_fabs"]). Inside program_intel: distinct_awards, distinct_recipients, total_obligated, median_award (the realistic ask when a notice omits the ceiling), top_recipient_share and top5_recipient_share (the single / top-five recipients' share of gross obligated dollars, bounded 0-1; near 0 = open field, near 1 = wired to incumbents), and incumbents (top recipients by dollars). A program with no award history returns the block with nulls and has_award_history: false.
{
"cfda": "93.213",
"program_intel": {
"distinct_awards": 502,
"distinct_recipients": 191,
"total_obligated": 147267122.91,
"median_award": 405588.0,
"top_recipient_share": 0.0648, /* top recipient holds ~6.5% — an open field */
"top5_recipient_share": 0.2013,
"incumbents": [
{ "recipient_name": "UNIVERSITY OF CALIFORNIA, SAN DIEGO", "awards": 14, "total_obligated": 10005309.0 },
{ "recipient_name": "YALE UNIV", "awards": 15, "total_obligated": 6533364.0 }
]
},
"open_opportunity_count": 70,
"_sources": ["grants_gov", "usaspending_fabs"]
}
Errors
- 402 — Pro plan required.
- 422 —
cfda is not a valid Assistance Listing number (format NN.NNN).
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/grant-programs/93.213"
GET /api/v1/awards/search Requires Auth
Search federal contract awards as a lean, award-focused list. Filter by awardee name, UEI, agency, NAICS, amount range, date range, or state. Each result is a 16-field record; pair the notice_id with /opportunities/{notice_id} for the full 59-field record when you need more.
For FPDS prime contract data, use /api/v1/contracts/*. This endpoint reads SAM Award Notices, which cover roughly 10 to 30 percent of federal contract obligations depending on the agency. The
/contracts/* surface covers every FPDS prime contract action in the same coverage window, with denser subaward enrichment on the detail endpoint and a dedicated modification-trail endpoint. This endpoint remains in service for integrations that depend on its 16-field shape and CO contact field.
How It Works
- All filters on every plan. Unlike opportunities, awards filters are not plan-gated. Plans differ on page size (Free 50, paid 1,000) and rate limit, not filter access.
- Partial matching:
awardee_name and agency are case-insensitive substring matches. awardee_name=boeing matches "BOEING DISTRIBUTION SERVICES, INC", "BELL BOEING JOINT PROJECT OFFICE", etc.
- Cross-reference to the full record: every result carries
notice_id; pass it to /opportunities/{notice_id} for the complete 59-field record.
- Exact
total, no estimate cap. Unlike opportunities search, pagination.total here is an exact count (no total_is_estimate flag). Page-forward math is reliable.
Concepts to know before you integrate.
award_amount is not always a clean dollar value. It can be 0 (common on indefinite-delivery-vehicle base records), null (no amount on the notice), or rarely a placeholder sentinel like 999999999999. Filter and aggregate defensively when you sum or sort.
award_date is the contract/award date, a calendar date with no time or timezone, distinct from posted_date on the parent notice. A small number of records carry implausible years (you may see a date like 9202-09-28 or 1921-09-27) straight from the source data. Because the default sort is award_date DESC, those corrupted future dates land at the very top of an unfiltered search. Add awarded_before=<today's date> or sort by award_amount if you need a clean newest-first list.
awardee_state is the awardee company's state, not the place of performance. If you want where the work happens, that lives on the parent notice (use the detail endpoint).
awardee_name is a raw source string and often has address fragments appended, e.g. "Boeing Company, The MO 63134-1939 USA". Match with substrings; prefer uei for identity when you have one.
award_uei_sam is missing on a share of records. A uei filter exact-matches only records where the UEI is populated; awards without a UEI are silently excluded even when the company is right. For broader coverage, fall back to awardee_name.
Filter Parameters
awardee_name — Company name (case-insensitive substring on awardee_name). Alias: name.
uei — Exact UEI match. Uppercased server-side; lowercase works.
naics — Exactly 6 digits. 2-5 digit prefix returns 400; a well-formed but nonexistent 6-digit code returns 200 with total=0 (an empty result can mean "bad code," not "no awards").
agency — Awarding agency, case-insensitive substring on the dotted hierarchy path.
amount_min — Minimum award_amount (≥ 0). amount_min=0 is applied — it excludes null-amount rows.
amount_max — Maximum award_amount.
awarded_after — Awards on or after this calendar date (YYYY-MM-DD). Subject to the plan history window (see note below). Alias: date_from.
awarded_before — Awards on or before this date (YYYY-MM-DD). Alias: date_to.
state — Awardee state code (2-letter, uppercased). This is the awardee's HQ state, NOT performance.
sort_by — award_amount, award_date, awardee_name. Default is award_date. Invalid value returns 400 with the valid list (no silent fallback).
sort_order — asc or desc (default desc). NULLs sort first on asc, last on desc. Tie-broken by notice_id for stable pagination.
limit — Page size. Framework floor 1 (limit=0 returns 422); over the plan cap returns 403 (Free 50, paid 1,000). Default 20.
offset — ≥ 0. Negative returns 422.
fields — Comma-separated projection; notice_id always included. Unknown name returns 400. See Response Shaping.
This endpoint is subject to the plan history window: awarded_after is injected (when omitted) or clamped (when older than the floor), the same way date_from behaves on opportunities search. Always read filters_applied.awarded_after to see the effective date. Because of the corrupted future-dated rows discussed in the concepts note above, awarded_before does not cleanly cap the top of the result set either — pin both bounds when you need a tight range.
Filters not available here (use
/opportunities/search instead):
keywords,
psc,
set_aside,
notice_type,
active_only,
has_attachments,
value_min /
value_max. Awards has the award-specific
amount_min /
amount_max and
awarded_* dates instead. There is no
keywords equivalent on this endpoint; use opportunities search and filter by
notice_type=Award Notice if you need full-text matching.
Response (16 fields per award)
{
"data": [
{
"award_number": "FA8620-25-C-0012",
"awardee_name": "NORTHROP GRUMMAN SYSTEMS CORP",
"awardee_uei": "MF2LE5RK6L84",
"award_amount": 12500000,
"award_date": "2026-03-15",
"agency": "DEPT OF THE AIR FORCE",
"naics": ["336411"],
"solicitation_number": "FA8620-25-R-0009",
"title": "Advanced Sensor Integration Support",
"set_aside_type": null,
"awardee_cage_code": "80205",
"awardee_city": "MELBOURNE",
"awardee_state": "FL",
"contact_name": "John Smith",
"contact_email": "
[email protected]",
"notice_id": "abc123def456"
}
],
"pagination": {
"limit": 20,
"offset": 0,
"total": 847,
"has_next": true
},
"filters_applied": {}
}
Examples
Find awards by company name:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/awards/search?awardee_name=boeing&limit=10"
DoD awards over $1M in 2025:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/awards/search?agency=defense&amount_min=1000000&awarded_after=2025-01-01"
IT services awards in Virginia:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/awards/search?naics=541519&state=VA"
Find all awards for a specific company by UEI:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/awards/search?uei=XX2WFHJEFB45&sort_by=award_date"
For FFATA subaward enrichment on a specific contract, use the single-record /awards/{award_number} endpoint; the full prime→sub flow with named sub-vendors is on the dedicated /subawards/* surface.
GET /api/v1/awards/{award_number} Requires Auth
Fetch a single award by its contract / award number (also called the PIID). Returns the most recent record when more than one row shares that number.
Path is the contract number, not a notice_id. Award numbers are free-form government contract numbers like
N00019-21-G-0006,
1240LT22P0040, or
SPE7M326P0980. URL-encode the value if it contains slashes or spaces. This is the opposite of
/opportunities/{notice_id}, which requires a 32-character hex string. There is
no format validation on this path: any string is accepted and simply 404s if it matches no award.
Parameters
award_number (path) — free-form contract / PIID. URL-encode slashes or spaces.
No query parameters are accepted; ?fields= projection is not available on this endpoint.
Response
The record is wrapped under award and contains the same 16 fields as a /awards/search result.
{
"award": {
"award_number": "SPE7M326P0980",
"awardee_name": "BOEING DISTRIBUTION SERVICES X, INC.",
"awardee_uei": "X3K6MA9ZLTW6",
"award_amount": 57162.78,
"award_date": "2026-05-05",
"agency": "DEPT OF DEFENSE.DEFENSE LOGISTICS AGENCY...",
"naics": ["332996"],
"solicitation_number": "SPE7M325T5343",
"title": "47--TEE,TUBE",
"set_aside_type": null,
"awardee_cage_code": "2N935",
"awardee_city": null,
"awardee_state": null,
"contact_name": "William Cain",
"contact_email": "
[email protected]",
"notice_id": "16a371c902134176812010635c459345"
}
}
Same data caveats as /awards/search (corrupted dates, amount sentinels, address-laden names, null UEIs). For the full ~59-field record (place of performance, full contacts, links, description, archive dates), take the notice_id from this response and call /api/v1/opportunities/{notice_id}.
Why "most recent if multiple"
One award_number can map to more than one stored row. An award gets modifications over its life, and modified awards sometimes appear as separate rows with the same contract number. This endpoint resolves the ambiguity by returning the latest by award_date (ORDER BY award_date DESC NULLS LAST LIMIT 1). To see every version, list the company's awards via /companies/{uei}/awards, or search by the parent solicitation on opportunities search.
Errors
- 404 — no award with that number. Body:
{"detail": "Award not found: {award_number}"}.
- 429 — rate limit exceeded.
- 500 — unexpected. Body:
{"detail": "Failed to retrieve award"} (sanitized).
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/awards/SPE7M326P0980"
Scope reminder: like all award endpoints, this is SAM Award Notice data, not the full FPDS contract history. See the /awards/search scope note.
Subaward enrichment
For subaward context on a federal prime contract, use the /api/v1/contracts/{piid} endpoint. The PIID-based join through the prime contract layer covers roughly 88% of FY2025+ subaward activity, versus under 1% for the SAM Award Notice slice this endpoint serves.
GET /api/v1/entities/{uei} Requires Auth
Single SAM-registered entity by UEI. Returns the registration block (status, expiration, dates) and the entity block (legal name, address, NAICS, PSC, business-type certifications, CAGE codes). Available on Developer tier; Pro subscribers can use /api/v1/companies/{uei} for the same data merged with award history.
Parameters
uei (path) - 12-character SAM Unique Entity Identifier. Normalized: lowercase, mixed case, and surrounding whitespace are accepted.
Response
{
"uei": "XX2WFHJEFB45",
"registration": {
"status": "A",
"active": true,
"registration_date": "2001-08-16",
"activation_date": "2026-01-21",
"expiration_date": "2027-01-19",
"expiring_soon": false,
"source_extract_date": "2026-04-05"
},
"entity": {
"legal_business_name": "KAMPI COMPONENTS CO INC",
"dba_name": null,
"entity_structure_code": "2L",
"entity_url": "www.kampi.com",
"physical_address": {
"street1": "...", "city": "FAIRLESS HILLS",
"state": "PA", "zip": "19030", "country": "USA"
},
"primary_naics": "423990",
"naics_codes": ["423990Y", "332710Y", "..."],
"psc_codes": ["...", "..."],
"business_types": ["2X", "XS"],
"business_types_labels": [
"For Profit Organization",
"Subchapter S Corporation"
],
"cage_codes": ["7Z016"]
}
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/entities/XX2WFHJEFB45"
Errors: 401 (no auth), 404 (UEI not in current SAM data), 429 (rate limit).
Not every valid-shape UEI is in the registry. A 12-character UEI passing format validation can still 404 here. Reasons include: the entity has expired its SAM registration and dropped out of the public extract; the UEI was issued for a registration that never completed; it's a non-public or excluded entity. We carry ~873K firms (the public V2 monthly snapshot). Expect a non-trivial 404 rate when batch-looking-up UEIs from external lists. If you need only firms currently active in SAM, append ?active_only=true to /api/v1/entities/search instead.
Use cases: compliance checks before contract signing (registration.active + registration.expiration_date), CRM enrichment, vendor-onboarding form auto-fill, set-aside qualification preview (entity.business_types_labels).
Pro enrichment fields Pro
When the caller has Pro, two families of enrichment fields are added inline alongside the SAM data. Fields are omitted entirely on non-Pro keys; existing Developer-tier integrations see exactly the SAM record above.
FFATA subaward income — what this UEI received as a sub-vendor:
sub_revenue_total — sum of FFATA dollars received as a sub-vendor within current subaward coverage (FY2025 + FY2026 today; window scales as backfill lands).
top_paying_primes — up to 10 {uei, name, total, subaward_count} objects, sorted desc by total.
FPDS prime contract activity — what this UEI has been awarded directly as a prime:
fpds_obligated_total — sum of federal action obligation across every FPDS transaction for this UEI in the FY2025-onward window (since 2024-10-01).
fpds_distinct_contracts / fpds_transaction_count — count of distinct contracts and total transactions (base awards + every modification).
fpds_first_action_date / fpds_latest_action_date — ISO date bounds.
Field shapes are documented once at the top of the Endpoints section under Pro enrichment fields (universal pattern).
Worked example (Pro response, both enrichment families present)
Live GET /api/v1/entities/CKV2L9GZKJK3 excerpt (verified 2026-06-01):
{
"uei": "CKV2L9GZKJK3",
"registration": { "..." },
"entity": { "..." },
"sub_revenue_total": 126453199.25,
"top_paying_primes": [
{"uei": "SMNWM6HN79X5", "name": "GENERAL DYNAMICS INFORMATION TECHNOLOGY, INC.",
"total": 26501723.69, "subaward_count": 1},
{"uei": "XDDKMXTVJSN8", "name": "COGNOSANTE MVH LLC",
"total": 21702000.00, "subaward_count": 1},
"...up to 10 entries"
],
"fpds_obligated_total": 4179687234.11,
"fpds_distinct_contracts": 908,
"fpds_transaction_count": 2808,
"fpds_first_action_date": "2024-10-01",
"fpds_latest_action_date": "2026-05-29",
"_sources": ["sam_entities", "usaspending_ffata", "usaspending_fpds"]
}
For per-record drill-down, use the underlying surfaces: /api/v1/contracts/search?uei=… for every FPDS transaction; /api/v1/companies/{uei}/prime-relationships for every subaward received. The combined prime + sub revenue picture with prime_revenue_share lives on /api/v1/companies/{uei} (also Pro). The bidirectional vendor-risk view (as_prime + as_sub + contract_exposure) lives on /api/v1/vendor-risk/{uei}.
GET /api/v1/entities/by-cage/{cage_code} Requires Auth
Same record as /api/v1/entities/{uei}, keyed by 5-character CAGE code instead of UEI. Adds a queried_cage field at the top of the response so callers can confirm the match. Useful for legacy DoD systems that key on CAGE.
Parameters
cage_code (path) - 5-character DLA-issued CAGE code. Normalized: lowercase and surrounding whitespace are accepted and converted to uppercase.
Response
{
"queried_cage": "53YC5",
"uei": "C111ATT311C8",
"registration": { "status": "A", "active": true, "...": "..." },
"entity": { "legal_business_name": "K & K CONSTRUCTION SUPPLY INC", "...": "..." }
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/entities/by-cage/53YC5"
Errors: 401, 404 (CAGE not found), 429.
Note: Most entities have one CAGE code. Some large organizations (USPS, large banks) have many - up to 80. The entity.cage_codes array in the response lists all CAGE codes registered to the resolved UEI.
Pro enrichment fields Pro. When the caller has Pro, the response carries the same enrichment families as /entities/{uei} — FFATA subaward income (sub_revenue_total, top_paying_primes) and FPDS prime contract activity (fpds_obligated_total, fpds_distinct_contracts, fpds_transaction_count, fpds_first_action_date, fpds_latest_action_date) — computed against the UEI the CAGE resolves to. See the /entities/{uei} section for worked example and field documentation.
GET /api/v1/entities/search Requires Auth Pro (filters)
Filter-based entity search. Name-only search (q) is available on Developer tier. Multi-filter search (any of naics / state / business_type / active_only) requires Pro. The DSBS replacement: programmatic NAICS x state x certification x active-status filtering across the SAM directory.
Parameters
q - Name substring (2-250 chars, case-insensitive, trigram-indexed). Developer tier.
naics - 6-digit NAICS code, no Y/N suffix. Matches both primary_naics and any code in naics_codes[]. Pro tier.
state - 2-character US state code. Pro tier.
business_type - 2-3 character SAM business-type code (e.g. 8W = WOSB, QF = SDVOSB, 27 = Self-Cert SDB). Unknown codes return 400. Pro tier.
active_only - true restricts to registration_status='A'. Pro tier.
limit - Results per page (1-100, default 20).
offset - Pagination offset (default 0).
fields - Comma-separated response fields. uei always included. Example: fields=uei,legal_business_name,primary_naics. See Response Shaping.
At least one of q / naics / state / business_type / active_only must be provided.
Response
The row array is returned under BOTH results AND data (identical contents). Either key is safe to read.
{
"query": {"q": null, "naics": "541330", "state": "CA", "business_type": "8W", "active_only": true},
"pagination": {"limit": 20, "offset": 0, "total": 487, "has_next": true},
"results": [
{
"uei": "...",
"legal_business_name": "ACME ENGINEERING LLC",
"dba_name": null,
"registration_status": "A",
"registration_expiration_date": "2026-08-12",
"primary_naics": "541330",
"business_types": ["27", "2X", "8W", "A2", "LJ"],
"business_types_labels": [
"Self Certified Small Disadvantaged Business",
"For Profit Organization",
"Women-Owned Small Business (WOSB)",
"Woman-Owned Business",
"Limited Liability Company"
],
"physical_city": "OAKLAND",
"physical_state": "CA",
"physical_country": "USA"
}
],
"data": [ "...same rows as results above..." ]
}
Examples
# Developer tier: name search
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/entities/search?q=KAMPI&limit=5"
# Pro: multi-filter
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/entities/search?state=CA&business_type=8W&active_only=true"
Errors: 400 (no params provided OR unknown business_type), 401, 402 (Pro filter without contacts_access), 422 (validation), 429.
Note: Results are ranked by name similarity when q is provided; filter-only searches are ordered by legal_business_name. SBA-certified codes (A6=8(a), XX=HUBZone, A4=SBA-SDB) are essentially absent from this dataset; the closest available signals are self-cert variants (27, 8W, QF).
GET /api/v1/entities/expiring Requires Auth Pro
Active SAM registrations expiring within within_days days. Sorted by urgency (most urgent first). Past-due registrations are excluded (their status is 'E'). The renewal-radar use case: compliance dashboards, renewal-reminder SaaS, BD pipelines flagging at-risk leads.
Parameters
within_days - 1-365, default 60. Days from today to look ahead.
state - 2-character US state code (optional).
naics - 6-digit NAICS code, no suffix (optional). Matches both primary_naics and naics_codes[].
limit - 1-500, default 50.
offset - Pagination offset (default 0).
Response
The row array is returned under BOTH results AND data (identical contents). Either key is safe to read.
{
"query": {"within_days": 30, "state": "DC", "naics": null},
"pagination": {"limit": 50, "offset": 0, "total": 391, "has_next": true},
"results": [
{
"uei": "...",
"legal_business_name": "ACME CONSULTING LLC",
"registration_status": "A",
"registration_expiration_date": "2026-05-12",
"days_until_expiration": 12,
"primary_naics": "541611",
"business_types": ["27", "2X", "8W"],
"business_types_labels": [
"Self Certified Small Disadvantaged Business",
"For Profit Organization",
"Women-Owned Small Business (WOSB)"
],
"physical_city": "WASHINGTON",
"physical_state": "DC",
"physical_country": "USA"
}
],
"data": [ "...same rows as results above..." ]
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/entities/expiring?within_days=30&state=DC&limit=20"
Errors: 401, 402 (not on Pro), 422 (within_days out of 1-365), 429.
Note: days_until_expiration is computed at request time. Cached responses can drift. Sort is fixed at urgency-ascending.
GET /api/v1/federal-hierarchy Requires Auth
Search and filter the SAM Federal Hierarchy: the canonical tree of federal departments, agencies, offices, bureaus, and commands (~907 organizations). Use it to resolve and normalize agency identity, walk the org tree, or join external datasets on Treasury cgac codes. Free on any plan; this is reference data.
Parameters
type - Org type, uppercased: DEPARTMENT, AGENCY, OFFICE, BUREAU, MAJOR COMMAND, SUB COMMAND, DIVISION.
cgac - Treasury Common Government-wide Accounting Code, e.g. 097 (DoD), 017 (Navy). Many orgs share a department's cgac.
parent_id - Filter to immediate children of this organization_id.
hierarchy_level - Depth; 1 = root department.
is_active - Defaults to true. Pass is_active=false to include inactive orgs.
search - Case-insensitive match across canonical name, short name, and alternative names (≥ 2 chars).
limit - 1-1000, default 50.
offset - ≥ 0.
Response (list rows, 9 fields)
{
"data": [
{
"organization_id": 300000188,
"fh_key": "300000188",
"cgac": "017",
"canonical_name": "DEPT OF THE NAVY",
"short_name": "USN",
"type": "AGENCY",
"hierarchy_level": 2,
"parent_id": 100000000,
"is_active": true
}
],
"pagination": { "limit": 50, "offset": 0, "total": 1, "has_next": false }
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/federal-hierarchy?search=navy&limit=10"
Note: Both /federal-hierarchy and /federal-hierarchy/ work; no redirect. total is exact. Results ordered by hierarchy_level then canonical_name. Reference data; expect rare changes. Key your joins on organization_id (stable integer).
GET /api/v1/federal-hierarchy/{organization_id} Requires Auth
Look up one federal organization by integer ID, returning its full 17-field record plus its parent, immediate children, and full ancestor chain in a single call. Useful for rendering breadcrumbs, expanding tree nodes, or joining a downstream dataset against the org tree without extra round-trips.
Parameters
organization_id (path) - Integer org ID. Non-integer returns 422; unknown ID returns 404.
Response
{
"data": {
"organization_id": 300000188,
"fh_key": "300000188",
"cgac": "017",
"canonical_name": "DEPT OF THE NAVY",
"short_name": "USN",
"alternative_names": ["USN", "..."],
"type": "AGENCY",
"description": "...",
"is_active": true,
"parent_id": 100000000,
"hierarchy_level": 2,
"hierarchy_path": [100000000, 300000188],
"hierarchy_names": ["DEPT OF DEFENSE", "DEPT OF THE NAVY"],
"source_modified_at": "...",
"source_indexed_at": "...",
"last_seen": "...",
"source_version": "..."
},
"parent": { /* 9-field list-shape row; null for root departments */ },
"children": [ { /* 9-field rows, immediate children, name-sorted */ } ],
"ancestors": [ { /* 9-field rows, root department first */ } ]
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/federal-hierarchy/300000188"
Errors: 401, 404 (unknown ID), 422 (non-integer path), 429.
Note: data is the full 17-field record; parent / children / ancestors are the 9-field list shape. hierarchy_path is the ordered list of ancestor IDs (root first), the same source used to build the inline ancestors array.
GET /api/v1/federal-hierarchy/{organization_id}/children Requires Auth
Return the immediate child organizations of one org (one level down), ordered by name. Use it to expand one node of the tree without pulling the full detail response.
Response
{
"data": [
{ "organization_id": 300000188, "fh_key": "300000188", "cgac": "017",
"canonical_name": "DEPT OF THE NAVY", "short_name": "USN", "type": "AGENCY",
"hierarchy_level": 2, "parent_id": 100000000, "is_active": true }
],
"count": 1
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/federal-hierarchy/100000000/children"
Note: Immediate children only, not the full subtree. A leaf org (or an unknown integer ID) returns { "data": [], "count": 0 } with a 200, not a 404; if you need to confirm the org exists, use the detail endpoint instead.
GET /api/v1/federal-hierarchy/{organization_id}/ancestors Requires Auth
Return the chain of ancestors for one org, ordered root department first down to the immediate parent. Use it to render breadcrumbs ("DEPT OF DEFENSE > DEPT OF THE NAVY > ...") for any organization.
Response
{
"data": [
{ "organization_id": 100000000, "canonical_name": "DEPT OF DEFENSE",
"short_name": "DOD", "type": "DEPARTMENT", "hierarchy_level": 1,
"parent_id": null, "is_active": true, "cgac": "097", "fh_key": "100000000" }
],
"count": 1
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/federal-hierarchy/300000188/ancestors"
Errors: 401, 404 (unknown org), 422 (non-integer path), 429.
Note: Order is root → immediate parent. Root organizations return { "data": [], "count": 0 }. Unknown IDs return 404 (this endpoint checks existence first, unlike children which returns an empty list).
GET /api/v1/companies/search Requires Auth Pro
Find distinct awardees by name substring or UEI prefix. Returns each company once with aggregate stats, ranked by total award count. Pro only; Developer-tier keys get a 402.
Parameters
q (required) - Search string, 2-250 chars. Matches against awardee name (case-insensitive substring) and UEI prefix.
naics (optional) - 6-digit NAICS code. Filters to companies that have actually won at least one award under this NAICS. Non-6-digit values return a 400. Distinct from Federal Contractor Search, which filters by SAM-registration data ("registered for NAICS X" vs "won awards under NAICS X").
agency (optional) - Top-level agency name (e.g. DEPT OF DEFENSE). Matches the top-level of SAM's dotted agency path. Filters to companies with at least one award from this agency.
limit - Results per page (1-100, default 20)
offset - Pagination offset, default 0
fields - Comma-separated response fields. uei always included. Example: fields=uei,name,total_value. See Response Shaping.
Response
The row array is returned under BOTH results AND data (identical contents — data was added for envelope consistency with other list endpoints; results stayed for backward compatibility). Either key is safe to read.
{
"query": {"q": "LOCKHEED", "naics": null, "agency": null},
"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"
}
],
"data": [ "...identical to results array above..." ]
}
When naics or agency filters are applied, total_awards / total_value on each result reflect only the subset of awards matching the filter, not the company's full award history. Use GET /api/v1/companies/{uei} for the full profile.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/companies/search?q=lockheed&limit=5&offset=0"
# With filters:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/companies/search?q=kampi&naics=332510&agency=DEPT+OF+DEFENSE"
Notes: LIKE wildcard characters (%, _) in the query are escaped. Trigram search matches substrings at any position, so q=ARTIN finds MARTIN MILITARY INC. UEI prefix matching is case-insensitive. Use pagination.total + pagination.has_next to page through deep result sets.
GET /api/v1/companies/{uei} Requires Auth Pro
Combined SAM registration + award profile for one UEI. Returns 200 if either the SAM entity registry or our award data has the UEI; returns 404 only when both miss. Award fields populate when the UEI has at least one Award Notice; otherwise they zero out and the registration / entity blocks still populate.
Parameters
uei (path) - 12-character SAM Unique Entity Identifier. Normalized: lowercase, mixed case, and surrounding whitespace are accepted.
Response
{
"uei": "XX2WFHJEFB45",
"name": "KAMPI COMPONENTS CO INC",
"primary_city": "FAIRLESS HILLS",
"primary_state": "PA",
"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}
],
"top_agencies": [
{"agency": "DEPT OF DEFENSE", "awards": 601, "value": 168200000.0}
],
"top_agency_share_pct": 100.0,
"set_aside_distribution": [
{"set_aside": "UNRESTRICTED", "awards": 830, "value": 218000000.0, "pct_of_awards": 98.6},
{"set_aside": "SBA", "awards": 6, "value": 4500000.0, "pct_of_awards": 0.7},
{"set_aside": "NONE", "awards": 6, "value": 13000000.0, "pct_of_awards": 0.7}
],
"registration": {
"status": "A",
"active": true,
"registration_date": "2001-08-16",
"activation_date": "2026-01-21",
"expiration_date": "2027-01-19",
"expiring_soon": false,
"source_extract_date": "2026-04-05"
},
"entity": {
"legal_business_name": "KAMPI COMPONENTS CO INC",
"dba_name": null,
"entity_structure_code": "2L",
"entity_url": "www.kampi.com",
"physical_address": {
"street1": "...", "city": "FAIRLESS HILLS",
"state": "PA", "zip": "19030", "country": "USA"
},
"primary_naics": "423990",
"naics_codes": ["423990Y", "332710Y", "..."],
"psc_codes": ["...", "..."],
"business_types": ["2X", "XS"],
"business_types_labels": [
"For Profit Organization",
"Subchapter S Corporation"
],
"cage_codes": ["7Z016"]
}
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/companies/XX2WFHJEFB45"
Use cases: compliance check (registration.active + registration.expiration_date), customer-concentration risk (top_agency_share_pct — single-buyer dependents register near 100), set-aside mix (set_aside_distribution — what % of their wins are SDVOSB / WOSB / 8(a)), pipeline health (awards_last_90d vs awards_last_12mo), capability mapping (top_naics, entity.business_types_labels). UEI normalization: lowercase, mixed case, and surrounding whitespace are accepted.
For SAM-data-only lookups without the award merge, see /api/v1/entities/{uei} (Developer tier).
Subaward revenue fields
The profile carries three subaward fields alongside the prime-award totals (within current subaward coverage — FY2025 + FY2026 today). They surface the "true federal revenue" picture that prime-only data misses — for SMBs in particular, sub revenue is often the larger half:
sub_revenue_total — total dollars this UEI has received as a sub-vendor (sum of subaward_amount).
top_paying_primes — up to 10 primes that have paid this UEI as a sub, sorted by total $. Each entry: {uei, name, total, subaward_count}.
prime_revenue_share — float in [0, 1], the share of this UEI's combined federal revenue that came in as prime contracts (vs subs). Computed as fpds_obligated_total / (fpds_obligated_total + sub_revenue_total), using the FPDS prime obligation total (not the SAM-noticed total_value, which undercounts prime work and would read near 0 for FPDS-active firms). null when neither prime nor sub revenue exists; a pure-prime vendor reads 1.0.
Fields are populated for every UEI we have profile data on; sub_revenue_total and top_paying_primes zero out when no subawards exist (prime_revenue_share then reads 1.0 if the UEI has FPDS prime activity, and is null only when it has neither prime nor sub revenue). For the underlying records, use /api/v1/companies/{uei}/prime-relationships.
FPDS prime contract activity fields
The profile also carries FPDS prime contract aggregates from the federal procurement system of record. These cover the recipient's full direct prime contract activity (every base award and modification under their UEI in the plan window), where the SAM Award Notice total_value field above covers only the SAM-noticed slice (~10-30% of obligations). Both views are surfaced so callers can pick the denominator that matches their question.
fpds_obligated_total — total federal_action_obligation obligated to this UEI as a prime, summed across every FPDS transaction in the FY2025-onward window (since 2024-10-01).
fpds_distinct_contracts — count of distinct contracts (contract_award_unique_key) the recipient holds.
fpds_transaction_count — count of every FPDS row: base awards plus every modification.
fpds_first_action_date / fpds_latest_action_date — ISO date bounds on the recipient's FPDS activity in the window.
fpds_top_naics — array of up to 5 {code, description, transaction_count, value} objects, top NAICS by total $. Each object also includes a deprecated n field with the same value as transaction_count.
fpds_top_agencies — array of up to 5 {name, transaction_count, value} objects, top awarding sub-agencies by total $. Each object also includes a deprecated n field.
Worked example (Pro response, FPDS + subaward enrichment)
Calling GET /api/v1/companies/CKV2L9GZKJK3 (Deloitte Consulting LLP) on a Pro key returns the SAM profile + award aggregates documented above, plus enrichment fields. Live response excerpt (verified 2026-06-15):
{
"uei": "CKV2L9GZKJK3",
"name": "DELOITTE CONSULTING LLP",
"total_awards": 12,
"total_value": 1310256763.79,
"...": "SAM registration + award profile fields above",
"sub_revenue_total": 126453199.25,
"top_paying_primes": [
{"uei": "SMNWM6HN79X5", "name": "GENERAL DYNAMICS INFORMATION TECHNOLOGY, INC.",
"total": 26501723.69, "subaward_count": 1},
{"uei": "XDDKMXTVJSN8", "name": "COGNOSANTE MVH LLC",
"total": 21702000.00, "subaward_count": 1},
"...up to 10 entries"
],
"prime_revenue_share": 0.971,
"fpds_obligated_total": 4228940959.11,
"fpds_distinct_contracts": 914,
"fpds_transaction_count": 2856,
"fpds_first_action_date": "2024-10-01",
"fpds_latest_action_date": "2026-06-12",
"fpds_top_naics": [
{"code": "541512", "description": "COMPUTER SYSTEMS DESIGN SERVICES",
"transaction_count": 913, "n": 913, "value": 2051661176.18},
{"code": "541611", "description": "ADMINISTRATIVE MANAGEMENT AND GENERAL MANAGEMENT CONSULTING SERVICES",
"transaction_count": 1142, "n": 1142, "value": 1138031790.98},
"...up to 5 entries"
],
"fpds_top_agencies": [
{"name": "Federal Acquisition Service", "transaction_count": 228, "n": 228, "value": 905220054.81},
{"name": "Department of Veterans Affairs", "transaction_count": 70, "n": 70, "value": 529603511.82},
"...up to 5 entries"
],
"_sources": ["sam_entities", "sam_opportunities", "usaspending_ffata", "usaspending_fpds"]
}
Notice the magnitude split: total_value (the SAM-noticed slice, only 12 award notices) is ~$1.31B, while fpds_obligated_total (the full prime contract picture across 914 contracts and 2,856 transactions, FY2025 onward) is ~$4.23B. fpds_obligated_total is the authoritative federal-activity number for this recipient.
GET /api/v1/companies/{uei}/awards Requires Auth Pro
Paginated award history for one UEI. Same data as /api/v1/awards/search?uei=X, served under a company-centric URL for convenience.
Parameters
limit - Results per page (1-1000, default 50)
offset - Pagination offset (default 0, no upper bound)
sort - date (default, desc) or amount (desc). Strict: any other value returns 422.
sort_by / sort_order - cross-endpoint alias matching awards search: sort_by=award_date|award_amount with sort_order=asc|desc (default desc). Wins over sort when present, and unlike sort it supports ascending order. Invalid sort_by returns 400.
fields - Comma-separated response fields. notice_id always included. Example: fields=notice_id,award_amount,award_date,agency. See Response Shaping.
Response
{
"uei": "XX2WFHJEFB45",
"pagination": {"limit": 50, "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"
}
]
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/companies/XX2WFHJEFB45/awards?limit=100&sort=amount"
GET /api/v1/companies/{uei}/peers Requires Auth Pro
Similar companies ranked by NAICS and agency overlap with the target. Use for competitive mapping, teaming-partner discovery, and BD target lists.
Parameters
limit - Results (1-50, default 10)
Response
{
"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
}
]
}
Ranking
similarity_score = naics_overlap * 3 + agency_overlap. NAICS is weighted 3x higher because same-industry is a direct competition signal; shared customers is a weaker signal. Results sorted by similarity_score desc, then total_awards desc.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/companies/XX2WFHJEFB45/peers?limit=10"
GET /api/v1/subawards/search Requires Auth
Filter-based search across the FFATA subaward record set: every Section 2 report of a sub-vendor receiving more than $30K under a federal prime contract, sourced from USAspending's bulk_download. One denormalized 118-field row per FFATA report. Use it to map a prime contract's supply chain, find every prime that paid a given sub, or pull all subaward flow under one PIID. Refreshed daily; 2-day source lag.
At least one filter is required. One of prime_uei, sub_uei, piid, agency, naics, or sub_name must be present. A bare call returns 400. Dates, amounts, sort, and projection are not filters in this sense.
Concepts to know before you integrate.
- One row per FFATA report, not one row per prime contract. A single prime contract (one
prime_award_piid) appears in many subaward rows — one per sub-vendor per reporting modification. Aggregations over prime_award_amount grouped by anything other than the PIID will multi-count.
subcontract_share from SUM(subaward_amount) / prime_award_amount can exceed 1.0. FFATA reports modifications cumulatively (each modification re-reports the full subaward value), so summing subaward dollars across modifications can exceed the prime ceiling. Treat values >1.0 as "heavily modified, multi-revision contract" — useful signal, not a parsing bug. Documented in Data Freshness.
- Pre-UEI era records have DUNS only. FFATA reporting moved to UEI in 2022; older records carry
subawardee_duns / prime_awardee_duns but null _uei columns. Filtering by UEI silently excludes them; use both for full coverage.
- HCOs (Highly Compensated Officers) populate sparsely. Only entities above the FFATA Section 2 reporting threshold (federal income >$25M AND >80% of total annual income) report the five named HCO fields. Most rows have null HCOs by design.
prime_awardee_parent_uei and subawardee_parent_uei are sparse. Populated only when the awardee declared a corporate parent in FFATA reporting. Don't assume them for hierarchy queries.
subawardee_business_types is a TEXT comma-separated string, not an array. Avoid LIKE '%SDVOSB%' queries — those also match NON-SDVOSB-tagged records. Match against the canonical SAM codes if you need accuracy.
- Treasury account fields are pipe-delimited inside the cell.
treasury_accounts_funding_this_award and siblings carry the source funding breakdown as a single TEXT string with | separators. Parse client-side as needed.
Filter parameters
prime_uei — 12-character UEI. Returns subawards paid by this prime. Normalized (strip + upper). Exact length: a 13-char or 11-char value returns 422.
sub_uei — 12-character UEI. Returns subawards received by this sub-vendor. Same normalization.
piid — Prime award PIID (max 80 chars). Returns all subaward records flowing from that single contract. Normalized (strip + upper); free-form government contract numbers.
agency — Awarding agency name substring (case-insensitive, max 200 chars). Matches prime_award_awarding_agency_name.
naics — Exactly 6 digits. Matches prime_award_naics_code. A 1-digit / 5-digit / 7+ digit value returns 400; well-formed but nonexistent codes return 200 with total=0.
sub_name — Sub-vendor name substring (3-200 chars, case-insensitive). Matches subawardee_name.
Date, amount, sort, paging
date_from / date_to — YYYY-MM-DD. Filter subaward_action_date. Subject to the subaward history window (see Search Window); the window block in the response surfaces clamping. Effective floor today is the data floor (2024-10-01).
amount_min / amount_max — Filter subaward_amount. amount_min=0 is honored (excludes null-amount rows).
sort_by — subaward_action_date (default), subaward_amount, or subaward_sam_report_last_modified_date. Invalid value returns 400 with the valid list — no silent fallback.
sort_order — asc or desc (default desc). NULLs sort first on asc, last on desc. Tie-broken by subaward_sam_report_id for stable pagination.
limit — 1-250 (default 50). Capped lower than /opportunities/search and /awards/search (which allow 1,000) because each subaward row is wider: 250 rows is ~400 KB, 1,000 rows would be ~1.5 MB. Bounds violation returns 422 (not the awards-style 403). Page size is a fixed cap on this free base layer, so there is no higher tier to upgrade to for a larger page size.
offset — ≥ 0 (default 0).
fields — Comma-separated projection. subaward_sam_report_id always included. See Response Shaping.
Unknown query params return 400 with the valid set listed in the error detail. No silent dropping.
Response (29 fields per row, subset of the 118-column corpus)
{
"data": [
{
"subaward_sam_report_id": "01b6a2d8-3e02-44f7-9b8e-...",
"subaward_number": "1A4PZ-006-WTERX",
"subaward_action_date": "2026-04-22",
"subaward_amount": 487200.00,
"subaward_description": "Engineering analysis support for radar subsystem...",
"subaward_sam_report_last_modified_date": "2026-05-28",
"prime_award_piid": "FA8620-25-C-0012",
"prime_award_parent_piid": "FA8620-22-D-0001",
"prime_award_amount": 12500000.00,
"prime_award_project_title": null,
"prime_award_naics_code": "336411",
"prime_award_naics_description": "Aircraft Manufacturing",
"prime_award_awarding_agency_name": "DEPT OF DEFENSE",
"prime_award_awarding_sub_agency_name": "DEPT OF THE AIR FORCE",
"prime_awardee_uei": "H11HD5VHGHN3",
"prime_awardee_name": "LOCKHEED MARTIN CORPORATION",
"prime_awardee_parent_uei": null,
"prime_awardee_parent_name": null,
"prime_awardee_state_code": "MD",
"prime_awardee_country_code": "USA",
"subawardee_uei": "XX2WFHJEFB45",
"subawardee_name": "KAMPI COMPONENTS CO INC",
"subawardee_parent_uei": null,
"subawardee_parent_name": null,
"subawardee_business_types": "FOR PROFIT ORGANIZATION,SUBCHAPTER S CORPORATION",
"subawardee_state_code": "PA",
"subawardee_country_code": "USA",
"subaward_pop_state_code": "FL",
"subaward_pop_country_code": "USA",
"usaspending_permalink": "https://www.usaspending.gov/award/..."
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total": 247,
"total_is_estimate": false,
"has_next": true
},
"filters_applied": {
"prime_uei": "H11HD5VHGHN3",
"date_from": "2024-10-01",
"sort_by": "subaward_action_date",
"sort_order": "desc"
},
"window": {
"plan_window_days": 1825,
"earliest_searchable": "2024-10-01",
"clamped": false,
"reason": null
}
}
prime_award_project_title is null on the vast majority of procurement subawards — USAspending only populates it for assistance/grant subawards. prime_award_amount is the prime ceiling, the same value on every row sharing one PIID; aggregations by anything other than PIID will multi-count it.
Errors
- 400 — no filter passed / unknown query param / invalid
sort_by / naics not 6 digits.
- 401 — missing or invalid API key.
- 422 — malformed UEI length, bad date format,
limit out of range.
- 429 — rate limit exceeded.
Examples
What subs has Lockheed paid (most recent first):
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/subawards/search?prime_uei=H11HD5VHGHN3&limit=20"
Every sub under one prime contract:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/subawards/search?piid=FA8620-25-C-0012&sort_by=subaward_amount&sort_order=desc"
Sub-vendor reverse lookup (everyone who paid this UEI as a sub) over the last 12 months above $100K:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/subawards/search?sub_uei=XX2WFHJEFB45&date_from=2025-05-31&amount_min=100000"
Find subaward flow into a small-business sub-vendor by name fragment + NAICS:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/subawards/search?sub_name=acme+engineering&naics=541330"
GET /api/v1/subawards/{subaward_sam_report_id} Requires Auth
Single FFATA report by its SAM report ID (a UUID, the natural primary key of the subawards table). Returns the same 29-field row shape as a search result. Not subject to the subaward history window — if you have a report ID, the record returns regardless of age.
Parameters
subaward_sam_report_id (path) — the UUID from any row in /subawards/search (the subaward_sam_report_id field on each result). Normalized (strip + upper); accepted in mixed case. No query parameters; ?fields= is not supported on this endpoint.
Response
A flat object with the same 29 fields documented under /subawards/search → Response. No wrapper; no data / pagination / window envelope on single-record lookup.
Errors
- 401 — missing or invalid API key.
- 404 — well-formed ID, no such report. Body:
{"detail": "Subaward report not found"}.
- 429 — rate limit exceeded.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/subawards/01b6a2d8-3e02-44f7-9b8e-7b5e4c8a9d23"
Note: The natural-looking subaward_number field (e.g. 1A4PZ-006-WTERX) is not the unique identifier — empirically about 10% of subaward_number values collide across records (modifications, re-issues). The 32-character UUID subaward_sam_report_id is the only stable per-record key.
GET /api/v1/companies/{uei}/subawards Requires Auth
Prime-side reverse lookup: "what subs has this UEI paid?" Indexed on prime_awardee_uei. Same row shape as /subawards/search plus a top-level summary block aggregating across the filtered result set.
Parameters
uei (path) — 12-character UEI of the prime. Normalized.
sort_by — subaward_action_date (default), subaward_amount, or subaward_sam_report_last_modified_date.
sort_order — asc or desc (default desc).
date_from / date_to — YYYY-MM-DD. date_from is clamped to the effective subaward floor (2024-10-01 today).
limit — 1-250 (default 50). 422 on out-of-range. Tighter cap than awards/opportunities because subaward rows are wider.
offset — ≥ 0 (default 0).
fields — Comma-separated projection (subaward row columns). subaward_sam_report_id always included.
Response
{
"uei": "H11HD5VHGHN3",
"summary": {
"prime_name": "LOCKHEED MARTIN CORPORATION",
"total_subaward_amount": 48200000.00,
"distinct_sub_vendors": 127,
"distinct_prime_contracts": 14,
"first_subaward_date": "2021-08-12",
"last_subaward_date": "2026-05-28"
},
"data": [ /* same 29-field rows as /subawards/search */ ],
"pagination": { "limit": 50, "offset": 0, "total": 1247, "total_is_estimate": false, "has_next": true },
"filters_applied": { "sort_by": "subaward_action_date", "sort_order": "desc", "date_from": "2024-10-01" },
"window": { "plan_window_days": 1825, "earliest_searchable": "2024-10-01", "clamped": false }
}
UEIs with no subaward records return 200 with an empty data array and a zero summary, not a 404 — same pattern as /companies/{uei}/awards.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/companies/H11HD5VHGHN3/subawards?sort_by=subaward_amount&limit=50"
GET /api/v1/companies/{uei}/prime-relationships Requires Auth
Sub-side reverse lookup: "what primes have paid this UEI as a sub-vendor?" Indexed on subawardee_uei. Same row shape as /subawards/search plus a summary block with a top-10 paying-primes leaderboard.
Parameters
uei (path) — 12-character UEI of the sub-vendor. Normalized.
sort_by / sort_order — same as /companies/{uei}/subawards.
date_from / date_to — YYYY-MM-DD. date_from window-clamped.
limit — 1-250 (default 50). Same cap as the prime-side sibling.
offset — ≥ 0 (default 0).
fields — Comma-separated projection.
Response
{
"uei": "XX2WFHJEFB45",
"summary": {
"sub_name": "KAMPI COMPONENTS CO INC",
"total_received": 6420000.00,
"distinct_primes": 7,
"top_primes": [
{"prime_uei": "H11HD5VHGHN3", "prime_name": "LOCKHEED MARTIN CORPORATION",
"subaward_count": 12, "total": 3200000.00}
],
"first_subaward_date": "2021-08-12",
"last_subaward_date": "2026-05-12"
},
"data": [ /* same 29-field rows */ ],
"pagination": { "limit": 50, "offset": 0, "total": 31, "total_is_estimate": false, "has_next": false },
"filters_applied": { "sort_by": "subaward_action_date", "sort_order": "desc", "date_from": "2024-10-01" },
"window": { "plan_window_days": 1825, "earliest_searchable": "2024-10-01", "clamped": false }
}
For most SMBs, this is the better revenue picture than /companies/{uei}/awards — sub revenue is often the larger half of federal income, and prime-only data systematically undercounts it.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/companies/XX2WFHJEFB45/prime-relationships?limit=50"
Errors (both reverse-lookup endpoints): 401 (auth), 422 (bad UEI / out-of-range param), 429 (rate limit). 404 is not returned on "no records" — empty data with zero summary is.
GET /api/v1/partners/search Requires Auth Pro
Find federal contractors with proven past performance for a NAICS, awarding agency, place-of-performance state, or set-aside, ranked by gross obligated dollars, each with its socioeconomic status, SAM registration, and named points of contact. Composed from FPDS prime awards (FY2025 onward) plus the SAM registry. Built for teaming and subcontractor sourcing. Factual, not scored.
Parameters
At least one filter is required; the endpoint will not return the whole corpus. Unknown parameters return 400.
naics: NAICS code, exact, 2 to 6 digits.
agency: awarding agency name or acronym, resolved through the agency crosswalk (e.g. Army, Navy, Air Force). The only contractor endpoint that filters by agency.
state: 2-letter place-of-performance state.
set_aside: one of sdvosb, vosb, wosb, woman_owned, hubzone, 8a, sdb, minority_owned.
psc: Product or Service Code, exact.
keywords: matches the prime-award description text.
limit: 1 to 50, default 20.
offset: 0 to 200 (top ~250 firms per query; narrow filters for more).
Response
Standard list envelope: data, pagination, filters_applied, and _sources (["usaspending_fpds", "sam_entities"]). Results are ranked by gross_obligated descending, most recent award breaking ties; pagination.total is the exact distinct-firm count. Each row carries uei, name, contracts, gross_obligated, last_award_date, set_asides, agencies, registration_status, location, primary_naics, and pocs[] (named SAM points of contact with name, title, city, state, roles[]; no email or phone).
Rate limits
Tighter than general search because it surfaces contact data: 15 requests/minute per IP, 20/minute per key, pages capped at 50, pagination depth capped at 200. Bulk extraction is not supported by design.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/partners/search?set_aside=sdvosb&state=VA&naics=541512&limit=1"
Returns 135 SDVOSB IT firms in Virginia ranked by dollars won; the top result is Liberty IT Solutions ($228M, 5 contracts) with its Department of Veterans Affairs award record and named points of contact. See the Teaming Partner Finder guide for worked examples.
GET /api/v1/vendor-risk/{uei} Requires Auth Pro
Returns every red-flag signal the public federal record contains about one vendor UEI, plus a mechanical triage verdict so compliance teams can sort without parsing the full tree. Seven signals, all derived from SAM data: exclusion status, address cluster, name-variant cluster, individual exclusions at the same address, coordinated-wave membership, last-award-to-exclusion gap, and dual-CAGE detection.
Parameters
uei (path) - 12-character SAM UEI. Case-insensitive; non-alphanumeric input returns 422.
Response
{
"response_version": "1",
"uei": "N2EDPB1SMN55",
"entity_name": "Bella Mia Donna LLC",
"address": {"line1": "111 SW 1 ST", "city": "Pompano Beach", "state": "FL"},
"address_source": "exclusions",
"computed_at": "2026-04-24T16:22:10Z",
"triage": {
"category": "high",
"label": "High risk",
"reasons": [
"entity is currently on the federal exclusion list: Ineligible (Proceedings Pending) by DLA (create_date 2025-11-21)",
"debarred alongside 24 entities by the same agency on 2025-11-21 (coordinated enforcement wave)"
]
},
"signals": {
"exclusion_status": { "excluded": true, "exclusion_type": "Ineligible (Proceedings Pending)", "excluding_agency_code": "DLA", "create_date": "2025-11-21", "_more_keys": "see API reference for full shape" },
"address_cluster": { "total_at_address": 24, "excluded_at_address": 24, "address_type": "normal", "others": [{"uei": "...", "entity_name": "...", "create_date": "2025-11-21"}] },
"name_variant_cluster": { "match_count": 1, "excluded_match_count": 1, "variants": [] },
"individual_exclusions_at_address": { "count": 5, "individuals": [{"name": "...", "create_date": "2025-11-21"}] },
"wave_membership": { "in_coordinated_wave": true, "wave_date": "2025-11-21", "wave_size": 24, "wave_members": [{"uei": "...", "entity_name": "..."}] },
"timing_gap": { "last_sam_award_date": "2025-11-17", "exclusion_create_date": "2025-11-21", "days_between": 4 },
"dual_cage": { "has_dual_cage": false, "cage_codes": ["8SGL5"] }
},
"subaward_exposure": {
"as_prime": { "total_paid_to_subs": 0, "distinct_sub_vendors": 0, "subaward_count": 0,
"first_subaward_date": null, "last_subaward_date": null, "top_subs": [] },
"as_sub": { "total_received_from_primes": 482000.00, "distinct_primes": 3,
"subaward_count": 7, "first_subaward_date": "2024-06-04",
"last_subaward_date": "2025-11-17",
"top_primes": [{"uei": "H11HD5VHGHN3", "name": "LOCKHEED MARTIN CORP",
"total": 320000.00, "subaward_count": 4}] },
"window_days": 1825
},
"disclaimers": ["All signals derive from the public federal record."]
}
Triage categories
high - the entity itself is actively excluded.
elevated - not excluded, but ≥2 co-tenants at the same address are excluded, or a name-variant entity is excluded, or ≥1 individual exclusion shares the address.
needs_review - weaker signals only (e.g. multiple CAGE codes).
clean - no signals returned.
unknown - UEI not present in SAM exclusions or opportunities data at all.
Triage rules are deliberately simple and visible in triage.reasons so your compliance team can override by reading the signals themselves. Keys in the response are stable: values may be null, empty arrays, or false, but the shape never changes. Safe to parse with response_version branching if you need to stay compatible as we add signals.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/vendor-risk/N2EDPB1SMN55"
Notes: Returns 404 only when the UEI has no record in any of our SAM tables (exclusions, opportunities, or the ~873K-firm entity registry). SAM-registered vendors with no exclusion and no recent award still return 200 with a clean triage verdict. For non-US addresses where the state field is empty (Singapore, Hong Kong, Ankara, etc.), clustering falls back to line1+city. The address_source field tells you which table the address came from: exclusions, opportunities, entities, or unknown when no address was found. See /vendor-risk-api for signal definitions, the triage rules, and worked examples from real federal enforcement actions.
Enrichment blocks Pro
Two top-level blocks sit alongside signals and triage (NOT nested inside them) on Pro responses. Both are descriptive — they don't change the triage verdict — but compliance teams read them alongside the seven signals to size the supply-chain footprint around a single UEI.
subaward_exposure block — FFATA subaward dollar flow on both sides:
as_prime — what this UEI has paid out to sub-vendors: {total_paid_to_subs, distinct_sub_vendors, subaward_count, first_subaward_date, last_subaward_date, top_subs: [{uei, name, total, subaward_count}, ... up to 5]}.
as_sub — what this UEI has received from primes: {total_received_from_primes, distinct_primes, subaward_count, first_subaward_date, last_subaward_date, top_primes: [{uei, name, total, subaward_count}, ... up to 5]}.
window_days — the lookback (1825 today).
Both sub-blocks always populate (zero shape when no records); subaward_exposure itself is omitted only when this UEI has no record in any of our tables (i.e. when the whole response would be a 404 candidate).
contract_exposure block — FPDS prime contract activity (parallel to subaward_exposure):
fpds_obligated_total, fpds_distinct_contracts, fpds_transaction_count — magnitudes.
fpds_first_action_date, fpds_latest_action_date — activity bounds in the window.
top_agencies — array of up to 5 {name, value, transaction_count} objects, awarding sub-agencies ranked by total $.
window_days — the lookback (1825 today).
The block returns the zero shape when this UEI has no FPDS prime contract activity in the window.
Worked example (Pro response, actively excluded UEI with mixed compliance picture)
UEI C1ZLDAS18FJ3 (ATI Government Solutions) was placed on the SBA "Ineligible (Proceedings Pending)" list on 2025-10-21 alongside its 3 named principals, debarred as individuals the same day (a firm-plus-officers coordinated action; wave_size 4). The contract_exposure block surfaces activity from 2024-10-01 onward (FY2025+): $95.34M in net obligations across 33 contracts, with the IRS as the largest awarding sub-agency at $82.55M. The subaward_exposure.as_prime shows this UEI paid out $55.44M to 10 distinct sub-vendors over the same window. For the recency-focused "is the problem ongoing?" view, see the parallel example on /exclusions/{uei_sam}, where the last-365-days window shows -$9.31M net (deobligations exceeding new obligations recently). Triage scores on the seven signals above; the exposure blocks add descriptive supply-chain context.
{
"uei": "C1ZLDAS18FJ3",
"entity_name": "ATI Government Solutions",
"signals": { "..." },
"triage": {
"category": "high",
"label": "High risk",
"reasons": [
"entity is currently on the federal exclusion list: Ineligible (Proceedings Pending) by SBA (create_date 2025-10-21)",
"debarred alongside 4 entities by the same agency on 2025-10-21 (coordinated enforcement wave)"
]
},
"subaward_exposure": {
"as_prime": {
"total_paid_to_subs": 55440463.08,
"distinct_sub_vendors": 10,
"subaward_count": 16,
"first_subaward_date": "2024-10-01",
"last_subaward_date": "2025-10-22",
"top_subs": [
{"uei": "W6G5J8F8ETH7", "name": "VIBRANTECH SOLUTIONS INC.",
"total": 13591324.20, "subaward_count": 5},
{"uei": "NHPJUKUF8WL9", "name": "BASECAMP CONSULTING AND SOLUTIONS LLC",
"total": 13049945.55, "subaward_count": 1},
"...up to 5 entries"
]
},
"as_sub": {
"total_received_from_primes": 0.0,
"distinct_primes": 0,
"subaward_count": 0,
"first_subaward_date": null,
"last_subaward_date": null,
"top_primes": []
},
"window_days": 1825
},
"contract_exposure": {
"fpds_obligated_total": 95259892.19,
"fpds_distinct_contracts": 33,
"fpds_transaction_count": 122,
"fpds_first_action_date": "2024-10-23",
"fpds_latest_action_date": "2026-05-18",
"top_agencies": [
{"name": "Internal Revenue Service",
"value": 82545810.72, "transaction_count": 67},
{"name": "Office of the Assistant Secretary for Administration and Management",
"value": 5863769.27, "transaction_count": 13},
"...up to 5 entries"
],
"window_days": 1825
},
"_sources": ["derived_vendor_risk", "sam_exclusions", "sam_entities", "sam_opportunities", "usaspending_ffata", "usaspending_fpds"]
}
Field shapes for both blocks are also documented at the top of the Endpoints section under Pro enrichment fields (universal pattern). Live response verified 2026-06-01.
POST /api/v1/vendor-risk/bulk Requires Auth Pro
Bulk vendor screening. Upload up to 100 UEIs in one call and get back a risk report for each. Designed for quarterly vendor reviews where you want to screen your whole subcontractor list in one pass, not one-at-a-time.
Request body
{ "ueis": ["N2EDPB1SMN55", "C1BVCA2N9YB4", "SH2ER4W6LH13"] }
ueis - array of 1-100 UEIs. Duplicates deduplicated server-side. Max 100 per request (422 if exceeded).
Response
{
"requested_count": 3,
"returned_count": 3,
"results": [
{ "uei": "N2EDPB1SMN55", "status": "ok", "report": {"_shape": "same as GET /api/v1/vendor-risk/{uei}"} },
{ "uei": "C1BVCA2N9YB4", "status": "ok", "report": {"_shape": "same as GET /api/v1/vendor-risk/{uei}"} },
{ "uei": "SH2ER4W6LH13", "status": "not_found", "report": null },
{ "uei": "bad-uei", "status": "invalid", "report": null }
]
}
Per-row status is one of: ok (report present), not_found (UEI in none of our sources), or invalid (not 12 alphanumeric characters). A bad or stale UEI is surfaced per-row, never failing the whole request, since real vendor lists always contain some. returned_count reflects the post-dedup unique count, so it can be lower than requested_count. An empty ueis list or more than 100 entries returns 422. Each UEI counts against your hourly quota (a 100-UEI bulk = 100 quota hits). Expected latency: ~80ms per UEI on warm paths.
Example
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ueis":["N2EDPB1SMN55","C1BVCA2N9YB4","SH2ER4W6LH13"]}' \
https://govconapi.com/api/v1/vendor-risk/bulk
Use cases: quarterly subcontractor review ("which of my 200 vendors now need attention?"), pre-contract screening, M&A target due diligence on a portfolio company's vendor list.
GET /api/v1/contacts/lookup Requires Auth Pro
Resolver lookup for federal contracting officers: pass a name (and optionally an agency), get back up to 5 matching contacts with email, phone, agency, department, and location. Designed for BD / outreach / intelligence platforms that already know who they are looking for and need the contact info to act on it.
This is a resolver, not a directory. There is no listing endpoint, no pagination, and no filter-only browse. To explore the directory (search by NAICS, view award history, see colleague graphs, AI dossiers), use the GovCon Contacts web app at contacts.govconapi.com (included with Pro).
Parameters
One of name or email is required.
name - Name or partial name. Min 2 characters. Substring match, case-insensitive. Returns up to 5 results.
agency (optional, with name) - Agency or department substring for disambiguation (e.g. Air Force, DLA, Veterans). Matches both current_agency and current_department.
state (optional, with name) - 2-letter state/territory code (e.g. CA, DC, VA) for geographic disambiguation.
email - Exact email address for reverse lookup. Returns one record. Useful for CRM enrichment when you have the email on file and want the current name/agency/phone.
Response
{
"data": [
{
"name": "Joseph Nemedy",
"current_agency": "DEPT OF THE AIR FORCE",
"current_department": "DEPT OF DEFENSE",
"current_location_city": "Shaw Afb",
"current_location_state": "SC",
"email": "
[email protected]",
"phones": ["(803) 895-5354"],
"last_seen": "2026-05-09",
"slug": "a1b2c3d4e5f6"
}
],
"filters_applied": {"name": "Joseph", "agency": "Air Force"},
"result_count": 1,
"note": "Resolver lookup. Generic search terms like 'Coordinator' or 'Specialist' may return shared role inboxes rather than individual people; use `agency` and/or `state` to narrow. For directory browse / awards history / colleague graphs, use https://contacts.govconapi.com."
}
Examples
# Lookup by name
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/contacts/lookup?name=Joseph"
# Disambiguate with agency + state
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/contacts/lookup?name=Smith&agency=Air%20Force&state=GA"
# Reverse lookup by email (CRM enrichment)
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/contacts/lookup?email=joseph.nemedy.1%40us.af.mil"
Caching: Successful responses include Cache-Control: public, max-age=3600. Data refreshes nightly so an hour of client-side caching is safe and saves your quota on repeat queries.
Heads-up on generic search terms: "Coordinator", "Specialist", and similar return shared role inboxes (e.g. "BAA Coordinator" appears in 23 agencies as a shared queue address) rather than individual people. Use agency and/or state to narrow, or look up by email when you need exactly one record.
Errors: 401 (no auth), 402 (Developer key, Pro required), 404 (no matches), 422 (neither name nor email provided, or name too short), 429 (rate limit), 503 (contacts data store transiently unavailable; retry).
Use cases: a BD platform sees a contracting officer mentioned in a news feed or post and resolves their email/phone for outreach; a CRM enriches contact records with agency and location; an intelligence system maps names from public discussions to verified federal buyer identities.
Coverage: ~23,000 federal contracting officers and contracting specialists across 124 agencies. 100% have an email; ~61% have phone numbers. Refreshed nightly from federal contract notices.
GET /api/v1/opportunities/delta Requires Auth
Get all opportunities that were added or updated since a given timestamp. Use this to keep your local database in sync without re-downloading the entire dataset.
How It Works
- Pass a timestamp, get changes. Returns every record that was added, updated, or backfilled since the timestamp you provide. This includes newly posted notices, updated deadlines, and historical records that were filled in during data reconciliation.
- Same 59 fields as the search endpoint. Each record is a complete opportunity, not a diff.
- Data updates daily around 2:00 AM UTC. A typical day has 1,000 to 2,000 changed records. Calling this once a day keeps you fully in sync.
- Save the
server_time from the response and use it as since on your next sync. This guarantees no gaps.
Parameters
since (required) - ISO 8601 timestamp (e.g. 2026-04-05T06:00:00Z). Clamped to the last 60 days: an older value still returns 200, and the sync block reports since (the effective value used), since_requested, and clamp_reason. Delta is a sync tool, not a backfill; for older data use search with date filters.
limit - Results per page (Free: max 50, Developer: max 1000, default 1000). Over your plan cap returns 403 (not a silent cap).
offset - Pagination offset
Only since, limit, and offset are accepted. Any other parameter (e.g. naics_multiple) returns 400; delta does not filter by content. Errors: 400 (unknown param, or unparseable since), 401 (no/invalid key), 403 (limit over plan cap), 422 (since missing), 429 (rate limit).
Response
{
"data": [
{
"notice_id": "185eefbdab5a4a39aa7b53cb349bf1f0",
"title": "Removal of Oil/Water Mixture and Contaminated Sand/Soil/Sludge from Oil Water Separators, Osan AB",
"notice_type": "Solicitation",
"agency": "DEPT OF DEFENSE.DEPT OF THE ARMY.AMC.ACC.ACC-OO.411TH CSB.0906 AQ CO CONTRACTING BAT",
"posted_date": "2026-05-31",
"response_deadline": "2026-06-08T04:00:00+00:00",
"_additional": "all 59 fields, same as search endpoint"
}
],
"pagination": {
"limit": 100,
"offset": 0,
"total": 1984,
"has_next": true
},
"sync": {
"since": "2026-05-30T22:00:00Z",
"records_changed": 1984,
"server_time": "2026-06-02T09:04:49.836940+00:00"
}
}
The sync.server_time field is the next-cursor. Save it from this response and pass it as since on your next pull. The field is not currently named next_since but it functions as one; treat it as the watermark of "everything up to here has been delivered." If you re-pass your original since instead, you will re-pull the same records you already saw.
What a real delta pull contains. A live pull on 2026-06-02 against since=2026-05-30T22:00:00Z returned 1,984 changed records. Across the first 1,000 sampled, the notice-type mix is Combined Synopsis/Solicitation (32%), Award Notice (25%), Solicitation (21%), Sources Sought (8%), Presolicitation (7%), Special Notice (6%), plus a small tail of Justification notices (1%). The endpoint reports every state change, not just new postings, so a BD pipeline sees the same notice cycle through pre-award stages and the award decision in the same delta stream.
Sync Workflow
# 1. Initial load: pull everything with the search endpoint
# (paginate with limit=1000 and offset)
# 2. Save the server_time from your last response
# 3. Next day: call delta with that timestamp
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/delta?since=2026-04-05T06:00:00Z"
# 4. If has_next is true, paginate with offset
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/delta?since=2026-04-05T06:00:00Z&offset=1000"
# 5. Save the new server_time, repeat tomorrow
Tip: On a typical day, the delta returns 1,000 to 2,000 records. That's 1 to 2 API calls at limit=1000, compared to 200+ calls to re-download the full database. If you're currently syncing by paginating through all records, switching to delta will reduce your API usage by ~99%.
GET /api/v1/exclusions/search Requires Auth
Search SAM.gov Exclusions database for debarred entities (companies and individuals prohibited from federal contracting). Perfect for vendor due diligence and compliance screening.
How It Works
- Dataset: 163,000+ exclusion records from SAM.gov (updated weekly). Check
/api/v1/stats for current count. For more frequent updates, contact [email protected].
- Search Logic: Multiple filters are combined with AND logic. For example,
classification_type=Firm&state=CA returns only California firms (not firms OR California)
- Partial Matching: Name and agency filters use case-insensitive partial matching.
entity_name=Smith matches "John Smith", "Smithson Corp", etc.
- Individuals vs Firms: Most records are individuals (
classification_type=Individual); fewer are firms. Most individuals don't have UEI identifiers, so search them by name.
Filter Parameters
entity_name - Entity or person name (partial match, case-insensitive). Alias: name (if both are sent, entity_name wins).
uei_sam - UEI SAM identifier (exact match). Note: most exclusions (individuals) have no UEI, so do not pass the literal string null to find them; it matches zero rows. Omit the param instead.
cage_code - CAGE code (exact match)
excluding_agency - Excluding agency code like "HHS", "DOJ" (partial, case-insensitive match on excluding_agency_code)
classification_type - Type: Individual, Firm, Vessel, Special Entity Designation (exact, case-sensitive: individual returns 0)
exclusion_type - Exclusion category (exact, case-sensitive; use SAM's exact string, e.g. Prohibition/Restriction)
state - State/province code (e.g., CA, TX)
country - Country code (e.g., USA)
active_only - Boolean, default true (only active exclusions)
limit - Results per page (Free: max 50, Developer: max 1000, default 20)
offset - Pagination offset
fields - Comma-separated response fields. uei_sam always included. Example: fields=uei_sam,entity_name,excluding_agency_code,activate_date. See Response Shaping.
Common Use Cases:
- Vendor screening: Search by company name before contract award
- Individual background checks: Search by person's full name
- Agency analysis: Find all HHS or DOJ exclusions
- Compliance reporting: Export all exclusions by state
Response
{
"data": [
{
"uei_sam": "N2EDPB1SMN55",
"entity_name": "Bella Mia Donna LLC",
"classification_type": "Firm",
"exclusion_type": "Ineligible (Proceedings Pending)",
"excluding_agency_name": "DEFENSE LOGISTICS AGENCY",
"record_status": "Active",
"city": "POMPANO BEACH",
"state_or_province_code": "FL",
"activate_date": "2025-11-19",
"termination_date": null,
"_additional": "30 fields total per record"
}
],
"pagination": {
"limit": 20,
"offset": 0,
"total": 162765,
"has_next": true
},
"filters_applied": {}
}
Examples
Search by entity name:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/exclusions/search?entity_name=Smith&limit=10"
Returns 1,089 individuals and firms with "Smith" in the name
Find California firms:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/exclusions/search?classification_type=Firm&state=CA"
Returns 742 excluded firms in California
HHS exclusions:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/exclusions/search?excluding_agency=HHS&limit=10"
Returns 69,356 HHS exclusions (largest excluding agency)
OFAC sanctions match by name:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/exclusions/search?entity_name=VIETNAM-RUSSIA%20JOINT%20VENTURE%20BANK&limit=1"
Returns the OFAC sanctions record for the named entity. Same response envelope as the DLA / HHS query above; the differentiating fields are excluding_agency_code: "OFAC", exclusion_type: "Prohibition/Restriction", exclusion_program: "Reciprocal", classification_type: "Special Entity Designation", and the international country_code (here "VNM"). The additional_comments field is "Redacted for security reasons" on OFAC records; the agency cite for the underlying action is on the published OFAC SDN list, not in our database. One screening pipeline reads OFAC and DLA records uniformly.
GET /api/v1/exclusions/{uei_sam} Requires Auth
Vendor-risk screening lookup: pass a UEI SAM and find out whether that entity has an active or historical exclusion on record.
Response semantics
200 — entity is on the exclusions list. Body returns the most recent exclusion record under an exclusion key (dates, location, agency, exclusion type, classification, ~37 fields total), a top-level additional_exclusion_records count (further records keyed to the same UEI, e.g. a debarment by a second agency; 0 for most entities, fetch the full set via /exclusions/search?uei_sam=), a top-level _sources array and, on Pro keys, the two enrichment blocks documented below.
404 — the UEI has no UEI-keyed exclusion. This is the expected answer for the vast majority of legitimate vendors, but it is not a full "clean" verdict: most exclusions are individuals with no UEI, so a 404 does not rule out a name-based debarment. See the coverage caveat below and pair this with a name search before treating a vendor as clear.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/exclusions/N2EDPB1SMN55"
Coverage caveat. Roughly 73% of SAM exclusions are individuals or small entities without a UEI. A 404 from this endpoint means no UEI-keyed exclusion; it does not rule out a name-based debarment of a principal, officer, or related individual. For full vendor screening, pair this lookup with /api/v1/exclusions/search?entity_name=....
Compliance enrichment blocks Pro
When the caller has Pro and the lookup returns a 200, the response carries two top-level blocks summarizing federal money flow to this excluded UEI in the last 12 months. The compliance question goes from "are they debarred?" to "is anyone in the federal supply chain still paying them — directly or indirectly?" in a single call. Both blocks default to a 365-day lookback and always return the zero shape when there's no activity, so client code can read fields without per-call null checks.
recent_sub_payments block — FFATA subaward dollars received indirectly (clean primes paying the excluded entity as a sub):
lookback_days, total_received, subaward_count, distinct_primes.
most_recent_subaward_date, most_recent_subaward_amount, most_recent_paying_prime: {uei, name} — the smoking-gun row.
top_paying_primes — array of up to 5 {uei, name, total, subaward_count} objects.
recent_contract_actions block — FPDS prime contract obligations received directly (the excluded entity is still being awarded contracts by federal agencies):
lookback_days, total_obligated_recent, transaction_count, distinct_contracts, distinct_agencies.
most_recent_action_date, most_recent_action_amount, most_recent_awarding_agency, most_recent_piid — the smoking-gun row.
top_paying_agencies — array of up to 5 {name, value, transaction_count} objects.
Net obligation (total_obligated_recent) can be negative — agencies clawing back contract money from an excluded vendor reads as a "compliance is working" pattern; positive amounts on an active exclusion read as "compliance gap, escalate." Both block shapes are also documented under Pro enrichment fields (universal pattern) at the top of the Endpoints section.
Worked example (Pro response on an excluded UEI with the recency view)
UEI C1ZLDAS18FJ3 (ATI Government Solutions): on the exclusions list since 2025-10-21. In the last 365 days agencies issued 64 contract actions across 21 distinct contracts and 6 agencies, with a NET obligation of -$9.31M, meaning deobligations are exceeding new awards. That's the "compliance is working" pattern. recent_sub_payments is zero (no recent FFATA sub income to this UEI). For the broader 5-year activity view, see the parallel example on /vendor-risk/{uei}.
Response shape. The exclusion record is wrapped under an exclusion key; enrichment blocks are siblings at the top level, per the multi-block detail convention. Free / Developer responses omit the two enrichment blocks; Pro responses include them with the zero-shape when no activity matches.
{
"exclusion": {
"entity_name": "...",
"...": "37 exclusion fields total (dates, address, agency, classification, etc.)"
},
"additional_exclusion_records": 0,
"recent_sub_payments": {
"lookback_days": 365,
"total_received": 0.0,
"subaward_count": 0,
"distinct_primes": 0,
"most_recent_subaward_date": null,
"most_recent_subaward_amount": null,
"most_recent_paying_prime": null,
"top_paying_primes": []
},
"recent_contract_actions": {
"lookback_days": 365,
"total_obligated_recent": -9312076.02,
"transaction_count": 64,
"distinct_contracts": 21,
"distinct_agencies": 6,
"most_recent_action_date": "2026-06-09",
"most_recent_action_amount": 85000.0,
"most_recent_awarding_agency": "Department of Energy",
"most_recent_piid": "89303023CMA000093",
"top_paying_agencies": [
{"name": "Office of the Assistant Secretary for Administration and Management",
"value": 5872530.47, "transaction_count": 6},
{"name": "Office of the Chief Financial Officer",
"value": 2258980.85, "transaction_count": 8},
"...up to 5 entries"
]
},
"_sources": ["sam_exclusions", "usaspending_fpds"]
}
If you only need the screening yes/no plus the recent-payment views, this endpoint is sufficient. If you also want address clusters, name variants, coordinated-wave membership, and the longer 5-year exposure picture, call /api/v1/vendor-risk/{uei} instead — that response includes the subaward_exposure + contract_exposure blocks (1825-day window) plus the seven risk signals. Live response verified 2026-06-01.
GET /health No Auth Required
Health check endpoint showing system status and database connection.
Response
{
"status": "healthy",
"database": "connected"
}
Note: For data freshness, see last_delta_utc on /meta or last_updated on /api/v1/stats.
Example
curl "https://govconapi.com/health"
GET /export.csv Requires Auth Developer
Export contract notices as CSV file. Free plan does not have CSV export access.
Query Parameters
A subset of the /opportunities/search filters. For the full filter set (date ranges, value ranges, sort, location, attachments, active_only, response shaping), use /opportunities/search and write a CSV client-side.
keywords - Full-text search across title, agency, description
naics - Single NAICS code
naics_multiple - Comma-separated NAICS codes (OR'd)
agency - Agency name (partial match)
state - 2-letter state code or full state name
set_aside - Set-aside code (e.g. SBA, 8(a))
notice_type - Notice type (e.g. Solicitation, Award Notice)
solicitation_number - Solicitation number (partial match)
limit - Max records to export (default 1000, max 1000)
Any other parameter returns 400 Bad Request. Unknown params are not silently dropped.
Plan Restrictions:
- Developer: All listed filters available. 15 exports/day.
- Free: No CSV export access.
CSV Format
CSV exports a 15-column analyst-friendly subset (the columns below in this exact order). Empty values show as blank cells. If you need fields not in this set, pull them from /api/v1/opportunities/search instead, which returns all 59 fields per record.
notice_id,title,notice_type,agency,naics,psc,
posted_date,response_deadline,solicitation_number,
set_aside_type,award_amount,awardee_name,
performance_state_code,contact_email,sam_url
Examples
Export defense awards:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/export.csv?notice_type=Award%20Notice&agency=defense&limit=1000" \
-o defense_awards.csv
Export by NAICS and state:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/export.csv?naics=541330&state=CA&limit=500" \
-o ca_it_contracts.csv
Need filters not listed above? Use /api/v1/opportunities/search for the full filter set (value ranges, date ranges, sort, etc.) and write the CSV yourself. The 59-field response gives you everything; the 15-column CSV here is the analyst-ready subset.
Free plan - Not available:
{"detail":"CSV export requires a paid plan. Upgrade at https://govconapi.com/#pricing"}
POST /api/v1/keys No Auth Required
Create a new API key. The key will be emailed to you instantly. Generating a new key deactivates the previous one for that email.
Query Parameters
email - Your email address (required)
plan - Plan type: "free" (default) or "developer"
Example
curl -X POST \
"https://govconapi.com/api/v1/keys?email=YOUR_EMAIL&plan=free"
Note: For the Developer plan, use the /api/v1/checkout endpoint to create a Stripe checkout session.
POST /api/v1/checkout No Auth Required
Create a Stripe checkout session for Developer plan subscription. Redirects to Stripe payment page.
Query Parameters
email - Your email address (required)
Response
{
"status": "success",
"checkout_url": "https://checkout.stripe.com/c/pay/cs_...",
"plan": "Developer Plan - $19/month",
"session_id": "cs_..."
}
Example
curl -X POST \
"https://govconapi.com/api/v1/checkout?email=YOUR_EMAIL"
Response Times (US West Coast)
- Search Queries: ~1.1s (measured average)
- Single Record: ~800ms
- Public Endpoints: ~600ms (cached)
- CSV Export: 1-2s (small datasets)
Operational Notes
- Concurrent Requests: 5-15 recommended for best performance
- Data Updates: daily (new postings and modifications). Check
last_updated on /api/v1/stats for current freshness.
- Compression: responses are gzip-encoded when your client sends
Accept-Encoding: gzip.
Best Practices for High-Volume Usage
Expect geographic variation in response times:
curl -w "Total: %{time_total}s (Network: ~%{time_connect}s + Server: ~%{time_starttransfer}s)\n" \
-H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?naics=541330&limit=100"
Use pagination within a filtered query:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?naics=541330&limit=100&offset=0"
For keeping a local mirror in sync, use /api/v1/opportunities/delta instead. It filters by last_seen via a since cursor (use the returned sync.server_time as your next since), so you only pull what changed.
Monitor your usage to stay within rate limits:
- Free plan: 25 requests/day
- Developer: 1,000 requests/hour
Every authenticated response reports your current rate-limit state in headers, so you can throttle before you hit the ceiling instead of reacting to a 429:
X-RateLimit-Limit — your plan's request ceiling for the window.
X-RateLimit-Remaining — requests left in the current window. Slow down as this approaches 0.
On a 429 response we also send Retry-After (in seconds), which tells you exactly when to resume. The pattern: back off on X-RateLimit-Remaining, recover on Retry-After.
Use specific filters to reduce server processing time:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?naics=541330&posted_after=2025-11-01"
Note: NAICS filtering is well-optimized and faster than generic searches
Error Handling Best Practices
import requests
import time
def make_api_request(url, headers):
response = requests.get(url, headers=headers)
# Proactive: slow down before you hit the ceiling.
remaining = int(response.headers.get('X-RateLimit-Remaining', 1))
if remaining < 10:
time.sleep(1) # ease off as the window runs low
if response.status_code == 429:
# Rate limit exceeded: Retry-After tells you exactly when to resume.
retry_after = int(response.headers.get('Retry-After', 3600))
print(f"Rate limited. Waiting {retry_after} seconds...")
time.sleep(retry_after)
return make_api_request(url, headers) # Retry
elif response.status_code == 403:
# Plan upgrade needed
error = response.json()
print(f"Upgrade required: {error['detail']}")
return None
return response.json()
Technical Architecture (Click to expand)
Rate Limiting
- Free: 25 requests/day
- Developer: 1,000 requests/hour
- Plan Restrictions: CSV export and page size (50 vs 1,000) enforced by plan level. All search filters available on every plan.
Performance
- Indexed filters: agency, NAICS, PSC, dates, and full-text are indexed; specific filters return faster than broad keyword-only scans.
- NAICS filtering is among the fastest paths; prefer it when you can.
- Data size: Loading... opportunities, refreshed daily.
- Transport: HTTPS only; responses gzip-encoded on
Accept-Encoding: gzip.
Data source & freshness
- Source: SAM.gov (opportunities, awards, entity registry, exclusions) plus contracting-officer contacts.
- Refresh: daily for opportunities/awards; the SAM entity registry is a monthly snapshot; exclusions refresh weekly. Check
/api/v1/stats for current freshness.
Production Usage Guide
Python client with pagination & error handling (Click to expand)
# Production-ready integration pattern
import requests
import time
from datetime import datetime, timedelta
class GovConAPIClient:
def __init__(self, api_key, plan='developer'):
self.api_key = api_key
self.base_url = 'https://govconapi.com/api/v1'
self.headers = {'Authorization': f'Bearer {api_key}'}
# Configure based on your plan
if plan == 'developer':
self.rate_limit = 1000 # hourly
self.burst_limit = 60 # per minute
else:
self.rate_limit = 25 # daily (free)
self.burst_limit = 10 # per minute
def search_opportunities(self, filters=None, limit=100):
"""Search with automatic pagination and rate limiting.
Pass at least one meaningful filter; /search rejects unfiltered
requests with 400 for keys created after the filter-required cutoff."""
all_results = []
offset = 0
while True:
params = {'limit': limit, 'offset': offset}
if filters:
params.update(filters)
response = self._make_request('/opportunities/search', params)
if not response or 'data' not in response:
break
all_results.extend(response['data'])
# Use the explicit pagination.has_next signal returned by the API.
if not response.get('pagination', {}).get('has_next'):
break
offset += limit
time.sleep(0.1) # gentle on the rate limit
return all_results
def _make_request(self, endpoint, params=None):
"""Make request with proper error handling"""
url = f"{self.base_url}{endpoint}"
try:
response = requests.get(url, headers=self.headers, params=params)
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 3600))
print(f"Rate limited. Waiting {retry_after} seconds...")
time.sleep(retry_after)
return self._make_request(endpoint, params)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
return None
# Example usage
client = GovConAPIClient('your_api_key_here', 'developer')
# Search for DoD opportunities in the last 30 days
filters = {
'agency': 'Department of Defense',
'posted_after': (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d')
}
opportunities = client.search_opportunities(filters)
print(f"Found {len(opportunities)} opportunities")
Load Testing Recommendations
- Burst Testing: Developer plan: up to 60 req/min for short bursts
- Sustained Load: Stay under 80% of your hourly limit for consistent performance
- Concurrent Requests: 5-15 concurrent requests recommended for optimal reliability
- Response Caching: Cache responses for 10-15 minutes to reduce API calls
- Geographic Considerations: Network latency varies 50-400ms by location
- Performance Monitoring: Use curl timing options to distinguish network vs server performance
Enterprise Integration Patterns (Click to expand)
Pattern 1: Daily Sync with the delta endpoint
Use /api/v1/opportunities/delta, not /search, for keeping a local copy in sync. Delta returns every record changed since your since timestamp (including backfilled records that posted_after would miss) and pages cleanly with has_next.
def daily_sync(client, last_sync_time):
"""Pull every opportunity that's been added or updated since last_sync_time."""
offset = 0
new_server_time = None
while True:
resp = client._make_request('/opportunities/delta', {
'since': last_sync_time,
'limit': 1000,
'offset': offset,
})
if not resp:
break
for op in resp['data']:
store_opportunity(op) # upsert by notice_id
# Capture the server's clock from the FIRST page so we use a single
# consistent cutoff across all paginated calls in this run.
if new_server_time is None:
new_server_time = resp['sync']['server_time']
if not resp['pagination']['has_next']:
break
offset += 1000
return new_server_time # save this; pass as last_sync_time tomorrow
Pattern 2: Agency Monitoring
Watching N agencies? Make one delta call (or one search call), filter agencies client-side. Looping the API once per agency burns the rate limit and adds latency for no benefit.
def monitor_agencies(client, agencies_of_interest, last_sync_time):
"""Pull all changes since last sync, route by agency client-side."""
of_interest = {a.lower() for a in agencies_of_interest}
resp = client._make_request('/opportunities/delta', {
'since': last_sync_time,
'limit': 1000,
})
if not resp:
return
for op in resp['data']:
agency = (op.get('agency') or '').lower()
if any(target in agency for target in of_interest):
if is_new_opportunity(op):
send_notification(op)
return resp['sync']['server_time']
Pattern 3: Bulk CSV Export for Analytics
For analytics warehouses, the CSV export endpoint is the lowest-overhead path. Stream the response straight to disk; it's not JSON.
def export_csv_to_file(api_key, filename, **filters):
"""Download /export.csv to a local file. Filters: naics, agency, state,
set_aside, notice_type, solicitation_number, keywords, naics_multiple, limit."""
response = requests.get(
'https://govconapi.com/export.csv',
headers={'Authorization': f'Bearer {api_key}'},
params=filters,
stream=True,
timeout=120,
)
response.raise_for_status()
with open(filename, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
return filename
# Example: pull DLA award notices to a CSV
export_csv_to_file('your_api_key', 'dla_awards.csv',
notice_type='Award Notice', agency='defense', limit=1000)
The CSV is the 15-column analyst subset documented in the CSV Export endpoint section. For the full 59-field record set, use the JSON search endpoint instead.
Pattern 4: Map a prime contractor's supply chain
For BD intel, M&A diligence, and set-aside compliance: combine prime award history with the subaward layer. Two calls give you "what they won as a prime" + "who they paid as subs" + a leaderboard of the top sub-vendors.
def supply_chain_map(client, prime_uei):
"""Profile a prime contractor's federal footprint, top to bottom."""
# 1. Prime-side awards: what contracts have they won?
profile = client._make_request(f'/companies/{prime_uei}', {})
awards = client._make_request(f'/companies/{prime_uei}/awards', {'limit': 1000, 'sort': 'amount'})
# 2. Sub-side flow: who have they paid, and how much?
# Subaward endpoints cap at limit=250 (rows are wider than /awards/search).
# For a top prime with thousands of FFATA reports, page through with offset.
subs = client._make_request(f'/companies/{prime_uei}/subawards', {'limit': 250})
return {
'prime_name': profile['name'],
'total_won_as_prime': profile['total_value'], # all-time award notices
'total_paid_to_subs': subs['summary']['total_subaward_amount'],
'distinct_sub_vendors': subs['summary']['distinct_sub_vendors'],
'distinct_contracts': subs['summary']['distinct_prime_contracts'],
'subaward_date_range': (subs['summary']['first_subaward_date'],
subs['summary']['last_subaward_date']),
'top_5_subs_by_dollars': _top_n_subs(subs['data'], 5),
'top_5_awards': awards['data'][:5],
}
For the per-contract supply-chain forensics (every sub on one prime PIID), use /subawards/search?piid=<piid>. For the agency or NAICS slice across all primes, use the same endpoint with those filters instead of a UEI.
Pattern 5: True federal revenue for a small business
A small business in federal contracting often earns the larger half of its federal income as a sub, not as a prime. Looking up /companies/{uei}/awards alone undercounts. The honest revenue view is the union:
def true_federal_revenue(client, uei):
"""Combined prime + sub revenue picture. /companies/{uei} returns this in one call."""
profile = client._make_request(f'/companies/{uei}', {})
return {
'name': profile['name'],
'prime_revenue': profile['total_value'], # SAM Award Notice value (see fpds_obligated_total for the fuller FPDS prime total)
'sub_revenue': profile['sub_revenue_total'], # subaward dollars received, current FFATA coverage
'combined': profile['total_value'] + profile['sub_revenue_total'],
'prime_share': profile['prime_revenue_share'], # 0..1; null when both are zero
'top_paying_primes': profile['top_paying_primes'], # who their actual customers are
'top_naics_as_prime': profile['top_naics'],
}
# Example output for an SMB:
# prime_revenue = $1.2M, sub_revenue = $8.4M, combined = $9.6M, prime_share = 0.13
# → 87% of their federal revenue is sub work; the prime-only view missed it.
Two different prime measures appear here: this snippet's hand-combined combined uses total_value (the SAM Award Notice slice) for prime, while the response's prime_revenue_share field uses the broader FPDS prime obligation total (fpds_obligated_total). Both the FPDS prime total and the FFATA subaward total cover the FY2025-onward window (since 2024-10-01), so prime_revenue_share compares like-for-like. For the authoritative prime figure use fpds_obligated_total; for the underlying records, see /companies/{uei}/prime-relationships.
Pattern 6: Active-payment compliance screen on an excluded vendor
For compliance and FCA investigation: when an entity hits the SAM exclusion list, the question that matters is whether clean primes are still paying them. /exclusions/{uei_sam} answers both halves of the screen — the exclusion record itself, and the recent-payments enrichment — in one call.
def active_payment_screen(client, uei):
"""Returns the exclusion record + the smoking-gun recent-payments view,
or None if the UEI is clean by UEI lookup (still pair with name search for full coverage)."""
resp = client.get(f'/api/v1/exclusions/{uei}')
if resp.status_code == 404:
return None # no UEI-keyed exclusion; check by entity_name for full coverage
body = resp.json()
return {
'exclusion_type': body['exclusion_type'],
'excluding_agency': body['excluding_agency_code'],
'create_date': body['create_date'],
'active': body['record_status'] == 'Active',
# The compliance signal:
'still_being_paid': body['recent_sub_payments']['subaward_count'] > 0,
'total_received_last_12mo': body['recent_sub_payments']['total_received'],
'most_recent_payment': body['recent_sub_payments']['most_recent_subaward_date'],
'most_recent_paying_prime': body['recent_sub_payments']['most_recent_paying_prime'],
'top_paying_primes': body['recent_sub_payments']['top_paying_primes'],
}
Pair this with /exclusions/search?entity_name=... for full screening coverage: ~80% of SAM exclusions are individuals or entities with no UEI, so a UEI lookup alone is not a full screen. For the broader risk surface (address clusters, name variants, coordinated waves), the same enrichment is also present on /vendor-risk/{uei} under subaward_exposure.
Error Codes
Unknown query parameters return 400. If you pass a parameter the endpoint doesn't recognize (a typo like ?nme= instead of ?name=, or a guess like ?q= on an endpoint that uses ?keywords=), we respond with 400 Bad Request and list the valid parameter names for that endpoint in the error detail. This is deliberate: silently dropping an unrecognized filter would return unfiltered results to a caller who thought they were filtering, which has caused real bugs in customer integrations. Stick to the documented parameter names listed under each endpoint above.
| Code |
Description |
Common Causes |
| 400 |
Bad Request |
Invalid query parameters, unknown query parameter names, or malformed request |
| 401 |
Unauthorized |
Missing or invalid API key |
| 402 |
Payment Required |
A Pro feature (Companies, Contacts, Vendor Risk, or a Pro-only filter on entities search) used without Pro entitlement |
| 403 |
Forbidden |
Page size exceeds your plan's max (Free: 50, Developer/Pro: 1,000) |
| 404 |
Not Found |
Resource (notice_id) doesn't exist |
| 422 |
Unprocessable Entity |
A parameter fails validation (e.g. limit out of range, negative offset, missing required since on delta, within_days out of range) |
| 429 |
Too Many Requests |
Rate limit exceeded for your plan |
| 500 |
Internal Server Error |
Server-side error (contact support) |
Data Freshness & Transparency
Contract notices are collected daily at 2:00 AM UTC from SAM.gov using their official API. The collection includes:
- 48-hour lookback window to ensure completeness
- Never archived - all historical data is retained (730+ days)
- Full descriptions extracted from SAM.gov notice pages
- Award data linked when available
Check the /meta endpoint for the exact timestamp of the last collection run.
Important: We Keep ALL Records
We intentionally never archive or delete records. This means:
- To filter for currently-open opportunities, pass
?active_only=true on /opportunities/search. This is a convenience filter we compute as archive_date_detailed > CURRENT_DATE, not a SAM source field.
- Use
response_deadline for bid-deadline awareness (independent of archive status).
- Use
notice_type to understand lifecycle (Solicitation → Award Notice).
- The stored
active field is always "Yes" by design (we never archive). Don't treat it as a status flag — use ?active_only=true or archive_date_detailed directly instead.
- Past-deadline and archived opportunities remain queryable for competitive intelligence by default — pass
?active_only=true to filter them out.
Check /api/stats for current counts.
Tracking amendments: Same solicitation_number appears multiple times (original + amendments). Use notice_id for unique records, or group by solicitation_number to track changes.
Tips for Getting the Most Out of the API
- Use
limit=1000 instead of paginating at 100. If you need 5,000 records, that's 5 requests instead of 50. Saves API calls and time.
- Use
posted_after for daily syncs. Instead of scanning all 200K+ records, fetch only what's new since your last sync. posted_after=2026-04-03 returns just today's notices.
- Know your
notice_type values:
Combined Synopsis/Solicitation (71K) - most common, open for bids
Award Notice (43K) - contracts already awarded, has winner data
Solicitation (40K) - open for bids
Sources Sought (15K) - market research, not yet a solicitation
Presolicitation (13K) - upcoming, not yet open
Special Notice (9K) - informational only
- Find who won a contract: Search by
solicitation_number and filter notice_type=Award Notice. The award record has awardee_name, award_amount, and award_date.
- Find open opportunities only: Use
due_after=2026-04-04 (today's date) to get only notices with a future deadline. Combine with notice_type=Solicitation or notice_type=Combined%20Synopsis/Solicitation.
- Cache responses locally. Data updates once daily at 2 AM UTC. If you're calling the same query multiple times per day, cache the first response.
Tested Integration Examples
1. Plan Verification Workflow
Step 1: Check your plan level
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/me"
Response: {"plan":"developer","email":"[email protected]"}
Step 2: Build the query
Multi-filter search (every plan supports all filters; paid plans get higher page size and rate limit):
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?agency=defense¬ice_type=Award%20Notice&value_min=1000000"
Single-filter search:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?naics=541330&state=CA"
2. Pagination Best Practices
Efficient pagination within a filtered query:
To keep a local mirror in sync, use /opportunities/delta with a since cursor (it returns only changed records). /search pagination is intended for paging through filtered result sets, not full-corpus backfill. For initial historical backfill, page a date-filtered search within your plan window.
offset=0
limit=100
total_collected=0
filter="naics=541330" # required: at least one filter on /search
while true; do
response=$(curl -s -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?${filter}&limit=$limit&offset=$offset")
has_next=$(echo "$response" | jq -r '.pagination.has_next')
data_length=$(echo "$response" | jq '.data | length')
total_collected=$((total_collected + data_length))
echo "Collected $total_collected records..."
if [ "$has_next" != "true" ] || [ "$data_length" -eq 0 ]; then
break
fi
offset=$((offset + limit))
sleep 0.1
done
Note: Be respectful of the API with small delays between requests
4. Working with Attachments
Option 1: Filter for opportunities with attachments (Developer plan):
import requests
API_KEY = "your_api_key"
headers = {"Authorization": f"Bearer {API_KEY}"}
response = requests.get(
"https://govconapi.com/api/v1/opportunities/search?has_attachments=true&limit=20",
headers=headers
)
results = response.json()
Option 2: Get attachments for specific opportunity:
import requests
# From search results
notice_id = results['data'][0]['notice_id']
# Get attachments via dedicated endpoint
attachments = requests.get(
f"https://govconapi.com/api/v1/opportunities/{notice_id}/attachments",
headers=headers
).json()
# Download files (SAM.gov URLs, no auth needed)
for url in attachments['attachments']:
file_response = requests.get(url)
# Save file to disk
with open(f"attachment_{attachments['attachments'].index(url)}.pdf", "wb") as f:
f.write(file_response.content)
Option 3: Use existing field in search response:
import requests
# Attachments already included in search response
for opp in results['data']:
if opp.get('resource_links_array'):
print(f"Opportunity {opp['notice_id']} has {len(opp['resource_links_array'])} attachments")
for url in opp['resource_links_array']:
file_response = requests.get(url)
# Process attachment directly
Which approach to use? Use resource_links_array from search results when processing multiple opportunities. Use the /attachments endpoint only if you need attachments for one specific opportunity without fetching the full record.
Feature Reference
Plan Restrictions Summary
All search filters (NAICS, PSC, state, keywords, agency, dates, location, amounts, set-aside, has_attachments, etc.) are available on every plan, including the 14-day free trial. CSV export, the larger page size (1,000 vs 50), and the 1,000/hour rate limit require the Developer plan.
Current Database Stats (Live)
- Total Records: Loading... contract opportunities
- Currently Open: Loading... active opportunities
Counts loaded live from /api/stats; data refreshed daily. For a precise freshness timestamp, read last_updated from /api/v1/stats.
Performance Benchmarks (Tested)
- Search Response: ~1.1s average (measured in production)
- Network Latency: ~20ms connection time
- Server Processing: ~980ms average
- CSV Export: 1-2s for small datasets
- Public Endpoints: 400-600ms (cached)
Federal Contracting Officers Directory
Need direct contact with government buyers? Our sister site contacts.govconapi.com provides verified contact information for federal contracting officers with phone numbers, emails, agency details, and recent procurement activity.
Need Help?
Questions or issues? Contact [email protected]
API Status: https://govconapi.com/health
Interactive Docs: https://govconapi.com/docs (auto-generated from OpenAPI schema)