Federal contract opportunities API. Clean, queryable data from SAM.gov with daily updates.
Endpoints
Search federal contract notices with filters. Returns paginated results.
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)
competition_type – Competition type filter
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"
// ... 59 total fields available
}
],
"pagination": {
"limit": 20,
"offset": 0,
"total": 646,
"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 (IT services) has 646 total opportunities nationwide
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 search returns 49,527 opportunities
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",
// ... 62 fields total
}
],
"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 1,300+ 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": 1563,
"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",
// ... all 60+ opportunity fields
},
"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": 62550,
"recent_opportunities": 6561,
"unique_agencies": 1563,
"unique_naics_codes": 849,
"total_exclusions": 162765,
"active_exclusions": 162765,
"last_updated": "2025-11-22T02:06:52.095708+00:00"
},
"data_freshness": {
"last_collection": "2025-11-07T06:15:23Z",
"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": 62550,
"currently_open": 8757,
"award_records": 17001,
"full_descriptions": 37452
}
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 scraped requirement text from SAM.gov
Example
curl "https://govconapi.com/api/stats"
GET /meta No Auth Required
Get metadata about the dataset including last collection time and total record count.
Response
{
"last_delta_utc": "2025-11-22T02:06:52.095708+00:00",
"records": 62550,
"description": "Federal contract opportunities from SAM.gov"
}
Example
curl "https://govconapi.com/meta"
Note: Use this endpoint to check data freshness. Collection runs daily at 2:00 AM UTC. The records value shown is an example - use the endpoint to get the current count.
GET /api/v1/me Requires Auth
Get information about your API key including plan type and email address.
Response
Example
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/me"
Exclusions API is in beta. The dataset is updated weekly and the API is stable, but additional filter options and fields are planned. Questions or edge cases?
[email protected]
GET /api/v1/exclusions/search Requires Auth BETA
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: ~80% of records are individuals (
classification_type=Individual), ~20% are firms. Most individuals don't have UEI identifiers.
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": "T1N3GNE9GBM3",
"entity_name": "John Doe",
"classification_type": "Individual",
"exclusion_type": "Ineligible (Proceedings Completed)",
"excluding_agency_name": "JUSTICE, DEPARTMENT OF",
"record_status": "Active",
"city": "Houston",
"state_or_province_code": "TX",
"activate_date": "2025-06-15",
"termination_date": "2226-06-15"
// ... 30 total fields
}
],
"pagination": {
"limit": 20,
"offset": 0,
"total": 162765, // actual current count — use pagination.total, not this example value
"has_next": true
},
"filters_applied": { /* applied filters */ }
}
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,095 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 745 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,418 HHS exclusions (largest excluding agency)
GET /api/v1/exclusions/{uei_sam} Requires Auth BETA
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/T1N3GNE9GBM3"
Note: Returns 404 if UEI not found. Most individuals (~71% of dataset) don't have UEI identifiers — use name search instead.
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 files include these columns (58 total fields):
notice_id,title,agency,naics,psc,posted_date,response_deadline,set_aside_type,
award_amount,awardee_name,contact_name,contact_email,contact_phone,
solicitation_number,description_text,sam_url,archive_date,active,
award_number,award_date,award_uei_sam,award_cage_code,
performance_city_name,performance_state_code,performance_country_code,
organization_type,notice_base_type,source_version,last_seen...
Note: All 62 structured fields are included. Empty fields show as blank cells in CSV.
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 (auto-scaling)
- 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?limit=100"
Use pagination for large datasets:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?limit=100&offset=0"
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"""
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
opportunities = response['data']
all_results.extend(opportunities)
# Check if we got fewer results than requested (end of data)
if len(opportunities) < limit:
break
offset += limit
# Optional: respect rate limits proactively
time.sleep(0.1) # Small delay between requests
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)
# Monitor response for rate limiting
if response.status_code == 429:
print("Rate limited - waiting before retry...")
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_filter': '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 Incremental Updates
Sync new opportunities from the last 24 hours to keep your internal database up to date.
def daily_sync():
"""Sync new opportunities from the last 24 hours"""
yesterday = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d')
client = GovConAPIClient('your_api_key')
new_ops = client.search_opportunities({
'posted_after': yesterday,
'limit': 1000 # Developer plan allows large pages
})
# Process and store in your system
for op in new_ops:
store_opportunity(op)
Pattern 2: Webhook Alternative (Agency Monitoring)
Poll for opportunities from specific agencies of interest and send notifications.
def monitor_agencies(agencies_of_interest):
"""Poll for opportunities from specific agencies"""
for agency in agencies_of_interest:
opportunities = client.search_opportunities({
'agency_filter': agency,
'posted_after': datetime.now().strftime('%Y-%m-%d'),
'limit': 100
})
for op in opportunities:
if is_new_opportunity(op):
send_notification(op)
time.sleep(1) # Small delay between agency checks
Pattern 3: Bulk Export for Analytics
Export large datasets for business intelligence using CSV for efficiency.
def export_for_analytics(date_range_days=90):
"""Export large datasets for business intelligence"""
start_date = (datetime.now() - timedelta(days=date_range_days)).strftime('%Y-%m-%d')
# Use CSV export for large datasets (more efficient)
csv_data = client._make_request('/opportunities/export', {
'posted_after': start_date,
'format': 'csv'
})
# Process CSV data for your analytics platform
return csv_data
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 scraped from SAM.gov solicitation 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.
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 for large datasets:
offset=0
limit=100
total_collected=0
while true; do
response=$(curl -s -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?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.
Confirmed Working
- All Public Endpoints: /health, /meta, /api/stats, /demo/opportunities, /api/agency-crosswalk
- Authentication System: Bearer token validation working correctly
- Plan Restrictions: Properly enforced - advanced filters require paid plan (Developer), CSV export requires paid plans
- Basic Search Filters: naics, psc, state, keywords, notice_type, solicitation_number (all plans)
- Advanced Filters: agency, value_min/max, date filters (Developer plan)
- Pagination: limit/offset working correctly with has_next indicator
- Individual Record Lookup: /api/v1/opportunities/{id} working
- CSV Export: Working for Developer plan
- Error Handling: Proper HTTP codes and messages
- POST Endpoints: API key creation and Stripe checkout working
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 15,917+ 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)