# GovCon API

Version: `1.0.0`

## Federal Contracts API for Developers

Clean JSON access to federal procurement data: contract opportunities, awards,
the SAM entity registry, debarment exclusions, and contracting-officer contacts.

### What's covered
- **Contract opportunities** (SAM.gov notices, daily refresh)
- **Award history** (winners, amounts, agencies, dates)
- **SAM entity registry** (~873K registered firms by UEI or CAGE; registration
  status, expiration, NAICS, business-type certifications)
- **Exclusions** (debarred / suspended entities)
- **Companies** (Pro: combined SAM profile + award history)
- **Vendor Risk** (Pro: 7-signal screening per UEI)

### Authentication
All endpoints (except public demo) require Bearer token authentication:
```
Authorization: Bearer your_api_key_here
```

### Plans
- **Free Trial**: 25 req/day, 14 days, no credit card
- **Developer ($19/mo)**: 1000 req/hr, all opportunities + awards + exclusions
  filters + SAM entity lookup (UEI, CAGE, name search) + CSV exports
- **Pro ($39/mo)**: everything Developer + Companies API + multi-filter
  entity search + SAM expiration radar + Vendor Risk + unlimited GovCon Contacts

Use `/api/v1/stats` and `/api/v1/me` endpoints for current data and plan details.

### 📚 Documentation
- **This page**: Interactive API reference for developers
- **[Comprehensive Guide](/api-guide)**: Business documentation with worked examples and use cases

Single-file Markdown bundle generated from the live OpenAPI 3.1 schema. Source: <https://govconapi.com/openapi.json>.

## Endpoints

### `GET /api-guide`

**Api Guide**

Comprehensive API documentation with performance metrics and enterprise patterns

**Responses:**
- `200`: Successful Response

### `GET /api/agency-crosswalk`

**Get Agency Crosswalk**

Public endpoint - returns agency name standardization mappings (pre-built by weekly cron).

Each row is enriched with the matched `federal_hierarchy` entry (organization_id, cgac, type)
when the canonical_agency resolves to a SAM Federal Hierarchy org. ~99% match rate.
Use organization_id to call GET /api/v1/federal-hierarchy/{id} for structured data.

**Responses:**
- `200`: Successful Response

### `GET /api/v1/awards/search`

**Search Federal Contract Awards**

Tags: Awards

Search awarded contracts by awardee name, UEI, agency, NAICS, amount range, and date range. All filters available on all plans. Free plan: max 50 results. Paid plan: max 1000 results.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `awardee_name` | query |  | no | Awardee company name (partial match, case-insensitive) |
| `uei` | query |  | no | Exact UEI match |
| `naics` | query |  | no | NAICS code |
| `agency` | query |  | no | Awarding agency (partial match) |
| `amount_min` | query |  | no | Minimum award amount |
| `amount_max` | query |  | no | Maximum award amount |
| `awarded_after` | query |  | no | Awards on or after this date (YYYY-MM-DD) |
| `awarded_before` | query |  | no | Awards on or before this date (YYYY-MM-DD) |
| `state` | query |  | no | Awardee state code (2-letter, e.g. CA) |
| `sort_by` | query |  | no | Sort field: award_amount, award_date, awardee_name |
| `sort_order` | query |  | no | Sort order: asc or desc |
| `limit` | query | integer | no | Results per page |
| `offset` | query | integer | no | Pagination offset |
| `fields` | query |  | no | Comma-separated response fields to return. `notice_id` always included. Example: `fields=notice_id,awardee_name,award_amount,award_date`. |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/awards/{award_number}`

**Get Award by Contract Number**

Tags: Awards

Get a single award record by award/contract number. Returns the most recent record if multiple exist.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `award_number` | path | string | yes |  |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `POST /api/v1/checkout`

**Create Checkout Session**

Create Stripe checkout session for Developer plan subscription

**Responses:**
- `200`: Successful Response

### `GET /api/v1/companies/search`

**Search awarded companies by name or UEI substring (firms with 1+ federal award; for all registered firms use /entities/search)**

Tags: Companies (Pro)

Case-insensitive substring (ILIKE) match across awardee names + UEI prefix match.
Scope: companies that have won at least one federal award (the awardee list),
NOT the full SAM registry. For all registered firms, use /api/v1/entities/search.

Returns distinct awardees ordered by total_awards desc. Paginated via
limit + offset. pagination.total is the full match count across all pages.

Optional `naics` and `agency` filters narrow the candidate set to companies
that have actually WON awards under that NAICS / from that agency (distinct
from Federal Contractor Search, which filters by SAM registration data —
"registered for NAICS X" vs "won awards under NAICS X").

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `q` | query | string | yes | Name substring or UEI prefix |
| `naics` | query |  | no | 6-digit NAICS code. Filters to companies that have won at least one award under this NAICS. |
| `agency` | query |  | no | Agency top-level name (e.g. 'DEPT OF DEFENSE'). Filters to companies that have won at least one award from this agency. Matches the top-level of SAM's dotted agency path. |
| `limit` | query | integer | no |  |
| `offset` | query | integer | no |  |
| `fields` | query |  | no | Comma-separated response fields. `uei` always included. Example: `fields=uei,name,total_value`. |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/companies/{uei}`

