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)
state – State code (e.g. CA, TX) or full name (e.g. California)
keywords – Search in title, agency name, or solicitation number
notice_type – Filter by notice type (e.g. Solicitation, Award Notice)
limit – Results per page (default 20, max 100)
offset – Pagination offset (default 0)
Advanced filters (Professional only)
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)
value_min – Minimum contract value in dollars
value_max – Maximum contract value in dollars
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
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
Professional plan - 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
Professional plan - High-value contracts:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?value_min=1000000&sort_by=posted_date"
Professional plan - Multiple NAICS codes:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?naics_multiple=541330,541511&limit=10"
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 6:00 AM UTC.
Response Format
{
"data": [
{
"notice_id": "abc123...",
"title": "Example Contract",
// ... 59 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/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,
"last_updated": "2025-11-22T02:06:52.095708+00:00"
},
"data_freshness": {
"last_collection": "2025-11-07T06:15:23Z",
"collection_frequency": "Daily at 6: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 6: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"
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 Starter+
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:
- Starter: Basic filters only (naics, psc, keywords). 3 exports/day.
- Professional: All advanced filters available. 15 exports/day.
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
Professional plan - Export with advanced filters:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/export.csv?agency=defense&value_min=1000000&limit=1000" \
-o defense_contracts.csv
Starter plan - Basic export (no advanced filters):
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), "starter", or "professional"
Example
Note: For paid plans (starter/professional), 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 paid plan subscription. Redirects to Stripe payment page.
Query Parameters
email - Your email address (required)
plan - Plan type: "starter" or "professional" (required)
Response
{
"status": "success",
"checkout_url": "https://checkout.stripe.com/c/pay/cs_...",
"plan": "Starter Plan - $9/month",
"session_id": "cs_..."
}
Example
Note: Redirect user to checkout_url from response
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 6 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
- Starter: 500 requests/hour
- Professional: 2,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 Implementation
- Current Status: Rate limiting is not actively enforced but documented limits should be respected
- Plan Restrictions: Advanced filters and CSV export restrictions are properly enforced according to plan levels
- Future Implementation: Rate limiting with proper HTTP headers planned for future release
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: 51,000+ 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 6 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
For High-Volume Applications
# Production-ready integration pattern
import requests
import time
from datetime import datetime, timedelta
class GovConAPIClient:
def __init__(self, api_key, plan='professional'):
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 == 'professional':
self.rate_limit = 2000 # hourly
self.burst_limit = 100 # per minute
else:
self.rate_limit = 500 # hourly
self.burst_limit = 25 # 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', 'professional')
# 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: Professional plan: up to 100 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 # Professional 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 Professional-only filters on lower 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
Contract notices are collected daily at 6: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.
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":"professional","email":"[email protected]"}
Step 2: Use features appropriate to your plan
Professional: All features available
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://govconapi.com/api/v1/opportunities/search?agency=defense&value_min=1000000"
Starter/Free: 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, fallback to basic search:
if [ $? -ne 0 ]; then
echo "Advanced filters require Professional plan, 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
API Validation & Testing
Validated November 22, 2025: All plan restrictions are properly enforced. Advanced filters (agency, value ranges, date filters, sorting) require Professional plan. Only basic filters (NAICS, state, keywords) available to Free and Starter plans.
All endpoints and features have been comprehensively tested. Below are the validation results:
Verified Working Features
- 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 Professional plan, CSV export requires paid plans
- Basic Search Filters: naics, state, keywords, notice_type (all plans)
- Advanced Filters: agency, value_min/max, date filters (Professional only)
- Pagination: limit/offset working correctly with has_next indicator
- Individual Record Lookup: /api/v1/opportunities/{id} working
- CSV Export: Working for Starter and Professional plans
- Error Handling: Proper HTTP codes and messages
- POST Endpoints: API key creation and Stripe checkout working
Current Database Stats (Tested)
- Total Records: 62,550 contract opportunities
- Currently Open: 8,757 active opportunities
- Award Records: 17,001 opportunities with award details
- Full Descriptions: 37,452 opportunities with complete requirement text
- Agency Coverage: 1,563 unique agencies and sub-agencies
- NAICS Coverage: 849 unique industry codes
- Last Updated: 2025-11-22 (daily collection at 6 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)
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)