Opportunities¶
Opportunities are SAM.gov opportunities/solicitations exposed at /api/opportunities/ (with a latest-notice pointer and history behind the scenes). For field definitions, see the Opportunities Data Dictionary.
Endpoints¶
GET /api/opportunities/(list + filtering + search + ordering)GET /api/opportunities/{opportunity_id}/(detail)
Notice UUID Resolution¶
If you pass a notice UUID (instead of an opportunity UUID) to the detail endpoint, the API automatically redirects (HTTP 302) to the parent opportunity. This is useful when you have a subsequent notice UUID (e.g., from an amendment) and want to reach the parent opportunity directly.
# Using a notice UUID redirects to the parent opportunity
GET /api/opportunities/{notice_id}/ → 302 /api/opportunities/{opportunity_id}/
If the notice UUID has no parent opportunity, the endpoint returns 404.
Filtering¶
Swagger is the canonical list of query parameters. These are the core filters most people use day-to-day. All date filters require YYYY-MM-DD format; invalid dates or inverted ranges return 400. See Date filters.
| Param | What it does |
|---|---|
search | Full-text search over opportunities (vector-backed). |
agency | Filter by agency or department (vector-backed). |
naics | Filter by NAICS. |
psc | Filter by PSC. |
set_aside | Filter by set-aside. |
notice_type | Filter by notice type (valid values are validated). |
solicitation_number | Filter by solicitation number. |
first_notice_date | First notice date (exact, YYYY-MM-DD). |
first_notice_date_after, first_notice_date_before | First notice date range. |
last_notice_date | Last notice date (exact, YYYY-MM-DD). |
last_notice_date_after, last_notice_date_before | Last notice date range. |
response_deadline | Response deadline (exact, YYYY-MM-DD). |
response_deadline_after, response_deadline_before | Response deadline range. |
place_of_performance | Full-text-ish filter over place-of-performance text. |
active | Filter active/inactive (default true). |
Ordering¶
Opportunities support ordering= with a strict allowlist:
first_notice_date(alias:posted_date)last_notice_dateresponse_deadline
Examples:
- Newest posted first:
GET /api/opportunities/?ordering=-posted_date - Soonest deadline first:
GET /api/opportunities/?ordering=response_deadline
Note: if you use search without an explicit ordering=..., results default to relevance ordering (rank).
Pagination¶
Opportunities use page-number pagination (page, limit) and return next/previous URLs.
Response Shaping¶
Opportunities support the ?shape= query parameter. When no ?shape= is provided, the endpoint returns a default shape.
Default shape (list): active,award_number,first_notice_date,last_notice_date,meta(*),naics_code,office(*),opportunity_id,place_of_performance(*),psc_code,response_deadline,sam_url,set_aside,solicitation_number,title
Default shape (detail): adds attachments(*), description, notice_history(*), primary_contact(*)
set_aside is available as a leaf (returns the code string) or as an expansion set_aside(code,description) for the full label.
See Response Shaping for syntax and examples.
Opportunities shaping notes¶
- New leaves:
latest_notice_id,archive_date, plus relation id leavesagency_id,department_id,office_id. - New expansions:
agency(*),department(*),latest_notice(notice_id,link). - Bare expand shorthand: common expansions can be requested without parentheses when the runtime must expand them for safety (e.g.,
officebehaves likeoffice(*), andattachmentsbehaves likeattachments(*)).
Examples:
# Include latest notice pointer + org expansions
/api/opportunities/?shape=opportunity_id,title,latest_notice_id,latest_notice(*),agency(*),department(*),office&limit=1
# Attachments without specifying subfields (shorthand)
/api/opportunities/{opportunity_id}/?shape=opportunity_id,title,attachments
SDK examples¶
Search opportunities (with shaping)¶
import { ShapeConfig, TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
const resp = await client.listOpportunities({
search: "cybersecurity",
agency: "DOD",
limit: 10,
shape: ShapeConfig.OPPORTUNITIES_MINIMAL,
});
for (const o of resp.results) {
console.log(o.opportunity_id, o.title);
}