**Company profile with aggregated stats**

Tags: Companies (Pro)

Aggregate profile for a single UEI.

Combines two sources:
  - **SAM entity registration** (legal name, DBA, address, NAICS, PSC,
    business-type certifications, registration dates, CAGE codes)
  - **Award history** (totals, top NAICS/agencies, activity windows)

Returns 200 if either source has the UEI. Returns 404 only when the UEI
is unknown to both. Award fields default to 0/empty when the company is
SAM-registered but has never won a contract (the common case for SMBs
in the SAM directory of ~880K registered entities).

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `uei` | path | string | yes |  |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/companies/{uei}/awards`

**Award history for a UEI (paginated)**

Tags: Companies (Pro)

Full paginated award history. sort=date (default, desc) | amount (desc).

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `uei` | path | string | yes |  |
| `limit` | query | integer | no |  |
| `offset` | query | integer | no |  |
| `sort` | query | string | no |  |
| `fields` | query |  | no | Comma-separated response fields. `notice_id` always included. |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/companies/{uei}/peers`

**Similar companies by NAICS + agency overlap**

Tags: Companies (Pro)

Find similar awardees based on overlap of NAICS codes and agencies.

Scoring: count NAICS overlap + count agency overlap (each weighted by
their award frequency at the target UEI). Not a true Jaccard; closer
to 'weighted match count'.

This is the slowest endpoint. Expect 200-1500ms on prod data.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `uei` | path | string | yes |  |
| `limit` | query | integer | no |  |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/contacts/lookup`

**Look Up Contracting Officer Contact Info**

Tags: Contacts (Pro)

Resolver lookup for a contracting officer.

Two query modes:
- **By name** (`name=X`, optional `agency=Y` and `state=ST`). Returns up to 5 substring matches.
- **By email** (`email=foo@bar.gov`). Exact match, single record. Useful for CRM-enrichment workflows where the email is on file and the customer wants the current name / agency / phone for that address.

One of `name` or `email` is required.

**This is a resolver, not a directory.** It is not possible to list or paginate contacts via this endpoint. To browse the full directory, search by NAICS or agency, view award history, or see colleague graphs and AI dossiers, use the web app at https://contacts.govconapi.com (included with Pro).

**Auth:** Pro tier ($39/mo). Returns 402 on Developer-only keys.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `name` | query |  | no | Name (or partial name) of the contracting officer. Required unless `email` is provided. |
| `agency` | query |  | no | Optional agency substring for disambiguation (e.g. 'Air Force', 'DLA'). Used only with `name`. |
| `state` | query |  | no | Optional 2-letter state/territory code (e.g. 'CA', 'DC'). Used only with `name`. |
| `email` | query |  | no | Exact email address for reverse lookup. Returns one record. Mutually exclusive with `name` (if both, `email` wins). |

**Responses:**
- `200`: Up to 5 contacts matching the query.
- `402`: Caller's plan does not include contacts_access. Upgrade to Pro.
- `404`: No matching contacts.
- `422`: Required parameter missing or invalid.
- `429`: Rate limit exceeded.
- `503`: Contacts data store temporarily unavailable. Retry.

### `GET /api/v1/entities/by-cage/{cage_code}`

**SAM entity lookup by CAGE code (Developer tier)**

Tags: Entities

SAM-registered entity by Commercial and Government Entity (CAGE) code.

CAGE is the DoD/DLA-issued 5-character identifier used by contracting
officers and legacy procurement systems. Each CAGE code is assigned to
one entity by DLA. Large entities (USPS, financial institutions) can
have multiple CAGE codes per UEI; this endpoint returns the entity
that owns the CAGE you queried.

Response is the same shape as `/entities/{uei}` plus a `queried_cage`
field echoing the input. Developer tier (matches `/entities/{uei}` —
both are alternate-identifier lookups for the same underlying record).

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `cage_code` | path | string | yes |  |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/entities/expiring`

