GovCon API Documentation

Federal contract opportunities API. Clean, queryable data from SAM.gov with daily updates.

For interactive API testing, visit /docs.

Contents

🚀 Try the API Instantly

Import our complete federal contract notice API collection into Postman with sample requests, environment setup, and Bearer token authentication examples.

Includes: All API endpoints • Environment variables • Bearer token auth • CSV export examples • Live federal notice data from SAM.gov

Plan restrictions. Advanced filters (agency, value ranges, date filters) require Professional plan. CSV export requires paid plans.

Plans & Limits

Plan Daily / Hourly Requests CSV Exports / Day Key Features
Free Trial (14 days) 25 / day 0 All endpoints, basic filters
Starter 500 / hour 3 All endpoints, basic filters, CSV export
Professional 2,000 / hour 15 Advanced filters, multiple NAICS, CSV export

Authentication

Base URL: https://govconapi.com/api/v1

Send your API key in the Authorization header using the Bearer format:

Authorization: Bearer YOUR_API_KEY

API keys are available at https://govconapi.com.

Endpoints

GET

/api/v1/opportunities/search

Requires auth

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

{ "plan": "professional", "email": "[email protected]" }

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

curl -X POST \ "https://govconapi.com/api/v1/[email protected]&plan=free"

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

curl -X POST \ "https://govconapi.com/api/v1/[email protected]&plan=starter"

Note: Redirect user to checkout_url from response

Performance & Reliability

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:

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

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:

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

Current Database Stats (Tested)

Performance Benchmarks (Tested)

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)