Skip to content

Search opportunities

Search federal contract notices with filters. Returns paginated results.

Every filter is optional. To keep a full local copy in sync, use /api/v1/opportunities/delta: pass a timestamp, get only what changed since.

Combining filters

Every filter on this endpoint combines with AND. A request with naics=541512, state=VA, and content=CMMC returns only opportunities that match all three at once, and any filter can be mixed with any other (content with set_aside, active_only with date_from, and so on). The server echoes the filters it actually applied in filters_applied on every response, so you can confirm nothing was dropped. Two pairs are mutually exclusive, and both are covered below: naics vs naics_multiple (if both are sent, naics_multiple wins), and the value_*/amount_* money bounds (sending both forms of the same bound returns 400).

Basic filters (all plans)

  • naics: Single NAICS code (e.g. 541330)
  • psc: Product Service Code (e.g. D302). Accepts a comma-separated list (OR'd) and a trailing-* prefix: psc=7510,R408, psc=70* (all 70-series), or psc=R* (all R-series service codes). A bare code stays an exact match.
  • psc_type: coarse class of the notice's primary PSC, supply (numeric codes, products) or services (letter-prefixed codes). A first-pass supply-vs-services split without listing individual codes.
  • 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. Results are ranked by relevance to title and agency by default (descriptions still participate in matching but not in ranking, since they include standard regulatory clause text that would otherwise dilute results).
  • notice_type: Filter by notice type (e.g. Solicitation, Award Notice, Presolicitation). Accepts multiple comma-separated values, matched as OR: notice_type=Solicitation,Presolicitation,Combined Synopsis/Solicitation
  • solicitation_number: Exact solicitation number (e.g. W52P1J-25-R-0001)
  • limit: Results per page. Default 100; maximum 100 on the free trial and 1,000 on paid plans. Over the maximum returns 402.
  • offset: Pagination offset (default 0)
  • fields: Comma-separated response fields to return. notice_id always included. Example: fields=notice_id,title,naics,posted_date. See Response Shaping, and Response fields below for the full list of the 59 field names.
  • active_only: true / false. When true, returns only currently-open notices (those whose archive date is in the future). Echoed in filters_applied when set so a client can confirm the filter applied. Computed as archive_date_detailed > today; the stored active field is always "Yes" by design and is not what this filter reads.

Concepts to know before you integrate. These are assumptions the data makes that are not obvious from the field names; they cause the most integration mistakes.

  • notice_id vs solicitation_number. One procurement (one solicitation_number) moves through a lifecycle: Sources Sought → Presolicitation → Solicitation → amendments → Award Notice. Every stage and every amendment is a separate notice_id (a new 32-char hex). One solicitation maps to many notice_ids. To count unique procurements, dedupe on solicitation_number (falling back to notice_id when null). To walk a procurement's lifecycle, filter by solicitation_number=....
  • Three different date fields. posted_date is a calendar date (no time). response_deadline is a timezone-aware timestamp in UTC (+00:00), the bid deadline (precision varies by source). archive_date_detailed is a future calendar date (when the notice will be archived). All timestamp fields on this endpoint (including last_seen) are returned in UTC. Filters map to these: date_from / date_to / posted_after filter posted_date; due_after / due_before filter response_deadline; active_only reads archive_date_detailed.
  • active is always "Yes". The stored active field is a constant by design ("never archived" is a product feature). Do not filter on it. Use active_only=true to get currently-open notices.
  • description_text is tri-state. Real description text, the literal sentinel "NO_DESCRIPTION_AVAILABLE" (the notice has no description in the source), or null (description not yet retrieved). Handle all three.
  • set_aside_type "none" is tri-state too: "", "NONE", or null all mean unrestricted. A real code (SDVOSBC, 8A, WOSB, HZC, SBA, etc.) means restricted. Majority of set-asides are SBA.
  • Combined notices are common. "Combined Synopsis/Solicitation" is roughly a third of opportunities. When pulling bidding opportunities, pass the types together in one call (comma-separated values are OR'd): notice_type=Solicitation,Presolicitation,Combined Synopsis/Solicitation.
  • Award amounts only on Award Notices. award_amount, awardee_name, award_date, and related fields are populated only when notice_type=Award Notice. Solicitations and Sources Sought do not have these fields.

notice_type valid values (exact case-insensitive match, enforced — anything else returns 400 with the valid list): Solicitation, Combined Synopsis/Solicitation, Presolicitation, Sources Sought, Award Notice, Justification, Justification and Approval (J&A), Special Notice, Sale of Surplus Property, Modification/Amendment/Cancel, Consolidate/(Substantially) Bundle. Solicitation does NOT match Presolicitation. Pass several at once, comma-separated, to match any of them (notice_type=Solicitation,Presolicitation) — every value in the list must be valid, or the whole request 400s.

set_aside valid values (case-insensitive; a plain-English term OR the exact SAM code both work, anything else returns 400 with the valid list): a generic family term matches every variant of that set-aside (competitive and sole-source together).

Term you can type Also matches (exact codes)
8(a) 8A, 8AN (competed + sole source)
SDVOSB SDVOSBC, SDVOSBS (competed + sole source)
WOSB / Women Owned WOSB, WOSBSS (competed + sole source)
EDWOSB EDWOSB, EDWOSBSS (competed + sole source)
HUBZone HZC, HZS (competed + sole source)
VOSB / Veteran VSA, VSS (competed + sole source)
Small Business SBA (the majority of set-asides)
Indian Small Business ISBEE
Indian Economic Enterprise IEE
Buy Indian BICiv (Dept. of Health & Human Services / Indian Health Service specific)
Local Area LAS
Emerging Small Business ESB (rare)

To get only the sole-source half of a family, pass the exact code directly (set_aside=SDVOSBS, set_aside=HZS, set_aside=8AN, ...) instead of the family term. set_aside=SBP (Partial Small Business Set-Aside) has no shorter alias — it's distinct from SBA (Total Small Business Set-Aside) and uncommon enough that most callers want SBA.

Undocumented aliases. Four parameter aliases are accepted for forgiveness: q and keyword map to keywords; posted_from maps to date_from; posted_to maps to date_to. Canonical names win if both forms are sent.

naics + naics_multiple: if both are sent, naics_multiple wins and the single naics is silently dropped. Pick one. A 1-digit or 7+ digit value returns 400; a 2-5 digit prefix returns 400 with the "must be 6-digit" message; a well-formed but nonexistent 6-digit code returns 200 with total=0 (an empty result can mean "bad code," not "no opportunities").

Date, location, amount, and agency filters

  • agency: Agency name (partial match, e.g. defense)
  • set_aside: Set-aside type. Accepts either a plain-English term or the exact SAM code (both case-insensitive) — anything else returns 400 with the valid list. See set_aside valid values below.
  • 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)
  • date_from: Posted date from (YYYY-MM-DD format)
  • date_to: Posted date to (YYYY-MM-DD format)
  • sort_by: Sort field. Valid: posted_date (default when no keywords), due_date (maps to response_deadline), award_amount, title, agency, relevance. Invalid value returns 400 with the valid list (no silent fallback). When keywords is set and sort_by is omitted, results default to relevance (best title and agency matches first); pass sort_by=posted_date to override.
  • sort_order: asc or desc (default desc). Ignored when sort_by=relevance. NULLs sort first on asc, last on desc. Results are tie-broken by notice_id so pagination is stable.
  • naics_multiple: Comma-separated NAICS codes for multiple search
  • has_attachments: Filter by attachment availability: true or false

Search inside attachment documents (Pro)

  • content: Full-text search across the documents attached to an opportunity (PDF, Word, Excel, PowerPoint, and scanned pages read by OCR), not just the notice title and description that keywords covers. Over 209,000 opportunities carry at least one searchable attachment.

content and keywords search different layers. keywords matches the notice's title, agency, and description. content matches the text inside the attached solicitation, statement of work, and price schedule, where the requirements that decide whether you bid usually live: the award method (lowest-price-technically-acceptable vs best-value), the clearance level, the period of performance and option years, the incumbent, wage determinations, subcontracting plans, and compliance bars such as FedRAMP or CMMC. None of those are notice-level fields.

Query syntax matches keywords: multiple words match documents containing all of them (content=CMMC Level 2), and a quoted string matches that exact phrase (content="active secret clearance").

content is not tied to any one filter, it combines with all of them (every filter on this endpoint ANDs together, as described under Combining filters above). Scope a document search to an industry (content=CMMC&naics=541512), to open opportunities only (content=FedRAMP&active_only=true), to a place of performance (content=incumbent&state=VA), to a set-aside (content="Berry Amendment"&set_aside=SDVOSB), or to a date range (content=SBOM&date_from=2025-06-01).

content requires the Pro plan. On other plans the request returns 402 and reports how many opportunities match, so you can see the coverage before upgrading:

{
  "detail": "5,312 opportunities have solicitation documents matching 'CMMC'. Full-text search inside attachment documents requires the Pro plan ($39/mo), no per-query limits, 1,000 requests/hour. Upgrade at https://govconapi.com/#pricing"
}

Response

{
  "data": [
    {
      "notice_id": "abc123def456",
      "title": "IT Services Contract",
      "agency": "Department of Defense",
      "posted_date": "2025-11-01",
      "response_deadline": "2025-12-15T17:00:00+00:00",
      "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/...",
      "resource_links_array": ["https://sam.gov/api/prod/opps/v3/opportunities/resources/files/<id>/download"],
      "performance_city_name": "Washington",
      "performance_state_code": "DC",
      "_additional": "59 fields total per record"
    }
  ],
  "pagination": {
    "limit": 20,
    "offset": 0,
    "total": 343,
    "total_is_estimate": false,
    "has_next": true
  },
  "filters_applied": {
    "naics": "541330",
    "state": "CA"
  },
  "window": {
    "plan_window_days": null,
    "earliest_searchable": null,
    "clamped": false
  }
}

Total count is capped at 10,000

On broad searches, pagination.total stops at 10000 and the response sets "total_is_estimate": true (read it as "10,000+"). Exact counts on very broad full-text matches are expensive, so the count short-circuits past 10,001. Page forward with has_next; do not compute the last page from total when total_is_estimate is true. The other list endpoints (awards, companies, entities, exclusions) return an exact total.

The window block is always present on this endpoint. On paid plans it reads as in the example above: no window. On the free trial it shows the 90-day window and whether your query was clamped; see Search Window above for the field-by-field explanation.

Response fields (59 per record)

Every record carries the same 59 fields, and the single-notice endpoint /opportunities/{notice_id} returns this identical shape. Pass fields= to request only the ones you need. The response is a flat object; the groups below are for reading only.

Identity and lifecycle

  • notice_id (string): 32-char hex, unique per notice stage and amendment. Always returned, your row-to-query join key.
  • solicitation_number (string, nullable): human contract identifier, shared across a procurement's stages. Dedupe on this for unique procurements.
  • title (string): notice title.
  • notice_type (string): stage or type (Solicitation, Award Notice, and the rest listed above).
  • notice_base_type (string): base type before amendment suffixing, usually equal to notice_type.
  • active (string): always "Yes" by design (notices are never archived). Do not filter on it, use active_only.
  • source_version (string): record vintage (live for pipeline-ingested, historical for backfilled).

Dates

  • posted_date (string, YYYY-MM-DD): calendar date the notice posted (no time component).
  • response_deadline (string, timestamp, nullable): bid deadline, timezone-aware, precision varies by source. Filtered by due_after / due_before.
  • archive_date_detailed (string, YYYY-MM-DD, nullable): future date the notice will be archived, and what active_only reads.
  • archive_type_detailed (string, nullable): how the archive date is derived (e.g. auto15).
  • last_seen (string, timestamp): when the ingest pipeline last observed this notice.

Classification

  • naics (array of string): NAICS code(s), an array even when there is one.
  • psc (array of string): Product and Service Code(s), an array.
  • set_aside_type (string, nullable): set-aside code (SDVOSBC, 8A, WOSB, and so on). "", "NONE", and null all mean unrestricted (tri-state).
  • set_aside_description (string, nullable): human-readable set-aside label.

Agency

  • agency (string): full org hierarchy as a dotted name path (department.sub-tier.office).
  • agency_path_code (string, nullable): the same hierarchy as numeric codes (e.g. 097.97F2.HE1254).
  • office_country_code (string, nullable): issuing office country.
  • organization_type (string, nullable): issuing org level (e.g. OFFICE).

Award (populated on notice_type=Award Notice only)

  • award_number (string, nullable): award or contract number.
  • award_amount (number, nullable): award value in dollars.
  • award_date (string, YYYY-MM-DD, nullable): date awarded.
  • award_uei_sam (string, nullable): awardee SAM UEI, often null on older or thin award notices.
  • award_cage_code (string, nullable): awardee CAGE code.

Awardee (on Award Notices)

  • awardee_name (string, nullable).
  • awardee_street_address, awardee_street_address2 (string, nullable).
  • awardee_city_name, awardee_city_code (string, nullable).
  • awardee_state_name, awardee_state_code (string, nullable).
  • awardee_zip (string, nullable).
  • awardee_country_name, awardee_country_code (string, nullable).

Place of performance

  • performance_city_name, performance_city_code (string, nullable).
  • performance_state_name, performance_state_code (string, nullable).
  • performance_zip (string, nullable).
  • performance_country_name, performance_country_code (string, nullable).
  • performance_street_address, performance_street_address2 (string, nullable).

Contacts

  • contact_name, contact_title, contact_email, contact_phone, contact_fax (string, nullable): primary point of contact.
  • primary_contact_type (string, nullable): label for the primary contact.
  • secondary_contact_name, secondary_contact_email (string, nullable): secondary point of contact.

Links and description

  • sam_url (string): human sam.gov workspace URL for the notice.
  • ui_link (string): sam.gov UI link (frequently identical to sam_url).
  • api_self_link (string): SAM API self link for the notice.
  • additional_info_link (string, nullable): extra information URL when the notice provides one.
  • description_url (string, nullable): SAM API URL for the raw description.
  • description_text (string, nullable): full description. Tri-state: real text, the literal "NO_DESCRIPTION_AVAILABLE" (no description in the source), or null (not yet retrieved, newly posted notices populate within a short window).
  • resource_links_array (array of string): canonical sam.gov download URLs for the notice's attached documents, [] when the notice has none. To search inside those documents, use the Pro content filter above.

Examples

NAICS + state:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://govconapi.com/api/v1/opportunities/search?naics=541330&state=CA&limit=10"

NAICS 541330 (engineering services) in California returns the matching opportunities (343 on a paid plan on 2026-09-14; the free trial sees the last 90 days)

Agency filter:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://govconapi.com/api/v1/opportunities/search?agency=defense&limit=20"

A broad filter like this matches far more than the count cap, so pagination.total reads 10000 with total_is_estimate: true (page forward with has_next)

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.

Pro - Search inside the documents, scoped to a NAICS:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://govconapi.com/api/v1/opportunities/search?content=CMMC&naics=541512&sort_by=posted_date&limit=2"
{
  "data": [
    {
      "notice_id": "9844dc9a31814234bbfef9359f22676f",
      "title": "CIO Microsoft Sentinel Implementation FY26",
      "agency": "DEPT OF DEFENSE.DEPT OF THE ARMY.AMC.ACC.MISSION INSTALLATION CONTRACTING COMMAND.FDO EUSTIS.W6QM MICC-CARLISLE BARRACKS",
      "posted_date": "2026-07-01"
    }
  ],
  "pagination": { "limit": 2, "offset": 0, "total": 108, "total_is_estimate": false, "has_next": true },
  "filters_applied": { "naics": "541512", "content": "CMMC", "date_from": "2024-07-15", "sort_by": "posted_date", "sort_order": "desc" }
}

Both filters apply together: every row is NAICS 541512 and its attached documents mention CMMC. content=CMMC alone matches 5,312 opportunities; adding the NAICS narrows it to 108. The matching text lives in the solicitation or statement of work, not the notice title.

A REST API and MCP server for U.S. federal procurement data.

Get a free key, emailed instantly, or follow the quickstart.

Found something wrong, missing or confusing on this page?

Press Ctrl + Enter to send a note. Highlight text first and it travels with your note.