**Registrations expiring within N days (Pro)**

Tags: Entities

Active SAM registrations expiring within `within_days` days.

Pro. Renewal-radar use case: customers monitor a state, a NAICS
cohort, or the full population for entities that need to renew. Past-due
expirations are excluded (status would already be 'E').

Sorted by expiration_date ascending (most urgent first). Result includes
`days_until_expiration` for direct rendering.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `within_days` | query | integer | no | Days from today to look ahead |
| `state` | query |  | no |  |
| `naics` | query |  | no |  |
| `limit` | query | integer | no |  |
| `offset` | query | integer | no |  |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/entities/search`

**Search SAM entities (q = Developer; filters = Pro)**

Tags: Entities

Filter-based entity search.

**Developer tier**: pass `q` only (name substring, trigram-indexed).

**Pro**: combine `q` with `naics` / `state` / `business_type` /
`active_only` filters. The DSBS replacement.

At least one of `q` / `naics` / `state` / `business_type` / `active_only`
must be provided. NAICS values omit the Y/N small-business suffix (we
match either flag).

`business_type` accepts SAM 2-3 char codes like `8W` (WOSB), `QF`
(SDVOSB), `27` (Self-Cert SDB), `2X` (For Profit), etc. Full list in
`entities/business_types.py`. Note: SBA-certified codes (A6, XX, JT, A4)
are valid but appear ~zero times in the Public V2 SAM extract.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `q` | query |  | no | Name substring (Developer tier) |
| `naics` | query |  | no | NAICS code, no Y/N suffix (Pro) |
| `state` | query |  | no | 2-letter US state (Pro) |
| `business_type` | query |  | no | SAM business-type code (Pro). See entities/business_types.py. |
| `active_only` | query | boolean | no | Only Active registrations (Pro) |
| `limit` | query | integer | no |  |
| `offset` | query | integer | no |  |
| `fields` | query |  | no | Comma-separated response fields. `uei` always included. Example: `fields=uei,legal_business_name,primary_naics`. |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/entities/{uei}`

**SAM entity lookup by UEI (Developer tier)**

Tags: Entities

Single SAM-registered entity by UEI.

Returns registration block (status, dates, expiring_soon flag) and entity
block (legal name, DBA, address, NAICS/PSC, business-type certifications,
decoded labels, CAGE codes).

Available on Developer tier (any active API key). For award-history merge
on top of this data, Pro subscribers should use `/companies/{uei}`.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `uei` | path | string | yes |  |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/exclusions/search`

**Search Excluded Entities**

Tags: Exclusions

Search SAM.gov exclusions database for debarred entities. Search by name, UEI, CAGE code, agency, or location.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `entity_name` | query |  | no | Entity or person name (partial match) |
| `name` | query |  | no | Alias for entity_name (accepted for backwards compatibility) |
| `uei_sam` | query |  | no | UEI SAM identifier |
| `cage_code` | query |  | no | CAGE code |
| `excluding_agency` | query |  | no | Excluding agency code (e.g., DOJ, DOD) |
| `classification_type` | query |  | no | Classification: Individual, Firm, Vessel, Special Entity Designation |
| `exclusion_type` | query |  | no | Type: Ineligible (Proceedings Pending), Ineligible (Proceedings Completed), etc. |
| `state` | query |  | no | State/province code |
| `country` | query |  | no | Country code |
| `active_only` | query | boolean | no | Only show currently active exclusions |
| `limit` | query | integer | no | Results per page |
| `offset` | query | integer | no | Pagination offset |
| `fields` | query |  | no | Comma-separated response fields to return. `uei_sam` always included. Example: `fields=entity_name,uei_sam,excluding_agency_code,activate_date`. Omit to return all fields (default). |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/exclusions/{uei_sam}`

