Federal contracts API for developers. Clean JSON: opportunities, awards, 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
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 (keyset-based, no depth penalty).
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.
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)
Important Data Patterns:
- To find open opportunities - Use
due_after=<today> to filter to opportunities where the response deadline hasn't passed. Combine with notice_type for best results.
- Combined notices are very common - About a third of opportunities are "Combined Synopsis/Solicitation". When searching for bidding opportunities, filter for both
notice_type=Solicitation and notice_type=Combined%20Synopsis/Solicitation to catch everything.
- Award amounts only exist on awards - "Award Notice" records have award_amount, awardee_name, etc. Solicitations don't have these fields yet.
- Amendments create duplicate solicitation_numbers - Same solicitation can appear multiple times as it's modified. Use posted_date or notice_id to track versions.
- Most are for small business - Majority of set-asides are type "SBA".
Advanced filters (Developer plan)
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 (posted_date, response_deadline, award_amount, title, agency)
sort_order – Sort order: asc or desc (default: desc)
naics_multiple – Comma-separated NAICS codes for multiple search
has_attachments – Filter by attachment availability: true or false
Response
{
"data": [
{
"notice_id": "abc123def456",
"title": "IT Services Contract",
"agency": "Department of Defense",
"posted_date": "2025-11-01",
"response_deadline": "2025-12-15",
"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,
"has_next": true
},
"filters_applied": {
"naics": "541330",
"state": "CA",
"agency": null,
"keywords": null
}
}
Examples
Basic search (all plans):
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
Paid plans - 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 /demo/opportunities No Auth Required
Public demo endpoint that returns 2 sample contract notices. Perfect for testing integration without an API key.
Performance: Responses are cached for 6 hours since data updates daily at 2:00 AM UTC.
Response Format
{
"data": [
{
"notice_id": "abc123...",
"title": "Example Contract",
"_additional": "59 fields total per record"
}
],
"total": 2,
"message": "Demo data - sign up for full API access"
}
Example
curl "https://govconapi.com/demo/opportunities"
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 daily"
}
Example
curl "https://govconapi.com/api/agency-crosswalk"
GET /api/v1/opportunities/{notice_id} Requires Auth
Get complete details for a specific contract notice by its ID.
Response Format
{
"opportunity": {
"notice_id": "abc123def456",
"title": "IT Services Contract",
"agency": "Department of Defense",
"_additional": "all 59 opportunity fields returned"
},
"has_raw_data": true,
"last_updated": "2025-11-22T02:06:35.259767+00:00"
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/abc123def456"
GET /api/v1/opportunities/{notice_id}/attachments Requires Auth
Get direct download URLs for all attachments associated with a specific contract opportunity. Returns SAM.gov file links ready to download.
Response
{
"notice_id": "abc123def456",
"title": "IT Services Contract",
"attachment_count": 3,
"attachments": [
"https://sam.gov/api/prod/opps/v3/opportunities/resources/files/...",
"https://sam.gov/api/prod/opps/v3/opportunities/resources/files/...",
"https://sam.gov/api/prod/opps/v3/opportunities/resources/files/..."
]
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/abc123def456/attachments"
Note: Attachment URLs are direct SAM.gov download links. If an opportunity has no attachments, attachments will be an empty array. Attachments are also available in the main opportunity response via the resource_links_array field.
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",
"retention_period": "730 days"
}
}
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 including plan type and email address.
Response
{
"plan": "developer",
"email": "
[email protected]",
"docs_url": "https://govconapi.com/api-guide"
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/me"
GET /api/v1/awards/search Requires Auth
Search federal contract awards by awardee name, UEI, agency, NAICS, amount range, and date range. All filters available on all plans.
How It Works
- Dataset: 51,000+ award records from SAM.gov award notices covering 10,000+ unique companies. Updated daily.
- All filters open: Unlike opportunity search, all award filters are available on every plan. The only plan restriction is result count (Free: 50, Developer: 1000).
- Partial matching:
awardee_name and agency use case-insensitive partial matching. awardee_name=boeing matches "BOEING DISTRIBUTION SERVICES", "BELL BOEING JOINT PROJECT OFFICE", etc.
- Cross-reference: Each result includes
notice_id so you can fetch the full 59-field opportunity record via /api/v1/opportunities/{notice_id}.
Filter Parameters
awardee_name - Company name (partial match, case-insensitive)
uei - Exact UEI match
naics - NAICS code
agency - Awarding agency (partial match)
amount_min - Minimum award amount
amount_max - Maximum award amount
awarded_after - Awards on or after this date (YYYY-MM-DD)
awarded_before - Awards on or before this date (YYYY-MM-DD)
state - Awardee state code (2-letter, e.g. CA)
sort_by - Sort by: award_amount, award_date, awardee_name
sort_order - asc or desc (default: desc)
limit - Results per page (Free: max 50, Developer: max 1000, default 20)
offset - Pagination offset
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"
GET /api/v1/awards/{award_number} Requires Auth
Get a single award record by contract/award number. Returns the same 16 fields as the search endpoint. If multiple records share the same award number, returns the most recent.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/awards/SPE4A626PL503"
Note: Returns 404 if the award number is not found.
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 Bundle 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).
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).
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.
GET /api/v1/entities/search Requires Auth Pro Bundle (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 Bundle. The DSBS replacement: programmatic NAICS x state x certification x active-status filtering across the SAM directory.
Parameters
q - Name substring (2-100 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).
At least one of q / naics / state / business_type / active_only must be provided.
Response
{
"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"
}
]
}
Examples
# Developer tier: name search
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/entities/search?q=KAMPI&limit=5"
# Pro Bundle: 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: Sort is alphabetical 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 Bundle
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
{
"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"
}
]
}
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 Bundle), 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/companies/search Requires Auth Pro Bundle
Find distinct awardees by name substring or UEI prefix. Returns each company once with aggregate stats, ranked by total award count. Pro Bundle only; Developer-tier keys get a 402.
Parameters
q (required) - Search string, 2-100 chars. Matches against awardee name (case-insensitive trigram) and UEI prefix.
limit - Results per page (1-100, default 20)
offset - Pagination offset, default 0
Response
{
"query": "LOCKHEED",
"count": 5,
"pagination": {"limit": 5, "offset": 0, "total": 37, "has_next": true},
"results": [
{
"uei": "H11HD5VHGHN3",
"name": "Lockheed Martin Corporation",
"total_awards": 16,
"total_value": 26800000.0,
"last_award_date": "2026-03-10"
}
]
}
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/companies/search?q=lockheed&limit=5&offset=0"
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 Bundle
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.
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}
],
"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), due diligence (customer concentration via top_agencies), 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).
GET /api/v1/companies/{uei}/awards Requires Auth Pro Bundle
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)
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 Bundle
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/vendor-risk/{uei} Requires Auth Pro Bundle
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"] }
},
"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 if the UEI has no identity data in our SAM tables. 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 where the address came from (exclusions, opportunities, or unknown). See /vendor-risk-api for signal definitions, the triage rules, and worked examples from real federal enforcement actions.
POST /api/v1/vendor-risk/bulk Requires Auth Pro Bundle
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 }
]
}
UEIs not found in our data come back with status: "not_found" rather than failing the whole request; stale UEIs in vendor lists are normal. 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/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)
limit - Results per page (Free: max 50, Developer: max 1000, default 1000)
offset - Pagination offset
Response
{
"data": [
{
"notice_id": "abc123",
"title": "IT Support Services",
"notice_type": "Solicitation",
"agency": "DEPT OF VETERANS AFFAIRS",
"_additional": "all 59 fields, same as search endpoint"
}
],
"pagination": {
"limit": 1000,
"offset": 0,
"total": 1547,
"has_next": true
},
"sync": {
"since": "2026-04-05T06:00:00Z",
"records_changed": 1547,
"server_time": "2026-04-06T06:30:12.345678+00:00"
}
}
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)
uei_sam - UEI SAM identifier (exact match)
cage_code - CAGE code (exact match)
excluding_agency - Agency code or name like "HHS", "DOJ" (partial match)
classification_type - Type: Individual, Firm, Vessel, Special Entity Designation
exclusion_type - Exclusion category
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
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)
GET /api/v1/exclusions/{uei_sam} Requires Auth
Get detailed exclusion record by UEI SAM identifier. Returns full 39-field record including dates, location, and exclusion details.
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/exclusions/N2EDPB1SMN55"
Note: Returns 404 if UEI not found. Most individuals don't have UEI identifiers, so name search via /api/v1/exclusions/search?entity_name=... is the better default lookup for people.
GET /health No Auth Required
Health check endpoint showing system status and database connection.
Response
{
"status": "healthy",
"database": "connected",
"last_sync": "2025-11-07T06:15:23Z"
}
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
Supports the same filters as /opportunities/search, plus:
limit - Max records to export (default: 100, max: 1000)
Plan Restrictions:
- Developer: All 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 high-value awards:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/export.csv?notice_type=Award%20Notice&agency=defense&value_min=1000000&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
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)
Technical Details
- Database: PostgreSQL 16 with connection pooling
- Platform: Railway (managed hosting)
- Concurrent Requests: 5-15 recommended for best performance
- Data Updates: Daily at 2 AM UTC (99.9% uptime)
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 full-database sync, use /api/v1/opportunities/delta instead. It's keyset-based and scales to any volume.
Monitor your usage to stay within rate limits:
- Free plan: 25 requests/day
- Developer: 1,000 requests/hour
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)
if response.status_code == 429:
# Rate limit exceeded
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: Advanced filters and CSV export enforced by plan level
Database Performance
- Database: PostgreSQL 16 on Railway (managed)
- Connection Pool: 2-20 connections via psycopg2 ThreadedConnectionPool
- Query Optimization: Indexed on common search fields (agency, naics, dates)
- Performance Notes: NAICS filtering is well-optimized and 2x faster than generic searches
- Data Size: Loading... opportunities updated daily
Infrastructure
- Platform: Railway (Docker-based deployment)
- Server: FastAPI with uvicorn ASGI server
- Monitoring: Built-in health checks and error logging
- SSL/TLS: Automatic HTTPS with Railway managed certificates
Data Pipeline
- Source: SAM.gov API (daily collection at 2:00 AM UTC)
- Processing: Dual storage (raw JSON + normalized fields)
- Deduplication: SHA256 hash comparison to prevent duplicates
- Historical Tracking: Full version history for opportunities
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.
Error Codes
| Code |
Description |
Common Causes |
| 400 |
Bad Request |
Invalid query parameters or malformed request |
| 401 |
Unauthorized |
Missing or invalid API key |
| 403 |
Forbidden |
Attempting to use advanced filters on Free plan |
| 404 |
Not Found |
Resource (notice_id) doesn't exist |
| 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:
- Use
response_deadline to determine if opportunities are still open for bidding
- Use
notice_type to understand lifecycle (Solicitation → Award Notice)
- Don't use
active field - it's always "Yes" (meaningless SAM.gov value)
- Past-deadline opportunities remain queryable for competitive intelligence
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: Use features appropriate to your plan
Paid plans: All features available
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?agency=defense¬ice_type=Award%20Notice&value_min=1000000"
Free plan: Basic filters only
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?naics=541330&state=CA"
2. Error-Aware Search Implementation
Try advanced filter and handle graceful fallback:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?agency=defense" 2>/dev/null
If 403 error (Free plan), fallback to basic search:
if [ $? -ne 0 ]; then
echo "Free plan detected, using basic search..."
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?keywords=defense"
fi
3. Pagination Best Practices
Efficient pagination within a filtered query:
For full-database sync or backfills use /opportunities/delta (keyset-based, no depth penalty). /search pagination is intended for paging through filtered result sets.
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
Basic filters (NAICS, PSC, state, keywords, notice_type, solicitation_number) available on all plans. Advanced filters (agency, value_min/max, date range, has_attachments) require a paid plan. CSV export is paid-only.
Current Database Stats (Live)
- Total Records: Loading... contract opportunities
- Currently Open: Loading... active opportunities
- Last Updated: Loading...
Stats loaded live from /api/stats endpoint. Updates daily at 2:00 AM UTC.
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)