GovCon API Documentation

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

For interactive API testing, visit /docs.

Quick Start: Get a free API key (emailed instantly):
curl -X POST "https://govconapi.com/api/v1/keys?email=YOUR_EMAIL&plan=free"

Contents

Critical: The active field is always "Yes"
Do NOT filter by active - it's meaningless (always "Yes" from SAM.gov).
Use response_deadline to find open opportunities and notice_type to understand lifecycle stage.
Plan restrictions. Advanced filters require the Developer plan. CSV export requires the Developer plan. Free trial has basic filters only.

Plans & Limits

Plan Rate Limit Results / Request CSV Exports / Day Key Features
Free Trial (14 days) 25 / day 50 0 All endpoints, basic filters only
Developer 1,000 / hour 1,000 15 All filters, 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 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)
  • psc – Product Service Code (e.g. D302)
  • 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, 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:
  • 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)
  • 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

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"

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", // ... 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/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": "developer", "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 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"

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: 112,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='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

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 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.

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

Current data (Dec 2025): 88,115 total records | 7,625 still open for bidding | 56,665 past deadline | 23,825 awards/pre-solicitations

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

API Validation & Testing

Validated December 2025: Plan restrictions are properly enforced. Advanced filters require a paid plan (Developer). Free plan has access to basic filters only (NAICS, PSC, state, keywords, notice_type, solicitation_number).

All endpoints and features have been comprehensively tested. Below are the validation results:

Verified Working Features

Current Database Stats (Tested)

Performance Benchmarks (Tested)

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)