**Check UEI Against Exclusions List**

Tags: Exclusions

Vendor-risk screening lookup: pass a UEI SAM and find out whether that entity has an active or historical exclusion record.

**Response semantics**
- `200` — entity IS on the exclusions list. Body contains the full record.
- `404` — UEI is **not** on the exclusions list. This is the expected answer for the vast majority of legitimate vendors and means the entity is clean.

**Coverage caveat:** roughly 73% of SAM exclusions are individuals or small entities without a UEI. A 404 here means *no UEI-keyed exclusion*; to also screen against name-based debarments (e.g. principals, officers, individuals), pair this lookup with `/api/v1/exclusions/search?entity_name=...`.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `uei_sam` | path | string | yes |  |

**Responses:**
- `200`: Entity is on the exclusions list. Full record returned.
- `404`: No UEI-keyed exclusion found. Entity is clean by UEI; screen names separately for full coverage.
- `422`: Validation Error
- `429`: Rate limit exceeded.

### `GET /api/v1/federal-hierarchy/`

**List Federal Organizations**

Tags: Federal Hierarchy

Search and filter the SAM Federal Hierarchy (~907 federal departments, agencies, and offices). All filters are optional. Free tier — available to any authenticated API key.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `type` | query |  | no | Filter by type: DEPARTMENT or AGENCY (case-insensitive) |
| `cgac` | query |  | no | Filter by Treasury account code (e.g. 097 for DoD) |
| `parent_id` | query |  | no | Filter by parent organization_id |
| `hierarchy_level` | query |  | no | Filter by depth (1 = root department) |
| `is_active` | query |  | no | Filter by active status (default: true) |
| `search` | query |  | no | Match on canonical_name, short_name, or alternative_names (case-insensitive) |
| `limit` | query | integer | no | Results per page (default 50, max 1000) |
| `offset` | query | integer | no | Pagination offset |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/federal-hierarchy/{organization_id}`

**Federal Organization Detail**

Tags: Federal Hierarchy

Lookup a single federal organization by `organization_id`. Response includes the full record plus inline `parent`, `children`, and `ancestors` for traversal in one call.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `organization_id` | path | integer | yes |  |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/federal-hierarchy/{organization_id}/ancestors`

**Ancestor Chain**

Tags: Federal Hierarchy

Return the chain of ancestors (root → immediate parent) for `organization_id`. Empty array if the organization is a root department.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `organization_id` | path | integer | yes |  |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/federal-hierarchy/{organization_id}/children`

**Immediate Children**

Tags: Federal Hierarchy

Return immediate child organizations of `organization_id`.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `organization_id` | path | integer | yes |  |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `POST /api/v1/keys`

**Create API Key**

Tags: Management

Create or regenerate API key. New users get free trial, existing users keep current plan.

**Responses:**
- `200`: Successful Response

### `GET /api/v1/me`

**Current User Info**

Tags: Management

Get current user's plan and account information

**Responses:**
- `200`: Successful Response

### `GET /api/v1/opportunities/delta`

**Delta Sync**

Tags: Delta Sync

Get all opportunities added or modified since a given timestamp. Use this to keep your local database in sync without re-pulling everything.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `since` | query | string | yes | ISO 8601 timestamp (e.g. 2026-04-05T06:00:00Z). Returns records where last_seen >= this value. |
| `limit` | query | integer | no | Results per page |
| `offset` | query | integer | no | Pagination offset |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/opportunities/search`

**Search Contract Opportunities**

Tags: Search

Search federal contract opportunities. All filters available on every plan. Developer plan adds CSV export, larger page size (1,000 vs 50), and 1,000/hour rate limit.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `naics` | query |  | no |  |
| `psc` | query |  | no |  |
| `agency` | query |  | no |  |
| `state` | query |  | no |  |
| `posted_after` | query |  | no |  |
| `due_before` | query |  | no |  |
| `due_after` | query |  | no |  |
| `keywords` | query |  | no | Full-text search across title, agency name, and contract description. Also matches solicitation number. |
| `set_aside` | query |  | no |  |
| `notice_type` | query |  | no |  |
| `solicitation_number` | query |  | no | Exact solicitation number (e.g., USCA25Q0053) |
| `value_min` | query |  | no |  |
| `value_max` | query |  | no |  |
| `location` | query |  | no |  |
| `date_from` | query |  | no |  |
| `date_to` | query |  | no |  |
| `sort_by` | query |  | no |  |
| `sort_order` | query |  | no |  |
| `naics_multiple` | query |  | no |  |
| `has_attachments` | query |  | no |  |
| `active_only` | query | boolean | no | Convenience filter, computed by us from `archive_date_detailed`. When true, returns only notices whose archive date is in the future (i.e. currently open). This is NOT a SAM source field — the stored `active` column is always 'Yes' by design (we never archive). Equivalent to filtering `archive_date_detailed > CURRENT_DATE` yourself. |
| `limit` | query | integer | no | Results per page (1-1000, plan-capped further). Use Query so 0/negative reject at validator instead of returning empty data. |
| `offset` | query | integer | no | Pagination offset |
| `format` | query | string | no |  |
| `fields` | query |  | no | Comma-separated list of response fields to return. Reduces payload size when you only need a few columns. Example: `fields=notice_id,title,naics,posted_date`. `notice_id` is always included. Omit to return all 59 fields per record (default). |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/opportunities/{notice_id}`

**Get Single Opportunity**

Tags: Search

Retrieve detailed information for a specific contract opportunity

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `notice_id` | path | string | yes |  |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/opportunities/{notice_id}/attachments`

**Get Opportunity Attachments**

Tags: Search

Retrieve attachment URLs for a specific contract opportunity. Returns direct SAM.gov download links.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `notice_id` | path | string | yes |  |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/stats`

**Database Statistics**

Tags: Public

Get current database statistics and data freshness information

**Responses:**
- `200`: Successful Response

### `POST /api/v1/vendor-risk/bulk`

**Bulk vendor risk screening (up to 100 UEIs)**

Tags: Vendor Risk (Pro)

Return risk reports for each supplied UEI. Not-found UEIs come back
with status='not_found' rather than failing the whole request — stale
UEIs in vendor lists are normal.

**Request body:**
- Content type: `application/json`

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /api/v1/vendor-risk/{uei}`

**Vendor risk report for a UEI**

Tags: Vendor Risk (Pro)

Return all seven risk signals for a single UEI.

Always returns 200 with the full signal shape, even for clean vendors.
Never returns a risk score; callers interpret the signals themselves.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `uei` | path | string | yes |  |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /dashboard`

**Get Dashboard Html**

Tags: Admin

Visual dashboard shell.
Authentication handled client-side via JavaScript + localStorage.

**Responses:**
- `200`: Successful Response

### `GET /dashboard.json`

**Get Dashboard Json**

Tags: Admin

Dashboard data as JSON - view app health, user stats, and performance metrics

**Responses:**
- `200`: Successful Response

### `GET /demo/opportunities`

**Demo Opportunities**

Public demo endpoint - returns latest 2 opportunities (cached for 6 hours)

**Responses:**
- `200`: Successful Response

### `GET /export.csv`

**Export Csv**

Export opportunities as CSV. Max 1000 records. Subset of /opportunities/search filters.

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `keywords` | query |  | no |  |
| `naics` | query |  | no |  |
| `naics_multiple` | query |  | no |  |
| `agency` | query |  | no |  |
| `state` | query |  | no |  |
| `set_aside` | query |  | no |  |
| `notice_type` | query |  | no |  |
| `solicitation_number` | query |  | no |  |
| `limit` | query | integer | no |  |

**Responses:**
- `200`: Successful Response
- `422`: Validation Error

### `GET /favicon.ico`

**Favicon Ico**

Serve favicon.ico (redirect to SVG)

**Responses:**
- `200`: Successful Response

### `GET /health`

**Health**

Health check endpoint.

**Responses:**
- `200`: Successful Response

### `GET /robots.txt`

**Robots**

Generate robots.txt for search engine crawlers

**Responses:**
- `200`: Successful Response

### `GET /sitemap.xml`

**Sitemap**

Generate XML sitemap for search engines including daily snapshots

**Responses:**
- `200`: Successful Response
