On this page
Welcome to Tango API Documentation¶
The Tango API provides comprehensive access to federal procurement and assistance data, including contracts, grants, entities, and opportunities. This documentation will help you integrate with our API quickly and effectively.
What is Tango?¶
Tango is an integrated platform that consolidates federal procurement and assistance data from multiple sources (FPDS, USAspending, SAM) into a unified system. Our API provides:
- Contract Data: Federal contract awards, modifications, and transactions
- Grant Data: Financial assistance awards and transactions
- Entity Information: Vendor and recipient details with business classifications
- Opportunity Data: Contract opportunities and solicitation notices (SAM.gov)
- Agency Data: Government department, agency, and office information
- Procurement Forecasts: Upcoming procurement opportunities across many agencies
- Webhooks: Near-real-time notifications when new data is available (awards, opportunities, entities, grants, forecasts)
- And much more to come...
Getting Started¶
Quick Start Guide¶
Get up and running in 5 minutes.
Swagger documentation¶
See the full documentation for the endpoints.
OpenAPI spec (JSON)¶
Full endpoint definitions, parameters, and response models in one fetch — for tools, scripts, and AI consumers.
API Reference¶
Filtering, ordering, and pagination by endpoint (curated reference; Swagger remains canonical for full surface area).
Data Dictionary¶
Field definitions for API resources.
Rate limits¶
Learn how to read rate limit headers, handle 429s, and retry responsibly.
Machine-readable: For AI and scripts, use the OpenAPI spec (JSON), the single-page HTML reference, or the combined markdown (all docs in one file).
Key Features¶
🔐 Flexible Authentication¶
- API Keys: Simple server-to-server integration
- OAuth2: For web applications and user tokens
📊 Rich Data Model¶
- Comprehensive Coverage: Contracts, grants, entities, opportunities
- Historical Data: Years of federal spending data
- Real-time Updates: Frequent data refreshes + optional webhooks for near-real-time notifications
⚡ High Performance¶
- Smart Filtering: Efficient query optimization
- Pagination: Handle large result sets
- Caching: Fast response times
- Rate Limiting: Fair usage policies
🔍 Advanced Search¶
- Full-text Search: Search across titles and descriptions
- Complex Filtering: OR/AND patterns for precise queries
- Geographic Search: Location-based filtering
- Date Ranges: Flexible temporal queries
🎯 Response Shaping¶
- Custom Field Selection: Request only the data you need to reduce payload size
- Nested Expansions: Include related objects (recipients, offices, transactions) in a single request
- Flattening Support: Convert nested JSON to flat structures for easier consumption
- Flexible Aliasing: Rename fields to match your application's naming conventions
Learn more in the Response Shaping Guide. For field definitions, see the Data Dictionary.
🔔 Webhooks¶
Subscribe to event notifications when new data is available (awards, opportunities, entities, grants, forecasts).
Learn more in the Webhooks Partner Guide.
MCP (AI agents)¶
Use Tango from Claude Desktop, Cursor, or other MCP-compatible clients. The Tango MCP server exposes 4 tools to discover, search, and get details on contracts, opportunities, entities, and more.
Learn more in the MCP (AI agents) guide.
Data Sources¶
Tango integrates data from authoritative federal sources:
- FPDS (Federal Procurement Data System) - Contract awards and modifications
- USAspending - Financial assistance and sub-award data
- SAM.gov - Entity registrations and contract opportunities
- Grants.gov - Federal grant opportunities
- Agency Systems - Direct agency data feeds including the Federal Hierarchy
Provenance¶
Learn more about our data sources and how we use them in Provenance.
Changelog¶
See what's new and what's changed in each release in the Changelog.
Guides
Quick Start Guide¶
Get up and running with the Tango API in 5 minutes or less.
Prerequisites¶
- Basic knowledge of HTTP and JSON
- A web browser or API client (like Postman, Insomnia, or curl)
- Optional: Programming language of your choice (Python, JavaScript, etc.)
Step 1: Get Your API Key¶
- Visit Tango Web Interface
- Sign up for an account or log in
- Navigate to your API keys section
- Create a new API key
- Copy your API key (you'll need it for all requests)
Note: The API requires authentication for all access. Anonymous access is not supported. You'll need an API key for any usage.
Step 2: Make Your First API Call¶
Let's start with a simple request to get information about a government agency:
Using cURL¶
Using Python¶
import requests
headers = {'X-API-KEY': 'your-api-key-here'}
response = requests.get(
'https://tango.makegov.com/api/agencies/7200/',
headers=headers
)
agency = response.json()
print(f"Agency: {agency['name']}")
print(f"Department: {agency['department']['name']}")
Using JavaScript¶
const response = await fetch('https://tango.makegov.com/api/agencies/7200/', {
headers: {
'X-API-KEY': 'your-api-key-here'
}
});
const agency = await response.json();
console.log(`Agency: ${agency.name}`);
console.log(`Department: ${agency.department.name}`);
Step 3: Explore the Response¶
You should receive a JSON response like this:
{
"code": "7200",
"name": "Department of Veterans Affairs",
"department": {
"code": "36",
"name": "Department of Veterans Affairs"
},
"abbreviation": "VA",
"website": "https://www.va.gov"
}
Step 4: Try a More Complex Query¶
Now let's search for contracts awarded to a specific company:
curl -H "X-API-KEY: your-api-key-here" \
"https://tango.makegov.com/api/contracts/?recipient=ACME&ordering=-award_date&limit=5"
This query:
- Searches for contracts with "ACME" in the recipient name
- Orders by award date (newest first)
- Limits results to 5 contracts
Step 5: Understand the Response Format¶
Most API endpoints return paginated responses:
{
"count": 1250,
"next": "https://tango.makegov.com/api/contracts/?recipient=ACME&ordering=-award_date&limit=5&page=2",
"previous": null,
"results": [
{
"key": "CONT_AWD_47QSWA24P0BWF_4732_-NONE-_-NONE-",
"piid": "47QSWA24P0BWF",
"recipient": {
"name": "ACME Corporation",
"uei": "ZMXAHH8M8VL8"
},
"award_date": "2024-01-15",
"obligated": 1500000.00,
"description": "IT Services Contract"
}
// ... more results
]
}
Step 6: Use Response Shaping to Customize Your Data¶
Response shaping lets you request only the specific fields you need, reducing data transfer and speeding up your application.
Basic Shaping Example¶
Instead of receiving all fields, request just what you need using the shape parameter:
curl -H "X-API-KEY: your-api-key-here" \
"https://tango.makegov.com/api/contracts/?shape=key,piid,award_date,recipient(display_name,uei)&limit=5"
This request returns only:
- Contract key
- PIID (contract identifier)
- Award date
- Recipient name and UEI (nested)
Why Use Response Shaping?¶
- Faster responses: Less data to transfer means quicker API calls
- Reduced bandwidth: Only get the fields you actually need
- Cleaner code: Shape the response to match your application's data model
- Flexible expansions: Include related data (offices, transactions, recipients) without separate API calls
Response Example¶
{
"count": 1250,
"results": [
{
"key": "CONT_AWD_47QSWA24P0BWF_4732_-NONE-_-NONE-",
"piid": "47QSWA24P0BWF",
"award_date": "2024-01-15",
"recipient": {
"display_name": "ACME Corporation",
"uei": "ZMXAHH8M8VL8"
}
}
]
}
Learn more about advanced features like flattening, aliasing, and multiple expansions in the Response Shaping Guide.
Common Issues¶
Rate Limit Exceeded¶
If you see a 429 Too Many Requests error, you've hit a rate limit. Check X-RateLimit-Remaining and X-RateLimit-Reset (seconds until reset), and follow the retry guidance in the Rate limits guide.
Authentication Error¶
If you get a 401 Unauthorized error, check that:
- Your API key is correct
- You're including the
X-API-KEYheader - Your API key is active
Invalid Request¶
If you get a 400 Bad Request error, check that:
- Your URL parameters are properly formatted
- Required parameters are included
- Date formats are YYYY-MM-DD
Authentication¶
The Tango API supports multiple authentication methods to suit different use cases and security requirements.
Authentication Methods¶
1. API Keys (Recommended)¶
API keys are the simplest and most secure method for server-to-server integration.
Getting an API Key¶
- Visit Tango Web Interface
- Sign up for an account or log in
- Navigate to your account profile
- Copy your API key (keep it secure!)
Using API Keys¶
Include your API key in the X-API-KEY header with every request:
import httpx
headers = {'X-API-KEY': 'your-api-key-here'}
response = httpx.get(
'https://tango.makegov.com/api/contracts/',
headers=headers
)
const response = await fetch('https://tango.makegov.com/api/contracts/', {
headers: {
'X-API-KEY': 'your-api-key-here'
}
});
2. OAuth2¶
OAuth2 is recommended for web applications and user-specific integrations.
OAuth2 Flow¶
- Register your application in the Tango web interface
- Get client credentials (client ID and secret)
- Implement OAuth2 flow in your application
- Use access tokens for API requests
Example OAuth2 Implementation¶
import requests
from requests_oauthlib import OAuth2Session
# OAuth2 configuration
client_id = 'your-client-id'
client_secret = 'your-client-secret'
authorization_base_url = 'https://tango.makegov.com/oauth2/authorize/'
token_url = 'https://tango.makegov.com/oauth2/token/'
# Create OAuth2 session
oauth = OAuth2Session(client_id)
# Get authorization URL
authorization_url, state = oauth.authorization_url(authorization_base_url)
# Redirect user to authorization_url
print(f"Please go to {authorization_url} and authorize access")
# After authorization, get the authorization response URL
authorization_response = input('Enter the full callback URL: ')
# Fetch the access token
token = oauth.fetch_token(
token_url,
authorization_response=authorization_response,
client_secret=client_secret
)
# Use the token for API requests
response = oauth.get('https://tango.makegov.com/api/contracts/')
OAuth2 Scopes¶
Available scopes for OAuth2 applications:
read- Read access to all data
Monitoring Usage¶
Response Headers¶
Check these headers to monitor your API usage:
Response headers:
Rate Limit Headers¶
X-RateLimit-Limit: Total requests allowed for the most restrictive windowX-RateLimit-Remaining: Requests remaining in the most restrictive windowX-RateLimit-Reset: Seconds until reset for the most restrictive windowX-Execution-Time: Request execution time
For the full list of per-window headers (daily/burst) and practical retry guidance, see the Rate limits guide.
Error Handling¶
Authentication Errors¶
401 Unauthorized¶
Causes:
- Missing API key
- Invalid API key
- Expired API key
- Inactive API key
Solutions:
- Check that you're including the
X-API-KEYheader - Verify your API key is correct
- Ensure your API key is active
- Generate a new API key if needed
403 Forbidden¶
{
"error": "InsufficientPermissions",
"message": "You don't have permission to access this resource",
"code": 403
}
Causes:
- Insufficient permissions for the requested resource
- Account type doesn't support the requested feature
Solutions:
- Check your account type and permissions
- Contact support to upgrade your account if needed
Rate Limit Errors¶
429 Too Many Requests¶
{
"detail": "Rate limit exceeded for burst. Please try again in 45 seconds.",
"wait_in_seconds": 45
}
Solutions:
- Wait for the rate limit window to reset
- Implement exponential backoff in your application
- Consider upgrading your account for higher limits
- Optimize your requests to reduce frequency
See the Rate limits guide for header semantics, examples (curl/Python/JS), and recommended client behavior.
Rate limits¶
Tango enforces rate limits to keep the API fast and reliable for everyone. Limits apply at the account level: requests made via API keys and OAuth2 tokens for the same account all draw from the same quotas.
Where to see your limits and usage¶
- Your current plan limits + near-real-time usage: Account profile
- Upgrade pricing / higher limits: Pricing
How rate limits work (burst + daily)¶
Most plans have more than one rate limit window:
- Burst: short window (e.g. per minute) that protects the API from sudden spikes
- Daily: long window (rolling 24-hour) that caps total volume
You may be “fine” on daily usage but still hit burst limits (or vice versa).
Rate limit headers¶
Every /api/* response includes rate limit headers.
Overall headers (most restrictive window)¶
These headers summarize the most restrictive window (the one you’re closest to hitting):
X-RateLimit-Limit: total requests allowed for that windowX-RateLimit-Remaining: requests remaining in that windowX-RateLimit-Reset: seconds until reset for that window
Per-window headers (daily, burst, etc.)¶
For each configured window (commonly Daily and Burst), you’ll also see:
X-RateLimit-Daily-Limit,X-RateLimit-Daily-Remaining,X-RateLimit-Daily-ResetX-RateLimit-Burst-Limit,X-RateLimit-Burst-Remaining,X-RateLimit-Burst-Reset
Each *-Reset value is seconds until that specific window resets.
Quick header check (curl)¶
curl -s -D - -o /dev/null \
-H "X-API-KEY: your-api-key-here" \
"https://tango.makegov.com/api/contracts/?limit=1"
Example response headers:
X-RateLimit-Daily-Limit: 2400
X-RateLimit-Daily-Remaining: 2350
X-RateLimit-Daily-Reset: 86400
X-RateLimit-Burst-Limit: 100
X-RateLimit-Burst-Remaining: 95
X-RateLimit-Burst-Reset: 45
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 45
X-Execution-Time: 0.045s
What happens when you exceed a limit (HTTP 429)¶
When you hit a rate limit, Tango responds with HTTP 429 and a JSON body like:
{
"detail": "Rate limit exceeded for burst. Please try again in 45 seconds.",
"wait_in_seconds": 45
}
Recommended client behavior¶
- Stop retrying immediately after a 429.
- Sleep for at least
wait_in_seconds(preferred) orX-RateLimit-Reset. - Then retry with exponential backoff + jitter to avoid a thundering herd.
Python example¶
import random
import time
import httpx
url = "https://tango.makegov.com/api/contracts/?limit=1"
headers = {"X-API-KEY": "your-api-key-here"}
backoff = 1.0
for _ in range(10):
r = httpx.get(url, headers=headers)
if r.status_code != 429:
r.raise_for_status()
break
body = r.json()
wait = body.get("wait_in_seconds")
if wait is not None:
time.sleep(float(wait))
continue
reset = r.headers.get("X-RateLimit-Reset")
if reset is not None:
time.sleep(float(reset))
continue
time.sleep(backoff + random.random())
backoff = min(backoff * 2, 60)
JavaScript example¶
This example assumes fetch is available (modern browsers or Node 18+).
(async () => {
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const url = "https://tango.makegov.com/api/contracts/?limit=1";
const headers = { "X-API-KEY": "your-api-key-here" };
let backoffMs = 1000;
for (let i = 0; i < 10; i++) {
const r = await fetch(url, { headers });
if (r.status !== 429) {
if (!r.ok) throw new Error(`HTTP ${r.status}`);
break;
}
const body = await r.json();
if (body.wait_in_seconds != null) {
await sleep(body.wait_in_seconds * 1000);
continue;
}
const reset = r.headers.get("X-RateLimit-Reset");
if (reset != null) {
await sleep(Number(reset) * 1000);
continue;
}
await sleep(backoffMs + Math.random() * 250);
backoffMs = Math.min(backoffMs * 2, 60_000);
}
})().catch((err) => {
console.error("Request failed:", err);
});
Reduce calls (and avoid limits) in practice¶
- Use response shaping (
shape=) to avoid extra “follow-up” requests. See the Response Shaping Guide. - Paginate responsibly; avoid re-fetching the same pages repeatedly.
- Cache hot lookups on your side when appropriate (e.g. “entity by UEI”).
- Prefer webhooks for event-driven updates instead of polling where possible.
Result counts¶
Every paginated response includes a count field with the total number of matching results. The X-Results-CountType response header indicates whether that count is exact or approximate.
Which endpoints use approximate counts?¶
Most endpoints always return exact counts. Only these high-volume endpoints use approximate counting by default:
/api/contracts//api/idvs//api/opportunities//api/notices/
All other endpoints (entities, agencies, offices, grants, forecasts, subawards, vehicles, etc.) always return exact counts. The ?exact=true parameter has no effect on these endpoints — they are already exact.
How approximate counts work¶
Approximate counts use PostgreSQL query planner estimates for large result sets and fall back to exact COUNT(*) for small ones (typically under 1,000 rows). This means even the endpoints listed above often return exact counts when the result set is small enough.
Requesting exact counts¶
For the endpoints that use approximate counting, add ?exact=true to force an exact count:
Performance note: Exact counts run a full COUNT(*) query, which can be slow on large, unfiltered result sets (e.g., all contracts). Use this when accuracy matters more than speed.
Knowing whether a count is exact¶
Check the X-Results-CountType response header:
This header is present on all paginated list responses. It is not included on detail (single-resource) endpoints.
Examples¶
Contracts (approximate by default)¶
Contracts with exact count¶
curl -sI -H "X-API-KEY: your-key" \
"https://tango.makegov.com/api/contracts/?exact=true" | grep X-Results
Entities (always exact)¶
Vehicles¶
Vehicles provide a solicitation-centric way to discover groups of related IDVs and then expand into the underlying awards.
What is a Vehicle?¶
In Tango, a Vehicle is a grouping of multiple IDVs that share the same solicitation_identifier and the same awarding-agency identifier derived from the IDV award key.
In federal data, each IDV award is a vehicle. In practice, people often think of a “vehicle” as the solicitation that produced many IDV awards (one per awardee). We model that higher-level grouping explicitly.
Vehicles are useful when you want to:
- Find “the contract vehicle” behind a set of IDVs (e.g., the solicitation that produced a schedule/IDIQ vehicle)
- Search across a vehicle’s underlying IDVs
- Pull a shaped list of the IDVs that make up a vehicle
Endpoints¶
- List:
GET /api/vehicles/ - Detail:
GET /api/vehicles/{uuid}/ - Task Orders:
GET /api/vehicles/{uuid}/orders/
Search¶
Vehicle-level search (list)¶
Use ?search= on the list endpoint to search vehicles:
Award-within-vehicle search (detail, when expanding awards)¶
On the detail endpoint, ?search= is used to filter expanded awardees (IDVs) when your shape includes awardees(...).
Ordering¶
The vehicles list endpoint supports ordering by activity metrics and statistics using the ?ordering= query parameter.
Available ordering fields¶
vehicle_obligations- Total obligations across all IDVs in the vehiclelatest_award_date- Most recent IDV award date in the vehicle
Ordering syntax¶
- Ascending:
?ordering=vehicle_obligations - Descending:
?ordering=-vehicle_obligations(prefix with-) - Multiple fields:
?ordering=-vehicle_obligations,-latest_award_date
Examples¶
Sort by total obligations (highest first):
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/?ordering=-vehicle_obligations&page=1"
Sort by most recent award activity:
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/?ordering=-latest_award_date&page=1"
Sort by obligations, then by latest award date:
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/?ordering=-vehicle_obligations,-latest_award_date&page=1"
Note: When no ?ordering= parameter is provided, vehicles are ordered by solicitation_identifier, agency_id, and uuid (default ordering).
Task Orders¶
The GET /api/vehicles/{uuid}/orders/ endpoint returns all task orders (contracts) issued against all IDVs within a vehicle. This endpoint supports pagination, response shaping, filtering, search, and transaction expansion, similar to the /api/contracts/ endpoint.
Basic usage¶
Filtering¶
Filter task orders using the same filters available on /api/contracts/:
# Filter by date range
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/<vehicle-uuid>/orders/?award_date_gte=2024-01-01&award_date_lte=2024-12-31"
# Filter by recipient
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/<vehicle-uuid>/orders/?recipient=ACME"
Response shaping¶
Use the shape parameter to customize fields and expand related objects:
# Include recipient and transaction details
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/<vehicle-uuid>/orders/?shape=key,piid,award_date,recipient(display_name,uei),transactions(description,action_date,modification_number)"
Search¶
Search task order descriptions:
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/<vehicle-uuid>/orders/?search=software"
Ordering¶
The orders endpoint supports ordering by contract fields using the ?ordering= parameter:
award_date- Contract award date (default: descending, newest first)obligated- Obligated amountpotential_total_value- Total contract valuerecipient_name- Recipient legal business name
Default ordering: When no ?ordering= parameter is provided, task orders are ordered by -award_date, -uuid (newest first).
Examples:
# Default ordering (newest first)
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/<vehicle-uuid>/orders/?page=1"
# Order by obligated amount (highest first)
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/<vehicle-uuid>/orders/?ordering=-obligated&page=1"
# Order by recipient name
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/<vehicle-uuid>/orders/?ordering=recipient_name&page=1"
The response includes vehicle context in the metadata (vehicle UUID and solicitation identifier).
Response shaping¶
Vehicles support the shape parameter, including the awardees(...) expansion.
Example: fetch a vehicle with a shaped list of its IDVs:
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/<vehicle-uuid>/?shape=uuid,solicitation_identifier,organization_id,awardee_count,order_count,vehicle_obligations,vehicle_contracts_value,awardees(key,uuid,piid,award_date,recipient(display_name,uei))"
Example: include opportunity-derived fields and expand the linked Opportunity:
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/<vehicle-uuid>/?shape=uuid,solicitation_identifier,solicitation_title,solicitation_date,naics_code,opportunity(opportunity_id,title,first_notice_date,office(office_name,agency_name))"
Example: expand JSON detail fields to select specific sub-fields:
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/<vehicle-uuid>/?shape=uuid,solicitation_identifier,competition_details(extent_competed,number_of_offers_received),type_of_idc,contract_type"
Example: filter expanded awards within a vehicle:
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/vehicles/<vehicle-uuid>/?shape=uuid,awardees(key,uuid,recipient(display_name))&search=acme"
See Response Shaping for full syntax and flattening options.
API Reference
API Reference¶
These pages are a curated reference for filtering, ordering, and pagination on Tango's highest-traffic endpoints, with copy/pasteable examples (including SDK usage).
Swagger is still the canonical surface-area reference, but these pages aim to be faster to use day-to-day.
- Swagger (OpenAPI): https://tango.makegov.com/api/
- For field definitions, see the Data Dictionary.
Awards¶
Definitive contracts, indefinite-delivery vehicles, other transactions, subawards, and solicitation-level groupings.
- Contracts — Definitive contract awards. Response shaping →
- IDVs — Indefinite delivery vehicles (GWACs, IDIQs, etc.). Response shaping →
- OTAs — Other Transaction Agreements from FPDS. Response shaping →
- OTIDVs — Other Transaction IDVs from FPDS. Response shaping →
- Subawards — Sub-contracts and sub-grants under prime awards. Response shaping →
- Vehicles — Solicitation-centric grouping of IDVs. Response shaping →
- GSA eLibrary contracts — Persisted GSA eLibrary contract metadata (direct endpoint).
Entities¶
- Entities — Vendors and recipients in federal contracting and assistance; UEI is the canonical identifier (from SAM.gov). Response shaping →
Forecasts¶
- Forecasts — Upcoming procurement opportunities from agency feeds (e.g., HHS, DHS) before they appear as SAM.gov solicitations. Response shaping →
Grants¶
- Grants — Grant opportunities from Grants.gov (funding opportunities, not assistance transactions). Response shaping →
Opportunities¶
SAM.gov contract opportunity and notice data.
- Opportunities — Contract opportunities aggregated by parent. Response shaping →
- Notices — Individual SAM.gov notice records (amendments, updates) under an opportunity. Response shaping →
Metrics¶
- Metrics — Time-series obligation and award-count metrics for entities, NAICS codes, and PSC codes (same URL pattern and query params for all).
Reference data¶
Lookup tables and codes used across awards and entities.
- Assistance listings (CFDA) — CFDA program numbers and titles for federal grants/assistance. Response shaping →
- Business types — SAM.gov business type codes (e.g., small business, 8(a), HUBZone). Response shaping →
- MAS SINs — MAS Special Item Numbers (SINs) reference data. Response shaping →
- NAICS — North American Industry Classification System codes. Response shaping →
- Organizations — Unified federal hierarchy (departments, agencies, offices in one tree with search and obligations). Response shaping →
- PSC — Product/Service Codes for federal contracting. Response shaping →
Shared¶
Objects and legacy endpoints shared across multiple resources. These data structures appear in response shaping expands on many endpoints (e.g., awarding_office(...), department(...), set_aside(...)).
- Shared response objects — Common expanded objects (set-aside, office) returned across endpoints.
- Agencies (deprecated) — Federal agencies (legacy endpoint; use Organizations instead). Response shaping →
- Departments (deprecated) — Top-level federal departments (legacy endpoint; use Organizations instead). Response shaping →
- Offices (deprecated) — Sub-agency offices (legacy endpoint; use Organizations instead). Response shaping →
- Set-aside codes — Set-aside type codes and descriptions.
Awards
Contracts¶
Contracts are awards (FPDS “definitive contracts”) exposed at /api/contracts/. For field definitions, see the Contracts Data Dictionary.
Endpoints¶
GET /api/contracts/(list + filtering + search + ordering)GET /api/contracts/{key}/(detail)GET /api/contracts/{key}/transactions/(detail transactions)GET /api/contracts/{key}/subawards/(subawards scoped to a contract)
Related “scoped” list endpoints that behave like /api/contracts/:
GET /api/entities/{uei}/contracts/GET /api/idvs/{key}/awards/(child awards under an IDV)GET /api/vehicles/{uuid}/orders/(task orders under a vehicle)
Filtering¶
Swagger is the canonical list of query parameters. These are the core filters most people use day-to-day.
Text / parties¶
| Param | What it does |
|---|---|
search |
Full-text-ish search across contract search vectors (good for keywords). |
recipient |
Search by recipient/vendor name. |
uei |
Filter by recipient UEI (exact). |
piid |
Filter by PIID (case-insensitive). |
solicitation_identifier |
Filter by solicitation identifier (exact). |
Agencies¶
| Param | What it does |
|---|---|
awarding_agency |
Filter by awarding agency (code/name/abbrev; best-effort matching). Implemented via organization UUID for performance; response awarding_office shape unchanged. |
funding_agency |
Filter by funding agency (code/name/abbrev; best-effort matching). Implemented via organization UUID for performance; response funding_office shape unchanged. |
Codes / set-asides¶
| Param | What it does |
|---|---|
naics |
Filter by NAICS. |
psc |
Filter by PSC. |
set_aside |
Filter by set-aside. |
Dates / fiscal years¶
All date filters require YYYY-MM-DD format. Invalid dates or inverted ranges return 400. See Date filters for details.
| Param | What it does |
|---|---|
award_date |
Award date (exact). |
award_date_gte, award_date_lte |
Award date range. |
fiscal_year |
Fiscal year (exact, YYYY). |
fiscal_year_gte, fiscal_year_lte |
Fiscal year range (YYYY). |
Period of performance¶
| Param | What it does |
|---|---|
pop_start_date_gte, pop_start_date_lte |
Period of performance start date range. |
pop_end_date_gte, pop_end_date_lte |
Period of performance current end date range. |
expiring_gte, expiring_lte |
Ultimate completion date range (useful for “expiring soon”). |
Dollars / types¶
| Param | What it does |
|---|---|
obligated |
Filter by obligated amount (exact USD value). |
obligated_gte, obligated_lte |
Obligated amount range (USD). |
award_type |
Award type code. |
ordering |
Sort results (allowlist: award_date, obligated, total_contract_value; prefix with - for descending). |
Filter value syntax (AND / OR)¶
Some filters support basic boolean syntax:
- Use
|orORfor OR - Use
,orANDfor AND
Example: naics=541511|541512
Ordering¶
Contracts support ordering= with a strict allowlist:
award_dateobligatedtotal_contract_value
Examples:
- Newest first:
GET /api/contracts/?ordering=-award_date - Largest obligations first:
GET /api/contracts/?ordering=-obligated
Pagination¶
High-volume award endpoints use cursor-based (keyset) pagination.
- Use
limitto control page size. - Follow the
next/previousURLs in responses. - If you’re constructing requests manually, you’ll typically pass a
cursorparameter from thenextURL.
SDK examples¶
Search + ordering + shaping¶
import os
from tango import ShapeConfig, TangoClient
client = TangoClient(api_key=os.environ["TANGO_API_KEY"])
resp = client.list_contracts(
keyword="cloud services", # SDK maps to API param: search
awarding_agency="4700", # GSA
fiscal_year=2024,
sort="award_date", # SDK maps (sort+order) -> API ordering
order="desc",
limit=10,
shape=ShapeConfig.CONTRACTS_MINIMAL,
)
for c in resp.results:
print(c.piid, c.award_date, c.recipient.display_name)
import { ShapeConfig, TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
const resp = await client.listContracts({
keyword: "cloud services", // SDK maps to API param: search
awarding_agency: "4700", // GSA
fiscal_year: 2024,
sort: "award_date", // SDK maps (sort+order) -> API ordering
order: "desc",
limit: 10,
shape: ShapeConfig.CONTRACTS_MINIMAL,
});
for (const c of resp.results) {
console.log(c.piid, c.award_date, c.recipient.display_name);
}
Cursor pagination (using the next URL)¶
import os
from urllib.parse import parse_qs, urlparse
from tango import TangoClient
client = TangoClient(api_key=os.environ["TANGO_API_KEY"])
resp = client.list_contracts(limit=25, sort="award_date", order="desc")
print("next:", resp.next)
if resp.next:
qs = parse_qs(urlparse(resp.next).query)
cursor = (qs.get("cursor") or [None])[0]
if cursor:
resp2 = client.list_contracts(limit=25, cursor=cursor, sort="award_date", order="desc")
print("page 2 results:", len(resp2.results))
import { TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
const resp = await client.listContracts({ limit: 25, sort: "award_date", order: "desc" });
console.log("next:", resp.next);
if (resp.next) {
const url = new URL(resp.next);
const cursor = url.searchParams.get("cursor");
if (cursor) {
const resp2 = await client.listContracts({ limit: 25, cursor, sort: "award_date", order: "desc" });
console.log("page 2 results:", resp2.results.length);
}
}
IDVs¶
IDVs (Indefinite Delivery Vehicles) are awards exposed at /api/idvs/.
If you’re trying to work at the “solicitation that produced many IDV awards” level, also see Vehicles. For field definitions, see the IDVs Data Dictionary.
IDV responses include a vehicle UUID when the IDV is grouped under a Tango Vehicle, which you can use to fetch vehicle details at GET /api/vehicles/{uuid}/.
Endpoints¶
GET /api/idvs/(list + filtering + search + ordering)GET /api/idvs/{key}/(detail)GET /api/idvs/{key}/transactions/(detail transactions)GET /api/idvs/{key}/awards/(child awards / task orders under an IDV; behaves like/api/contracts/)GET /api/idvs/{key}/idvs/(child IDVs under an IDV; behaves like/api/idvs/)
Deprecated (legacy solicitation grouping):
GET /api/idvs/{identifier}/summary/GET /api/idvs/{identifier}/summary/awards/
Filtering¶
Swagger is the canonical list of query parameters. These are the core filters most people use day-to-day.
Text / parties¶
| Param | What it does |
|---|---|
search |
Full-text-ish search across IDV search vectors (good for keywords). |
recipient |
Search by recipient/vendor name. |
uei |
Filter by recipient UEI (exact). |
piid |
Filter by PIID (case-insensitive). |
solicitation_identifier |
Filter by solicitation identifier (exact). |
obligated |
Filter by obligated amount (exact USD value). |
ordering |
Sort results (allowlist: award_date, obligated, total_contract_value; prefix with - for descending). |
Agencies¶
| Param | What it does |
|---|---|
awarding_agency |
Filter by awarding agency (code/name/abbrev; best-effort matching). |
funding_agency |
Filter by funding agency (code/name/abbrev; best-effort matching). |
Codes / set-asides / types¶
| Param | What it does |
|---|---|
naics |
Filter by NAICS. |
psc |
Filter by PSC. |
set_aside |
Filter by set-aside. |
idv_type |
Filter by IDV type code. |
Dates / fiscal years¶
All date filters require YYYY-MM-DD format. Invalid dates or inverted ranges return 400. See Date filters for details.
| Param | What it does |
|---|---|
award_date |
Award date (exact). |
award_date_gte, award_date_lte |
Award date range. |
fiscal_year |
Fiscal year (exact, YYYY). |
fiscal_year_gte, fiscal_year_lte |
Fiscal year range (YYYY). |
Period of performance / ordering window¶
IDVs differ from contracts:
- They do not have contract-style period-of-performance end dates.
- The ordering window is typically expressed via last-date-to-order fields.
| Param | What it does |
|---|---|
pop_start_date_gte, pop_start_date_lte |
Period of performance start date range. |
last_date_to_order_gte, last_date_to_order_lte |
Last date to order range (primary IDV “expiring” concept). |
expiring_gte, expiring_lte |
Alias for last-date-to-order range filters. |
Filter value syntax (AND / OR)¶
Some filters support basic boolean syntax:
- Use
|orORfor OR - Use
,orANDfor AND
Example: naics=541511|541512
Ordering¶
IDVs support ordering= with a strict allowlist:
award_dateobligatedtotal_contract_value
You can also filter exact obligations with obligated.
Examples:
- Newest first:
GET /api/idvs/?ordering=-award_date - Largest obligations first:
GET /api/idvs/?ordering=-obligated
Pagination¶
High-volume award endpoints use cursor-based (keyset) pagination.
- Use
limitto control page size. - Follow the
next/previousURLs in responses. - If you’re constructing requests manually, you’ll typically pass a
cursorparameter from thenextURL.
Response shaping¶
IDV responses use the shaping pipeline by default — even without an explicit ?shape= parameter, responses go through the shaping system with a default shape that includes all standard fields plus expanded choice fields (idv_type(*), type_of_idc(*), multiple_or_single_award_idv(*)), relationships, and period of performance.
Use ?shape= to customize the response. See Response Shaping for the full field reference.
# Expand idv_type to structured code/description
/api/idvs/?shape=key,piid,idv_type(code,description)
# Period of performance (uses last_date_to_order, not end_date)
/api/idvs/?shape=key,piid,period_of_performance(start_date,last_date_to_order)
# Resolved NAICS/PSC lookups
/api/idvs/?shape=key,piid,naics(code,description),psc(code,description)
GSA eLibrary enrichment¶
IDV list and detail responses include best-effort enrichment from GSA eLibrary under gsa_elibrary (or null when no matching eLibrary row exists).
You can use shaping to request only the subfields you care about:
You can also query persisted eLibrary rows directly via GET /api/gsa_elibrary_contracts/.
SDK examples¶
The official SDKs don’t yet expose a first-class list_idvs() / listIdvs() method.
Until they do, you can still call the endpoint via the SDK’s internal HTTP helper.
import os
from tango import TangoClient
client = TangoClient(api_key=os.environ["TANGO_API_KEY"])
# Workaround until the SDK ships a first-class list_idvs()
data = client._get(
"/api/idvs/",
params={
"search": "SEWP",
"ordering": "-award_date",
"limit": 10,
},
)
print("count:", data.get("count"))
print("first key:", (data.get("results") or [{}])[0].get("key"))
import { TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
// Workaround until the SDK ships a first-class listIdvs()
const http = (client as any).http;
const data = await http.get("/api/idvs/", {
search: "SEWP",
ordering: "-award_date",
limit: 10,
});
console.log("count:", data.count);
console.log("first key:", data?.results?.[0]?.key);
OTAs¶
OTAs (Other Transaction Awards) are awards exposed at /api/otas/. For field definitions, see the OTAs Data Dictionary.
Endpoints¶
GET /api/otas/(list + filtering + search + ordering)GET /api/otas/{key}/(detail)
Entity-scoped list:
GET /api/entities/{uei}/otas/(behaves like/api/otas/scoped to an entity)
Filtering¶
OTAs share most of the "award" filtering surface with contracts/IDVs, except they do not support some contracts-specific filters (like NAICS).
Common filters you can use:
| Param | What it does |
|---|---|
search |
Full-text-ish search over award search vectors. |
recipient |
Search by recipient/vendor name. |
uei |
Filter by recipient UEI (exact). |
piid |
Filter by PIID (case-insensitive). |
awarding_agency, funding_agency |
Filter by awarding/funding agency (best-effort matching). |
psc |
Filter by PSC. |
award_date, award_date_gte, award_date_lte |
Award date filters. |
fiscal_year, fiscal_year_gte, fiscal_year_lte |
Fiscal year filters. |
pop_start_date_gte, pop_start_date_lte |
Period of performance start date range (when present). |
pop_end_date_gte, pop_end_date_lte |
Period of performance end date range (when present). |
expiring_gte, expiring_lte |
Expiration window range filters. |
obligated |
Filter by obligated amount (exact USD value). |
ordering |
Sort results (allowlist: award_date, obligated, total_contract_value; prefix with - for descending). |
Ordering¶
OTAs support ordering= with a strict allowlist:
award_dateobligatedtotal_contract_value
Examples:
- Newest first:
GET /api/otas/?ordering=-award_date - Largest obligations first:
GET /api/otas/?ordering=-obligated
Pagination¶
High-volume award endpoints use cursor-based (keyset) pagination:
limitcursor(follownext/previousURLs)
Response Shaping¶
OTA endpoints support the ?shape= parameter for customizing response fields. See Response Shaping for full syntax.
Shapeable fields¶
| Field | Type | Notes |
|---|---|---|
key |
scalar | Award key |
piid |
scalar | |
award_date |
scalar | |
award_type |
scalar or expand | Expandable to {code, description} (OTA-specific: "O" = Other Transaction Non-Research, "R" = Other Transaction for Research) |
fiscal_year |
scalar | |
obligated |
scalar | |
total_contract_value |
scalar | |
description |
scalar | |
base_and_exercised_options_value |
scalar | |
psc_code |
scalar | |
consortia |
scalar | |
consortia_uei |
scalar | |
dod_acquisition_program |
scalar | |
non_governmental_dollars |
scalar | |
non_traditional_government_contractor_participation |
scalar | |
parent_award_modification_number |
scalar | |
type_of_ot_agreement |
scalar or expand | Expandable to {code, description} |
extent_competed |
scalar or expand | Expandable to {code, description} |
transactions |
scalar | Raw snapshot list |
Expandable fields¶
| Expand | Fields |
|---|---|
recipient(*) |
uei, display_name, legal_business_name, cage, duns |
place_of_performance(*) |
country_code, country_name, state_code, state_name, city_name, zip_code |
awarding_office(*) |
office_code, office_name, agency_code, agency_name, department_code, department_name |
funding_office(*) |
same as awarding_office |
parent_award(key,piid) |
key, piid |
period_of_performance(*) |
start_date, current_end_date, ultimate_completion_date |
transactions(*) |
modification_number, transaction_date, obligated, description, action_type |
psc(*) |
code, description |
award_type(*) |
code, description (OTA-specific choices) |
type_of_ot_agreement(*) |
code, description |
extent_competed(*) |
code, description |
Examples¶
Request only key fields:
Expand recipient and extent competed with description:
Expand type of OT agreement:
SDK examples¶
The official SDKs don't yet expose a first-class list_otas() / listOTAs() method.
You can still call the endpoint via the SDK's internal HTTP helper.
OTIDVs¶
OTIDVs (Other Transaction IDVs) are awards exposed at /api/otidvs/. For field definitions, see the OTIDVs Data Dictionary.
Endpoints¶
GET /api/otidvs/(list + filtering + search + ordering)GET /api/otidvs/{key}/(detail)GET /api/otidvs/{key}/awards/(child OTAs under an OTIDV; behaves like/api/otas/scoped to the OTIDV)
Entity-scoped list:
GET /api/entities/{uei}/otidvs/(behaves like/api/otidvs/scoped to an entity)
Filtering¶
OTIDVs share most of the "award" filtering surface with contracts/IDVs, except they do not support some contracts-specific filters (like NAICS).
Common filters you can use:
| Param | What it does |
|---|---|
search |
Full-text-ish search over award search vectors. |
recipient |
Search by recipient/vendor name. |
uei |
Filter by recipient UEI (exact). |
piid |
Filter by PIID (case-insensitive). |
awarding_agency, funding_agency |
Filter by awarding/funding agency (best-effort matching). |
psc |
Filter by PSC. |
award_date, award_date_gte, award_date_lte |
Award date filters. |
fiscal_year, fiscal_year_gte, fiscal_year_lte |
Fiscal year filters. |
pop_start_date_gte, pop_start_date_lte |
Period of performance start date range (when present). |
pop_end_date_gte, pop_end_date_lte |
Period of performance end date range (when present). |
expiring_gte, expiring_lte |
Expiration window range filters. |
obligated |
Filter by obligated amount (exact USD value). |
ordering |
Sort results (allowlist: award_date, obligated, total_contract_value; prefix with - for descending). |
Ordering¶
OTIDVs support ordering= with a strict allowlist:
award_dateobligatedtotal_contract_value
Examples:
- Newest first:
GET /api/otidvs/?ordering=-award_date - Largest obligations first:
GET /api/otidvs/?ordering=-obligated
Pagination¶
High-volume award endpoints use cursor-based (keyset) pagination:
limitcursor(follownext/previousURLs)
Response Shaping¶
OTIDV endpoints support the ?shape= parameter for customizing response fields. See Response Shaping for full syntax.
Shapeable fields¶
| Field | Type | Notes |
|---|---|---|
key |
scalar | Award key |
piid |
scalar | |
award_date |
scalar | |
idv_type |
scalar | Raw code |
fiscal_year |
scalar | |
obligated |
scalar | |
total_contract_value |
scalar | |
description |
scalar | |
base_and_exercised_options_value |
scalar | |
psc_code |
scalar | |
consortia |
scalar | |
consortia_uei |
scalar | |
dod_acquisition_program |
scalar | |
non_governmental_dollars |
scalar | |
non_traditional_government_contractor_participation |
scalar | |
type_of_ot_agreement |
scalar or expand | Expandable to {code, description} |
extent_competed |
scalar or expand | Expandable to {code, description} |
transactions |
scalar | Raw snapshot list |
Expandable fields¶
| Expand | Fields |
|---|---|
recipient(*) |
uei, display_name, legal_business_name, cage, duns |
place_of_performance(*) |
country_code, country_name, state_code, state_name, city_name, zip_code |
awarding_office(*) |
office_code, office_name, agency_code, agency_name, department_code, department_name |
funding_office(*) |
same as awarding_office |
period_of_performance(*) |
start_date, current_end_date, ultimate_completion_date |
transactions(*) |
modification_number, transaction_date, obligated, description, action_type |
psc(*) |
code, description |
type_of_ot_agreement(*) |
code, description |
extent_competed(*) |
code, description |
Examples¶
Request only key fields:
Expand recipient and extent competed with description:
Expand type of OT agreement:
SDK examples¶
The official SDKs don't yet expose a first-class list_otidvs() / listOTIDVs() method.
You can still call the endpoint via the SDK's internal HTTP helper.
Subawards¶
Subawards (FSRS/USAspending subawards) are exposed at /api/subawards/. For field definitions, see the Subawards Data Dictionary.
Endpoints¶
GET /api/subawards/(list + filtering + ordering)GET /api/subawards/{key}/(detail)
Scoped lists:
GET /api/contracts/{key}/subawards/(subawards under a contract)GET /api/entities/{uei}/subawards/(subawards for an entity)
Default response¶
All subaward responses use the shaping pipeline by default. No ?shape= parameter is required to get a shaped response.
Default fields (equivalent to requesting):
award_key,awarding_office(*),fsrs_details(*),funding_office(*),key,piid,
place_of_performance(*),prime_recipient(uei,display_name),
subaward_details(*),subaward_recipient(uei,display_name)
Shaping¶
Use ?shape= to request a custom field set. Subawards support the following leaves and expansions.
Leaves¶
Identity and prime award scalar fields:
| Field | Description |
|---|---|
key |
Subaward primary key |
award_key |
Prime award identifier |
piid |
Prime award PIID (mapped from prime_award_piid) |
prime_award_amount |
Total prime award amount |
prime_award_total_outlayed_amount |
Prime award total outlayed amount |
prime_award_base_action_date |
Prime award base action date |
prime_award_base_action_date_fiscal_year |
Fiscal year of base action date |
prime_award_latest_action_date |
Prime award latest action date |
prime_award_latest_action_date_fiscal_year |
Fiscal year of latest action date |
prime_award_base_transaction_description |
Prime award description |
prime_award_project_title |
Prime award project title |
prime_award_naics_code |
NAICS code |
prime_award_naics_description |
NAICS description |
prime_awardee_uei |
Prime awardee UEI |
prime_awardee_name |
Prime awardee name |
prime_awardee_parent_uei |
Prime awardee parent UEI |
prime_awardee_parent_name |
Prime awardee parent name |
subawardee_uei |
Subawardee UEI |
subawardee_duns |
Subawardee DUNS |
subawardee_name |
Subawardee name |
subawardee_dba_name |
Subawardee DBA name |
subawardee_parent_uei |
Subawardee parent UEI |
subawardee_parent_duns |
Subawardee parent DUNS |
subawardee_parent_name |
Subawardee parent name |
subawardee_business_types |
Subawardee business types |
usaspending_permalink |
USASpending.gov link |
Expansions¶
| Expansion | Fields |
|---|---|
subaward_details(*) |
description, type, number, amount, action_date, fiscal_year |
fsrs_details(*) |
last_modified_date, id, year, month |
place_of_performance(*) |
city, state, zip, country_code |
highly_compensated_officers(*) |
name, amount — list of up to 5 officers |
prime_recipient(uei,display_name) |
Prime awardee identity, resolved from the Entities table when available (falling back to denormalized subaward fields when no match exists) |
subaward_recipient(uei,display_name,duns) |
Subawardee identity, resolved from the Entities table when available (falling back to denormalized subaward fields when no match exists) |
awarding_office(*) |
office_code, office_name, agency_code, agency_name, department_code, department_name |
funding_office(*) |
Same fields as awarding_office |
Examples¶
# Default response (no shape needed)
/api/subawards/
# Minimal fields
/api/subawards/?shape=key,piid,award_key
# Subaward details with recipient info
/api/subawards/?shape=key,piid,subaward_details(*),subaward_recipient(uei,display_name)
# Office hierarchy for awarding office
/api/subawards/?shape=key,awarding_office(office_code,office_name,agency_name)
# All offices
/api/subawards/?shape=key,awarding_office(*),funding_office(*)
# Place of performance
/api/subawards/?shape=key,place_of_performance(city,state,country_code)
# FSRS report details
/api/subawards/?shape=key,fsrs_details(id,year,month,last_modified_date)
# Highly compensated officers
/api/subawards/?shape=key,highly_compensated_officers(name,amount)
# Discover available fields
/api/subawards/?show_shapes=true
Filtering¶
Core filters:
| Param | What it does |
|---|---|
award_key |
Filter by prime award key (exact). |
prime_uei |
Filter by prime awardee UEI (exact). |
sub_uei |
Filter by subawardee UEI (exact). |
recipient |
Search by recipient name (best-effort mapping to UEIs). |
awarding_agency |
Filter by prime awarding agency code (exact). |
funding_agency |
Filter by prime funding agency code (exact). |
fiscal_year |
Filter by subaward action-date fiscal year (exact). |
fiscal_year_gte, fiscal_year_lte |
Fiscal year range. |
Ordering¶
Subawards support ordering= with a strict allowlist:
last_modified_date
Examples:
- Most recently modified first:
GET /api/subawards/?ordering=-last_modified_date
Pagination¶
Subawards use standard page-number pagination:
page(default 1)limit(max 100)
SDK examples¶
The official SDKs don't yet expose a first-class list_subawards() / listSubawards() method.
You can still call the endpoint via the SDK's internal HTTP helper.
import { TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
const http = (client as any).http;
const data = await http.get("/api/subawards/", {
recipient: "deloitte",
ordering: "-last_modified_date",
limit: 10,
});
console.log("count:", data.count);
Vehicles¶
Vehicles are a solicitation-centric grouping of multiple IDVs (the “thing people usually mean” when they say “this vehicle”), exposed at /api/vehicles/.
If you want the conceptual model first, start with Getting Started – Vehicles. For field definitions, see the Vehicles Data Dictionary.
Endpoints¶
GET /api/vehicles/(list + search + ordering)GET /api/vehicles/{uuid}/(detail; supports shaping)GET /api/vehicles/{uuid}/awardees/(the underlying IDVs; supports shaping)GET /api/vehicles/{uuid}/orders/(task orders / contracts under all IDVs in the vehicle; behaves like/api/contracts/)
Filtering / search¶
Vehicle list search¶
| Param | What it does |
|---|---|
search |
Full-text-ish vehicle search (solicitation + aggregated award terms). |
Vehicle detail “awardees” filtering¶
On GET /api/vehicles/{uuid}/, search is not vehicle search. It’s reserved for filtering the expanded awardees when your shape includes awardees(...).
Example:
GET /api/vehicles/{uuid}/?shape=uuid,solicitation_identifier,awardees(key,piid,recipient(display_name,uei))&search=deloitte
Response shaping / flattening¶
Vehicle responses use the shaping pipeline by default — even without an explicit ?shape= parameter, responses go through the shaping system with a default shape. See Response Shaping for the full field reference and default shapes.
Vehicles support:
shape=...(see Response Shaping)flat=true|falseflat_lists=true|falsejoiner=.(only relevant whenflat=true)
Ordering¶
Vehicles support ordering= with a strict allowlist:
vehicle_obligationslatest_award_date
Examples:
- Most obligations first:
GET /api/vehicles/?ordering=-vehicle_obligations - Most recently-active first:
GET /api/vehicles/?ordering=-latest_award_date
Pagination¶
Vehicle lists use standard page-number pagination:
page(default 1)limit(max 100)
Vehicle awardees (IDVs) are returned as a list endpoint and are paginated as well (see Swagger for details).
Vehicle orders (/api/vehicles/{uuid}/orders/) behave like contracts:
- cursor-based (keyset) pagination via
limit+cursor - ordering allowlist: award date, obligated, total contract value
SDK examples¶
The official SDKs don’t yet expose a first-class list_vehicles() / listVehicles() method.
Until they do, you can still call the endpoint via the SDK’s internal HTTP helper.
List vehicles (search + ordering)¶
import os
from tango import TangoClient
client = TangoClient(api_key=os.environ["TANGO_API_KEY"])
# Workaround until the SDK ships a first-class list_vehicles()
data = client._get(
"/api/vehicles/",
params={
"search": "SEWP",
"ordering": "-vehicle_obligations",
"page": 1,
"limit": 10,
},
)
print("count:", data.get("count"))
print("first uuid:", (data.get("results") or [{}])[0].get("uuid"))
import { TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
// Workaround until the SDK ships a first-class listVehicles()
const http = (client as any).http;
const data = await http.get("/api/vehicles/", {
search: "SEWP",
ordering: "-vehicle_obligations",
page: 1,
limit: 10,
});
console.log("count:", data.count);
console.log("first uuid:", data?.results?.[0]?.uuid);
Vehicle detail with awardees expansion + filtering¶
import os
from tango import TangoClient
client = TangoClient(api_key=os.environ["TANGO_API_KEY"])
vehicle_uuid = "00000000-0000-0000-0000-000000000000" # replace
data = client._get(
f"/api/vehicles/{vehicle_uuid}/",
params={
"shape": "uuid,solicitation_identifier,awardees(key,piid,recipient(display_name,uei))",
"search": "deloitte", # filters expanded awardees
},
)
print(data["uuid"], data.get("solicitation_identifier"))
import { TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
const vehicleUuid = "00000000-0000-0000-0000-000000000000"; // replace
const http = (client as any).http;
const data = await http.get(`/api/vehicles/${vehicleUuid}/`, {
shape: "uuid,solicitation_identifier,awardees(key,piid,recipient(display_name,uei))",
search: "deloitte", // filters expanded awardees
});
console.log(data.uuid, data.solicitation_identifier);
GSA eLibrary contracts¶
Persisted GSA eLibrary contract metadata is exposed directly at /api/gsa_elibrary_contracts/.
For field definitions, see the GSA eLibrary Contracts Data Dictionary.
These endpoints exist in addition to the gsa_elibrary enrichment on /api/idvs/.
Endpoints¶
GET /api/gsa_elibrary_contracts/(list + filtering + ordering)GET /api/gsa_elibrary_contracts/{uuid}/(detail)
Response shape (non-shaped)¶
Each result includes:
uuid,schedule,contract_numbersins,cooperative_purchasing,disaster_recovery_purchasing,file_urlsrecipient(cached lookup by UEI; fields:uei,display_name)idv(best-effort; fields:key,award_date)
Filtering¶
Core filters:
| Param | What it does |
|---|---|
schedule |
Filter by schedule (exact). Example: MAS |
contract_number |
Filter by contract number (exact, case-insensitive). Example: GS-07F-0251W |
uei |
Filter by recipient UEI (from eLibrary provenance; exact). Supports \| (OR) and , (AND). |
sin |
Filter by SIN code (exact). Supports \| (OR) and , (AND). |
search |
Search across schedule, contract_number, UEI, SIN, and linked IDV fields. Supports \| (OR) and , (AND). |
key |
Filter by linked IDV key (exact, case-insensitive). |
piid |
Filter by linked IDV PIID (exact, case-insensitive). |
Ordering¶
Supports ordering= with:
last_updatedschedulecontract_number
Example:
Pagination¶
Uses page-number pagination.
Response shaping¶
Like other endpoints, shaping is available via shape=:
CALC Labor Category Rates¶
CALC (Contract Awarded Labor Category) labor rates are exposed as nested endpoints under IDVs and entities. For field definitions, see the CALC Labor Rates Data Dictionary.
Access: Requires Pro tier or above.
Endpoints¶
GET /api/idvs/{key}/lcats/(rates for a specific IDV)GET /api/entities/{uei}/lcats/(rates for a specific entity, via IDV recipient linkage)
These are nested endpoints -- there is no top-level /api/lcats/ route. Use the IDV key or entity UEI to scope the results.
Filtering¶
Core filters:
| Param | What it does |
|---|---|
search |
Full-text search across vendor name, labor category, category, and subcategory. |
vendor_name |
Case-insensitive partial match on vendor name. |
labor_category |
Case-insensitive partial match on labor category title. |
price_gte, price_lte |
Filter by current price range (decimal). |
education_level |
Exact match on education level (case-insensitive). |
min_years_experience_gte, min_years_experience_lte |
Filter by minimum years of experience range. |
security_clearance |
Exact match on security clearance requirement (case-insensitive). |
worksite |
Exact match on work location type (case-insensitive). |
business_size |
Exact match on business size code (case-insensitive). |
sin |
Exact match on Special Item Number (case-insensitive). |
category |
Case-insensitive partial match on service category. |
idv_piid |
Exact match on the stored PIID from CALC. |
key |
IDV key (case-insensitive). |
piid |
IDV PIID (case-insensitive). |
Ordering¶
CALC labor rates support ordering= with a strict allowlist:
current_pricevendor_namelabor_categoryeducation_levelmin_years_experiencemodified
Prefix with - for descending order.
Examples:
- Cheapest first:
GET /api/idvs/{key}/lcats/?ordering=current_price - Most experienced first:
GET /api/idvs/{key}/lcats/?ordering=-min_years_experience
Pagination¶
Uses page-number pagination:
page(default 1)page_size(default 10, max 100)
Response shaping¶
Use ?shape= to customize the response. Root fields:
uuid,labor_category,current_priceeducation_level,min_years_experience,experience_rangesecurity_clearance,worksitesin,category,subcategory,schedulecontract_start,contract_end
Expansions:
idv(key, piid, award_date)-- linked IDV details (Pro tier required)recipient(uei, display_name)-- entity details via IDV recipient (Pro tier required)business_size(code, description)-- business size with human-readable description
A default shape is applied when no ?shape= parameter is provided, so ?flat=true works without needing an explicit shape.
Example:
Flat example:
Rate limiting¶
These endpoints have separate premium query rate limits. See your account dashboard for current limits.
Entities¶
Entities are vendors/recipients exposed at /api/entities/ (UEI is canonical). For field definitions, see the Entities Data Dictionary.
Endpoints¶
GET /api/entities/(list + filtering + search)GET /api/entities/{uei}/(detail; UEI lookup is case-insensitive)
Related “scoped” list endpoints (awards for an entity):
GET /api/entities/{uei}/contracts/GET /api/entities/{uei}/idvs/GET /api/entities/{uei}/otas/GET /api/entities/{uei}/otidvs/GET /api/entities/{uei}/subawards/
Metrics: Time-series obligation/award metrics for an entity: GET /api/entities/{uei}/metrics/<months>/<period_grouping>/. See Metrics for parameters and behavior.
Response Shaping¶
Entities default to the shaping pipeline — all responses go through shaping even without ?shape=. Use ?shape= to customize which fields are returned.
- List default:
uei,legal_business_name,dba_name,entity_url,cage_code,business_types(*),sba_business_types(*),primary_naics,physical_address(*),purpose_of_registration(*),relationships(*) - Detail default: All list fields plus
display_name,uuid,dodaac,description,email_address,capabilities,congressional_district,keywords,registered,registration_status,federal_obligations(*),naics_codes(*),psc_codes,highest_owner(*),immediate_owner(*),mailing_address(*), all date fields, and structured code/description expands:entity_structure(*),entity_type(*),profit_structure(*),organization_structure(*),state_of_incorporation(*),country_of_incorporation(*). - On-demand expand:
past_performance(*)— aggregated contract history withsummaryandtop_agencies. Accepts[top=N]bracket param (default 5, max 100). Example:?shape=uei,past_performance[top=10](*).
Complex fields are normalized by the shaping pipeline: address keys are always snake_case, business_types and sba_business_types are always [{code, description, ...}] arrays, naics_codes are always [{code, sba_small_business}] objects, and code/description pairs (entity_structure, purpose_of_registration, etc.) are always {code, description} objects with map-based description fallback.
See Response Shaping for full syntax and the Entities Data Dictionary for field definitions.
Filtering¶
Swagger is the canonical list of query parameters. These are the core filters most people use day-to-day.
Identity / text search¶
| Param | What it does |
|---|---|
search |
Search entities (name + aliases + other indexed fields). |
uei |
Filter by UEI (exact, case-insensitive). |
cage_code |
Filter by CAGE code (exact, case-insensitive). |
name |
Filter by legal business name (substring match). |
Location¶
| Param | What it does |
|---|---|
state |
Filter by entity physical address state/province code. |
zip_code |
Filter by ZIP code (exact). |
Classification¶
| Param | What it does |
|---|---|
naics |
Filter by NAICS. |
psc |
Filter by PSC. |
socioeconomic |
Filter by business type / socioeconomic code. |
Other¶
| Param | What it does |
|---|---|
purpose_of_registration_code |
Filter by purpose-of-registration code (when present). |
total_awards_obligated_gte |
Filter entities with total obligated amount greater than or equal to a USD value. |
total_awards_obligated_lte |
Filter entities with total obligated amount less than or equal to a USD value. |
Filter value syntax (AND / OR)¶
Some filters support basic boolean syntax:
- Use
|orORfor OR - Use
,orANDfor AND
Example: socioeconomic=8A|WOSB
Ordering¶
/api/entities/ does not currently support ordering=....
If you send ?ordering=... anyway, Tango returns HTTP 400 (ordering is opt-in per endpoint).
Pagination¶
Entities use standard page-number pagination:
page(default 1)limit(max 100)
SDK examples¶
List entities (search + filters + shaping)¶
import { ShapeConfig, TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
const resp = await client.listEntities({
search: "acme",
state: "VA",
naics: "541511",
limit: 10,
shape: ShapeConfig.ENTITIES_MINIMAL,
});
for (const e of resp.results) {
console.log(e.uei, e.legal_business_name);
}
Get an entity (detail)¶
Forecasts¶
Forecasts are procurement forecasts exposed at /api/forecasts/. For field definitions, see the Forecasts Data Dictionary. For which agency sources we ingest (HHS, DHS, GSA, COMMERCE, DOE, TREASURY, DOI, DOL, DOT, VA, NRC), see Forecasts we track.
Endpoints¶
GET /api/forecasts/(list + filtering + search + ordering)GET /api/forecasts/{pk}/(detail)
Response Shaping¶
Forecasts default to the shaping pipeline — all responses go through shaping even without ?shape=. Use ?shape= to customize which fields are returned.
- List default:
id,source_system,external_id,agency,title,description,anticipated_award_date,fiscal_year,naics_code,is_active,status,primary_contact,place_of_performance,estimated_period,set_aside,contract_vehicle - Detail default: Same as list, plus
raw_dataanddisplay(*)
See Response Shaping for full syntax and the Forecasts Data Dictionary for field definitions.
Filtering¶
Core filters (all support OR/AND syntax unless noted; date filters require YYYY-MM-DD format — invalid dates or inverted ranges return 400, see Date filters):
| Param | What it does |
|---|---|
agency |
Filter by agency acronym. |
source_system |
Filter by source system identifier. |
naics_code |
Filter by exact NAICS. |
naics_starts_with |
Filter by NAICS prefix (e.g. 54). |
fiscal_year |
Filter by exact fiscal year. |
fiscal_year_gte, fiscal_year_lte |
Fiscal year range. |
award_date_after, award_date_before |
Anticipated award date range (YYYY-MM-DD). |
modified_after, modified_before |
Modified-in-Tango date range (YYYY-MM-DD). |
status |
Status (case-insensitive, partial match). |
title |
Filter by forecast title (case-insensitive substring). |
search |
Full-text search over title/description (vector-backed). |
Ordering¶
Forecasts support ordering= with a strict allowlist:
anticipated_award_datefiscal_yeartitle
Examples:
- Soonest award first:
GET /api/forecasts/?ordering=anticipated_award_date - Most recent fiscal year first:
GET /api/forecasts/?ordering=-fiscal_year
Pagination¶
Forecasts use standard page-number pagination:
page(default 1)limit(max 100)
SDK examples¶
import os
from tango import ShapeConfig, TangoClient
client = TangoClient(api_key=os.environ["TANGO_API_KEY"])
resp = client.list_forecasts(
agency="GSA",
naics_starts_with="54",
ordering="-anticipated_award_date",
limit=10,
shape=ShapeConfig.FORECASTS_MINIMAL,
)
for f in resp.results:
print(f.title, f.anticipated_award_date)
import { ShapeConfig, TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
const resp = await client.listForecasts({
agency: "GSA",
naics_starts_with: "54",
ordering: "-anticipated_award_date",
limit: 10,
shape: ShapeConfig.FORECASTS_MINIMAL,
});
for (const f of resp.results) {
console.log(f.title, f.anticipated_award_date);
}
Grants¶
Grant opportunities are exposed at /api/grants/. For field definitions, see the Grants Data Dictionary.
Endpoints¶
GET /api/grants/(list + filtering + search + ordering)GET /api/grants/{grant_id}/(detail)
Response Shaping¶
Grants default to the shaping pipeline — all responses go through shaping even without ?shape=. Use ?shape= to customize which fields are returned.
- List default:
grant_id,opportunity_number,agency_code,title,description,applicant_eligibility_description,funding_activity_category_description,grantor_contact,last_updated, plus expandedstatus(*),category(*),cfda_numbers(*),applicant_types(*),funding_categories(*),funding_instruments(*),funding_details(*),important_dates(*),additional_info(*) - Detail default: Same as list, plus
synopsis,forecast,opportunity_history
See Response Shaping for full syntax and the Grants Data Dictionary for field definitions.
Filtering¶
Core filters (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 (vector-backed). |
agency |
Filter by agency abbreviation (substring). |
opportunity_number |
Exact opportunity number. |
cfda_number |
CFDA number (substring match). |
status |
Opportunity status (case-insensitive choice). |
applicant_types |
Eligibility/applicant types (case-insensitive choice). |
funding_categories |
Funding category codes (case-insensitive choice). |
funding_instruments |
Funding instruments (case-insensitive choice). |
posted_date |
Posted date (exact, YYYY-MM-DD). |
posted_date_after, posted_date_before |
Posted date range. |
response_date_after, response_date_before |
Response/deadline date range. |
rank |
Relevance rank threshold (primarily useful with search). |
Ordering¶
Grants support ordering= with a strict allowlist:
posted_date(also acceptslast_updated)deadline_currentrank(relevance ranking; most useful whensearchis present)
Examples:
- Most recently posted first:
GET /api/grants/?ordering=-posted_date - Soonest deadline first:
GET /api/grants/?ordering=deadline_current
Pagination¶
Grants use standard page-number pagination:
page(default 1)limit(max 100)
SDK examples¶
import os
from tango import ShapeConfig, TangoClient
client = TangoClient(api_key=os.environ["TANGO_API_KEY"])
resp = client.list_grants(
agency="HHS",
search="opioid",
ordering="-posted_date",
limit=10,
shape=ShapeConfig.GRANTS_MINIMAL,
)
for g in resp.results:
print(g.grant_id, g.posted_date, g.title)
import { ShapeConfig, TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
const resp = await client.listGrants({
agency: "HHS",
search: "opioid",
ordering: "-posted_date",
limit: 10,
shape: ShapeConfig.GRANTS_MINIMAL,
});
for (const g of resp.results) {
console.log(g.grant_id, g.posted_date, g.title);
}
Opportunities
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);
}
Notices¶
Notices are individual SAM.gov notice records exposed at /api/notices/.
If you want “one row per solicitation/opportunity”, use Opportunities. For field definitions, see the Notices Data Dictionary.
Endpoints¶
GET /api/notices/(list + filtering + search)GET /api/notices/{notice_id}/(detail)
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 notices (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 (exact). |
posted_date_after, posted_date_before |
Posted date range (YYYY-MM-DD). |
response_deadline_after, response_deadline_before |
Response deadline range (YYYY-MM-DD). |
active |
Filter active/inactive. |
Ordering¶
/api/notices/ does not support ordering=....
Pagination¶
Notices use standard page-number pagination:
page(default 1)limit(max 100)
Response Shaping¶
Notices support the ?shape= query parameter. When no ?shape= is provided, the endpoint returns a default shape.
Default shape (list): active,address(*),attachment_count,award_number,description,last_updated,meta(*),naics_code,notice_id,office(*),opportunity(*),place_of_performance(*),posted_date,psc_code,response_deadline,sam_url,set_aside,solicitation_number,title
Default shape (detail): adds archive(*), primary_contact(*), secondary_contact(*)
set_aside is available as a leaf (returns the description text) or as an expansion set_aside(code,description) for the structured form.
See Response Shaping for syntax and examples.
Notices shaping notes¶
- New leaf:
opportunity_idis available directly as a leaf (UUID). - Bare expand shorthand: common expansions can be requested without parentheses when the runtime must expand them for safety (e.g.,
officebehaves likeoffice(*), andopportunitybehaves likeopportunity(*)).
Examples:
# Leaf opportunity_id + bare office/opportunity expansions
/api/notices/?shape=notice_id,opportunity_id,office,opportunity&limit=1
SDK examples¶
import { ShapeConfig, TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
const resp = await client.listNotices({
agency: "DOD",
notice_type: "presol",
limit: 10,
shape: ShapeConfig.NOTICES_MINIMAL,
});
for (const n of resp.results) {
console.log(n.notice_id, n.title);
}
Protests¶
Protests are bid protest records exposed at /api/protests/. For field definitions, see the Protests Data Dictionary.
Authentication: Protests endpoints require authentication (API key or OAuth2). Unauthenticated requests receive HTTP 401.
Endpoints¶
GET /api/protests/(list + filtering + search + pagination)GET /api/protests/{case_id}/(detail by deterministic case UUID)
Both list and detail return case-level objects identified by case_id (a deterministic UUID derived from source_system + base_case_number). Subordinate dockets are available via ?shape=...,dockets(...) expansion. The path segment must be a valid RFC 4122 UUID (version 1–5, variant 8/9/a/b).
Filtering¶
Core filters:
| Param | What it does |
|---|---|
source_system |
Filter by source system (for example gao). Supports OR/AND syntax. |
outcome |
Filter by protest outcome (for example Denied, Dismissed, Withdrawn, Sustained). Supports OR/AND syntax. |
case_type |
Filter by case type (for example Bid Protest, Bid Protest: Cost). Supports OR/AND syntax. |
agency |
Filter by protested agency text. Supports OR/AND syntax. |
case_number |
Filter by case number (B-number, for example b-423274). Supports OR/AND syntax. |
solicitation_number |
Filter by exact solicitation number. |
protester |
Filter by protester name text. Supports OR/AND syntax. |
filed_date_after, filed_date_before |
Filed date range filters. |
decision_date_after, decision_date_before |
Decision date range filters. |
search |
Full-text search over protest searchable fields. |
Ordering¶
Protests do not support custom ordering via ordering=.
Results are returned in a fixed timeline order:
decision_datewhen present, otherwisefiled_date(newest first)- UUID descending as a deterministic tie-breaker
If ordering is provided, the API returns HTTP 400.
Pagination¶
Protests use standard page-number pagination:
page(default 1)limit(max 100)
List response: one result per case¶
The list endpoint returns one result per case (distinct base_case_number), not one per docket. Each result includes case-level fields from the most recent docket in the case. case_id is a deterministic UUID from (source_system, base_case_number) used for grouping and detail lookup. Pagination and filters apply to dockets first; results are then grouped, so count is the total number of matching cases across all pages.
The default (unshaped) response does not include nested dockets. To get dockets, use the dockets expansion via ?shape=...,dockets(...).
Detail response: case-level¶
The detail endpoint (GET /api/protests/{case_id}/) returns a single case-level object, the same structure as a list item. Use ?shape=...,dockets(...) to include nested dockets.
Shaping¶
Protests support shape on both list and detail endpoints:
GET /api/protests/?shape=...GET /api/protests/{case_id}/?shape=...
Both list and detail return case-level objects. You can request case-level fields and the dockets expansion (e.g. shape=case_id,case_number,title,dockets(case_number,docket_number,filed_date)).
Allowed shape fields (case-level for both list and detail):
case_id(deterministic case UUID; use for detail lookup)source_system,case_number(base B-number),title,protester,agencysolicitation_number,case_type,outcomefiled_date,posted_date,decision_date,due_datedocket_url,decision_urldigest(opt-in only; fromraw_data.digest, e.g. decision summary text)dockets(expand with docket fields, e.g.dockets(case_number,docket_number,filed_date))resolved_protester(expand: entity resolution for the protester name)resolved_agency(expand: organization resolution for the agency name)
Allowed shape fields inside dockets(...):
source_system,case_number(base B-number),docket_number(specific docket, e.g.b-424046.1)title,protester,agency,solicitation_number,case_type,outcomefiled_date,posted_date,decision_date,due_datedocket_url,decision_urldigest
The case_number field (e.g. b-424214) identifies the case. The docket_number field (e.g. b-424214.1, b-424214.2) identifies the specific sub-docket within a case and is only available inside dockets(...).
Entity Resolution: resolved_protester(...)¶
When a protester name has been resolved to a canonical entity in Tango, you can expand the match via resolved_protester(...). Only high-confidence (confident) and medium-confidence (review) matches are returned; unresolved or low-confidence names return null.
Allowed fields inside resolved_protester(...):
uei— Unique Entity Identifier of the matched entityname— Display name of the matched entitymatch_confidence—"confident"(auto-linkable) or"review"(needs human review)rationale— Human-readable explanation of why the match was made
Organization Resolution: resolved_agency(...)¶
When an agency name has been resolved to a canonical organization in Tango, you can expand the match via resolved_agency(...). Same confidence rules as resolved_protester.
Allowed fields inside resolved_agency(...):
key— UUID key of the matched organizationname— Display name of the matched organizationmatch_confidence—"confident"or"review"rationale— Human-readable explanation
Not exposed in the API (internal only):
raw_data,field_provenance,external_id,data_quality,source_last_updated,created,modified- internal search/index fields (for example
search_vector)
Examples:
# Case-level fields and nested dockets
GET /api/protests/?shape=case_id,case_number,title,dockets(case_number,docket_number,filed_date,outcome)
# Case-level only
GET /api/protests/?shape=case_id,source_system,case_number,title,outcome,filed_date
More examples:
# Timeline-focused list payload
GET /api/protests/?source_system=gao&shape=case_id,title,outcome,filed_date,decision_date
# Link-focused payload
GET /api/protests/?shape=case_id,docket_url,decision_url
# Detail by case UUID with shaped response
GET /api/protests/550e8400-e29b-41d4-a716-446655440000/?shape=case_id,source_system,title,agency,protester,filed_date,decision_date
# Detail with nested dockets
GET /api/protests/550e8400-e29b-41d4-a716-446655440000/?shape=case_id,title,dockets(docket_number,filed_date,outcome)
# Entity resolution for protester
GET /api/protests/?shape=case_id,protester,resolved_protester(*)
# Organization resolution for agency
GET /api/protests/?shape=case_id,agency,resolved_agency(*)
# Selective resolution fields
GET /api/protests/?shape=case_id,resolved_protester(uei,match_confidence)
Notes:
- Use the
docketsexpansion to request nested docket fields (e.g.dockets(docket_number,case_number)). *is only valid inside expansions. Use explicit field lists at the root.- Invalid
shapefields return HTTP 400 with structured validation errors.
Metrics¶
Metrics endpoints return time-series obligation and award counts for a specific entity, NAICS code, or PSC code. They share the same URL pattern and query parameters, so this page describes behavior once, then lists the available endpoints.
How metrics work¶
Each metrics endpoint is:
GET /api/{resource}/{id}/metrics/<months>/<period_grouping>/
- Path parameters (required):
{id}— The resource identifier (entity UEI, NAICS code, or PSC code).months— Lookback window in months (positive integer). Example:24for the last 24 months.-
period_grouping— How to bucket time:year,quarter, ormonth. -
Query parameters (optional):
group_by— Comma-separated list of dimensions to break out:agency,department. When used, each result row includes the grouped dimension(s). Rolling averages are not supported when grouping; if both are used, rolling is skipped and awarningis returned.fiscal_year— Iftrueor1, buckets use federal fiscal year (Oct–Sep). Default is calendar year.rolling— Iftrueor1, adds a rolling average to each result (when not usinggroup_by).
Response shape (same for all three):
count— Number of result rows.description— Human-readable description of the time range and grouping.warning— Present only when e.g. rolling was requested withgroup_by(rolling skipped).- The resource object —
recipient(entity),naics_code, orpsc_code(the one you queried). results— Array of objects. Each has:year(and optionallymonth,quarterdepending onperiod_grouping),awards,subawards(obligation/count values),rolling_avg(ifrolling=trueand nogroup_by),department,agency(ifgroup_byincludes them).
Invalid period_grouping, non-positive months, or invalid group_by values return HTTP 400 with an error message.
Available endpoints¶
| Resource | Endpoint | Identifier |
|---|---|---|
| Entity | GET /api/entities/{uei}/metrics/<months>/<period_grouping>/ |
Entity UEI. See Entities. |
| NAICS | GET /api/naics/{code}/metrics/<months>/<period_grouping>/ |
NAICS code. See NAICS. |
| PSC | GET /api/psc/{code}/metrics/<months>/<period_grouping>/ |
PSC code. See PSC. |
All three support the same optional query parameters: group_by, fiscal_year, rolling.
Example¶
Entity obligations for the last 12 months, by month, with rolling average:
NAICS code 541512 for the last 24 months by quarter, grouped by department:
SDK¶
The official SDKs don’t yet expose first-class methods for metrics. Use the HTTP helper with the paths above:
import { TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
const http = (client as any).http;
const data = await http.get("/api/entities/ABC123DEF456/metrics/12/month/", {
rolling: "true",
});
console.log("count:", data.count, "results:", data.results?.length ?? 0);
Reference data
Assistance listings¶
Assistance listings (CFDA) reference data is exposed at /api/assistance_listings/. This is not the assistance transactions endpoint; it’s just the static reference list. For field definitions, see the Assistance Listings Data Dictionary.
Endpoints¶
GET /api/assistance_listings/(list)GET /api/assistance_listings/{number}/(detail;{number}supports digits and.)
Filtering¶
None.
Ordering¶
/api/assistance_listings/ does not support ordering=....
Pagination¶
Assistance listings use standard page-number pagination:
page(default 1)limit(default 1000, max 10000)
Response shaping¶
This endpoint supports response shaping via the shape query parameter.
- Leaves:
number,title,published_date,archived_date,popular_name,objectives,applicant_eligibility,benefit_eligibility - No expansions.
Default shape (list, no ?shape= param): number,title
Note: Detail responses (/api/assistance_listings/{number}/) use the full serializer (includes all fields) when no ?shape= param is provided.
# Include extra fields
/api/assistance_listings/?shape=number,title,objectives
# Detail with specific fields
/api/assistance_listings/10.001/?shape=number,title,objectives,popular_name
SDK examples¶
The official SDKs don’t yet expose a first-class list_assistance_listings() / listAssistanceListings() method.
You can still call the endpoint via the SDK’s internal HTTP helper.
Business types¶
Business type reference data is exposed at /api/business_types/. For field definitions, see the Business Types Data Dictionary.
Endpoints¶
GET /api/business_types/(list)GET /api/business_types/{code}/(detail)
Value formats¶
code: 2-character alphanumeric, typically uppercase (examples:A6,JT,XX,2R).certifier: In practice you’ll see a small set of values:SBA,AbilityOne,Government,Self.
Filtering¶
None.
Ordering¶
/api/business_types/ does not support ordering=....
Pagination¶
Business types use page-number pagination (static reference pagination defaults to larger pages):
page(default 1)limit(default 1000, max 10000)
Response shaping¶
This endpoint supports response shaping via the shape query parameter.
- Leaves:
name,code - No expansions.
Default shape (no ?shape= param): name,code
SDK examples¶
MAS SINs¶
MAS SIN reference data is exposed at /api/mas_sins/. For field definitions, see the MAS SINs Data Dictionary.
Endpoints¶
GET /api/mas_sins/(list)GET /api/mas_sins/{sin}/(detail)
Value formats and normalization¶
sin: String SIN code (examples:334310,541611,561210FS,ANCILLARY).large_category_code: Single-letter category code (example:A).sub_category_code: 3-character subcategory code (example:A01).set_aside_code: One ofY,N,B.service_comm_code: One ofB,C,S,P.naics_codes: List of NAICS code integers. Some SINs may use special values (e.g.0forANCILLARY).expiration_date: Parsed to an ISO date. The source uses aYYYYDDD(year + day-of-year) numeric format in some rows (example:2022181→ 2022-06-30).
Filtering¶
search: matches against SIN code, NAICS code, PSC code, title, and description.
Examples:
- Search by SIN:
GET /api/mas_sins/?search=334310 - Search by NAICS:
GET /api/mas_sins/?search=541611 - Search by PSC:
GET /api/mas_sins/?search=R799 - Search by text:
GET /api/mas_sins/?search=facilities
Ordering¶
/api/mas_sins/ does not support ordering=....
Pagination¶
MAS SINs use page-number pagination (static reference pagination defaults to larger pages):
page(default 1)limit(default 1000, max 10000)
Response shaping¶
This endpoint supports response shaping via the shape query parameter.
- Leaves:
sin,large_category_code,large_category_name,sub_category_code,sub_category_name,psc_code,state_local,set_aside_code,service_comm_code,expiration_date,tdr,olm,naics_codes,title,description - No expansions.
Default shape (no ?shape= param): all 15 fields above.
SDK examples¶
NAICS¶
NAICS codes are exposed at /api/naics/. For field definitions, see the NAICS Data Dictionary.
External references¶
Endpoints¶
GET /api/naics/(list + filtering)GET /api/naics/{code}/(detail)
Metrics: Time-series obligation/award metrics for a NAICS code: GET /api/naics/{code}/metrics/<months>/<period_grouping>/. See Metrics for parameters and behavior.
Filtering¶
| Param | What it does |
|---|---|
search |
Matches code__startswith or description__icontains. |
revenue_limit |
Filter by SBA revenue size standard (in millions of USD). |
revenue_limit_gte, revenue_limit_lte |
Revenue size standard range (in millions). |
employee_limit |
Filter by SBA employee size standard. |
employee_limit_gte, employee_limit_lte |
Employee size standard range. |
Example:
- NAICS starting with 54:
GET /api/naics/?search=54 - NAICS with revenue limit \(\le 15M\):
GET /api/naics/?revenue_limit_lte=15
Ordering¶
/api/naics/ does not support ordering=....
Pagination¶
NAICS uses page-number pagination (static reference pagination defaults to larger pages):
page(default 1)limit(default 1000, max 10000)
Response shaping¶
This endpoint supports response shaping via the shape query parameter.
- Leaves:
code,description - Expansions:
size_standards(employee_limit,revenue_limit)— SBA size standards.revenue_limitis in whole dollars.federal_obligations(total,active)— obligation rollups withawards_obligatedandawards_count.
Default shape (list, no ?shape= param): code,description
Default shape (detail or ?show_limits=1): code,description,size_standards(*),federal_obligations(*)
Deprecation note: The legacy ?show_limits=1 parameter is still supported but produces the same result as ?shape=code,description,size_standards(*),federal_obligations(*). Prefer ?shape= directly.
# List defaults
/api/naics/?shape=code,description
# Full detail equivalent (replaces ?show_limits=1)
/api/naics/?shape=code,description,size_standards(*),federal_obligations(*)
# Size standards only
/api/naics/541330/?shape=code,description,size_standards(*)
# Just the total obligations
/api/naics/541330/?shape=code,federal_obligations(total)
SDK examples¶
The official SDKs don’t yet expose a first-class list_naics() / listNaics() method.
You can still call the endpoint via the SDK’s internal HTTP helper.
Organizations¶
Organizations are the unified Federal Hierarchy model exposed at /api/organizations/ (departments, agencies, offices, and other intermediate nodes).
If you’re looking for field definitions, see the Organizations Data Dictionary.
Endpoints¶
GET /api/organizations/(list + filtering + search)GET /api/organizations/{identifier}/(detail — accepts either an integer Federal Hierarchy key or a UUID primary key)
Filtering¶
| Param | What it does |
|---|---|
search |
Multi-stage org search (aliases → trigram → full-text → fuzzy). |
type |
Filter by organization type (lenient allowlist; invalid values are ignored + warnings may be returned). |
level |
Filter by hierarchy level (1 = department, 2 = agency, etc.). |
cgac |
Filter by CGAC code. |
parent |
Filter by parent organization (accepts organization key or common names/abbreviations). |
include_inactive |
Include inactive orgs in list results (default false). Detail lookups always return the org regardless of active status. |
Response shaping¶
Organizations support shape=... (see Response Shaping).
Default shape (no ?shape= param):
key, fh_key, name, short_name, type, level, is_active, code, fpds_code, cgac, canonical_code, parent_fh_key, full_parent_path_name
All responses go through the shaping pipeline, even without a ?shape= parameter.
Root fields available via shaping:
| Field | Description |
|---|---|
key |
Tango's internal UUID primary key. |
fh_key |
Zero-padded 9-character string (e.g., "000000001"). Accepted for detail lookups alongside key (UUID). |
name |
Full official name. |
short_name |
Abbreviation or common name (e.g., "DOD"). |
type |
Organization type (DEPARTMENT, AGENCY, OFFICE, etc.). |
level |
Hierarchy depth (1 = department). |
is_active |
Whether the organization is currently active. |
code |
Office or agency code. |
fpds_code |
FPDS 4-digit agency code. |
cgac |
CGAC 3-character code. |
canonical_code |
Level-prefixed canonical code (e.g., "L1:097"). |
fpds_org_id |
FPDS organization identifier. |
aac_code |
Activity Address Code. |
parent_fh_key |
Parent's fh_key (zero-padded). |
full_parent_path_name |
Human-readable hierarchy path. |
l1_fh_key .. l8_fh_key |
Ancestor fh_key at each hierarchy level (zero-padded). |
start_date |
Organization start date from Federal Hierarchy. |
end_date |
Organization end date from Federal Hierarchy. |
logo |
Logo URL, when available. |
summary |
Short description or mission summary. |
mod_status |
Modification status (ACTIVE, INACTIVE). |
description |
Organization description. |
obligations |
Total rolled-up obligations (alias for tree_obligations). |
total_obligations |
Direct obligations for this organization. |
tree_obligations |
Obligations for the entire subtree. |
obligation_rank |
Percentile ranking (1–100) by obligations. |
Expansions:
| Expand | Fields | Notes |
|---|---|---|
parent(...) |
key, fh_key, name, short_name, type, level, is_active, code, cgac |
Immediate parent org. |
ancestors(...) |
fh_key, name, short_name, level |
All ancestors from L1 down to immediate parent. |
children(...) |
key, fh_key, name, short_name, type, level, is_active, code, cgac |
Immediate child organizations. |
department(...) |
code, name, abbreviation |
L1 ancestor as a department. Returns null for level 1 orgs (they are the department). |
agency(...) |
code, name, abbreviation |
L2 ancestor as an agency. Returns null for level 1 and 2 orgs (no agency above them). |
# Default response (no shape param)
/api/organizations/
# Select specific fields
/api/organizations/?shape=fh_key,name,type,level
# Include department and agency expands
/api/organizations/?shape=fh_key,name,department(code,name),agency(code,name,abbreviation)
# Include enriched ancestors
/api/organizations/?shape=fh_key,name,ancestors(fh_key,name,short_name,level)
department and agency expand level behavior
The department expand returns null for level 1 organizations (a department doesn't have a department — it is one). The agency expand returns null for level 1 or 2 organizations (departments and agencies don't have an agency above them). This means list responses with mixed levels work without errors.
Ordering¶
/api/organizations/ does not support ordering=....
(Results are returned in a stable way; searches preserve their own relevance ordering, and non-search lists are returned in a consistent key order.)
Pagination¶
Organizations use standard page-number pagination:
page(default 1)limit(max 100)
SDK examples¶
The SDKs don’t yet expose a first-class list_organizations() / listOrganizations() method.
You can still call the endpoint via the SDK’s internal HTTP helper.
import { TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
const http = (client as any).http;
const data = await http.get("/api/organizations/", {
search: "Treasury",
type: "DEPARTMENT|AGENCY",
include_inactive: "false",
limit: 25,
});
console.log("count:", data.count);
Product and Service Code (PSC)¶
Product and Service Code (PSC) reference data is exposed at /api/psc/. For field definitions, see the PSC Data Dictionary.
External references¶
Endpoints¶
GET /api/psc/(list)GET /api/psc/{code}/(detail)
Metrics: Time-series obligation/award metrics for a PSC code: GET /api/psc/{code}/metrics/<months>/<period_grouping>/. See Metrics for parameters and behavior.
Filtering¶
| Param | What it does |
|---|---|
has_awards |
If truthy, restrict to PSCs that appear in award data. |
Response options:
| Param | What it does |
|---|---|
complete |
If truthy, returns a “complete” representation (serializer context-dependent). |
Ordering¶
/api/psc/ does not support ordering=....
Pagination¶
PSC uses page-number pagination (static reference pagination defaults to larger pages):
page(default 1)limit(default 1000, max 10000)
Note: Reference-data endpoints like /api/psc/ allow larger page sizes than transactional award endpoints because the underlying datasets are relatively small and static, and larger pages reduce client round-trips.
Response shaping¶
This endpoint supports response shaping via the shape query parameter.
- Leaves:
code,parent,category,level_1_category,level_1_category_code,level_2_category,level_2_category_code - Expansions:
current(name,active,start_date,end_date,description,includes,excludes)— active or latest descriptionhistorical(name,active,start_date,end_date,description,includes,excludes)— all descriptions
Default shape (no ?shape= param): code,current(*),parent,category,level_1_category,level_1_category_code,level_2_category,level_2_category_code
# Just code and current description name
/api/psc/?shape=code,current(name)
# Code with current and historical descriptions
/api/psc/AD12/?shape=code,current(name,active),historical(name,active)
SDK examples¶
The official SDKs don’t yet expose a first-class list_psc() / listPsc() method.
You can still call the endpoint via the SDK’s internal HTTP helper.
Shared
Agencies¶
Deprecated endpoint
This endpoint is deprecated. Use Organizations for the unified federal hierarchy. This endpoint will be removed in a future version.
Deprecated scoped contract endpoints
The /api/agencies/{code}/contracts/awarding/ and /api/agencies/{code}/contracts/funding/ endpoints are deprecated. Use /api/contracts/?awarding_agency={code} or /api/contracts/?funding_agency={code} instead.
Agencies are federal organizations exposed at /api/agencies/ (with a small amount of structure via department).
If you need the unified Federal Hierarchy model (departments/agencies/offices all as one tree), see Organizations. For field definitions, see the Organizations Data Dictionary.
Endpoints¶
GET /api/agencies/(list)GET /api/agencies/{code}/(detail)
Agency-scoped contract lists (these behave like /api/contracts/, but scoped by agency code):
GET /api/agencies/{code}/contracts/awarding/GET /api/agencies/{code}/contracts/funding/
Filtering¶
| Param | What it does |
|---|---|
search |
Full-text search over agencies (best-effort, vector-backed). |
Ordering¶
/api/agencies/ does not support ordering=....
Pagination¶
Agencies use standard page-number pagination:
page(default 1)limit(max 100)
Response shaping¶
This endpoint supports response shaping via the shape query parameter.
- Leaves:
code,name,abbreviation - Expansions:
department(code,name,abbreviation,description,cgac,website,congressional_justification)
Default shape (no ?shape= param): code,name,abbreviation,department(name,code)
# Just codes and names
/api/agencies/?shape=code,name
# Include department info
/api/agencies/4700/?shape=code,name,department(name,code)
# All department fields
/api/agencies/4700/?shape=code,name,department(*)
SDK examples¶
List agencies¶
Awarding/funding contracts for an agency¶
The SDKs don’t yet expose a first-class method for these scoped endpoints. Use the contracts endpoint with awarding/funding agency filters, or call the scoped path directly.
import { ShapeConfig, TangoClient } from "@makegov/tango-node";
const client = new TangoClient({ apiKey: process.env.TANGO_API_KEY });
const http = (client as any).http;
const data = await http.get("/api/agencies/4700/contracts/awarding/", {
limit: 10,
shape: ShapeConfig.CONTRACTS_MINIMAL,
});
console.log("count:", data.count);
Departments¶
Deprecated endpoint
This endpoint is deprecated. Use Organizations for the unified federal hierarchy. This endpoint will be removed in a future version.
Departments are top-level organizations exposed at /api/departments/.
If you need the full organization tree + richer search, see Organizations. For field definitions, see the Organizations Data Dictionary.
Endpoints¶
GET /api/departments/(list)GET /api/departments/{code}/(detail)
Filtering¶
None.
Ordering¶
/api/departments/ does not support ordering=....
Pagination¶
Departments use standard page-number pagination:
page(default 1)limit(max 100)
Response shaping¶
This endpoint supports response shaping via the shape query parameter.
- Leaves:
code,name,abbreviation,description,cgac,website,congressional_justification - No expansions.
Default shape (no ?shape= param): code,name,abbreviation
# Select specific fields
/api/departments/?shape=code,name
# Extended department info
/api/departments/1400/?shape=code,name,description,website,congressional_justification
SDK examples¶
The SDKs don’t yet expose a first-class list_departments() / listDepartments() method.
You can still call the endpoint via the SDK’s internal HTTP helper.
Offices¶
Deprecated endpoint
This endpoint is deprecated. Use Organizations for the unified federal hierarchy. This endpoint will be removed in a future version.
Offices are sub-agency organizations exposed at /api/offices/.
If you need the unified Federal Hierarchy model (departments/agencies/offices all as one tree), see Organizations. For field definitions, see the Organizations Data Dictionary.
Endpoints¶
GET /api/offices/(list)GET /api/offices/{code}/(detail)
Filtering¶
| Param | What it does |
|---|---|
search |
Full-text search over offices (vector-backed). |
Ordering¶
/api/offices/ does not support ordering=....
Pagination¶
Offices use standard page-number pagination:
page(default 1)limit(max 100)
Response shaping¶
This endpoint supports response shaping via the shape query parameter.
- Leaves:
code,name, plus flat aliasesoffice_code,office_name,agency_code,agency_name,department_code,department_name - Expansions:
agency(code,name,abbreviation)department(code,name,abbreviation,description,cgac,website,congressional_justification)
Default shape (no ?shape= param): office_code,office_name,agency_code,agency_name,department_code,department_name (flat aliases)
# Default flat format
/api/offices/?shape=office_code,office_name,agency_name
# Direct leaves with nested expansion
/api/offices/4700/?shape=code,name,agency(code,name,abbreviation)
# Office with department details
/api/offices/4700/?shape=code,name,department(name,description,website)
SDK examples¶
The SDKs don’t yet expose a first-class list_offices() / listOffices() method.
You can still call the endpoint via the SDK’s internal HTTP helper.
Set-aside codes¶
This page documents the set-aside codes used across Tango’s awards and opportunities APIs (including shaped set_aside(code,description) expansions).
Codes¶
| Code | Meaning |
|---|---|
NONE |
No set aside used |
SBA |
Small Business Set Aside - Total |
8A |
8a Competed |
SBP |
Small Business Set Aside - Partial |
HMT |
HBCU or MI Set Aside - Total |
HMP |
HBCU or MI Set Aside - Partial |
VSB |
Very Small Business |
ESB |
Emerging Small Business Set-Aside |
HZC |
HUBZone Set Aside |
SDVOSBC |
Service-Disabled Veteran-Owned Small Business Set Aside |
BI |
Buy Indian |
IEE |
Indian Economic Enterprise |
ISBEE |
Indian Small Business Economic Enterprise |
HZS |
HUBZone Sole Source |
SDVOSBS |
SDVOSB Sole Source |
8AN |
8(a) Sole Source |
RS |
Reserved for Small Business |
HS3 |
8(a) with HUBZone Preference |
VSA |
Veteran Set Aside |
VSS |
Veteran Sole Source |
WOSB |
Women-Owned Small Business |
EDWOSB |
Economically Disadvantaged Women-Owned Small Business |
WOSBSS |
Women-Owned Small Business Sole Source |
EDWOSBSS |
Economically Disadvantaged Women-Owned Small Business Sole Source |
Source of truth¶
Tango maintains a canonical mapping internally and publishes it here for API consumers.
Data Dictionary
Data Dictionary¶
Tango's Data Dictionary documents the fields you can expect on key resources and what they mean.
If you're looking for how to query/filter/order endpoints, see the API Reference.
Awards¶
Definitive contracts, indefinite-delivery vehicles, other transactions, subawards, and solicitation-level groupings.
- Contracts — Definitive contract awards (materialized from FPDS and USAspending inputs). Response shaping →
- IDVs — Indefinite delivery vehicles (GWACs, IDIQs, etc.). Response shaping →
- OTAs — Other Transaction Agreements from FPDS. Response shaping →
- OTIDVs — Other Transaction IDVs from FPDS. Response shaping →
- Subawards — Sub-contracts and sub-grants under prime awards; sourced from USAspending/FSRS. Response shaping →
- Vehicles — Solicitation-centric grouping of IDVs. Response shaping →
- GSA eLibrary contracts — Persisted GSA eLibrary contract metadata.
Entities¶
- Entities — Vendors and recipients in federal contracting and assistance; UEI is the canonical identifier (from SAM.gov). Response shaping →
Forecasts¶
- Forecasts — Upcoming procurement opportunities from agency feeds (e.g., HHS, DHS) before they appear as SAM.gov solicitations. Response shaping →
Grants¶
- Grants — Grant opportunities from Grants.gov (funding opportunities, not assistance transactions). Response shaping →
Opportunities¶
SAM.gov contract opportunity and notice data.
- Opportunities — Contract opportunities aggregated by parent. Response shaping →
- Notices — Individual SAM.gov notice records (amendments, updates) under an opportunity. Response shaping →
Reference data¶
Lookup tables and codes used across awards and entities.
- Assistance listings (CFDA) — CFDA program numbers and titles for federal grants/assistance. Response shaping →
- Business types — SAM.gov business type codes (e.g., small business, 8(a), HUBZone). Response shaping →
- MAS SINs — MAS Special Item Numbers (SINs) reference data. Response shaping →
- NAICS — North American Industry Classification System codes. Response shaping →
- Organizations — Unified federal hierarchy (departments, agencies, offices in one tree). Response shaping →
- PSC — Product/Service Codes for federal contracting. Response shaping →
Shared¶
Data structures shared across multiple endpoints via response shaping expands.
- Set-aside codes — Set-aside type codes and descriptions.
- Agencies — Agency fields and expansions as they appear in shaped responses. Response shaping →
- Departments — Department fields as they appear in shaped responses. Response shaping →
- Offices — Office fields, flat aliases, and expansions as they appear in shaped responses. Response shaping →
Awards
Contracts Data Dictionary¶
This document describes the fields available in the Contracts API endpoints (/api/contracts/). For filtering, ordering, and pagination, see the Contracts API Reference.
Overview¶
Contracts are definitive contract awards from FPDS (Federal Procurement Data System). Contracts are sourced from both FPDS and USAspending, and Tango merges those inputs during award materialization.
Identifiers¶
key(canonical): The canonical award identifier derived from FPDS/USAspending award keys. This is what the API uses for lookups:GET /api/contracts/{key}/.uuid(internal): Tango’s deterministic internal UUID used as the database primary key and for stable internal joins/orderings. This is not intended as a public lookup key.
Note: The full set of fields is available via the shape query parameter. The base response includes a subset of commonly-used fields. See Response Shaping for details.
Update Frequency¶
Contract data is refreshed via the awards ETL pipeline (FPDS updates twice daily; USAspending inputs update daily).
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
key |
String | Canonical award identifier (stable across FPDS and USAspending). Used for detail lookups and cross-referencing. | FPDS / USAspending |
piid |
String | Procurement Instrument Identifier. The official contract number. | FPDS / USAspending |
award_date |
Date | Date the contract was awarded. | FPDS / USAspending |
award_type |
Object | Type of award (e.g., contract type code and description). Use the award_type expansion for code, description. |
FPDS / USAspending |
naics_code |
Integer | NAICS code on the award (when stored as a single code). | FPDS / USAspending |
psc_code |
String | Product/Service Code on the award (when stored as a single code). | FPDS / USAspending |
total_contract_value |
Decimal | Total value of the contract (base + options, when reported). Expressed in US dollars. | FPDS / USAspending |
base_and_exercised_options_value |
Decimal | Base contract value plus exercised options. Expressed in US dollars. | FPDS / USAspending |
fiscal_year |
Integer | Federal fiscal year of the award (Oct–Sep). | FPDS / USAspending |
obligated |
Decimal | Total obligated amount (dollars) on the contract. | FPDS / USAspending |
description |
String | Contract description or title, when available. | FPDS / USAspending |
set_aside |
Object | Set-aside type (e.g., small business, 8(a)). Use the set_aside expansion for code, description. |
FPDS / USAspending |
transactions |
Array | List of transaction/modification records. Use the transactions expansion; each item can include modification_number, transaction_date, obligated, description, action_type. |
FPDS / USAspending |
subawards_summary |
Object | Summary of subawards under this contract. Use the subawards_summary expansion for count, total_amount. |
USAspending / Tango |
Expansions (via shape)¶
recipient¶
Returns the awardee (entity). Fields: uei, display_name, legal_business_name, cage, duns.
place_of_performance¶
Returns the place of performance. Fields: country_code, country_name, state_code, state_name, city_name, zip_code.
awarding_office / funding_office¶
Returns the awarding or funding office. Fields: office_code, office_name, agency_code, agency_name, department_code, department_name.
parent_award¶
Returns the parent award (e.g., IDV) when this contract is a child order. Fields: key, piid.
The default (non-shaped) response includes parent_award as a minimal {key, piid} reference derived from the award key without a database query. Use ?shape= with parent_award(key,piid) to get the same fields via the shaping pipeline, or expand to the full parent award object.
period_of_performance¶
Returns period of performance. Fields: start_date, current_end_date, ultimate_completion_date.
award_type / set_aside¶
Returns code and description for award type or set-aside type.
transactions¶
Returns the list of modifications/transactions. Each item: modification_number, transaction_date, obligated, description, action_type.
competition¶
Returns competition-related fields: contract_type, extent_competed, number_of_offers_received, other_than_full_and_open_competition, solicitation_date, solicitation_identifier, solicitation_procedures.
legislative_mandates¶
Returns legislative mandate flags (e.g., Clinger-Cohen, labor standards, employment eligibility).
officers¶
Returns contracting/officer information (when available).
naics / psc¶
Returns NAICS or PSC as {code, description}.
subawards_summary¶
Returns count and total_amount for subawards under this contract.
Common code values¶
These fields use standardized code systems. The canonical mappings live in src/awards/choices.py.
award_type¶
| Code | Meaning |
|---|---|
A |
BPA Call |
B |
Purchase Order |
C |
Delivery Order |
D |
Definitive Contract |
competition.contract_type¶
| Code | Meaning |
|---|---|
J |
Firm Fixed Price |
U |
Cost Plus Fixed Fee |
R |
Cost Plus Award Fee |
Y |
Time and Materials |
Z |
Labor Hours |
1 |
Order Dependent |
2 |
Combination |
3 |
Other |
(Many additional contract-type codes exist; see CONTRACT_TYPE_CHOICES.)
competition.extent_competed¶
| Code | Meaning |
|---|---|
A |
Full and Open Competition |
C |
Not Competed |
D |
Full and Open after exclusion of sources |
F |
Competed under SAP |
G |
Not Competed under SAP |
CDO |
Competitive Delivery Order |
NDO |
Non-Competitive Delivery Order |
(See EXTENT_COMPETED_CHOICES for the complete mapping.)
set_aside¶
| Code | Meaning |
|---|---|
NONE |
No set aside used |
SBA |
Small Business Set Aside - Total |
8A |
8(a) Competed |
HZC |
HUBZone Set Aside |
SDVOSBC |
Service-Disabled Veteran-Owned Small Business Set Aside |
WOSB |
Women-Owned Small Business |
EDWOSB |
Economically Disadvantaged Women-Owned Small Business |
(See Set-aside codes for the complete mapping.)
Data Sources¶
- FPDS – Contract actions, PIID, dates, values, NAICS, PSC, set-aside, competition, offices, recipient reference.
- USAspending – Supplemental award/transaction inputs used in award materialization and subaward linkage.
- Tango – Internal deterministic
uuidand merged award materialization.
Usage Notes¶
- Use
keyfor API references –keyis the canonical award identifier used by the Contracts API. - Use
piidfor human/FPDS lookups – PIID is the contract number users see in FPDS and solicitations. - Scoped endpoints – Use
/api/entities/{uei}/contracts/,/api/idvs/{key}/awards/, or/api/vehicles/{uuid}/orders/for contract lists scoped to an entity, IDV, or vehicle; see Contracts API Reference.
IDVs Data Dictionary¶
This document describes the fields available in the IDVs API endpoints (/api/idvs/). For filtering, ordering, and pagination, see the IDVs API Reference.
Overview¶
IDVs (Indefinite Delivery Vehicles) are contract vehicles that can have multiple orders/task orders issued against them. IDVs are sourced from both FPDS and USAspending, and Tango merges those inputs during award materialization.
Identifiers¶
key(canonical): The canonical award identifier derived from FPDS/USAspending award keys. This is what the API uses for lookups:GET /api/idvs/{key}/.uuid(internal): Tango’s deterministic internal UUID used as the database primary key and for stable internal joins/orderings. This is not intended as a public lookup key.
Note: The full set of fields is available via the shape query parameter. See Response Shaping for details.
Update Frequency¶
IDV data is refreshed via the awards ETL pipeline (FPDS updates twice daily; USAspending inputs update daily).
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
key |
String | Canonical award identifier (stable across FPDS and USAspending). Used for detail lookups and cross-referencing. | FPDS / USAspending |
piid |
String | Procurement Instrument Identifier. | FPDS / USAspending |
vehicle_uuid |
UUID | UUID of the Tango Vehicle this IDV is grouped under. Use to fetch vehicle detail at GET /api/vehicles/{uuid}/. null when not linked to a Vehicle. |
Tango |
award_date |
Date | Date the IDV was awarded. | FPDS / USAspending |
naics_code |
Integer | NAICS code on the award. | FPDS / USAspending |
psc_code |
String | Product/Service Code on the award. | FPDS / USAspending |
total_contract_value |
Decimal | Total value (base + options). | FPDS / USAspending |
base_and_exercised_options_value |
Decimal | Base plus exercised options. | FPDS / USAspending |
fiscal_year |
Integer | Federal fiscal year of the award. | FPDS / USAspending |
obligated |
Decimal | Total obligated amount. | FPDS / USAspending |
description |
String | Contract description/title. | FPDS / USAspending |
idv_type |
Object | IDV type (e.g., GWAC, IDIQ). Use expansion for code, description. |
FPDS / USAspending |
multiple_or_single_award_idv |
Object | Multiple or single award indicator. | FPDS / USAspending |
type_of_idc |
Object | Type of IDC (Indefinite Delivery Contract). Use expansion for code, description. |
FPDS / USAspending |
set_aside |
Object | Set-aside type. Use expansion for code, description. |
FPDS / USAspending |
transactions |
Array | Modification/transaction records. Use expansion for modification_number, transaction_date, obligated, description, action_type. |
FPDS / USAspending |
subawards_summary |
Object | Summary of subawards. Use expansion for count, total_amount. |
USAspending / Tango |
Expansions (via shape)¶
Same pattern as Contracts: recipient, place_of_performance, awarding_office, funding_office, parent_award, period_of_performance (fields: start_date, last_date_to_order), set_aside, transactions, competition, legislative_mandates, officers, naics, psc, subawards_summary, plus:
Note: The default (non-shaped) response includes parent_award as a minimal {key, piid} reference without a database query. Use ?shape= with parent_award(...) for the full parent award object. See Contracts for details.
gsa_elibrary(schedule,contract_number,uei,sins,cooperative_purchasing,disaster_recovery_purchasing,file_urls,extracted_text,external_id,source_data)– best-effort enrichment row from GSA eLibrary; returnsnullwhen no match is present.
Common code values¶
These fields use standardized code systems. The canonical mappings live in src/awards/choices.py.
idv_type¶
| Code | Meaning |
|---|---|
A |
GWAC |
B |
IDC |
C |
FSS |
D |
BOA |
E |
BPA |
type_of_idc¶
| Code | Meaning |
|---|---|
A |
Indefinite Delivery / Requirements |
B |
Indefinite Delivery / Indefinite Quantity |
C |
Indefinite Delivery / Definite Quantity |
set_aside¶
| Code | Meaning |
|---|---|
NONE |
No set aside used |
SBA |
Small Business Set Aside - Total |
8A |
8(a) Competed |
HZC |
HUBZone Set Aside |
SDVOSBC |
Service-Disabled Veteran-Owned Small Business Set Aside |
WOSB |
Women-Owned Small Business |
EDWOSB |
Economically Disadvantaged Women-Owned Small Business |
(See Set-aside codes for the complete mapping.)
Data Sources¶
- FPDS – IDV actions, PIID, dates, values, types, set-aside, competition, offices.
- USAspending – Supplemental award/transaction inputs used in award materialization and subaward linkage.
- Tango – Internal deterministic
uuidand merged award materialization.
Usage Notes¶
- Use
keyfor API references. Usepiidfor FPDS/solicitation lookups. - Child awards: Use
/api/idvs/{key}/awards/for contracts/orders under this IDV; see IDVs API Reference.
OTAs Data Dictionary¶
This document describes the fields available in the OTAs API endpoints (/api/otas/). For filtering, ordering, and pagination, see the OTAs API Reference.
Overview¶
OTAs (Other Transaction Agreements) are non-standard procurement instruments. OTAs are sourced from FPDS only.
Identifiers¶
key(canonical): The canonical award identifier derived from FPDS award keys. This is what the API uses for lookups:GET /api/otas/{key}/.uuid(internal): Tango’s deterministic internal UUID used as the database primary key and for stable internal joins/orderings. This is not intended as a public lookup key.
Note: The full set of fields is available via the shape query parameter. See Response Shaping for details.
Update Frequency¶
OTA data is loaded from FPDS twice daily via the awards ETL pipeline.
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
key |
String | Canonical award identifier (FPDS). Used for detail lookups and cross-referencing. | FPDS |
piid |
String | Procurement Instrument Identifier. | FPDS |
award_date |
Date | Date the OTA was awarded. | FPDS |
psc_code |
String | Product/Service Code on the award. | FPDS |
total_contract_value |
Decimal | Total value. | FPDS |
base_and_exercised_options_value |
Decimal | Base plus exercised options. | FPDS |
fiscal_year |
Integer | Federal fiscal year. | FPDS |
obligated |
Decimal | Total obligated amount. | FPDS |
description |
String | OTA description/title. | FPDS |
award_type |
String | Award type code. Expandable to {code, description} via ?shape=. |
FPDS |
type_of_ot_agreement |
String | Type of OT agreement code. Expandable to {code, description} via ?shape=. |
FPDS |
extent_competed |
String | Extent competed code. Expandable to {code, description} via ?shape=. |
FPDS |
consortia |
String | Consortia indicator. | FPDS |
consortia_uei |
String | Consortia UEI. | FPDS |
dod_acquisition_program |
String | DoD acquisition program identifier. | FPDS |
non_governmental_dollars |
Decimal | Non-governmental dollars. | FPDS |
non_traditional_government_contractor_participation |
String | Non-traditional government contractor participation indicator. | FPDS |
parent_award_modification_number |
String | Parent award modification number. | FPDS |
transactions |
Array | Modification/transaction records. Use expansion for same fields as contracts. | FPDS |
Expansions (via shape)¶
recipient, place_of_performance, parent_award, awarding_office, funding_office, period_of_performance, award_type, type_of_ot_agreement, extent_competed, transactions, psc.
Data Sources¶
- FPDS – OTA actions, PIID, dates, values, types.
- Tango – Internal deterministic
uuidand award materialization.
Usage Notes¶
- Use
keyfor API references. Usepiidfor FPDS lookups.
OTIDVs Data Dictionary¶
This document describes the fields available in the OTIDVs API endpoints (/api/otidvs/). For filtering, ordering, and pagination, see the OTIDVs API Reference.
Overview¶
OTIDVs (Other Transaction IDVs) are indefinite-delivery Other Transaction vehicles. OTIDVs are sourced from FPDS only.
Identifiers¶
key(canonical): The canonical award identifier derived from FPDS award keys. This is what the API uses for lookups:GET /api/otidvs/{key}/.uuid(internal): Tango’s deterministic internal UUID used as the database primary key and for stable internal joins/orderings. This is not intended as a public lookup key.
Note: The full set of fields is available via the shape query parameter. See Response Shaping for details.
Update Frequency¶
OTIDV data is loaded from FPDS twice daily via the awards ETL pipeline.
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
key |
String | Canonical award identifier (FPDS). Used for detail lookups and cross-referencing. | FPDS |
piid |
String | Procurement Instrument Identifier. | FPDS |
award_date |
Date | Date the OTIDV was awarded. | FPDS |
psc_code |
String | Product/Service Code on the award. | FPDS |
total_contract_value |
Decimal | Total value. | FPDS |
base_and_exercised_options_value |
Decimal | Base plus exercised options. | FPDS |
fiscal_year |
Integer | Federal fiscal year. | FPDS |
obligated |
Decimal | Total obligated amount. | FPDS |
description |
String | OTIDV description/title. | FPDS |
idv_type |
Object | IDV type. | FPDS |
consortia |
String | Consortia indicator. | FPDS |
consortia_uei |
String | Consortia UEI. | FPDS |
dod_acquisition_program |
String | DoD acquisition program identifier. | FPDS |
non_governmental_dollars |
Decimal | Non-governmental dollars. | FPDS |
non_traditional_government_contractor_participation |
String | Non-traditional government contractor participation indicator. | FPDS |
type_of_ot_agreement |
String | Type of OT agreement code. Expandable to {code, description} via ?shape=. |
FPDS |
extent_competed |
String | Extent competed code. Expandable to {code, description} via ?shape=. |
FPDS |
transactions |
Array | Modification/transaction records. Use expansion for same fields as contracts. | FPDS |
Expansions (via shape)¶
recipient, place_of_performance, awarding_office, funding_office, period_of_performance, type_of_ot_agreement, extent_competed, transactions, psc.
Data Sources¶
- FPDS – OTIDV actions, PIID, dates, values, types.
- Tango – Internal deterministic
uuidand award materialization.
Usage Notes¶
- Use
keyfor API references. Usepiidfor FPDS lookups. - Child awards: Use
/api/otidvs/{key}/awards/for orders under this OTIDV; see OTIDVs API Reference.
Subawards Data Dictionary¶
This document describes the fields available in the Subawards API endpoints (/api/subawards/). For filtering, ordering, and pagination, see the Subawards API Reference.
Overview¶
Subawards are sub-contracts or sub-grants under a prime award, sourced from USAspending/FSRS. Each subaward has an auto-incrementing integer key. Data links the prime award (contract/assistance) to the subrecipient and amounts.
Identifiers¶
key(subaward): Tango’s primary key for the subaward record (integer). This is what the API uses for lookups:GET /api/subawards/{key}/.award_key(prime award, canonical): Canonical identifier of the prime award (e.g., contract/IDV) using the same award-key convention as/api/contracts/{key}/and/api/idvs/{key}/.award_uuid(prime award, internal): When available, Tango’s internal deterministic UUID for the prime award (used for resilient joins/backfills).
Note: The full set of fields is available via the shape query parameter. See Response Shaping for details.
Update Frequency¶
Subaward data is loaded from USAspending daily via the subawards ETL pipeline.
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
key |
Integer | Primary identifier for the subaward record in Tango (auto-increment). | Tango |
award_key |
String | Canonical identifier of the prime award (award-key convention). | USAspending / Tango |
piid |
String | Prime award PIID (contract) or equivalent. | USAspending |
prime_award_total_outlayed_amount |
Decimal | Total outlayed on the prime award. | USAspending |
prime_award_amount |
Decimal | Prime award amount. | USAspending |
prime_award_base_action_date |
String | Prime award base action date (YYYY-MM-DD date string). |
USAspending |
prime_award_base_action_date_fiscal_year |
Integer | Fiscal year of base action. | Tango (derived) |
prime_award_latest_action_date |
String | Latest action date on prime (YYYY-MM-DD date string). |
USAspending |
prime_award_latest_action_date_fiscal_year |
Integer | Fiscal year of latest action. | Tango (derived) |
prime_award_base_transaction_description |
String | Prime award transaction description. | USAspending |
prime_award_project_title |
String | Prime award project title. | USAspending |
prime_award_naics_code |
Integer | NAICS on prime award. | USAspending |
prime_award_naics_description |
String | NAICS description. | USAspending |
prime_awardee_uei |
String | Prime recipient UEI. | USAspending |
prime_awardee_name |
String | Prime recipient name. | USAspending |
prime_awardee_parent_uei |
String | Prime recipient parent UEI. | USAspending |
prime_awardee_parent_name |
String | Prime recipient parent name. | USAspending |
subawardee_uei |
String | Subrecipient UEI. | USAspending |
subawardee_duns |
String | Subrecipient DUNS (legacy). | USAspending |
subawardee_name |
String | Subrecipient name. | USAspending |
subawardee_dba_name |
String | Subrecipient DBA name. | USAspending |
subawardee_parent_uei |
String | Subrecipient parent UEI. | USAspending |
subawardee_parent_duns |
String | Subrecipient parent DUNS. | USAspending |
subawardee_parent_name |
String | Subrecipient parent name. | USAspending |
subawardee_business_types |
String | Subrecipient business types (comma-separated codes). | USAspending |
usaspending_permalink |
String | Link to USAspending subaward. | USAspending |
Expansions (via shape)¶
subaward_details–description,type,number,amount,action_date,fiscal_yearfsrs_details–last_modified_date,id,year,monthplace_of_performance–city,state,zip,country_codehighly_compensated_officers–name,amountprime_recipient–uei,display_name(and other recipient fields)subaward_recipient–uei,display_name,dunsawarding_office/funding_office– office fields
Data Sources¶
- USAspending – Subaward and prime award data, FSRS.
- Tango –
key,award_key,award_uuid, and fiscal year derivations/joins.
Usage Notes¶
- Use
keyfor subaward lookups. Useaward_keyto link to the prime contract/award record. - Scoped lists: Use
/api/contracts/{key}/subawards/for subawards under a contract; see Subawards API Reference.
Vehicles Data Dictionary¶
This document describes the fields available in the Vehicles API endpoints (/api/vehicles/). For filtering, ordering, and pagination, see the Vehicles API Reference.
Overview¶
Vehicles provide a solicitation-centric grouping of multiple IDVs. Each vehicle represents a unique \(solicitation_identifier, agency identifier\) pair and can expand into the underlying IDVs via response shaping.
In federal data, each IDV award is a vehicle. In practice, people often think of a “vehicle” as the solicitation that produced many IDV awards (one per awardee). We model that higher-level grouping explicitly.
Note: The full set of fields is available via the shape query parameter. The base response includes a subset of commonly-used fields. See Response Shaping for details.
Update Frequency¶
Vehicle data is refreshed via the refresh_vehicles management command.
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
uuid |
UUID | Stable identifier for the vehicle in Tango. Deterministic from solicitation_identifier + agency identifier derived from the IDV key. |
Tango |
solicitation_identifier |
String | Solicitation identifier shared by the underlying IDVs. | FPDS (via awards) |
agency_id |
String | Agency identifier derived from the IDV award key suffix (award-key convention). |
Tango |
organization_id |
UUID | Best-effort mapping to an Organization (agencies_organization.key) for consistent agency joins/filtering. |
Tango (derived) |
vehicle_type |
Object | Aggregated IDV type for the vehicle, derived from underlying IDVs. Returned as {code, description} (e.g., {code: "A", description: "GWAC"}). |
FPDS (via awards) |
fiscal_year |
Integer | Representative fiscal year for the vehicle (derived from the underlying IDVs). | FPDS (via awards) |
agency_details |
Object | Aggregated awarding/funding office details derived from underlying IDVs. | FPDS (via awards) |
descriptions |
Array[String] | Set of distinct descriptions found across the underlying IDVs. | FPDS (via awards) |
competition_details |
Object | Aggregated competition information derived from the underlying IDVs. | FPDS (via awards) |
type_of_idc |
Object | Aggregated IDC type for the vehicle, derived from underlying IDVs. Returned as {code, description} (e.g., {code: "A", description: "Indefinite Delivery / Requirements"}). |
FPDS (via awards) |
contract_type |
Object | Aggregated contract type for the vehicle, derived from underlying IDVs. Returned as {code, description} (e.g., {code: "J", description: "Firm Fixed Price"}). |
FPDS (via awards) |
awardee_count |
Integer | Number of IDVs in the vehicle (computed from a materialized view). | Tango |
order_count |
Integer | Total number of child awards/orders under the vehicle's IDVs (computed from a materialized view). | Tango |
vehicle_obligations |
Decimal | Sum of obligations across child awards/orders under the vehicle's IDVs (computed from a materialized view). | Tango |
vehicle_contracts_value |
Decimal | Sum of total contract value across child awards/orders under the vehicle's IDVs (computed from a materialized view). | Tango |
solicitation_title |
String | Title of the solicitation from the latest SAM.gov notice (via linked Opportunity). | SAM.gov (via opportunities) |
solicitation_description |
String | Description of the solicitation from the latest SAM.gov notice (via linked Opportunity). | SAM.gov (via opportunities) |
solicitation_date |
Date | First notice date from the linked SAM.gov Opportunity. | SAM.gov (via opportunities) |
naics_code |
Integer | NAICS code from the linked SAM.gov Opportunity. | SAM.gov (via opportunities) |
psc_code |
String | Product/Service Code from the linked SAM.gov Opportunity. | SAM.gov (via opportunities) |
set_aside |
String | Set-aside type from the linked SAM.gov Opportunity. | SAM.gov (via opportunities) |
Expansions (via shape)¶
awards¶
Expands to the underlying IDVs that make up the vehicle.
opportunity¶
Expands to the linked SAM.gov Opportunity (if present). Supports all Opportunity shaping fields and expansions (e.g., office, attachments, meta).
competition_details¶
Expands the competition_details JSON object, allowing you to select specific fields. Available fields: commercial_item_acquisition_procedures, evaluated_preference, extent_competed, most_recent_solicitation_date, number_of_offers_received, original_solicitation_date, other_than_full_and_open_competition, set_aside, simplified_procedures_for_certain_commercial_items, small_business_competitiveness_demonstration_program, solicitation_identifier, solicitation_procedures, or * for all fields.
Example:
/api/vehicles/<vehicle-uuid>/?shape=uuid,solicitation_identifier,awardees(key,uuid,piid,recipient(display_name,uei))
Search¶
- Vehicle list search:
GET /api/vehicles/?search=...searches across vehicle metadata and aggregated award search terms. - Awardee-within-vehicle filtering:
GET /api/vehicles/<vehicle-uuid>/?shape=...,awardees(...)&search=...filters the expanded awardees.
GSA eLibrary Contracts Data Dictionary¶
This document describes the fields available in the GSA eLibrary Contracts API endpoints (/api/gsa_elibrary_contracts/). For filtering, ordering, and pagination, see the GSA eLibrary Contracts API Reference.
Overview¶
GSA eLibrary contracts are persisted contract records from the GSA eLibrary system, representing contracts awarded under the MAS (Multiple Award Schedule) program. Tango syncs this data to provide a queryable view of MAS schedule contracts with links to IDVs and recipients.
Update Frequency¶
GSA eLibrary data is updated periodically via the sync pipeline.
Fields¶
Core identity¶
| Field | Type | Description | Source |
|---|---|---|---|
uuid |
UUID | Tango internal identifier for this persisted record. | Tango |
schedule |
String | Schedule identifier, typically MAS. |
GSA eLibrary |
contract_number |
String | MAS contract number (join key to IDV piid, best-effort). |
GSA eLibrary |
Party¶
| Field | Type | Description | Source |
|---|---|---|---|
recipient |
Object | null | Best-effort cached entity lookup by uei (fields: uei, display_name). |
GSA eLibrary / Tango |
Linked IDV (best-effort)¶
| Field | Type | Description | Source |
|---|---|---|---|
idv |
Object | null | Only present when the row is linked to an IDV (fields: key, award_date). |
Tango |
Enrichment¶
| Field | Type | Description | Source |
|---|---|---|---|
sins |
List[String] | Special Item Numbers (SINs). | GSA eLibrary |
cooperative_purchasing |
Boolean | Cooperative Purchasing program flag (best-effort). | GSA eLibrary |
disaster_recovery_purchasing |
Boolean | Disaster Recovery Purchasing program flag (best-effort). | GSA eLibrary |
file_urls |
List[String] | Public document URLs (T&Cs, price list, catalog), best-effort merged. | GSA eLibrary |
Usage Notes¶
- Use
uuidfor API lookups. Theuuidis the primary key for detail requests:GET /api/gsa_elibrary_contracts/{uuid}/. - These are GSA MAS schedule contracts. Each record represents a contract awarded under the Multiple Award Schedule program.
- IDV and recipient links are best-effort. The
idvexpansion is populated when Tango can match thecontract_numberto an IDV PIID. Therecipientexpansion is populated via UEI lookup. - SINs connect to the MAS SINs reference table. Use
sinfiltering to find contracts by Special Item Number; see MAS SINs Data Dictionary.
Data Sources¶
- GSA eLibrary — Contract metadata from the GSA eLibrary system.
CALC Labor Rates Data Dictionary¶
This document describes the fields available in the CALC labor category rate endpoints (/api/idvs/{key}/lcats/, /api/entities/{uei}/lcats/). For filtering, ordering, and pagination, see the CALC Labor Rates API Reference.
Overview¶
CALC (Contract Awarded Labor Category) rates are labor category pricing records sourced from the GSA CALC API. Each record represents a single labor category rate on a GSA MAS (Multiple Award Schedule) contract. The dataset contains approximately 238,000 records.
Primary identifier: uuid (deterministic, derived from the external CALC record ID).
Update Frequency¶
CALC labor rate data is refreshed daily from the GSA CALC API.
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
uuid |
UUID | Deterministic primary key (derived from external CALC ID). | CALC / Tango |
labor_category |
String | Labor category title. | CALC |
current_price |
Decimal | Current hourly rate. | CALC |
education_level |
String | Required education level. | CALC |
min_years_experience |
Integer | Minimum years of experience required. | CALC |
experience_range |
String | Experience range description (e.g., "5-7 years"). | CALC |
security_clearance |
String | Security clearance requirement. | CALC |
worksite |
String | Work location type. | CALC |
sin |
String | Special Item Number. | CALC |
category |
String | Service category. | CALC |
subcategory |
String | Service subcategory. | CALC |
schedule |
String | GSA schedule name. | CALC |
contract_start |
Date | Contract period start date. | CALC |
contract_end |
Date | Contract period end date. | CALC |
Expansions (via shape)¶
idv-- Linked IDV details:key,piid,award_daterecipient-- Entity details via IDV recipient linkage:uei,display_namebusiness_size-- Business size as structuredcode/description(e.g.,{"code": "S", "description": "Small Business"})
The idv and recipient expansions require Pro tier access. The business_size expansion is available on all tiers.
Data Sources¶
- GSA CALC -- Contract Awarded Labor Category API. Provides labor category pricing data from GSA MAS contracts.
Usage Notes¶
- Use
uuidfor unique identification. The UUID is deterministic and stable across data refreshes for the same CALC record. - IDV linkage is best-effort. The
idvexpansion is populated when Tango can match the CALC contract number to an IDV PIID in the awards dataset. - Recipient is derived from the IDV. The
recipientexpansion comes from the linked IDV's recipient entity, not directly from CALC data. - These are nested endpoints. Access rates via
/api/idvs/{key}/lcats/or/api/entities/{uei}/lcats/-- there is no top-level route. - Pro tier required. Both the endpoints and the
idv/recipientexpansions require Pro tier access or above.
Entities Data Dictionary¶
This document describes the fields available in the Entities API endpoints (/api/entities/). For filtering, ordering, and pagination, see the Entities API Reference.
Overview¶
Entities represent vendors and recipients in federal contracting and assistance. The canonical identifier is UEI (Unique Entity ID). Data is sourced from SAM.gov, with supplemental data from DSBS and Tango-calculated obligation metrics.
Identifiers¶
uei(canonical): Public identifier for entities and the API lookup key:GET /api/entities/{uei}/.uuid(internal): Tango's internal UUID primary key for the entity record. This is not intended as a public lookup key; other tables typically reference entities byuei.
Note: The full set of fields is available via the shape query parameter. The base response includes a subset of commonly-used fields. See Response Shaping for details.
Update Frequency¶
Entity data is updated from SAM.gov on a regular sync cadence (typically within 20–60 minutes of SAM changes). Federal obligation rollups are derived from award data.
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
uei |
String | Unique Entity Identifier. Canonical identifier for the entity; use for API lookups and cross-referencing. | SAM.gov |
uuid |
UUID | Internal primary key. Not intended as a public lookup key. | Tango |
display_name |
String | Display name for the entity (e.g., legal name or DBA when useful). | Tango (derived) |
legal_business_name |
String | Official legal business name as registered in SAM. | SAM.gov |
dba_name |
String | "Doing business as" name, when different from legal name. | SAM.gov |
description |
String | Entity description, when available (e.g., from DSBS). | DSBS |
cage_code |
String | Commercial and Government Entity (CAGE) code. 5-character code used in defense and federal contracting. | SAM.gov |
dodaac |
String | Department of Defense Activity Address Code. | SAM.gov |
registered |
String | Whether the entity is registered in SAM (e.g., "Y"/"N"). | SAM.gov |
registration_status |
String | Current SAM registration status (e.g., "Active"). | SAM.gov |
purpose_of_registration_code |
String | Code indicating the primary purpose of SAM registration. | SAM.gov |
purpose_of_registration_desc |
String | Description of the purpose of registration. | SAM.gov |
sam_registration_date |
Date | Date the entity was registered in SAM. | SAM.gov |
sam_expiration_date |
Date | Date the entity's SAM registration expires. | SAM.gov |
sam_activation_date |
Date | Date the entity's SAM registration was activated. | SAM.gov |
last_update_date |
Date | Date the entity record was last updated. | SAM.gov |
email_address |
String | Primary email address on file. | SAM.gov |
entity_url |
String | Entity website or profile URL, when available. | SAM.gov / DSBS |
physical_address |
Object | Physical address. Expand with physical_address(*) for normalized subfields: address_line1, address_line2, city, state_or_province_code, zip_code, zip_code_plus4, country_code, country_name. Keys are always snake_case regardless of data source. |
SAM.gov |
mailing_address |
Object | Mailing address. Same normalized subfields as physical_address. |
SAM.gov |
congressional_district |
String | Congressional district (e.g., for physical location). | SAM.gov |
primary_naics |
String | Primary NAICS code (6-digit). | SAM.gov |
naics_codes |
Array of Objects | NAICS codes. Expand with naics_codes(*) → [{code, sba_small_business}]. Plain string arrays from legacy data are auto-normalized. |
SAM.gov |
psc_codes |
Array of Strings | Product/Service Codes associated with the entity. | SAM.gov |
business_types |
Array of Objects | Business type classifications. Expand with business_types(*) → [{code, description}]. Dict-format data from DSBS is auto-normalized. |
SAM.gov / DSBS |
sba_business_types |
Array of Objects | SBA certifications. Expand with sba_business_types(*) → [{code, description, entry_date, exit_date}]. |
DSBS / SAM.gov |
keywords |
String | Keywords or capability text, when available. | DSBS |
capabilities |
String | Capability narrative, when available. | DSBS |
federal_obligations |
Object (expand-only) | Federal contract obligations. Use federal_obligations(*) → {total, active} or federal_obligations(total). Each sub-object contains awards_obligated, awards_count, idv_count, and (for total) subawards_obligated, subawards_count. |
Tango (derived) |
highest_owner |
Object | Highest-level corporate owner. Expand with highest_owner(*) → {cage_code, legal_business_name, uei}. |
SAM.gov |
immediate_owner |
Object | Immediate parent entity. Expand with immediate_owner(*) → {cage_code, legal_business_name, uei}. |
SAM.gov |
relationships |
Array | Related entities (parent/subsidiary). Expand with relationships(*) → [{relation, type, uei, display_name}]. |
SAM.gov / Tango |
evs_source |
String | Entity validation source (e.g., "E&Y"). | SAM.gov |
uei_status |
String | UEI status (e.g., "Active"). | SAM.gov |
uei_expiration_date |
Date | UEI expiration date, if applicable. | SAM.gov |
uei_creation_date |
Date | UEI creation date, if applicable. | SAM.gov |
public_display_flag |
String | Whether the entity record is publicly visible ("Y"/"N"). | SAM.gov |
exclusion_status_flag |
String | Whether the entity has an active exclusion ("Y"/"N"). | SAM.gov |
exclusion_url |
String | URL for exclusion details, if applicable. | SAM.gov |
entity_division_name |
String | Entity division name. | SAM.gov |
entity_division_number |
String | Entity division number. | SAM.gov |
entity_start_date |
String | Date the entity was started/established. | SAM.gov |
fiscal_year_end_close_date |
String | Fiscal year end close date (e.g., "12/31"). | SAM.gov |
submission_date |
Date | Registration submission date. | SAM.gov |
entity_structure |
Object (expand) | Entity structure. Expand with entity_structure(*) → {code, description}. Description falls back to ENTITY_STRUCTURE_MAP when missing on the model. |
SAM.gov |
entity_type |
Object (expand) | Entity type. Expand with entity_type(*) → {code, description}. |
SAM.gov |
profit_structure |
Object (expand) | Profit structure. Expand with profit_structure(*) → {code, description}. |
SAM.gov |
organization_structure |
Object (expand) | Organization structure. Expand with organization_structure(*) → {code, description}. |
SAM.gov |
state_of_incorporation |
Object (expand) | State of incorporation. Expand with state_of_incorporation(*) → {code, description}. |
SAM.gov |
country_of_incorporation |
Object (expand) | Country of incorporation. Expand with country_of_incorporation(*) → {code, description}. |
SAM.gov |
purpose_of_registration |
Object (expand) | Purpose of registration. Expand with purpose_of_registration(*) → {code, description}. Description falls back to PURPOSE_OF_REGISTRATION_MAP when missing. |
SAM.gov |
Common code values¶
purpose_of_registration_code (SAM.gov)¶
From src/entities/loaders/maps.py:
| Code | Meaning |
|---|---|
Z1 |
Federal Assistance Awards |
Z2 |
All Awards |
Z3 |
IGT-Only |
Z4 |
Federal Assistance Awards & IGT |
Z5 |
All Awards & IGT |
sba_business_types (DSBS / SAM.gov)¶
These are SBA program classifications you'll commonly see (non-exhaustive). From SBA_BUSINESS_TYPE_MAP:
| Code | Meaning |
|---|---|
A0 |
SBA-Certified Economically Disadvantaged Women-Owned Small Business |
A4 |
SBA Certified Small Disadvantaged Business |
A6 |
SBA Certified 8A Program Participant |
A9 |
SBA Certified Woman Owned Small Business |
JT |
SBA Certified 8A Joint Venture |
XX |
SBA Certified Hub Zone Firm |
business_types (SAM.gov)¶
Entities store business types as 2-character codes (e.g., A6, 2R, QF). The canonical list (including certifier) is exposed at /api/business_types/ (see Business Types Data Dictionary).
Expansions (via shape)¶
physical_address / mailing_address¶
Returns the address as an object with normalized snake_case keys:
address_line1,address_line2,city,state_or_province_code,zip_code,zip_code_plus4,country_code,country_name
Address data from different sources (SAM uses snake_case, DSBS uses camelCase) is automatically normalized to the canonical snake_case format above.
business_types¶
Returns a normalized array of {code, description} objects. Raw data may be stored as:
[{code, description}](SAM format — passed through){"2X": true, "F": true}(DSBS format — normalized with description lookups)
sba_business_types¶
Returns a normalized array of {code, description, entry_date, exit_date} objects. Same normalization as business_types.
naics_codes¶
Returns a normalized array of {code, sba_small_business} objects. Plain string arrays (e.g., ["541512", "541511"]) are normalized to [{code: "541512", sba_small_business: null}, ...].
federal_obligations¶
Expand-only field (not available as a leaf). Returns obligation rollups with child fields total and active.
# Both total and active
/api/entities/{uei}/?shape=uei,federal_obligations(*)
# Only total obligations
/api/entities/{uei}/?shape=uei,federal_obligations(total)
Each sub-object structure:
total:{awards_obligated, awards_count, subawards_obligated, subawards_count, idv_count}active:{awards_obligated, awards_count, idv_count}
highest_owner / immediate_owner¶
Returns the corporate owner as {cage_code, legal_business_name, uei}. Supports child field selection.
relationships¶
Returns the list of related entities. Each item can include:
relation,type,uei,display_name
Code/description pair expands¶
The following fields are structured {code, description} expands. When the model's description is missing or empty, the system falls back to a lookup map (where available).
entity_structure(code, description)— falls back toENTITY_STRUCTURE_MAPentity_type(code, description)— falls back toBUSINESS_TYPE_MAPprofit_structure(code, description)— falls back toBUSINESS_TYPE_MAPorganization_structure(code, description)— falls back toBUSINESS_TYPE_MAPstate_of_incorporation(code, description)— uses model descriptioncountry_of_incorporation(code, description)— falls back todjango-genc(GENC country names)purpose_of_registration(code, description)— falls back toPURPOSE_OF_REGISTRATION_MAP
Returns null when the code is null.
# Get entity structure as structured object
/api/entities/{uei}/?shape=uei,entity_structure(*)
# Just the code
/api/entities/{uei}/?shape=uei,entity_structure(code)
Data Sources¶
- SAM.gov – Registration, UEI, legal name, addresses, NAICS/PSC/business types, dates, status, corporate ownership.
- DSBS – Description, capabilities, keywords, SBA business types (when available).
- Tango –
display_name,federal_obligations(derived from award data),relationships.
Usage Notes¶
- Use
ueifor lookups – All entity endpoints accept UEI; it is case-insensitive. - Use
shapefor large responses – Request only the fields you need to reduce payload size. - Scoped award endpoints – Use
/api/entities/{uei}/contracts/,.../idvs/, etc., for awards tied to an entity; see Entities API Reference. - Address key normalization – Address subfields are always returned in snake_case (
address_line1,state_or_province_code,zip_code), regardless of how the data was originally stored. - Business type normalization –
business_types(*)andsba_business_types(*)always return[{code, description, ...}]arrays, even when the source data uses dict format.
Forecasts Data Dictionary¶
This document describes the fields available in the Forecasts API endpoints (/api/forecasts/). For filtering, ordering, and pagination, see the Forecasts API Reference.
Overview¶
Forecasts are upcoming procurement opportunities from agency feeds (e.g., HHS, DHS). They represent anticipated contract actions before they appear as SAM.gov opportunities. Data is normalized from multiple source systems.
Note: The full set of fields is available via the shape query parameter. See Response Shaping for details.
Forecasts we track¶
Tango ingests procurement forecasts from the following agency sources. Filter by agency or source_system in the API (e.g. ?agency=HHS).
- COMMERCE
- DHS
- DOE
- DOI
- DOL
- DOT
- GSA
- HHS
- NRC
- TREASURY
- VA
Update Frequency¶
Forecast data is refreshed according to each agency feed’s cadence (varies by source).
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
id |
Integer | Primary key for the forecast in Tango. | Tango |
source_system |
String | Agency or system that provided the forecast (e.g., "HHS", "DHS"). | Tango |
external_id |
String | Identifier from the source system. | Agency feed |
agency |
String | Agency acronym or name. | Agency feed |
title |
String | Forecast title. | Agency feed |
description |
String | Forecast description. | Agency feed |
anticipated_award_date |
Date | Expected award date. | Agency feed |
fiscal_year |
Integer | Federal fiscal year. | Agency feed / Tango |
naics_code |
String | NAICS code. | Agency feed |
is_active |
Boolean | Whether the forecast is active. | Tango |
status |
String | Status (e.g., active, cancelled). | Agency feed |
created |
DateTime | When the record was created in Tango. | Tango |
modified |
DateTime | When the record was last updated. | Tango |
primary_contact |
Object | Primary contact for the forecast (display-derived). | Agency feed |
place_of_performance |
String | Place of performance (display-derived). | Agency feed |
estimated_period |
String | Estimated period of performance (display-derived). | Agency feed |
set_aside |
String | Set-aside designation (display-derived). | Agency feed |
contract_vehicle |
String | Contract vehicle type (display-derived). | Agency feed |
raw_data |
Object | Raw JSON from the source (expand for full payload). | Agency feed |
Expansions (via shape)¶
display– Normalized display fields:title,description,agency,anticipated_award_date,fiscal_year,naics_code,status,primary_contact,place_of_performance,estimated_period,set_aside,contract_vehicleraw_data– Raw source payload (wildcard fields)
Data Sources¶
- Agency feeds – See Forecasts we track for the full list of source systems (HHS, DHS, GSA, COMMERCE, DOE, TREASURY, DOI, DOL, DOT, VA, NRC).
- Tango –
id,source_system,is_active,created,modified, normalized fields.
Usage Notes¶
- Default shaping – Forecasts now default to the shaping pipeline. All responses render through shaping even without
?shape=. The list shape includes core identity fields; the detail shape addsraw_dataanddisplay(*). - Only active forecasts are returned by default; filter by
agency,fiscal_year,naics_starts_with, orsearchas needed; see Forecasts API Reference.
Grants Data Dictionary¶
This document describes the fields available in the Grants API endpoints (/api/grants/). For filtering, ordering, and pagination, see the Grants API Reference.
Overview¶
Grants are grant opportunities from Grants.gov. Each record is a funding opportunity with grant_id as the primary identifier. Data is sourced from Grants.gov.
Note: The full set of fields is available via the shape query parameter. See Response Shaping for details.
Update Frequency¶
Grant opportunity data is refreshed from Grants.gov on a regular sync cadence.
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
grant_id |
String | Unique identifier for the grant opportunity (Grants.gov). | Grants.gov |
opportunity_number |
String | Opportunity number. | Grants.gov |
agency_code |
String | Funding agency code. | Grants.gov |
status |
Object | Opportunity status. Use expansion for code, description. |
Grants.gov |
title |
String | Grant title. | Grants.gov |
description |
String | Grant description. | Grants.gov |
last_updated |
DateTime | Last updated timestamp. | Grants.gov |
applicant_eligibility_description |
String | Who may apply. | Grants.gov |
funding_activity_category_description |
String | Funding activity category. | Grants.gov |
grantor_contact |
Object | Grantor contact info (expand for subfields). | Grants.gov |
forecast |
Object | Forecast data associated with the grant, if any. | Grants.gov |
synopsis |
Object | Synopsis data for the grant opportunity. | Grants.gov |
opportunity_history |
Array | History of changes to the opportunity. | Grants.gov |
Common code values¶
These are the most important “code → meaning” mappings used in grants data (see src/grants/lib/maps.py).
status¶
| Code | Meaning |
|---|---|
P |
Posted |
F |
Forecasted |
category¶
| Code | Meaning |
|---|---|
A |
Mandatory |
B |
Continuation |
C |
Earmark |
D |
Discretionary |
E |
Discretionary Cooperative Agreement |
O |
Other |
funding_instruments (examples)¶
| Code | Meaning |
|---|---|
G |
Grant |
CA |
Cooperative Agreement |
PC |
Procurement Contract |
L |
Loan Guarantee |
D |
Direct Payment |
O |
Other |
applicant_types and funding_categories are also coded lists (Grants.gov standard taxonomies); the canonical enumerations are large and are best treated as reference data rather than memorized.
Expansions (via shape)¶
cfda_numbers– List of CFDA numbers:number,titleapplicant_types–code,descriptioncategory–code,descriptionfunding_categories–code,descriptionfunding_instruments–code,descriptionimportant_dates–posted_date,response_date,response_date_description,estimated_synopsis_post_date,estimated_application_response_date,estimated_application_response_date_description,estimated_project_start_date(fields vary by opportunity status)funding_details–award_ceiling,award_floor,estimated_total_funding,expected_number_of_awardsgrantor_contact–name,phone,emailadditional_info–link,descriptionattachments–mime_type,name,posted_date,resource_id,type,url
Data Sources¶
- Grants.gov – Grant opportunities, CFDA linkage, contacts, attachments.
Usage Notes¶
- Default shaping – Grants now default to the shaping pipeline. All responses render through shaping even without
?shape=. The list shape includes core fields; the detail shape adds all expanded objects. - Use
grant_idfor lookups. Filter byagency,status, or other params; see Grants API Reference.
Opportunities
Opportunities Data Dictionary¶
This document describes the fields available in the Opportunities API endpoints (/api/opportunities/). For filtering, ordering, and pagination, see the Opportunities API Reference.
Overview¶
Opportunities represent SAM.gov contract opportunity notices aggregated by parent opportunity (one opportunity can have multiple notices over time). Each opportunity has an opportunity_id. Data is sourced from SAM.gov.
Note: The full set of fields is available via the shape query parameter. See Response Shaping for details.
Update Frequency¶
Opportunity data is refreshed from SAM.gov on a regular sync cadence (typically 20–60 minutes).
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
opportunity_id |
UUID | Primary identifier for the opportunity in Tango (parent notice). | Tango / SAM.gov |
latest_notice_id |
UUID | The Tango notice_id of the latest notice associated with this opportunity (when available). |
Tango |
active |
Boolean | Whether the opportunity is active. | Tango (derived) |
archive_date |
DateTime | Archive date for the opportunity (derived from SAM.gov notice archive metadata when present). | Tango / SAM.gov |
agency_id |
String | Agency code associated with the opportunity (when available). | Tango / SAM.gov |
award_number |
String | Award number when awarded. | SAM.gov |
department_id |
String | Department code associated with the opportunity (when available). | Tango / SAM.gov |
description |
String | Opportunity description (from latest notice). | SAM.gov |
first_notice_date |
DateTime | First notice date. | SAM.gov |
last_notice_date |
DateTime | Last notice date. | SAM.gov |
meta |
Object | Metadata: notices_count, attachments_count, notice_type. Use expansion for subfields. |
Tango |
naics_code |
String | NAICS code. | SAM.gov |
office |
Object | Contracting office. Use expansion for office_code, office_name, agency_code, agency_name, department_code, department_name. |
SAM.gov |
office_id |
String | Office code associated with the opportunity (when available). | Tango / SAM.gov |
place_of_performance |
Object | Place of performance. Use expansion for street_address, city, state, zip, country. |
SAM.gov |
primary_contact |
Object | Primary contact (expand for subfields). | SAM.gov |
secondary_contact |
Object | Secondary contact. | SAM.gov |
psc_code |
String | Product/Service Code. | SAM.gov |
response_deadline |
DateTime | Response deadline. | SAM.gov |
sam_url |
String | Canonical SAM.gov opportunity URL. | Tango (derived) |
set_aside |
String | Set-aside code. Use expansion set_aside(code,description) for the structured form. |
SAM.gov |
solicitation_number |
String | Solicitation number. | SAM.gov |
title |
String | Opportunity title (from latest notice). | SAM.gov |
Expansions (via shape)¶
attachments–attachment_id,mime_type,name,posted_date,resource_id,type,url(and optionallyextracted_textwhen enabled)office– office and agency fieldsagency–code,name,abbreviationdepartment–code,name,abbreviation,description,cgac,website,congressional_justificationlatest_notice–notice_id,linkplace_of_performance– address fieldsmeta–notices_count,attachments_count,notice_type(with nestednotice_type(code, type))
Notice type codes¶
Opportunities and notices classify the notice “type” using a short code. These values come from SAM.gov and Tango’s loader mapping (src/opportunities/lib/maps.py):
| Code | Meaning |
|---|---|
a |
Award Notice |
g |
Sale of Surplus Property |
i |
Consolidate/(Substantially) Bundle |
j |
Justification and Approval (J&A) |
k |
Combined Synopsis/Solicitation |
l |
Fair Opportunity / Limited Sources Justification (deprecated) |
m |
Modification/Amendment/Cancel |
o |
Solicitation |
p |
Pre solicitation |
r |
Sources Sought |
s |
Special Notice |
u |
Justification (J&A) |
Data Sources¶
- SAM.gov – Contract opportunity notices, offices, contacts, attachments.
- Tango –
opportunity_id, aggregation,sam_url,active.
Usage Notes¶
- Use
opportunity_idfor API references. Usesam_urlfor linking to SAM.gov. - Notices: For individual notice-level data, use
/api/notices/; see Notices API Reference and Notices Data Dictionary.
Notices Data Dictionary¶
This document describes the fields available in the Notices API endpoints (/api/notices/). For filtering, ordering, and pagination, see the Notices API Reference.
Overview¶
Notices are individual SAM.gov contract opportunity notices. Each notice has a notice_id (UUID). An opportunity can have multiple notices (e.g., amendments); notices are the versioned records. Data is sourced from SAM.gov.
Note: The full set of fields is available via the shape query parameter. See Response Shaping for details.
Update Frequency¶
Notice data is refreshed from SAM.gov on a regular sync cadence (typically 20–60 minutes).
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
notice_id |
UUID | Primary identifier for the notice in Tango. | Tango / SAM.gov |
active |
Boolean | Whether the notice is active (not archived/cancelled/deleted). | Tango (derived) |
address |
Object | Notice address. Use expansion for city, state, zip, country. |
SAM.gov |
attachments |
Array | Attachments. Use expansion for attachment_id, mime_type, name, posted_date, resource_id, type, url (and optionally extracted_text when enabled). |
SAM.gov |
attachment_count |
Integer | Number of attachments. | Tango (derived) |
description |
String | Notice description. | SAM.gov |
last_updated |
DateTime | Last modified. | SAM.gov |
meta |
Object | parent_notice_id, related_notice_id, notice_type, link. Use expansion for subfields; notice_type has code, type. |
Tango |
naics_code |
String | NAICS code. | SAM.gov |
office |
Object | Contracting office. Use expansion for office/agency/department fields. | SAM.gov |
opportunity |
Object | Parent opportunity reference. | Tango |
opportunity_id |
UUID | The Tango opportunity_id of the parent opportunity (when available). |
Tango |
place_of_performance |
Object | Place of performance. Use expansion for street_address, city, state, zip, country. |
SAM.gov |
posted_date |
DateTime | Posted date. | SAM.gov |
psc_code |
String | Product/Service Code (classification_code). | SAM.gov |
response_deadline |
DateTime | Response deadline. | SAM.gov |
sam_url |
String | Canonical SAM.gov notice URL. | Tango (derived) |
set_aside |
String | Set-aside description. Use expansion set_aside(code,description) for the structured form. |
SAM.gov |
solicitation_number |
String | Solicitation number. | SAM.gov |
title |
String | Notice title. | SAM.gov |
Expansions (via shape)¶
attachments,address,archive,place_of_performance,primary_contact(fields:title,full_name,email,phone,fax),secondary_contact,meta(withnotice_type(code, type)),office,opportunity,set_aside(code,description)
Notice type codes¶
Notices classify the notice “type” using a short code. These values come from SAM.gov and Tango’s loader mapping (src/opportunities/lib/maps.py):
| Code | Meaning |
|---|---|
a |
Award Notice |
g |
Sale of Surplus Property |
i |
Consolidate/(Substantially) Bundle |
j |
Justification and Approval (J&A) |
k |
Combined Synopsis/Solicitation |
l |
Fair Opportunity / Limited Sources Justification (deprecated) |
m |
Modification/Amendment/Cancel |
o |
Solicitation |
p |
Pre solicitation |
r |
Sources Sought |
s |
Special Notice |
u |
Justification (J&A) |
Data Sources¶
- SAM.gov – Notice records, offices, contacts, attachments.
- Tango –
notice_id,active,attachment_count,meta,sam_url,opportunity.
Usage Notes¶
- Use
notice_idfor notice lookups. For the parent opportunity useopportunityor the Opportunities API Reference; see Opportunities Data Dictionary and Notices API Reference.
Protests Data Dictionary¶
This document describes the fields available in the Protests API endpoints (/api/protests/). For filtering, ordering, and pagination, see the Protests API Reference.
Overview¶
Protests are bid protest records from GAO, with schema support for additional protest venues in the future. The API exposes a narrow set of client-facing fields. Source ingest payload details and internal fields (e.g. external_id, data_quality) are not exposed.
Authentication: Protests endpoints require authentication (API key or OAuth2).
Date range: The API only serves protests from 2015 onward. Pre-2015 records exist in the database but are not available through the API.
Note: Both list and detail endpoints return case-level objects. Each case is identified by case_id (a deterministic UUID from source_system + base_case_number). Detail lookup uses case_id in the URL path: GET /api/protests/{case_id}/. Use ?shape=...,dockets(...) to expand nested docket records. The default (unshaped) response does not include dockets.
Update Frequency¶
GAO protest data is refreshed by loader schedule and available source files.
Fields (API response)¶
Only the following fields are returned in list and detail responses (and are available via shape):
| Field | Type | Description | Source |
|---|---|---|---|
case_id |
UUID | Deterministic case UUID derived from source_system + base_case_number. Use for detail lookup: GET /api/protests/{case_id}/. |
Tango |
source_system |
String | Source venue identifier (for example gao). |
Tango |
case_number |
String | Base case for grouping sub-dockets (for example b-424214 from B-424214.1). Model field: base_case_number. Use with decision_date for decision-level counting. |
Derived |
docket_number |
String | Source docket identifier (for example b-424214.1, b-424214.2). Model field: case_number. Only available inside the dockets(...) expansion. Use to distinguish sub-dockets under the same case_number. |
Source |
title |
String | Protest title. | Source |
protester |
String | Protester name. | Source |
agency |
String | Protested agency. | Source |
solicitation_number |
String | Solicitation number when provided. | Source |
case_type |
String | Protest case type. | Source |
outcome |
String | Protest outcome, when available. | Source |
filed_date |
Date | Date the protest was filed. | Source |
posted_date |
Date | Date the protest was posted. | Source |
decision_date |
Date | Decision date, when available. | Source |
due_date |
Date | Protest due date, when available. | Source |
docket_url |
String | Source docket URL. | Source |
decision_url |
String | Source decision URL, when available. | Source |
Opt-in via shape only: digest — when requested with ?shape=...,digest, the value from raw_data.digest (e.g. decision summary text) is returned. Not included in the default list/detail response.
Resolution Fields (shape expansions)¶
Protests support entity and organization resolution via the Bayesian resolver. These fields are available as shape expansions and return null when no confident match exists.
resolved_protester(...) — Entity Resolution¶
| Field | Type | Description |
|---|---|---|
uei |
String | Unique Entity Identifier of the matched entity. |
name |
String | Display name of the matched entity. |
match_confidence |
String | "confident" (high confidence, auto-linkable) or "review" (medium confidence, needs human review). |
rationale |
String | Human-readable explanation (e.g. "Exact name match", "Similar name match; multiple entities share this name"). |
resolved_agency(...) — Organization Resolution¶
| Field | Type | Description |
|---|---|---|
key |
String (UUID) | UUID primary key of the matched organization in Tango. |
name |
String | Display name of the matched organization. |
match_confidence |
String | "confident" or "review". |
rationale |
String | Human-readable explanation (e.g. "Exact name match; parent agency confirmed"). |
Confidence mapping: Internal resolution tiers map to public labels as follows: high → "confident", medium → "review". Low-confidence and no-match results are excluded (return null).
The following are not exposed in the API: external_id, data_quality, source_last_updated, created, modified, raw_data, field_provenance.
Data Quality (internal)¶
Every protest record has an internal data_quality tier (not exposed in the API response). Records with quarantined or unknown quality are always excluded from API responses. The reprocess_protest_quality management command recomputes quality internally.
Shaping¶
Both list and detail return case-level objects. shape lets you request a subset of fields. Use the dockets(...) expansion to include nested docket records.
Allowed shape fields (case-level):
case_id,source_system,case_number,title,protester,agencysolicitation_number,case_type,outcomefiled_date,posted_date,decision_date,due_datedocket_url,decision_urldigest(fromraw_data.digest; opt-in only)dockets(expand with docket fields, e.g.dockets(case_number,docket_number,filed_date))resolved_protester(expand:uei,name,match_confidence,rationale)resolved_agency(expand:key,name,match_confidence,rationale)
Inside dockets(...), these additional fields are available:
docket_number(specific sub-docket identifier, e.g.b-424214.1)
Examples:
# List: case-level and nested dockets
GET /api/protests/?shape=case_id,case_number,title,dockets(docket_number,filed_date,outcome)
# List: case-level only
GET /api/protests/?shape=case_id,title,outcome,decision_date
# Detail with nested dockets
GET /api/protests/{case_id}/?shape=case_id,title,dockets(docket_number,filed_date)
raw_data and field-level provenance metadata are internal-only and not exposed in API responses.
Data Sources¶
- GAO – primary source for protest records.
- Tango –
case_id(deterministic case UUID) and normalized API behavior.
Reference data
Assistance Listings (CFDA) Data Dictionary¶
This document describes the fields available in the Assistance Listings API endpoints (/api/assistance_listings/). For filtering, ordering, and pagination, see the Assistance Listings API Reference.
Overview¶
Assistance listings are CFDA (Catalog of Federal Domestic Assistance) program codes used for federal grants and assistance. Each listing has a number (e.g., "84.027") and title. This is reference data, not the assistance transactions endpoint. Data is sourced from USAspending reference files.
Note: This endpoint supports response shaping via the shape query parameter. On list requests, the default shape is number,title. Detail responses use the full serializer when no ?shape= is provided.
Update Frequency¶
Assistance listing reference data is updated when USAspending CFDA reference data is refreshed (periodic).
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
number |
String | CFDA program number (primary key; digits and dots, e.g., "84.027"). | USAspending |
title |
String | Program title. | USAspending |
popular_name |
String | Popular or common name, when available. | USAspending |
objectives |
Text | Program objectives. | USAspending |
applicant_eligibility |
Text | Applicant eligibility description. | USAspending |
benefit_eligibility |
Text | Benefit eligibility description. | USAspending |
published_date |
Date | Date published. | USAspending |
archived_date |
Date | Date archived, when applicable. | USAspending |
Data Sources¶
- USAspending – CFDA reference data (e.g., cfda.csv).
Usage Notes¶
- Use
numberfor lookups. Detail at/api/assistance_listings/{number}/(number supports digits and.). This endpoint is for the reference list only; for assistance transactions use the assistance/awards endpoints; see Assistance Listings API Reference.
Business Types Data Dictionary¶
This document describes the fields available in the Business Types API endpoints (/api/business_types/). For filtering, ordering, and pagination, see the Business Types API Reference.
Overview¶
Business types are SAM.gov codes that classify entities (e.g., small business, 8(a), HUBZone). Each type has a code and name. Data is sourced from SAM.gov.
Note: This endpoint supports response shaping via the shape query parameter. Default shape: name,code.
Update Frequency¶
Business type reference data is updated when SAM.gov reference data is refreshed (periodic).
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
code |
String | SAM code for the business type (e.g., 2-character). | SAM.gov |
name |
String | Human-readable business type name. | SAM.gov |
certifier |
String | Certifier for the business type (e.g., SBA). | SAM.gov |
Value formats and common values¶
code: 2-character alphanumeric, typically uppercase (examples:A6,JT,XX,2R). This is what entities store inbusiness_types.certifier: Who “owns” / attests the classification. In practice you’ll see a small set of values:SBA: SBA-certified programs (e.g., 8(a), HUBZone, WOSB variants).AbilityOne: AbilityOne nonprofit agency classification.Government: Government-entity classifications (federal/state/local/tribal/foreign).Self: Self-reported classifications in SAM (ownership/demographic/org-type, etc.).
If you need the full canonical list in one place, the /api/business_types/ endpoint is the source of truth.
Data Sources¶
- SAM.gov – Business type codes and names.
Usage Notes¶
- Use
codefor lookups. List and detail at/api/business_types/and/api/business_types/{code}/; see Business Types API Reference.
MAS SINs Data Dictionary¶
This document describes the fields available in the MAS SINs API endpoints (/api/mas_sins/). For filtering, ordering, and pagination, see the MAS SINs API Reference.
Overview¶
MAS SINs (Special Item Numbers) are GSA schedule line items used to categorize offerings under the MAS schedule. Tango stores SINs as reference data so other datasets (e.g. GSA eLibrary enrichment) can store only SIN codes and join to this table for details.
Note: This endpoint supports response shaping via the shape query parameter. Default shape includes all 15 fields.
Update Frequency¶
This data is updated by re-running the loader command against the repo-tracked CSV:
- Management command:
load_mas_sins - Source file:
src/api/data/mas_sins.csv
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
sin |
String | Special Item Number code. Primary key. | GSA MAS SIN export |
large_category_code |
String (1 char) | Large category code (e.g., A). |
GSA MAS SIN export |
large_category_name |
String | Large category name (e.g., Office Management). |
GSA MAS SIN export |
sub_category_code |
String | Subcategory code (e.g., A01). |
GSA MAS SIN export |
sub_category_name |
String | Subcategory name (e.g., Audio Visual Products). |
GSA MAS SIN export |
psc_code |
String | null | PSC code from source (4 chars, may be alphanumeric). | GSA MAS SIN export |
state_local |
Boolean | Whether SIN is eligible for state/local/cooperative purchasing. | GSA MAS SIN export |
set_aside_code |
String (1 char) | null | One of Y, N, B. |
GSA MAS SIN export |
service_comm_code |
String (1 char) | null | One of B, C, S, P. |
GSA MAS SIN export |
expiration_date |
Date | null | Parsed from a 7-digit YYYYDDD numeric format when present. |
GSA MAS SIN export |
tdr |
Boolean | TDR flag (Y/N in source). |
GSA MAS SIN export |
olm |
Boolean | OLM flag (Y/N in source). |
GSA MAS SIN export |
naics_codes |
List[Integer] | NAICS codes associated with the SIN. | GSA MAS SIN export |
title |
String | SIN title (normalized to remove leading SIN code prefix). | GSA MAS SIN export |
description |
String | null | SIN description (normalized to remove leading SIN code prefix). | GSA MAS SIN export |
Category codes and names¶
The MAS SIN dataset includes a small, stable hierarchy:
- Large category:
large_category_code+large_category_name - Subcategory:
sub_category_code+sub_category_name
For convenience, here is the full mapping present in src/api/data/mas_sins.csv.
Large categories¶
| Code | Name |
|---|---|
A |
Office Management |
B |
Facilities |
C |
Furniture and Furnishings |
D |
Human Capital |
E |
Professional Services |
F |
Information Technology |
G |
Miscellaneous |
H |
Scientific Management and Solutions |
I |
Industrial Products and Services |
J |
Security and Protection |
K |
Transportation and Logistics Services |
L |
Travel |
Subcategories¶
| Large category code | Subcategory code | Subcategory name |
|---|---|---|
A |
A01 |
Audio Visual Products |
A |
A02 |
Audio Visual Services |
A |
A03 |
Document Services |
A |
A04 |
Mail Management |
A |
A05 |
Office Management Maintenance and Repair |
A |
A06 |
Media Products |
A |
A07 |
Media Services |
A |
A08 |
Office Services |
A |
A09 |
Office Supplies |
A |
A10 |
Printing and Photographic Equipment |
A |
A11 |
Records Management |
B |
B01 |
Facilities Maintenance and Repair |
B |
B02 |
Facilities Services |
B |
B03 |
Facilities Solutions |
B |
B04 |
Facilities Supplies |
B |
B05 |
Food Service Equipment |
B |
B06 |
Structures |
C |
C01 |
Flooring |
C |
C02 |
Furniture Services |
C |
C03 |
Healthcare Furniture |
C |
C04 |
Household Dormitory and Quarters Furniture |
C |
C05 |
Miscellaneous Furniture |
C |
C06 |
Office Furniture |
C |
C07 |
Packaged Furniture |
C |
C08 |
Signs |
D |
D01 |
Background Investigations |
D |
D02 |
Compensation and Benefits |
D |
D03 |
Human Resources |
D |
D04 |
Social Services |
E |
E01 |
Business Administrative Services |
E |
E02 |
Environmental Services |
E |
E03 |
Financial Services |
E |
E04 |
Identity Protection Services |
E |
E05 |
Language Services |
E |
E06 |
Legal Services |
E |
E07 |
Logistical Services |
E |
E08 |
Marketing and Public Relations |
E |
E09 |
Technical and Engineering Services (non- IT) |
E |
E10 |
Training |
F |
F01 |
Electronic Commerce |
F |
F02 |
IT Hardware |
F |
F03 |
IT Services |
F |
F04 |
IT Software |
F |
F05 |
IT Solutions |
F |
F06 |
IT Training |
F |
F07 |
Telecommunications |
G |
G01 |
Apparel |
G |
G02 |
Awards |
G |
G03 |
Flags |
G |
G04 |
Musical Instruments |
G |
G05 |
Personal Hair Care Items |
G |
G06 |
Complementary SINs |
H |
H01 |
Laboratory Animals |
H |
H02 |
Laboratory Equipment |
H |
H03 |
Medical Equipment |
H |
H04 |
Scientific Services |
H |
H05 |
Search and Navigation |
H |
H06 |
Testing and Analysis |
I |
I01 |
Cleaning Supplies |
I |
I02 |
Fire/Rescue/Safety/Environmental Protection Equipment |
I |
I03 |
Fuel Management |
I |
I04 |
Hardware and Tools |
I |
I05 |
Industrial Products |
I |
I06 |
Industrial Products and Services Maintenance and Repair |
I |
I07 |
Machinery and Components |
I |
I08 |
Packaging |
I |
I09 |
Test and Measurement Supplies |
J |
J01 |
Marine and Harbor |
J |
J02 |
Protective Equipment |
J |
J03 |
Security Animals and Related Services |
J |
J04 |
Security Services |
J |
J05 |
Security Systems |
J |
J06 |
Testing Equipment |
K |
K01 |
Automotive Body Maintenance and Repair |
K |
K02 |
Motor Vehicles (non-Combat) |
K |
K03 |
Package Delivery |
K |
K04 |
Packaging Services |
K |
K05 |
Transportation of Things |
L |
L01 |
Employee Relocation |
L |
L02 |
Lodging |
L |
L03 |
Travel Agent and Misc. Services |
Data sources¶
- GSA eLibrary reference export (
yoni/MAS_Schedule-SIN.csv), normalized intosrc/api/data/mas_sins.csv.
NAICS Data Dictionary¶
This document describes the fields available in the NAICS API endpoints (/api/naics/). For filtering, ordering, and pagination, see the NAICS API Reference.
External references¶
Overview¶
NAICS (North American Industry Classification System) codes are industry classification codes used in federal contracting. Each code has a numeric code (primary key) and description. Detail responses also include SBA size standards and obligation rollups.
Note: This endpoint supports response shaping via the shape query parameter. On list requests, the default shape is code,description. Detail requests and ?show_limits=1 default to code,description,size_standards(*),federal_obligations(*). The legacy ?show_limits=1 parameter is still accepted but shaping is preferred.
Update Frequency¶
NAICS reference data is updated when size standards or code lists are refreshed (periodic).
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
code |
Integer | NAICS code (primary key). | NAICS / SBA |
description |
String | NAICS industry description. | NAICS / SBA |
size_standards |
Expansion | SBA size standards for this NAICS. Expand with size_standards(employee_limit,revenue_limit) or size_standards(*). revenue_limit is in whole dollars. Included in detail/show_limits default shape. |
SBA |
federal_obligations |
Expansion | Obligation rollups for this NAICS. Expand with federal_obligations(total,active) or federal_obligations(*). Each sub-object has awards_obligated (float) and awards_count (int). Included in detail/show_limits default shape. |
Tango (derived from awards) |
Metrics: Time-series obligation metrics are available at /api/naics/{code}/metrics/<months>/<period_grouping>/; see Metrics.
Data Sources¶
- NAICS / SBA – Code descriptions and size standards.
- Tango –
year, obligation rollups (via metrics endpoint).
Usage Notes¶
- NAICS codes are hierarchical — 2-digit sector, 3-digit subsector, up to 6-digit national industry codes.
- Use
searchfor text-based lookup; usecodefor exact match. Filter bysearch,revenue_limit,employee_limit; see NAICS API Reference. - Size standards and federal obligations are available as shaping expansions. Expand with
size_standards(*)orfederal_obligations(*); see Response Shaping. - NAICS codes are updated periodically by the Census Bureau. Tango reflects the current revision.
Organizations Data Dictionary¶
This document describes the fields available in the Organizations API endpoint (/api/organizations/). For filtering, ordering, and pagination, see the Organizations API Reference.
Overview¶
The Organizations resource provides a unified view of federal government organizations, consolidating data from multiple authoritative sources into a single hierarchical structure. Organizations include departments, agencies, sub-agencies, and offices.
Note: The full set of fields is available via the shape query parameter. Without a ?shape= parameter, a default shape is applied. See Response Shaping for details.
Update Frequency¶
All organization data is updated monthly via the sync_organizations management command.
Default Shape¶
All responses go through the shaping pipeline. When no ?shape= parameter is provided, the following fields are returned:
key, fh_key, name, short_name, type, level, is_active, code, fpds_code, cgac, canonical_code, parent_fh_key, full_parent_path_name
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
key |
UUID | Tango's internal UUID primary key for the organization record. Returned in shaped responses, but the Organizations API uses fh_key for lookups. |
Tango |
fh_key |
String | Zero-padded 9-character string representation of the Federal Hierarchy orgKey (e.g., "000000001"). Used for detail lookups: GET /api/organizations/{fh_key}/. Accepts both zero-padded and plain integer forms in URLs. Practically unique for "current" org lookups, but not guaranteed to be globally unique across all historical snapshots (Tango stores historical org versions separately). |
Federal Hierarchy (SAM.gov) |
name |
String | The full official name of the organization (e.g., "Federal Emergency Management Agency"). | Federal Hierarchy (SAM.gov) |
short_name |
String | The abbreviated or common name of the organization (e.g., "FEMA", "DHS"). | Federal Hierarchy (SAM.gov) |
type |
String | The organizational type within the federal hierarchy (e.g., "DEPARTMENT", "AGENCY", "OFFICE"). | Federal Hierarchy (SAM.gov) |
level |
Integer | The depth level in the organizational hierarchy. Level 1 represents top-level departments, with higher numbers indicating deeper nesting. | Federal Hierarchy (SAM.gov) |
cgac |
String | Common Government-wide Accounting Classification code. A 3-character code used for financial reporting (e.g., "069" for Department of Transportation). | USAspending |
fpds_code |
String | Federal Procurement Data System code. A 4-digit agency identifier used in contract transactions. | USAspending |
code |
String | Office or agency code. Used to identify specific offices within agencies, particularly in contract and financial assistance transactions. | Federal Hierarchy / USAspending |
canonical_code |
String | Level-prefixed canonical code combining hierarchy level and the appropriate code type (e.g., "L1:097" for a department, "L2:5700" for an agency). |
Calculated |
fpds_org_id |
String | The FPDS organization identifier, when available. | FPDS |
aac_code |
String | Activity Address Code, used in some procurement and financial transactions. | Federal Hierarchy (SAM.gov) |
is_active |
Boolean | Indicates whether the organization is currently active. Derived from the mod_status field in Federal Hierarchy. |
Federal Hierarchy (SAM.gov) |
parent_fh_key |
String | Zero-padded 9-character fh_key of this organization's parent. Null for top-level departments. |
Federal Hierarchy (SAM.gov) |
full_parent_path_name |
String | A human-readable path showing the full hierarchy from the top-level department to this organization, separated by " > " (e.g., "Department of Homeland Security > Federal Emergency Management Agency"). | Federal Hierarchy (SAM.gov) |
l1_fh_key .. l8_fh_key |
String | Zero-padded 9-character fh_key of the ancestor at each hierarchy level (L1 through L8). Null when no ancestor exists at that level. |
Federal Hierarchy (SAM.gov) |
start_date |
Date | The date the organization became active in the Federal Hierarchy. | Federal Hierarchy (SAM.gov) |
end_date |
Date | The date the organization was deactivated, if applicable. | Federal Hierarchy (SAM.gov) |
logo |
String | URL to the organization's logo, when available. | Various |
summary |
String | Short description or mission summary for the organization. | Federal Hierarchy (SAM.gov) |
mod_status |
String | The modification status of the organization in the Federal Hierarchy (e.g., "ACTIVE", "INACTIVE"). | Federal Hierarchy (SAM.gov) |
description |
String | A description of the organization's mission or purpose, when available. | Federal Hierarchy (SAM.gov) |
obligations |
Float | Total federal contract and financial assistance obligations associated with this organization and all its descendants (rolled up from the entire subtree). Alias for tree_obligations. Expressed in US dollars. |
USAspending |
total_obligations |
Float | Direct obligations for this specific organization (not rolled up from descendants). Expressed in US dollars. | USAspending |
tree_obligations |
Float | Total obligations for this organization's entire subtree (the organization plus all descendants). Expressed in US dollars. | USAspending |
obligation_rank |
Integer | A percentile ranking (1-100) of this organization's obligations relative to other organizations. Higher values indicate larger obligation amounts. | Calculated |
Usage Notes¶
- The Organizations API lookup key is
fh_key(Federal HierarchyorgKey), returned as a zero-padded 9-character string. - The
fh_keyis intended for "current" lookups, but it is not a stable globally-unique identifier across all historical snapshots/versions. - If you need to track historical versions, use the internal
key(UUID) plus timestamps/versions (Tango stores org history separately).
Organization Types¶
Organization types define the position of an organization within the federal hierarchy. Each type corresponds to a specific hierarchy level:
| Type | Level | Description |
|---|---|---|
DEPARTMENT |
1 | Top-level federal departments (e.g., Department of Defense, Department of Health and Human Services) |
AGENCY |
2 | Major sub-components of departments (e.g., Department of the Army, Food and Drug Administration) |
SUBTIER AGENCY |
2 | Alternative designation for level-2 agencies in USAspending data |
MAJOR COMMAND |
2 | Military major command (e.g., Army Materiel Command) |
SUB COMMAND |
3 | Military sub-command within a major command |
OFFICE |
3+ | Sub-agencies, bureaus, and offices at various depths within the hierarchy |
Expansions¶
The following expansions are available via the shape query parameter to include related data:
parent¶
Returns the immediate parent organization with the following fields:
keyfh_key(zero-padded)nameshort_nametypelevelis_activecodecgac
ancestors¶
Returns a list of all ancestor organizations from the top-level department down to the immediate parent. Each ancestor includes:
fh_key(zero-padded)nameshort_namelevel
children¶
Returns a list of immediate child organizations (prefetched for performance). Each child includes:
keyfh_key(zero-padded)nameshort_nametypelevelis_activecodecgac
department¶
Returns the L1 (department-level) ancestor formatted as a legacy-compatible department object. Returns null for level 1 organizations (a department doesn't have a department — it is one).
code— the department's CGAC codename— the department's full nameabbreviation— the department's short name / abbreviation
agency¶
Returns the L2 (agency-level) ancestor formatted as a legacy-compatible agency object. Returns null for level 1 and 2 organizations (no agency above them).
code— the agency's FPDS codename— the agency's full nameabbreviation— the agency's short name (resolved via cached lookup)
Data Sources¶
Organization data is consolidated from multiple authoritative sources with a priority-based system:
-
Federal Hierarchy (SAM.gov) - The authoritative source for federal organization structure. Provides the canonical hierarchy, names, and parent-child relationships.
-
USAspending - Supplements Federal Hierarchy with operational codes (CGAC, FPDS codes) and obligation data that appear in financial transactions.
-
Legacy FPDS - Historical organization data from the Federal Procurement Data System, used to backfill organizations that appear in contract transactions but are missing from current reference sources.
Higher-priority sources are never overwritten by lower-priority ones, ensuring that Federal Hierarchy's authoritative structure is preserved while other sources fill in the gaps.
Example Response¶
The following example shows a default response (no ?shape= parameter):
{
"key": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"fh_key": "100012345",
"name": "Federal Emergency Management Agency",
"short_name": "FEMA",
"type": "AGENCY",
"level": 2,
"is_active": true,
"code": "7022",
"fpds_code": "7022",
"cgac": "070",
"canonical_code": "L2:7022",
"parent_fh_key": "100000123",
"full_parent_path_name": "Department of Homeland Security > Federal Emergency Management Agency"
}
The following example shows a shaped response with legacy-compatible expands:
/api/organizations/?shape=fh_key,name,type,department(code,name),agency(code,name,abbreviation)&level=3
{
"fh_key": "047020017",
"name": "FA8219 AFLCMC EGLIN",
"type": "OFFICE",
"department": {
"code": "097",
"name": "DEPT OF DEFENSE"
},
"agency": {
"code": "5700",
"name": "DEPT OF THE AIR FORCE",
"abbreviation": "USAF"
}
}
Usage Notes¶
- Use
fh_keyfor API lookups — The Organizations API usesfh_keyin the detail URL:GET /api/organizations/{fh_key}/. Thefh_keyis returned as a zero-padded 9-character string (e.g.,"000000001"). - Use
keyas an internal identifier —keyis Tango's internal UUID primary key and may be useful for internal joins/debugging. - Use code lookups for transaction matching — When matching contract or financial assistance transactions, use the specific code type (
cgac,fpds_code,code) that appears in your source data. - Use the
searchparameter for discovery — The/api/organizations/?search=endpoint handles abbreviations, acronyms, typos, and contextual queries (e.g., "Treasury OIG"). - Level behavior for
department/agencyexpands — Thedepartmentexpand is defined for level 2+ orgs; theagencyexpand is defined for level 3+ orgs. When these expands are requested on orgs below the applicable level, the corresponding field is included in the response asnull(no error is raised). Filter bylevelif you want to avoidnullvalues in list responses.
Product and Service Code (PSC) Data Dictionary¶
This document describes the fields available in the Product and Service Code (PSC) API endpoints (/api/psc/). For filtering, ordering, and pagination, see the PSC API Reference.
External references¶
Overview¶
Product and Service Codes (PSC) classify products and services in federal contracting. Each code has a code (string) and a current description; historical descriptions are available when requesting a “complete” representation.
Note: This endpoint supports response shaping via the shape query parameter. Expansions include current(...) for the active description and historical(...) for all descriptions.
Update Frequency¶
PSC reference data is updated when the PSC Manual or Tango loaders are refreshed (periodic).
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
code |
String | PSC code (primary key). | PSC Manual |
current |
Object | Full current description record (name, description, dates, includes/excludes). Present on list/detail responses. |
PSC Manual |
historical |
Array | Historical descriptions. Present only when ?complete=true. |
PSC Manual |
parent |
String | Parent PSC code in hierarchy. | PSC Manual |
category |
String | Category (e.g., S Service, P Product). |
PSC Manual |
level_1_category |
String | Level 1 category name. | PSC Manual |
level_1_category_code |
Integer | Level 1 category code. | PSC Manual |
level_2_category |
String | Level 2 category name. | PSC Manual |
level_2_category_code |
String | Level 2 category code. | PSC Manual |
Metrics: Time-series obligation metrics are available at /api/psc/{code}/metrics/<months>/<period_grouping>/; see Metrics.
Data Sources¶
- PSC Manual (acquisition.gov) – Code definitions, descriptions, hierarchy.
- Tango – Obligation rollups (via metrics endpoint).
Usage Notes¶
- Use
codefor lookups. Filter byhas_awardsto restrict to PSCs that appear in award data; see PSC API Reference.
Shared
Set-aside codes¶
This page documents the set-aside codes used across Tango’s awards and opportunities APIs (including shaped set_aside(code,description) expansions).
Codes¶
| Code | Meaning |
|---|---|
NONE |
No set aside used |
SBA |
Small Business Set Aside - Total |
8A |
8a Competed |
SBP |
Small Business Set Aside - Partial |
HMT |
HBCU or MI Set Aside - Total |
HMP |
HBCU or MI Set Aside - Partial |
VSB |
Very Small Business |
ESB |
Emerging Small Business Set-Aside |
HZC |
HUBZone Set Aside |
SDVOSBC |
Service-Disabled Veteran-Owned Small Business Set Aside |
BI |
Buy Indian |
IEE |
Indian Economic Enterprise |
ISBEE |
Indian Small Business Economic Enterprise |
HZS |
HUBZone Sole Source |
SDVOSBS |
SDVOSB Sole Source |
8AN |
8(a) Sole Source |
RS |
Reserved for Small Business |
HS3 |
8(a) with HUBZone Preference |
VSA |
Veteran Set Aside |
VSS |
Veteran Sole Source |
WOSB |
Women-Owned Small Business |
EDWOSB |
Economically Disadvantaged Women-Owned Small Business |
WOSBSS |
Women-Owned Small Business Sole Source |
EDWOSBSS |
Economically Disadvantaged Women-Owned Small Business Sole Source |
Source of truth¶
Tango maintains a canonical mapping internally and publishes it here for API consumers.
Agencies Data Dictionary¶
This document describes the fields available on the agency data structure as it appears in response shaping expands across multiple endpoints (e.g., contracts, opportunities). For filtering, ordering, and pagination on the standalone endpoint, see the Agencies API Reference.
For the unified federal hierarchy, see Organizations.
Overview¶
Agencies are federal organizations that sit below departments in the federal hierarchy. When expanded via response shaping (e.g., agency(code,name,abbreviation)), agency objects use the fields below.
Update Frequency¶
Agency data is updated monthly via the organization sync process from the Federal Hierarchy (SAM.gov).
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
code |
String | FPDS 4-digit agency code (primary key for the legacy endpoint). | FPDS / USAspending |
name |
String | Full agency name. | Federal Hierarchy (SAM.gov) |
abbreviation |
String | Common abbreviation (e.g., "NASA"). | Federal Hierarchy (SAM.gov) |
Expansions¶
| Expansion | Fields | Description |
|---|---|---|
department(...) |
code, name, abbreviation, description, cgac, website, congressional_justification |
Parent department. See Departments data dictionary. |
Usage Notes¶
- Use
codefor lookups. The agencycodeis the FPDS 4-digit identifier used in contract and financial assistance transactions. - Prefer Organizations for new integrations. The agency data structure is a legacy shape. Use the Organizations API for the full hierarchy with richer search and obligation data.
Data Sources¶
- Federal Hierarchy (SAM.gov) — Authoritative source for agency names and hierarchy position.
- FPDS / USAspending — Agency codes (FPDS 4-digit) as they appear in contract and financial transactions.
Departments Data Dictionary¶
This document describes the fields available on the department data structure as it appears in response shaping expands across multiple endpoints (e.g., contracts, opportunities). For filtering, ordering, and pagination on the standalone endpoint, see the Departments API Reference.
For the unified federal hierarchy, see Organizations.
Overview¶
Departments are top-level federal organizations. When expanded via response shaping (e.g., department(code,name,abbreviation)), department objects use the fields below.
Update Frequency¶
Department data is updated monthly via the organization sync process from the Federal Hierarchy (SAM.gov).
Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
code |
String | CGAC 3-character department code (primary key for the legacy endpoint). | USAspending |
name |
String | Full department name. | Federal Hierarchy (SAM.gov) |
abbreviation |
String | Common abbreviation (e.g., "DOD"). | Federal Hierarchy (SAM.gov) |
description |
String | Department description/mission. | Federal Hierarchy (SAM.gov) |
cgac |
String | CGAC code (same as code for departments). |
USAspending |
website |
String | Department website URL. | Various |
congressional_justification |
String | URL to congressional budget justification. | Various |
Expansions¶
None.
Usage Notes¶
- Use
codefor lookups. The departmentcodeis the CGAC 3-character identifier used in financial transactions. - Prefer Organizations for new integrations. The department data structure is a legacy shape. Use the Organizations API for the full hierarchy with richer search and obligation data.
Data Sources¶
- Federal Hierarchy (SAM.gov) — Authoritative source for department names, codes, and hierarchy structure.
- USAspending — Supplements with CGAC codes used in financial transactions.
Offices Data Dictionary¶
This document describes the fields available on the office data structure as it appears in response shaping expands across multiple endpoints (e.g., contracts, opportunities). For filtering, ordering, and pagination on the standalone endpoint, see the Offices API Reference.
For the unified federal hierarchy, see Organizations.
Overview¶
Offices are sub-agency organizations in the federal hierarchy. When expanded via response shaping (e.g., awarding_office(office_code,office_name,agency_name)), office objects use the fields below. The default shape uses flat aliases for backwards compatibility.
Update Frequency¶
Office data is updated monthly via the organization sync process from the Federal Hierarchy (SAM.gov).
Direct Fields¶
| Field | Type | Description | Source |
|---|---|---|---|
code |
String | Office code. | Federal Hierarchy (SAM.gov) |
name |
String | Office name. | Federal Hierarchy (SAM.gov) |
Flat Aliases (Legacy Default Shape)¶
These fields are returned by default when no ?shape= parameter is provided. They flatten the office, agency, and department into a single level.
| Field | Type | Description | Source |
|---|---|---|---|
office_code |
String | Alias for code. |
Federal Hierarchy |
office_name |
String | Alias for name. |
Federal Hierarchy |
agency_code |
String | Parent agency code (resolved from agency.code). |
FPDS |
agency_name |
String | Parent agency name (resolved from agency.name). |
Federal Hierarchy |
department_code |
String | Parent department code (resolved from agency.department.code). |
USAspending |
department_name |
String | Parent department name (resolved from agency.department.name). |
Federal Hierarchy |
Expansions¶
| Expansion | Fields | Description |
|---|---|---|
agency(...) |
code, name, abbreviation |
Parent agency. See Agencies data dictionary. |
department(...) |
code, name, abbreviation, description, cgac, website, congressional_justification |
Parent department. See Departments data dictionary. |
Usage Notes¶
- Default shape uses flat aliases. Without
?shape=, offices returnoffice_code,office_name,agency_code,agency_name,department_code,department_name. - Use nested expansions for structured data. Pass
?shape=code,name,agency(code,name)for nested objects instead of flat aliases. - Prefer Organizations for new integrations. The office data structure is a legacy shape. Use the Organizations API for the full hierarchy with richer search and obligation data.
Data Sources¶
- Federal Hierarchy (SAM.gov) — Authoritative source for office names, codes, and parent relationships.
- FPDS — Office codes as they appear in contract transactions.
Response Shaping (Custom Fields)¶
Tango’s API lets you request only the fields you want by passing a shape query parameter. Shaped responses are built directly from your selection for speed and consistency. If you omit shape, the endpoint returns the default serializer output.
Endpoints with shaping¶
- Agencies (legacy lookups):
- Departments:
/api/departments/ - Agencies:
/api/agencies/ - Offices:
/api/offices/ - Reference data:
- Business Types:
/api/business_types/ - NAICS:
/api/naics/ - PSC:
/api/psc/ - Assistance Listings:
/api/assistance_listings/ - MAS SINs:
/api/mas_sins/ - Awards (canonical routes):
- Contracts:
/api/contracts/ - IDVs:
/api/idvs/ - OTAs:
/api/otas/ - OTIDVs:
/api/otidvs/ - Subawards:
/api/subawards/ - Vehicles:
/api/vehicles/ - GSA eLibrary Contracts:
/api/gsa_elibrary_contracts/ - CALC Rates (nested):
/api/idvs/{key}/lcats/,/api/entities/{uei}/lcats/ - Organizations:
/api/organizations/ - Entities:
/api/entities/ - Forecasts:
/api/forecasts/ - Grants:
/api/grants/ - Opportunities (canonical routes):
- Opportunities:
/api/opportunities/ - Opportunity Notices:
/api/notices/ - Protests:
/api/protests/
All standard filters, ordering, pagination, throttling, and rate‑limit headers still apply.
Shape syntax¶
- Root leaves:
key,piid,award_date - Expansions (related objects):
recipient(display_name,uei) - Multiple items:
key,piid,recipient(display_name),awarding_office(office_code,office_name) - Star in child selections:
recipient(*)returns all allowed fields ofrecipient - Aliasing:
field::aliasorchild(field::alias) - Bracket parameters:
expand[key=value](children)— pass configuration to an expansion
Bracket parameters¶
Some expansions accept parameters via bracket syntax. Parameters go between the expansion name and the child selection:
# Top 10 agencies in past_performance
/api/entities/?shape=uei,past_performance[top=10](*)
# Multiple params (comma-separated)
/api/entities/?shape=uei,past_performance[top=3](summary,top_agencies)
Parameters are validated server-side with type checking and range enforcement. Unknown or out-of-range parameters return a 400 error with details.
Leaves vs expansions¶
In the shape DSL there are two different kinds of selections:
- Leaf:
field_name - Expansion:
expand_name(child1,child2,...)
Some endpoints expose the same name as both a leaf and an expansion. In those cases, the API will keep the selection as a leaf unless the shaping runtime determines that treating the token as a leaf would be unsafe (see “Bare expansions” below).
Example (Opportunities set-aside):
# Leaf (code string)
/api/opportunities/?shape=opportunity_id,title,set_aside
# Expansion (structured form)
/api/opportunities/?shape=opportunity_id,title,set_aside(code,description)
Bare expansions (shorthand)¶
If you write an expansion name without parentheses, e.g. office instead of office(*), Tango will sometimes treat it as shorthand for office(*).
This shorthand is applied only when needed for safety:
- when the expansion is a relation fetch (
select_related/prefetch_related), or - when the expansion is a “virtual” expansion with
path="*"(builder reads from the parent object), unless the value is field-map-backed.
Examples (Notices):
# Bare expansions: office == office(*), opportunity == opportunity(*)
/api/notices/?shape=notice_id,opportunity_id,office,opportunity&limit=1
Example response (shape excerpt):
[
{
"notice_id": "d2e3f9bf-9c2e-4c58-84f1-2b2b8a1d3b4d",
"opportunity_id": "ff12a2d0-3b8a-4a1d-8d7f-7d8c2b6c0a11",
"office": {
"office_code": "W91QF5",
"office_name": "ACC-APG",
"agency_code": "9700",
"agency_name": "DEPT OF THE ARMY",
"department_code": "97",
"department_name": "DEPARTMENT OF DEFENSE"
},
"opportunity": {
"opportunity_id": "ff12a2d0-3b8a-4a1d-8d7f-7d8c2b6c0a11",
"link": "/api/opportunities/ff12a2d0-3b8a-4a1d-8d7f-7d8c2b6c0a11/"
}
}
]
Examples:
# Basic
/api/contracts/?shape=key,piid,recipient(display_name)
# Aliasing
/api/contracts/?shape=key::id,recipient(display_name::name)
# Star in nested expansion
/api/contracts/?shape=key,recipient(*),transactions(*)
Child field aliasing inside an expand:
Response:
Notes:
*is only valid inside a child selection (e.g.,recipient(*)). Root‑level*is not supported.- Shaping requests that include unknown fields/expands, malformed shapes, or
shapeon non-shaping endpoints return a 400 with a structured error payload.
Flattening¶
Add flat=true to flatten nested objects with a joiner (default .). Works with both paginated and single‑object responses.
curl -H "X-API-KEY: <key>" \
"https://tango.makegov.com/api/contracts/?shape=key,recipient(display_name)&flat=true&joiner=."
Response:
Notes:
- Flattening applies to nested objects (dicts). Lists remain arrays for readability and stability by default. Expansions like
relationships(entities) andattachments(opportunities/notices) will remain arrays of objects even whenflat=true. - Optional:
flat_lists=truewill additionally flatten lists of objects into indexed keys (e.g.,relationships.0.uei). This is opt‑in and defaults tofalse.
Examples:
# Flatten dicts only (default list behavior)
/api/entities/?shape=uei,relationships(uei,display_name)&flat=true
# Also flatten list elements into indexed keys
/api/entities/?shape=uei,relationships(uei,display_name)&flat=true&flat_lists=true&joiner=.
Validation & limits¶
- Unknown fields or expansions return a 400 with structured issues.
- Malformed shapes (syntax errors) return a 400 with a
parse_errorissue. - Passing
shapeto an endpoint that does not support shaping returns a 400 (instead of ignoringshape). - Default limits (subject to change):
SHAPE_MAX_DEPTH= 2SHAPE_MAX_FIELDS= 64 (for user-supplied?shape=params; server-controlled default shapes may exceed this)
Example errors:
{
"error": "Invalid shape",
"issues": [{"path": "foo", "reason": "unknown_field"}],
"available_fields": {
"fields": ["award_date", "key", "piid", "recipient"],
"expands": {"recipient": {"fields": ["uei", "display_name"], "expands": {}, "wildcard_fields": false}},
"wildcard_fields": false
}
}
{
"error": "Invalid shape",
"issues": [{"path": "$", "reason": "parse_error (Unclosed '(')"}],
"available_fields": {
"fields": ["award_date", "key", "piid", "recipient"],
"expands": {"recipient": {"fields": ["uei", "display_name"], "expands": {}, "wildcard_fields": false}},
"wildcard_fields": false
}
}
{
"error": "Invalid shape value(s): foo. Shaping is not available for /api/example/.",
"issues": [{"path": "$", "reason": "shape_not_supported"}]
}
Discovering available fields¶
Every shaped endpoint supports ?show_shapes=true for schema discovery. Truthy values: true, 1, yes, on.
It works in two modes:
Schema-only (no ?shape=)¶
Pass ?show_shapes=true without a ?shape= parameter to get just the schema — no data is fetched, no DB query is made:
{
"available_fields": {
"fields": ["award_date", "awarding_office", "description", "key", "naics_code", "piid", "recipient", "transactions"],
"expands": {
"awarding_office": {"fields": ["agency_code", "agency_name", "office_code", "office_name"], "expands": {}, "wildcard_fields": false},
"recipient": {"fields": ["cage_code", "display_name", "legal_business_name", "uei"], "expands": {}, "wildcard_fields": false},
"transactions": {"fields": ["action_type", "description", "modification_number", "obligated", "transaction_date"], "expands": {}, "wildcard_fields": false}
},
"wildcard_fields": false
}
}
Schema appended to data (with ?shape=)¶
Pass both ?shape=... and ?show_shapes=true to get the normal shaped response with a _shaping block appended:
{
"count": 1234,
"next": "...",
"previous": null,
"results": [
{"key": "CONT_AWD_...", "piid": "GS00Q14OADS134"}
],
"_shaping": {
"available_fields": {
"fields": ["award_date", "awarding_office", "description", "key", "naics_code", "piid", "recipient", "transactions"],
"expands": {
"awarding_office": {"fields": ["agency_code", "agency_name", "office_code", "office_name"], "expands": {}, "wildcard_fields": false},
"recipient": {"fields": ["cage_code", "display_name", "legal_business_name", "uei"], "expands": {}, "wildcard_fields": false},
"transactions": {"fields": ["action_type", "description", "modification_number", "obligated", "transaction_date"], "expands": {}, "wildcard_fields": false}
},
"wildcard_fields": false
}
}
}
Schema structure¶
Each level of the schema contains:
| Key | Type | Meaning |
|---|---|---|
fields |
array | All valid shape keys at this level, including both leaf fields and expand names. |
expands |
object | Expandable relations, each containing its own nested {fields, expands, wildcard_fields} schema. |
wildcard_fields |
boolean | When true, the expansion accepts any field name (i.e., expand(*) returns all keys from the underlying data, and you can also request arbitrary keys by name). When false, only the fields listed in fields are valid. Most endpoints return false; wildcard_fields: true appears on expansions backed by freeform JSON (e.g., raw_data(*) on forecasts). |
Notes:
- Schema-only mode (
?show_shapes=truealone) makes no DB queries — safe to call frequently. _shapingis appended afterresultsin paginated responses and after all other keys in detail responses, so existing clients that ignore unknown keys are unaffected.- All 400 error responses for invalid shapes also include
available_fieldsat the top level (no?show_shapesneeded).
Date/time formatting¶
All datetimes in shaped responses are formatted using a consistent ISO‑8601 format.
Identity fallback for missing relations¶
When an expanded relation is missing (e.g., a join yields no row), the API returns a minimal identity object using the FK value instead of null:
Field reference by endpoint (excerpt)¶
Below is a concise reference of commonly used fields and expansions per endpoint. Use (*) inside an expansion to request all allowed fields for that relation.
Departments /api/departments/¶
- Leaves:
code,name,abbreviation,description,cgac,website,congressional_justification - No expansions.
Default response (no ?shape=): code,name,abbreviation
# Select specific fields
/api/departments/?shape=code,name
# Extended department info
/api/departments/?shape=code,name,description,cgac,website,congressional_justification
Agencies /api/agencies/¶
- Leaves:
code,name,abbreviation - Expansions:
department(code,name,abbreviation,description,cgac,website,congressional_justification)
Default response (no ?shape=): code,name,abbreviation,department(name,code)
# Just codes and names
/api/agencies/?shape=code,name
# Include department info
/api/agencies/?shape=code,name,department(name,code)
# Department with extended fields
/api/agencies/?shape=code,department(name,description,cgac,website)
# All department fields
/api/agencies/?shape=code,department(*)
Offices /api/offices/¶
- Leaves:
code,name, plus flat aliasesoffice_code,office_name,agency_code,agency_name,department_code,department_name - Expansions:
agency(code,name,abbreviation)department(code,name,abbreviation,description,cgac,website,congressional_justification)
Default response (no ?shape=): office_code,office_name,agency_code,agency_name,department_code,department_name (flat aliases)
# Default flat format
/api/offices/?shape=office_code,office_name,agency_name
# Direct leaves with nested expansions
/api/offices/?shape=code,name,agency(code,name,abbreviation)
# Office with department details
/api/offices/?shape=code,name,department(name,description,website)
# Both expansions
/api/offices/?shape=code,name,agency(code,name),department(code,name)
Business Types /api/business_types/¶
- Leaves:
name,code - No expansions.
Default response (no ?shape=): name,code
NAICS /api/naics/¶
- Leaves:
code,description - Expansions:
size_standards(employee_limit,revenue_limit)— SBA size standards for this NAICS code.revenue_limitis in whole dollars (e.g.,2250000).federal_obligations(total,active)— obligation rollups. Each sub-object containsawards_obligated(float) andawards_count(int).
Default response (list, no ?shape=): code,description
Default response (detail or show_limits=1): code,description,size_standards(*),federal_obligations(*)
Note: The legacy ?show_limits=1 parameter is still supported — it triggers the same response as ?shape=code,description,size_standards(*),federal_obligations(*). Prefer using ?shape= directly.
# List with just code and description (default)
/api/naics/?shape=code,description
# Include size standards and obligations (equivalent to ?show_limits=1)
/api/naics/?shape=code,description,size_standards(*),federal_obligations(*)
# Size standards only
/api/naics/541330/?shape=code,description,size_standards(employee_limit,revenue_limit)
# Obligations total only
/api/naics/541330/?shape=code,federal_obligations(total)
PSC /api/psc/¶
- Leaves:
code,parent,category,level_1_category,level_1_category_code,level_2_category,level_2_category_code - Expansions:
current(name,active,start_date,end_date,description,includes,excludes)— active or latest descriptionhistorical(name,active,start_date,end_date,description,includes,excludes)— all descriptions
Default response (no ?shape=): code,current(*),parent,category,level_1_category,level_1_category_code,level_2_category,level_2_category_code
# Just code and current description name
/api/psc/?shape=code,current(name)
# Code with current and historical descriptions
/api/psc/AD12/?shape=code,current(name,active),historical(name,active)
Assistance Listings /api/assistance_listings/¶
- Leaves:
number,title,published_date,archived_date,popular_name,objectives,applicant_eligibility,benefit_eligibility - No expansions.
Default response (list, no ?shape=): number,title
Note: Detail responses (/api/assistance_listings/{number}/) use the full serializer (includes all fields) when no ?shape= param is provided.
# Include extra fields
/api/assistance_listings/?shape=number,title,objectives
# Detail with specific fields
/api/assistance_listings/10.001/?shape=number,title,objectives,popular_name
MAS SINs /api/mas_sins/¶
- Leaves:
sin,large_category_code,large_category_name,sub_category_code,sub_category_name,psc_code,state_local,set_aside_code,service_comm_code,expiration_date,tdr,olm,naics_codes,title,description - No expansions.
Default response (no ?shape=): all 15 fields above.
Organizations /api/organizations/¶
Organizations uses a default shape — all responses go through the shaping pipeline even without ?shape=.
- Default shape:
key,fh_key,name,short_name,type,level,is_active,code,fpds_code,cgac,canonical_code,parent_fh_key,full_parent_path_name - Additional leaves:
fpds_org_id,aac_code,start_date,end_date,logo,summary,l1_fh_keythroughl8_fh_key,total_obligations,tree_obligations,mod_status,description,obligations,obligation_rank - Expansions:
parent(key,fh_key,name,short_name,type,level,is_active,code,cgac)ancestors(fh_key,name,short_name,level)children(key,fh_key,name,short_name,type,level,is_active,code,cgac)department(code,name,abbreviation)agency(code,name,abbreviation)
# Default response (all responses are shaped)
/api/organizations/
# Select specific fields
/api/organizations/?shape=fh_key,name,type,level
# Include department and agency expands
/api/organizations/?shape=fh_key,name,department(code,name),agency(code,name,abbreviation)
Contracts /api/contracts/¶
- Leaves:
key,piid,award_date,naics_code,psc_code,total_contract_value,description,base_and_exercised_options_value,fiscal_year,obligated,set_aside,award_type,transactions,subawards_summary - Expansions:
recipient(uei,display_name,legal_business_name,cage,duns,...)awarding_office(office_code,office_name,agency_code,agency_name,department_code,department_name)funding_office(...)place_of_performance(country_code,country_name,state_code,state_name,city_name,zip_code)parent_award(key,piid)period_of_performance(start_date,current_end_date,ultimate_completion_date)transactions(modification_number,transaction_date,obligated,description,action_type)subawards_summary(count,total_amount)competition(contract_type,extent_competed,number_of_offers_received,other_than_full_and_open_competition,solicitation_date,solicitation_identifier,solicitation_procedures)officers(highly_compensated_officer_1_name,highly_compensated_officer_1_amount,highly_compensated_officer_2_name,highly_compensated_officer_2_amount,highly_compensated_officer_3_name,highly_compensated_officer_3_amount,highly_compensated_officer_4_name,highly_compensated_officer_4_amount,highly_compensated_officer_5_name,highly_compensated_officer_5_amount)– returnsnullif no officers are on record. Not included in default serializers; available only via shaping.
Examples:
# Minimal contract fields
/api/contracts/?shape=key,piid,award_date
# Recipient and awarding office
/api/contracts/?shape=key,recipient(display_name),awarding_office(office_code,office_name)
# Period and transactions
/api/contracts/?shape=key,period_of_performance(start_date,current_end_date),transactions(modification_number,obligated)
# Officers (subset)
/api/contracts/?shape=key,officers(highly_compensated_officer_1_name,highly_compensated_officer_1_amount)
# Officers (all allowed fields)
/api/contracts/?shape=key,officers(*)
IDVs /api/idvs/¶
- Leaves:
key,piid,vehicle_uuid,solicitation_identifier,award_date,naics_code,psc_code,total_contract_value,description,fiscal_year,obligated,idv_type,multiple_or_single_award_idv,type_of_idc,set_aside,transactions,subawards_summary - Detail-only leaves:
commercial_item_acquisition_procedures,consolidated_contract,contingency_humanitarian_or_peacekeeping_operation,contract_bundling,contract_financing,cost_accounting_standards_clause,cost_or_pricing_data,dod_acquisition_program,dod_transaction_number,domestic_or_foreign_entity,email_address,epa_designated_product,evaluated_preference,fair_opportunity_limited_sources,fed_biz_opps,fee_range_lower_value,fee_range_upper_value,fixed_fee_value,foreign_funding,government_furnished_property,idv_website,inherently_governmental_functions,local_area_set_aside,major_program,number_of_actions,number_of_offers_source,ordering_procedure,performance_based_service_acquisition,program_acronym,recovered_materials_sustainability,research,sam_exception,simplified_procedures_for_certain_commercial_items,small_business_competitiveness_demonstration_program,subcontracting_plan,total_estimated_order_value,tradeoff_process,type_of_fee_for_use_of_service,undefinitized_action,who_can_use - Expansions:
recipient(uei,display_name,legal_business_name,cage,duns,...)awarding_office(office_code,office_name,agency_code,agency_name,department_code,department_name)funding_office(...)place_of_performance(country_code,country_name,state_code,state_name,city_name,zip_code)parent_award(key,piid)period_of_performance(start_date,last_date_to_order)— note: useslast_date_to_orderinstead of contracts'current_end_date/ultimate_completion_datetransactions(modification_number,transaction_date,obligated,description,action_type)subawards_summary(count,total_amount)idv_type(code,description)— IDV type as structured code/descriptionmultiple_or_single_award_idv(code,description)— single/multiple award designationtype_of_idc(code,description)— IDC type as structured code/descriptionset_aside(code,description)— set-aside typenaics(code,description)— resolved NAICS lookuppsc(code,description)— resolved PSC lookupcompetition(contract_type,extent_competed,number_of_offers_received,other_than_full_and_open_competition,solicitation_date,solicitation_identifier,solicitation_procedures)officers(...)— same fields as contracts;nullwhen absent; shaping-onlyawards(key,piid,award_date,naics_code,psc_code,total_contract_value,description,base_and_exercised_options_value,fiscal_year,obligated,transactions)— child awards under this IDVgsa_elibrary(schedule,contract_number,uei,sins,cooperative_purchasing,disaster_recovery_purchasing,file_urls,extracted_text,external_id,source_data)— GSA eLibrary enrichment (nullwhen no match)legislative_mandates(...)— legislative mandate flags
Default response (list, no ?shape=): award_date,awarding_office(*),description,fiscal_year,funding_office(*),gsa_elibrary(*),idv_type(*),key,legislative_mandates(*),multiple_or_single_award_idv(*),naics_code,obligated,parent_award(*),period_of_performance(*),piid,place_of_performance(*),psc_code,recipient(*),set_aside,solicitation_identifier,subawards_summary(*),total_contract_value,type_of_idc(*),vehicle_uuid
Default response (detail): adds all detail-only leaves plus competition(*) and officers(*)
# Minimal IDV fields
/api/idvs/?shape=key,piid,award_date
# Expand idv_type to get code + description
/api/idvs/?shape=key,piid,idv_type(code,description)
# IDV with recipient and awarding office
/api/idvs/?shape=key,piid,recipient(display_name,uei),awarding_office(office_name,agency_name)
# Period of performance with last_date_to_order
/api/idvs/?shape=key,piid,period_of_performance(start_date,last_date_to_order)
# GSA eLibrary enrichment
/api/idvs/?piid=GS-35F-0001X&shape=key,piid,gsa_elibrary(schedule,contract_number,sins,file_urls)
# Child awards under an IDV
/api/idvs/{key}/?shape=key,piid,awards(key,piid,total_contract_value)
Vehicles /api/vehicles/¶
- Leaves:
uuid,solicitation_identifier,agency_id,organization_id,vehicle_type,fiscal_year,agency_details,descriptions,competition_details,type_of_idc,contract_type,awardee_count,order_count,vehicle_obligations,vehicle_contracts_value,solicitation_title,solicitation_description,solicitation_date,naics_code,psc_code,set_aside - Expansions:
awardees(...): expands to the underlying IDVs that make up the vehicleopportunity(...): expands to the linked SAM.gov Opportunity (supports all Opportunity fields and expansions likeoffice,attachments,meta)competition_details(...): expands thecompetition_detailsJSON object (fields:extent_competed,number_of_offers_received,set_aside,solicitation_procedures, etc., or*for all)
Default response (list, no ?shape=): agency_details,award_date,awardee_count,competition_details(*),contract_type,description,fiscal_year,last_date_to_order,latest_award_date,naics_code,order_count,psc_code,set_aside,solicitation_date,solicitation_identifier,solicitation_title,type_of_idc,uuid,vehicle_contracts_value,vehicle_obligations,vehicle_type,who_can_use
Default response (detail): adds agency_id, organization_id, solicitation_description
Notes:
GET /api/vehicles/?search=...performs vehicle-level full-text search.- On
GET /api/vehicles/{uuid}/,?search=is reserved for filtering expandedawardees(...)(it does not filter the vehicle itself). - Opportunity-derived fields (
solicitation_title,solicitation_description,solicitation_date,naics_code,psc_code,set_aside) are populated from the linked SAM.gov Opportunity's latest notice when available.
Examples:
# Find vehicles by term
/api/vehicles/?search=schedule
# Vehicle detail + shaped award expansion
/api/vehicles/<vehicle-uuid>/?shape=uuid,solicitation_identifier,awardees(key,uuid,piid,award_date,recipient(display_name,uei))
# Include opportunity-derived fields
/api/vehicles/<vehicle-uuid>/?shape=uuid,solicitation_identifier,solicitation_title,solicitation_date,naics_code,psc_code
# Expand linked Opportunity with office details
/api/vehicles/<vehicle-uuid>/?shape=uuid,solicitation_identifier,opportunity(opportunity_id,title,first_notice_date,office(office_name,agency_name))
# Expand JSON detail fields to select specific sub-fields
/api/vehicles/<vehicle-uuid>/?shape=uuid,competition_details(extent_competed,number_of_offers_received),type_of_idc,contract_type
# Filter expanded awards within a vehicle
/api/vehicles/<vehicle-uuid>/?shape=uuid,awardees(key,uuid,recipient(display_name))&search=acme
OTAs /api/otas/¶
- Leaves:
key,piid,award_date,psc_code,total_contract_value,description,base_and_exercised_options_value,fiscal_year,obligated,award_type,type_of_ot_agreement,extent_competed,consortia,consortia_uei,dod_acquisition_program,non_governmental_dollars,non_traditional_government_contractor_participation,parent_award_modification_number,transactions - Expansions:
recipient(uei,display_name,legal_business_name,cage,duns,...)awarding_office(office_code,office_name,agency_code,agency_name,department_code,department_name)funding_office(...)place_of_performance(country_code,country_name,state_code,state_name,city_name,zip_code)parent_award(key,piid)period_of_performance(start_date,current_end_date,ultimate_completion_date)transactions(modification_number,transaction_date,obligated,description,action_type)psc(code,description)award_type(code,description)— OTA-specific choices ("O" = Other Transaction Non-Research, "R" = Other Transaction for Research)type_of_ot_agreement(code,description)extent_competed(code,description)
Default response (no ?shape=): award_date,award_type,awarding_office(*),base_and_exercised_options_value,consortia,consortia_uei,dod_acquisition_program,extent_competed,fiscal_year,funding_office(*),key,non_governmental_dollars,non_traditional_government_contractor_participation,parent_award(key,piid),parent_award_modification_number,period_of_performance(start_date,current_end_date,ultimate_completion_date),piid,place_of_performance(*),psc_code,recipient(*),type_of_ot_agreement
Note: OTAs have no naics_code field and no naics expand.
# Minimal OTA fields
/api/otas/?shape=key,piid,award_date
# Expand award_type to get OTA-specific code + description
/api/otas/?shape=key,piid,award_type(code,description)
# Expand extent competed and type of OT agreement
/api/otas/?shape=key,piid,extent_competed(code,description),type_of_ot_agreement(code,description)
# OTA with recipient and awarding office
/api/otas/?shape=key,piid,recipient(display_name,uei),awarding_office(office_name,agency_name)
OTIDVs /api/otidvs/¶
- Leaves:
key,piid,award_date,psc_code,total_contract_value,description,base_and_exercised_options_value,fiscal_year,obligated,idv_type,type_of_ot_agreement,extent_competed,consortia,consortia_uei,dod_acquisition_program,non_governmental_dollars,non_traditional_government_contractor_participation,transactions - Expansions:
recipient(uei,display_name,legal_business_name,cage,duns,...)awarding_office(office_code,office_name,agency_code,agency_name,department_code,department_name)funding_office(...)place_of_performance(country_code,country_name,state_code,state_name,city_name,zip_code)period_of_performance(start_date,current_end_date,ultimate_completion_date)transactions(modification_number,transaction_date,obligated,description,action_type)psc(code,description)type_of_ot_agreement(code,description)extent_competed(code,description)
Default response (no ?shape=): award_date,awarding_office(*),base_and_exercised_options_value,consortia,consortia_uei,dod_acquisition_program,extent_competed,fiscal_year,funding_office(*),idv_type,key,non_governmental_dollars,non_traditional_government_contractor_participation,period_of_performance(start_date,current_end_date,ultimate_completion_date),piid,place_of_performance(*),psc_code,recipient(*),type_of_ot_agreement
Note: OTIDVs have no naics_code field, no naics expand, and no parent_award expand.
# Minimal OTIDV fields
/api/otidvs/?shape=key,piid,award_date
# Expand extent competed and type of OT agreement
/api/otidvs/?shape=key,piid,extent_competed(code,description),type_of_ot_agreement(code,description)
# OTIDV with recipient
/api/otidvs/?shape=key,piid,recipient(display_name,uei),awarding_office(office_name,agency_name)
Subawards /api/subawards/¶
Subawards use a default shape — all responses go through the shaping pipeline even without ?shape=.
- Default response (no
?shape=):award_key,awarding_office(*),fsrs_details(*),funding_office(*),key,piid,place_of_performance(*),prime_recipient(uei,display_name),subaward_details(*),subaward_recipient(uei,display_name) - Leaves: identity + prime award metadata (
piid,prime_award_total_outlayed_amount, dates/NAICS/description, prime/subawardee identities, business types, andusaspending_permalink) - Expansions:
subaward_details(description,type,number,amount,action_date,fiscal_year)fsrs_details(last_modified_date,id,year,month)place_of_performance(city,state,zip,country_code)highly_compensated_officers(name,amount)prime_recipient(uei,display_name),subaward_recipient(uei,display_name,duns)awarding_office(*),funding_office(*)
# Default response (shaped automatically)
/api/subawards/
# Select specific fields
/api/subawards/?shape=key,piid,subaward_details(*)
# Recipient and office info
/api/subawards/?shape=key,prime_recipient(uei,display_name),awarding_office(*)
GSA eLibrary Contracts /api/gsa_elibrary_contracts/¶
- Leaves:
uuid,schedule,contract_number,sins,cooperative_purchasing,disaster_recovery_purchasing,file_urls - Expansions:
recipient(uei,display_name)idv(key,award_date)
# Basic fields
/api/gsa_elibrary_contracts/?shape=uuid,schedule,contract_number
# With recipient info
/api/gsa_elibrary_contracts/?shape=uuid,contract_number,recipient(uei,display_name)
Opportunities /api/opportunities/¶
- Leaves:
opportunity_id,latest_notice_id,archive_date,title,description,naics_code,psc_code,response_deadline,first_notice_date,last_notice_date,active,set_aside,award_number,solicitation_number,snippet,sam_url, plus relation id leaves:agency_id,department_id,office_id - Expansions:
attachments(attachment_id,extracted_text,mime_type,name,posted_date,resource_id,type,url)(shorthand:attachments→attachments(*))office(office_code,office_name,agency_code,agency_name,department_code,department_name)(shorthand:office→office(*))agency(*)(shorthand:agency→agency(*))department(*)(shorthand:department→department(*))latest_notice(notice_id,link)(shorthand:latest_notice→latest_notice(*))place_of_performance(street_address,city,state,zip,country)meta(notices_count,attachments_count,notice_type(code,type))set_aside(code,description)notice_history(index,notice_id,latest,title,deleted,posted_date,notice_type_code,solicitation_number,parent_notice_id,related_notice_id)primary_contact(title,full_name,email,phone,fax)secondary_contact(title,full_name,email,phone,fax)
Default response (list, no ?shape=): 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 response (detail): adds attachments(*), description, notice_history(*), primary_contact(*)
# Expand set_aside to get code + description
/api/opportunities/?shape=opportunity_id,title,set_aside(code,description)
# Office + attachments using bare expand shorthand
/api/opportunities/?shape=opportunity_id,title,office,attachments&limit=1
# Detail with notice history
/api/opportunities/{id}/?shape=opportunity_id,title,notice_history(*)
# Contacts
/api/opportunities/{id}/?shape=opportunity_id,primary_contact(*),secondary_contact(*)
Notices /api/notices/¶
- Leaves:
notice_id,opportunity_id,title,description,naics_code,psc_code,posted_date,response_deadline,last_updated,active,set_aside,sam_url,attachment_count,award_number,solicitation_number - Expansions:
attachments(attachment_id,extracted_text,mime_type,name,posted_date,resource_id,type,url)(shorthand:attachments→attachments(*))address(city,state,zip,country)archive(date,type)place_of_performance(street_address,city,state,zip,country)primary_contact(title,full_name,email,phone,fax)secondary_contact(title,full_name,email,phone,fax)meta(parent_notice_id,related_notice_id,notice_type(code,type),link)office(office_code,office_name,agency_code,agency_name,department_code,department_name)(shorthand:office→office(*))opportunity(opportunity_id,link)(shorthand:opportunity→opportunity(*))set_aside(code,description)
Default response (list, no ?shape=): active,address(*),attachment_count,award_number,description,last_updated,meta(*),naics_code,notice_id,office(*),opportunity(*),place_of_performance(*),posted_date,psc_code,response_deadline,sam_url,set_aside,solicitation_number,title
Default response (detail): adds archive(*), primary_contact(*), secondary_contact(*)
# Expand set_aside to get code + description
/api/notices/?shape=notice_id,title,set_aside(code,description)
# Include archive and contacts on detail
/api/notices/{id}/?shape=notice_id,title,archive(*),primary_contact(*)
# Get linked opportunity reference
/api/notices/?shape=notice_id,opportunity(opportunity_id,link)
Entities /api/entities/¶
Entities default to the shaping pipeline. Default responses include core identity fields (list) or the full detail set (retrieve) with normalized field formats. Use ?shape= to customize.
- Leaves:
uei,uuid,display_name,legal_business_name,dba_name,cage_code,dodaac,registered,registration_status,primary_naics,psc_codes,email_address,entity_url,description,capabilities,keywords,sam_activation_date,sam_registration_date,sam_expiration_date,last_update_date,congressional_district,evs_source,uei_status,uei_expiration_date,uei_creation_date,public_display_flag,exclusion_status_flag,exclusion_url,entity_division_name,entity_division_number,entity_start_date,fiscal_year_end_close_date,submission_date - Expansions:
physical_address(address_line1,address_line2,city,state_or_province_code,zip_code,zip_code_plus4,country_code,country_name)— normalized snake_case keysmailing_address(...)— same fields asphysical_addressbusiness_types(code,description)— normalized[{code, description}]; auto-normalizes dict-format DSBS datasba_business_types(code,description,entry_date,exit_date)— normalized SBA certificationsnaics_codes(code,sba_small_business)— normalized; converts plain string arrays automaticallyfederal_obligations(total,active)— expand-only;totalandactivesub-objects with obligation metricshighest_owner(cage_code,legal_business_name,uei)— highest corporate ownerimmediate_owner(cage_code,legal_business_name,uei)— immediate parent entityrelationships(relation,type,uei,display_name)entity_structure(code,description)— falls back to ENTITY_STRUCTURE_MAP for descriptionentity_type(code,description)— falls back to BUSINESS_TYPE_MAP for descriptionprofit_structure(code,description)— falls back to BUSINESS_TYPE_MAP for descriptionorganization_structure(code,description)— falls back to BUSINESS_TYPE_MAP for descriptionstate_of_incorporation(code,description)— uses model descriptioncountry_of_incorporation(code,description)— falls back to django-genc (GENC country names)purpose_of_registration(code,description)— falls back to PURPOSE_OF_REGISTRATION_MAP for descriptionpast_performance[top=N](summary,top_agencies)— aggregated contract history;summaryhastotal_obligated,total_awards,agency_count,naics_count,psc_count;top_agencieslists top N agencies (default 5, max 100) withagency_code,agency_name,department_code,department_name,obligations,awards_count,top_naics,top_psc. Accepts bracket param[top=N].
# List with default shape (core identity fields)
/api/entities/
# Detail with all fields + normalized expands
/api/entities/ZQGGHJH74DW7/
# Custom shape: just UEI and business types
/api/entities/?shape=uei,business_types(code,description)
# Federal obligations for a specific entity
/api/entities/ZQGGHJH74DW7/?shape=uei,federal_obligations(total)
# Structured code/description fields
/api/entities/ZQGGHJH74DW7/?shape=uei,entity_structure(*),purpose_of_registration(*)
# Owner info
/api/entities/ZQGGHJH74DW7/?shape=uei,highest_owner(*),immediate_owner(*)
# Past performance (default top 5 agencies)
/api/entities/ZQGGHJH74DW7/?shape=uei,past_performance(*)
# Past performance with top 10 agencies
/api/entities/ZQGGHJH74DW7/?shape=uei,past_performance[top=10](summary,top_agencies)
Forecasts /api/forecasts/¶
- Leaves:
id,source_system,external_id,agency,title,description,anticipated_award_date,fiscal_year,naics_code,is_active,status,created,modified,primary_contact,place_of_performance,estimated_period,set_aside,contract_vehicle,raw_data - Expansions:
display(title,description,agency,anticipated_award_date,fiscal_year,naics_code,status,primary_contact,place_of_performance,estimated_period,set_aside,contract_vehicle)— normalized view of the forecast's display dataraw_data(*)— the raw JSON data from the source system; accepts wildcard fields
# Basic forecast fields
/api/forecasts/?shape=id,title,agency,anticipated_award_date,status
# With display expansion for normalized view
/api/forecasts/?shape=id,title,display(agency,anticipated_award_date,primary_contact,place_of_performance)
# Include raw source data
/api/forecasts/?shape=id,title,raw_data(*)
Grants /api/grants/¶
- Leaves:
agency_code,applicant_eligibility_description,description,forecast,funding_activity_category_description,grant_id,grantor_contact,last_updated,opportunity_history,opportunity_number,status,synopsis,title - Expansions:
cfda_numbers(number,title)— associated CFDA/Assistance Listing numbersapplicant_types(code,description)category(code,description)— opportunity categoryfunding_categories(code,description)funding_instruments(code,description)status(code,description)— expanded status with code and label (use this when you want the structured form;statusalone is treated as a leaf unless the runtime must expand it for safety)important_dates(posted_date,response_date,response_date_description,estimated_synopsis_post_date,estimated_application_response_date,estimated_application_response_date_description,estimated_project_start_date)— key dates (fields vary by status: posted opportunities returnposted_date/response_date; forecasted ones returnestimated_*fields)funding_details(award_ceiling,award_floor,estimated_total_funding,expected_number_of_awards)grantor_contact(name,phone,email)additional_info(link,description)attachments(mime_type,name,posted_date,resource_id,type,url)
# Basic grant fields
/api/grants/?shape=grant_id,title,status,agency_code
# With CFDA numbers and applicant types
/api/grants/?shape=grant_id,title,cfda_numbers(number,title),applicant_types(code,description)
# Expanded status and funding instruments
/api/grants/?shape=grant_id,title,status(code,description),funding_instruments(code,description)
Protests /api/protests/¶
Both list and detail return case-level objects identified by case_id. Dockets are available via the dockets(...) expansion.
- Leaves:
case_id,source_system,case_number,title,protester,agency,solicitation_number,case_type,outcome,filed_date,posted_date,decision_date,due_date,docket_url,decision_url,digest - Expansions:
dockets(source_system,case_number,docket_number,title,protester,agency,solicitation_number,case_type,outcome,filed_date,posted_date,decision_date,due_date,docket_url,decision_url,digest)
Default response (no ?shape=): case_id,source_system,case_number,title,protester,agency,solicitation_number,case_type,outcome,filed_date,posted_date,decision_date,due_date,docket_url,decision_url (no nested dockets)
Notes:
case_numberis the base B-number (e.g.b-424214) identifying the case.docket_number(e.g.b-424214.1) identifies a specific sub-docket; only available insidedockets(...).digestis opt-in only (decision summary text fromraw_data).
# Case-level fields with nested dockets
/api/protests/?shape=case_id,case_number,title,dockets(docket_number,filed_date,outcome)
# Case-level only
/api/protests/?shape=case_id,title,outcome,decision_date
# Detail with dockets
/api/protests/{case_id}/?shape=case_id,title,dockets(docket_number,filed_date)
Data Provenance
Provenance & auditing¶
Tango ingests data from multiple upstream systems (SAM.gov, USAspending, FPDS, agency feeds, etc.). Those sources overlap, disagree, and update on different cadences.
To keep the dataset consistent (and debuggable), Tango tracks two related concepts:
- Field provenance: “Which source last updated this specific field, and when?”
- Change logs (CDC): “Which fields changed on this row, by what operation (INSERT/UPDATE), and from what source?”
Even though we do not currently expose provenance or changelog tables in the public API, this tracking matters to API consumers because it helps us:
- Explain behavior: why a value changed (or why it didn’t).
- Prevent regressions: avoid overwriting authoritative sources with lower-quality sources.
- Improve reliability: tighten guarantees around “data is ready / stable” moments for downstream consumers.
Terminology¶
- CDC (Change Data Capture): a pattern for recording row-level changes (insert/update/delete) as data is ingested.
change_source: a normalized identifier of the ingest source (e.g."sam","dsbs","usaspending").changed_fields: the list of field names that were changed by an operation.- For UPDATE, this is a true diff.
- For INSERT, this is a best-effort list of fields set by the ingest path.
batch_id/etl_job_id: identifiers used to correlate changes to a specific loader run.
What models have this (so far)¶
Today, Tango tracks provenance/auditing for:
- Organizations
- Entities
- Opportunities
How it works (high level)¶
At ingest time, Tango typically writes incoming data into a staging representation, computes a diff against the current table, records the audit log, and then applies the update.
flowchart LR
A[Upstream source file/API] --> B[Loader parses + normalizes]
B --> C[(Staging / temp representation)]
C --> D[Compute diff vs target]
D --> E[(ChangeLog rows)]
D --> F[(Field provenance updates)]
C --> G[Apply upsert/update to target]
Why this is useful¶
- Multiple sources, different trust levels: provenance lets us define “who wins” per field (and why).
- Better debugging: we can query “what changed the name for UEI X?” or “why did this org’s code change?”
- Future-facing: this lays groundwork for exposing provenance in a controlled way (e.g. support tooling, exports, or opt-in API surfaces).
Example questions we can answer¶
- “What last updated an Organization’s
name(and from which source)?” - “What last updated
legal_business_namefor an entity UEI?” - “Which fields changed on organization FH key 12345 in the last sync?”
- “Did loader X actually change data, or was it a no-op?”
Webhooks
Tango – Webhooks Partner Guide¶
Welcome! This guide walks you through enabling and consuming outbound webhooks from Tango so your application can react to fresh federal-spending data without polling our API.
Jump to:
1. What you get¶
Tango pushes a JSON payload to your server whenever tracked resources change. Today this includes:
- Awards (new awards, new transactions)
- Opportunities (new opportunities, new notices, updates)
- Entities (new entities, updates)
- Grants (new grants, updates)
- Forecasts (new forecasts, updates)
-
Protests (new protests, updates)
-
Near–real-time: you'll be notified minutes after Tango's ETL jobs finish.
- Lightweight: one payload lists just the IDs that changed – you then pull full details via the existing REST API if needed.
- Flexible filtering: Control exactly what notifications you receive using subjects (entity, award, agency, etc.) and event types.
- Reliability features: Automatic circuit breaker pattern for endpoint health management and intelligent retry strategies.
Note (Awards): For correctness, awards webhooks are published after award bundling/materialization so a webhook will not arrive before the corresponding award is queryable via the API.
1.1 When events are published (“data is ready”)¶
We intentionally publish events only once the underlying data is queryable via the API.
awards.*: published after award bundling/materializationopportunities.*: published at the end ofload_opportunitiesentities.*: published at the end ofload_entities/load_dsbsgrants.*: published at the end ofload_grantsforecasts.*: published at the end ofload_forecastsprotests.*: published whenpublish_webhook_outboxruns (data is ready afterload_gao_protests)
1.2 Subjects you can subscribe to (current)¶
An event can match your subscription via any of its subjects.
- Awards (
awards.new_award,awards.new_transaction) entity:<UEI>(recipient)award:<award_key>awarding_agency:<org_fh_key>(best-effort; prefersOrganization.l2_fh_keywhen available)funding_agency:<org_fh_key>(best-effort; prefersOrganization.l2_fh_keywhen available)- Opportunities (
opportunities.updated,opportunities.new_opportunity,opportunities.new_notice) opportunity:<opportunity_id>notice:<notice_id>notice_type:<code>(1-letter notice type code)agency:<...>- Entities (
entities.new_entity,entities.updated) entity:<UEI>- Grants (
grants.updated,grants.new_grant) grant:<grant_id>agency:<...>- Forecasts (
forecasts.updated,forecasts.new_forecast) forecast:<source_system:external_id>agency:<...>(may be an acronym)- Protests (
protests.new_protest,protests.updated) protest:<source_system:external_id>(e.g.gao:gao-b-424214.1)
2. Access requirements¶
Important: Webhook subscriptions are only available to Large and Enterprise tier users.
If you're on a Free or Small tier, you'll need to upgrade your subscription to access webhook functionality. Contact [email protected] for tier upgrade information.
3. On-boarding checklist¶
- Verify your tier – Ensure you have Large or Enterprise tier access.
- Provide a callback URL – a publicly reachable
https://endpoint that accepts HTTP POSTs. ‑ Recommended path:/tango/webhooks. - Receive your shared secret – Tango generates a 32-byte hex secret (64 hex chars) and shares it out-of-band. You'll use this to verify signatures.
- Test your endpoint – Use the test delivery endpoint to verify connectivity.
- Configure your filters (via subscriptions) –
• Catch-all (Enterprise only) – use
subject_ids: []to match all subjects for an event type. • Entity filtering – specify which UEIs you want to track. • Change-type filtering – choose whichevent_typevalues you want (e.g. new awards vs new transactions)
Note We create the initial Webhook Endpoint record for you. All subsequent management is done via the Subscription API below.
4. Security & authenticity¶
Every POST from Tango includes an HMAC-SHA-256 signature:
The digest is computed over the raw request body using your secret. Verify it like so (Python snippet):
import hmac, hashlib, os, flask, json
SECRET = os.environ["TANGO_WEBHOOK_SECRET"]
app = flask.Flask(__name__)
@app.post("/tango/webhooks")
def recv():
body = flask.request.get_data()
sig = flask.request.headers.get("X-Tango-Signature", "")[7:] # strip "sha256="
if not hmac.compare_digest(
hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest(), sig):
return "Invalid signature", 401
payload = json.loads(body)
# ... handle events ...
return "ok", 200
If you respond with any 2xx status, Tango marks the delivery as successful. Non-2xx responses and time-outs are retried (at-least-once delivery). Current retry limits are error-aware:
- 4xx: up to 2 attempts total
- 5xx: up to 5 attempts total
- network errors/timeouts: up to 7 attempts total
5. Subscription API¶
Base URL: https://tango.makegov.com/api/webhooks/
Auth: API Key – send Authorization: Api-Key <your-key>
5.0 Discover supported event types¶
Tango exposes a discovery endpoint so clients can validate configurations without hard-coding event types:
Response:
{
"event_types": [
{
"event_type": "awards.new_award",
"default_subject_type": "entity",
"description": "A new award became available (subject defaults to entity UEI).",
"schema_version": 1
}
],
"subject_types": ["entity", "award", "opportunity", "notice", "notice_type", "grant", "forecast", "agency", "awarding_agency", "funding_agency", "naics", "psc"],
"subject_type_definitions": [
{
"subject_type": "entity",
"description": "Entity UEI (vendor/recipient).",
"id_format": "UEI string (e.g. 'ABCDEF123456').",
"status": "active"
},
{
"subject_type": "agency",
"description": "Agency dimension for non-award domains (opportunities, grants, forecasts).",
"id_format": "Preferred: Organization l2_fh_key/fh_key (string integer). Fallback: legacy Agency.code or (forecasts) source acronym when no org mapping exists.",
"status": "active"
},
{
"subject_type": "awarding_agency",
"description": "Awarding agency (award-side) keyed by a stable Organization fh_key.",
"id_format": "Organization fh_key (string integer; prefers L2 via l2_fh_key when available).",
"status": "active"
},
{
"subject_type": "funding_agency",
"description": "Funding agency (award-side) keyed by a stable Organization fh_key.",
"id_format": "Organization fh_key (string integer; prefers L2 via l2_fh_key when available).",
"status": "active"
},
{
"subject_type": "naics",
"description": "NAICS classification dimension.",
"id_format": "NAICS code string (e.g. '541330').",
"status": "reserved"
}
// ... full list returned by the API
]
}
Note: Only some event types may be actively emitted at any given time. If you subscribe to an event type that is not currently emitted, you will simply not receive those events.
Note:
status: "reserved"means the subject type is accepted/validated for subscription configs, but may not be emitted by Tango yet (so matching events may be zero until producers/publishers start tagging those subjects).
5.1 List current subscriptions¶
Response
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": "e4c4…", // UUID
"subscription_name": "Track key vendors",
"payload": {
"records": [
{
"event_type": "awards.new_award",
"subject_type": "entity",
"subject_ids": ["UEI123ABC", "UEI987XYZ"]
},
{
"event_type": "awards.new_transaction",
"subject_type": "entity",
"subject_ids": ["UEI123ABC", "UEI987XYZ"]
}
]
},
"created_at": "2024-06-01T12:00:00Z"
}
]
}
5.2 Create / replace a subscription¶
Payload schema (subjects)¶
Each record now supports an explicit subject model:
subject_type: what you are subscribing to (e.g.entity)subject_ids: list of IDs for that subject type
For backward compatibility, resource_ids is accepted as an alias for subject_ids (do not send both).
Note (Legacy):
resource_idsis legacy/v1 terminology. Prefersubject_idsfor all new integrations. We intend to deprecate v1-only fields over time.
Example 1: Filter by specific entities only¶
{
"subscription_name": "Track specific vendors",
"payload": {
"records": [
{
"event_type": "awards.new_award",
"subject_type": "entity",
"subject_ids": ["UEI123ABC", "UEI987XYZ"]
},
{
"event_type": "awards.new_transaction",
"subject_type": "entity",
"subject_ids": ["UEI123ABC", "UEI987XYZ"]
}
]
}
}
Example 2: Filter by change types only (all entities)¶
Enterprise tiers only: Large tier users must list specific
subject_ids(no catch-all).
{
"subscription_name": "All new awards",
"payload": {
"records": [
{
"event_type": "awards.new_award",
"subject_type": "entity",
"subject_ids": [] // Empty array means all entities (Enterprise only)
}
]
}
}
Example 3: Combined entity and change-type filtering¶
{
"subscription_name": "Key vendor new awards",
"payload": {
"records": [
{
"event_type": "awards.new_award",
"subject_type": "entity",
"subject_ids": ["UEI123ABC", "UEI987XYZ"]
}
]
}
}
Example 4: Receive everything (default)¶
Enterprise tiers only: Large tier users must list specific
subject_ids(no catch-all).
{
"subscription_name": "All events",
"payload": {
"records": [
{
"event_type": "awards.new_award",
"subject_type": "entity",
"subject_ids": []
},
{
"event_type": "awards.new_transaction",
"subject_type": "entity",
"subject_ids": []
}
]
}
}
Returns 201 Created + body of the new subscription.
Example 5: Subscribe by award (instead of entity)¶
{
"subscription_name": "Award-specific updates",
"payload": {
"records": [
{
"event_type": "awards.new_transaction",
"subject_type": "award",
"subject_ids": ["W15QKN24C1234"]
}
]
}
}
Example 6: Subscribe by agency¶
For awards, agency subscriptions must specify whether you mean the funding or awarding agency using
subject_type: "funding_agency"orsubject_type: "awarding_agency". For non-award domains,subject_type: "agency"is still used.
{
"subscription_name": "All awards for a specific agency",
"payload": {
"records": [
{
"event_type": "awards.new_award",
"subject_type": "funding_agency",
"subject_ids": ["123456789"]
}
]
}
}
Example 7: Subscribe to opportunities by notice type¶
{
"subscription_name": "SAM notices: Pre-solicitation",
"payload": {
"records": [
{
"event_type": "opportunities.updated",
"subject_type": "notice_type",
"subject_ids": ["p"]
}
]
}
}
Available event types:
- Use
GET /webhooks/event-types/for the authoritative list. - Today, the primary emitted sources are:
- Awards:
awards.new_awardawards.new_transaction
- Opportunities:
opportunities.new_opportunityopportunities.new_noticeopportunities.updated
- Entities:
entities.new_entityentities.updated
- Grants:
grants.new_grantgrants.updated
- Forecasts:
forecasts.new_forecastforecasts.updated(subject id is"<source_system>:<external_id>", e.g."HHS:abc-123")
- Protests:
protests.new_protestprotests.updated(subject id is"<source_system>:<external_id>", e.g."gao:gao-b-424214.1")
5.3 Update an existing subscription¶
Body identical to POST – it replaces the stored subscription configuration.
5.4 Delete a subscription¶
If you delete every subscription row, you will stop receiving webhooks until you create at least one new subscription.
Note: You must maintain at least one subscription row to receive webhooks.
5.5 Test webhook delivery¶
Sends a test webhook to your endpoint to verify connectivity. Returns detailed information about the delivery attempt.
Response (success):
{
"success": true,
"status_code": 200,
"response_time_ms": 145,
"message": "Test delivery successful! Response time: 145ms. Your webhook endpoint is configured correctly."
}
Response (failure):
{
"success": false,
"status_code": 500,
"message": "Test delivery failed with status 500. Please check your endpoint implementation and ensure it returns 2xx status codes.",
"response_body": "<first 1000 chars of response>"
}
5.6 Get sample payload¶
Returns a sample webhook payload for testing your handler implementation.
Notes:
GET /webhooks/endpoints/sample-payload/(no params) returns samples for all supported event types.GET /webhooks/endpoints/sample-payload/?event_type=<event_type>returns a single sample.
Response:
{
"event_type": "awards.new_award",
"sample_delivery": {
"timestamp": "2024-01-15T10:30:00Z",
"events": [
{
"event_type": "awards.new_award",
"created_at": "2024-01-15T10:29:12.123Z",
"change": "new_award",
"award_type": "contract",
"award_key": "CONT_AWD_12345_9700_SPE2DX22D0001_9700",
"recipient_id": "UEI123ABC"
}
]
},
"sample_subjects": [
{"subject_type": "entity", "subject_id": "UEI123ABC"},
{"subject_type": "award", "subject_id": "CONT_AWD_12345_9700_SPE2DX22D0001_9700"}
],
"sample_subscription_requests": {
"by_subject_type": {
"entity": {
"subscription_name": "Sample: awards.new_award by entity",
"payload": {
"records": [
{"event_type": "awards.new_award", "subject_type": "entity", "subject_ids": ["UEI123ABC"]}
]
}
}
},
"catch_all": {
"subscription_name": "Sample: awards.new_award (catch-all)",
"payload": {
"records": [
{"event_type": "awards.new_award", "subject_type": "entity", "subject_ids": []}
]
}
}
}
}
6. Payload format¶
A single delivery looks like:
{
"timestamp": "2024-01-15T10:30:00Z",
"events": [
{
"event_type": "awards.new_transaction",
"created_at": "2024-01-15T10:29:12.123Z",
"change": "new_transaction",
"award_key": "OT_AWD_FA24012490094_9700_-NONE-_-NONE-",
"award_type": "ota",
"recipient_id": "UEI123ABC",
"transaction_ids": [
"OT_9700_-NONE-_FA24012490094_0_-NONE-_-NONE-"
]
},
{
"event_type": "awards.new_award",
"created_at": "2024-01-15T10:29:12.123Z",
"change": "new_award",
"award_key": "OT_AWD_FA24012490094_9700_-NONE-_-NONE-",
"award_type": "ota"
}
]
}
6.1 Event types and payloads¶
New Award Events¶
{
"event_type": "awards.new_award",
"created_at": "2024-01-15T10:29:12.123Z",
"change": "new_award",
"award_type": "contract", // contract | idv | ota | otidv
"award_key": "W15QKN24C1234",
"recipient_id": "UEI123ABC"
}
New Transaction Events¶
{
"event_type": "awards.new_transaction",
"created_at": "2024-01-15T10:29:12.123Z",
"change": "new_transaction",
"award_type": "contract",
"award_key": "W15QKN24C1234",
"recipient_id": "UEI123ABC",
"transaction_ids": ["TXN_KEY_A", "TXN_KEY_B", "TXN_KEY_C"]
}
Entity Events¶
{
"event_type": "entities.new_entity",
"created_at": "2024-01-15T10:29:12.123Z",
"change": "new_entity",
"uei": "UEI123ABC"
}
{
"event_type": "entities.updated",
"created_at": "2024-01-15T10:29:12.123Z",
"change": "updated",
"uei": "UEI123ABC"
}
Protest Events¶
{
"event_type": "protests.new_protest",
"created_at": "2024-01-15T10:29:12.123Z",
"source_system": "gao",
"external_id": "gao-b-424214.1"
}
{
"event_type": "protests.updated",
"created_at": "2024-01-15T10:29:12.123Z",
"source_system": "gao",
"external_id": "gao-b-424214.1"
}
Key facts:
- Batched – events are grouped per endpoint per dispatch run.
- At-least-once – retries can cause duplicates; your handler must be idempotent. If you need a de-dupe key, derive it from stable identifiers in each event (e.g.
event_type+award_key+recipient_id+change). - Server-side filtered – only events matching your subscription filters are sent.
Examples¶
These are copy/paste subscription payloads for common use cases.
Notes:
- Replace placeholder IDs like
<UEI>/<ORG_FH_KEY>/<OPPORTUNITY_UUID>with real values. - For agency-based filters, we recommend using the Organization
fh_key/l2_fh_key(stable). You can look this up via/api/organizations/(search by agency name/acronym).
Subscribe to new awards funded by the VA¶
{
"subscription_name": "New awards funded by the VA",
"payload": {
"records": [
{
"event_type": "awards.new_award",
"subject_type": "funding_agency",
"subject_ids": ["<VA_ORG_FH_KEY>"]
}
]
}
}
Subscribe to new awards for Oshkosh¶
{
"subscription_name": "New awards for Oshkosh (by UEI)",
"payload": {
"records": [
{
"event_type": "awards.new_award",
"subject_type": "entity",
"subject_ids": ["<OSHKOSH_UEI>"]
}
]
}
}
Subscribe to new opportunities out of CMS¶
{
"subscription_name": "New opportunities from CMS",
"payload": {
"records": [
{
"event_type": "opportunities.new_opportunity",
"subject_type": "agency",
"subject_ids": ["<CMS_ORG_FH_KEY>"]
}
]
}
}
Subscribe to updates for opportunity <UUID>¶
If you want both updates and new notices for the same opportunity, include both records:
{
"subscription_name": "Updates + new notices for one opportunity",
"payload": {
"records": [
{
"event_type": "opportunities.updated",
"subject_type": "opportunity",
"subject_ids": ["<OPPORTUNITY_UUID>"]
},
{
"event_type": "opportunities.new_notice",
"subject_type": "opportunity",
"subject_ids": ["<OPPORTUNITY_UUID>"]
}
]
}
}
Subscribe to updates on forecasts out of GSA¶
{
"subscription_name": "Forecast updates from GSA",
"payload": {
"records": [
{
"event_type": "forecasts.updated",
"subject_type": "agency",
"subject_ids": ["<GSA_ORG_FH_KEY>"]
}
]
}
}
Subscribe to new and updated GAO protests¶
{
"subscription_name": "GAO bid protests",
"payload": {
"records": [
{
"event_type": "protests.new_protest",
"subject_type": "protest",
"subject_ids": ["gao:gao-b-424214.1"]
},
{
"event_type": "protests.updated",
"subject_type": "protest",
"subject_ids": ["gao:gao-b-424214.1"]
}
]
}
}
7. Filtering strategies¶
Note (catch-all / wildcard):
subject_ids: [](or legacyresource_ids: []) means “all subjects” for that record. This is Enterprise only; Large tier users must list specific IDs.
7.1 High-volume integrations¶
For applications processing many entities, filter by event type to reduce noise:
{
"subscription_name": "New awards only",
"payload": {
"records": [
{
"event_type": "awards.new_award",
"resource_ids": [] // All entities, only new awards
}
]
}
}
7.2 Entity-focused integrations¶
For applications tracking specific vendors, filter by entity:
{
"subscription_name": "Track key vendors",
"payload": {
"records": [
{
"event_type": "awards.new_award",
"resource_ids": ["UEI123ABC", "UEI987XYZ"]
},
{
"event_type": "awards.new_transaction",
"resource_ids": ["UEI123ABC", "UEI987XYZ"]
}
]
}
}
7.3 Precision integrations¶
For maximum control, specify exactly what you need:
{
"subscription_name": "Critical vendor new awards",
"payload": {
"records": [
{
"event_type": "awards.new_award",
"resource_ids": ["UEI123ABC"] // Only new awards for this specific vendor
}
]
}
}
7.4 Multiple event type combinations¶
You can create complex filters by combining multiple records:
{
"subscription_name": "Mixed tracking",
"payload": {
"records": [
{
"event_type": "awards.new_award",
"resource_ids": [] // All new awards
},
{
"event_type": "awards.new_transaction",
"resource_ids": ["UEI123ABC", "UEI456DEF"] // Transactions for specific vendors only
}
]
}
}
7.5 Client-side filtering¶
You can still filter in your webhook handler if needed:
@app.post("/tango/webhooks")
def handle_webhook():
payload = json.loads(request.get_data())
for event in payload["events"]:
if event.get("change") == "new_award":
# Handle only new awards
process_new_award(event)
But server-side filtering is more efficient and reduces bandwidth usage.
8. Best practices on your side¶
- Return 200 quickly — enqueue the work in your own job queue and respond; do not block processing.
- Test your endpoint first — use the test delivery endpoint to verify connectivity before going live.
- Harden the endpoint — HTTPS only, accept
POSTonly, max-payload 256 KB. - Store the last successful timestamp — helps spot missed deliveries.
- Use exponential back-off when pulling details — Tango's public API has rate limits; stagger follow-up fetches if you receive a large batch.
- Configure appropriate filters — reduce bandwidth and processing by filtering server-side.
- Monitor endpoint health — Tango uses circuit breaker patterns to protect both systems from cascading failures.
9. Reliability features¶
Circuit Breaker Pattern¶
Tango implements automatic circuit breaker protection for webhook endpoints:
- Automatic failure detection — After repeated failures (currently: 5 consecutive failures), the circuit opens
- Cool-down — While open, deliveries are skipped for a short period (currently: 5 minutes)
- Recovery testing — After cool-down, Tango allows a single probe delivery (half-open)
- Automatic recovery — Upon success, normal operation resumes; upon failure, the circuit re-opens (currently: 10 minute cool-down)
- Resource protection — Prevents wasting resources on consistently failing endpoints
This ensures both Tango and your systems remain stable even during outages.
Retry Strategy¶
Failed webhooks are retried with:
- Error-aware retry limits — Retry caps differ by error type:
- Client errors (4xx): up to 2 attempts total
- Server errors (5xx): up to 5 attempts total
- Network errors/timeouts: up to 7 attempts total
10. Troubleshooting¶
| Symptom | Most likely cause | Next steps |
|---|---|---|
| Receive 401 from Tango on Subscription API | Missing/invalid API key | Ensure Authorization: Api-Key … header |
| Receive 403 on Subscription API | Insufficient tier access | Upgrade to Large or Enterprise tier |
| Webhook payloads stop arriving | Circuit breaker activated due to failures | Fix endpoint issues; circuit will auto-recover after cool-down |
| Test delivery fails | Endpoint connectivity issues | Check HTTPS cert, firewall rules, response time |
| Signature mismatch | Using wrong secret or modified body | Re-sync secret; ensure you hash the raw bytes exactly |
| Not receiving expected events | Incorrect subscription filters | Review your payload.records configuration |
| Receiving too many events | No filters or broad filters | Add specific subject_ids (or legacy resource_ids) or limit event_type values |
Need help? Email [email protected] with your endpoint URL & the approximate timestamp of the last delivery you saw.
Happy shipping! 🚀
Tango MCP (AI agents)¶
The Tango MCP server gives AI agents access to federal procurement competitive intelligence via the Tango API. The server is hosted at https://govcon.dev/mcp and uses HTTP transport — you connect your MCP client to the remote endpoint; no local install required. Use it from Claude Desktop, Cursor, the OpenAI Responses API, or any MCP-compatible client.
What it does¶
The server exposes 4 tools that let an AI agent research government contracting data on your behalf:
- Discover what's in the data — Use
resolveto find entities, agencies, vehicles, NAICS/PSC codes, contracts, opportunities, and more by name or keyword; get identifiers and previews to use with other tools. - Search contracts and related data — Use
searchto query contracts, IDVs, vehicles, OTAs, OTIDVs, subawards, and organizations by vendor, agency, NAICS, PSC, dates, and other filters; optionally get aggregate statistics (obligated amounts, set-aside breakdown, etc.). - Search active opportunities — Use
search_opportunitiesto find SAM.gov opportunities, forecasts, and notices by agency, NAICS, set-aside type, response deadline, and keyword. - Get full details for any item — Use
get_detailsto retrieve detailed information for a specific entity, contract, IDV, vehicle, agency, opportunity, OTA, OTIDV, or organization by ID, with optional related-data enrichment.
Quick start¶
Prerequisites¶
- A Tango API key (from the Tango web interface), or for OAuth clients: access tokens via
Authorization: Bearer <access_token> - An MCP-compatible client (e.g. Cursor, Claude Desktop)
Connect via HTTP¶
The server is hosted at https://govcon.dev. The MCP endpoint is https://govcon.dev/mcp. Configure your client to connect to this URL over HTTP and send your API key (see Using with MCP clients below).
Using with MCP clients¶
Remote MCP (HTTP) — recommended¶
Connect your client to the hosted server over HTTP using mcp-remote. The server expects your Tango API key in the X-Tango-API-Key header (or an OAuth bearer token in Authorization: Bearer).
Cursor / Claude with remote URL (API key):
{
"mcpServers": {
"tango-remote": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://govcon.dev/mcp",
"--header",
"X-Tango-API-Key: your_api_key_here"
]
}
}
}
Cursor / Claude with remote URL (OAuth bearer token):
{
"mcpServers": {
"tango-remote-oauth": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://govcon.dev/mcp",
"--header",
"Authorization: Bearer your_oauth_token_here"
]
}
}
}
Use a fresh access token from your Tango OAuth flow; refresh the token when it expires.
Streamable HTTP (JSON mode) — The server uses HTTP transport and returns JSON responses rather than Server-Sent Events (SSE). If you see errors like "Unexpected content type" or "Failed to open SSE stream", ensure the client uses JSON mode.
API key security — Prefer setting the API key via environment variable or a secrets manager. When using mcp-remote with --header X-Tango-API-Key: ..., avoid committing the key to config; use a local env var or secret so the key is not logged or stored in plain text.
Claude Desktop¶
If you have the Tango MCP Desktop Extension (.mcpb), install it in Claude Desktop (Settings → Extensions), set the Server URL to https://govcon.dev/mcp, and enter your Tango API key when prompted. The extension connects to the hosted server over HTTP — no local server required.
OAuth flow¶
When connecting over HTTP, you can authenticate with a bearer token instead of an API key. This is useful for clients that support OAuth (e.g. ChatGPT MCP) or when you obtain access tokens from Tango's OAuth server.
-
Obtain an access token from the Tango OAuth server at tango.makegov.com. Use the authorization code or client credentials flow; supported grant types include
authorization_code,client_credentials, andrefresh_token. Required scope is typicallyread. -
Send the token on each request via the
Authorizationheader:Authorization: Bearer <your_access_token>. -
Auth precedence — The server resolves auth in this order: (1)
Authorization: Bearerif present, (2)X-Tango-API-Keyif present, (3)TANGO_API_KEYfrom the environment (stdio/local only).
OAuth discovery — The server exposes standard discovery endpoints so clients can find the Tango authorization server and required scopes:
- Authorization server metadata:
GET /.well-known/oauth-authorization-serverandGET /mcp/.well-known/oauth-authorization-server - Protected resource metadata:
GET /.well-known/oauth-protected-resource
These return JSON (issuer, authorization_endpoint, token_endpoint, scopes_supported, etc.). The default issuer is https://tango.makegov.com.
OpenAI Responses API¶
OpenAI's MCP integration requires a publicly accessible server. Use the hosted MCP endpoint https://govcon.dev/mcp in your tools configuration. See the OpenAI MCP documentation for details.
Available tools¶
| Tool | Description |
|---|---|
resolve |
Find entities, agencies, vehicles, NAICS/PSC codes, contracts, opportunities, OTAs, OTIDVs, subawards, and organizations matching a search query. Use first when you have a name or keyword and need to discover what's in the data; returns identifiers and previews for use with other tools. |
search |
Search contracts, IDVs, vehicles, OTAs, OTIDVs, subawards, and organizations. Primary data tool: filter by vendor, agency, NAICS, PSC, dates, keyword, and more. Set include_summary=true for aggregate statistics (total obligated, set-aside breakdown, etc.) across matching records. |
search_opportunities |
Search open opportunities, forecasts, and notices. Filter by agency, NAICS, PSC, set-aside type, response deadline, keyword, and other criteria. |
get_details |
Get detailed information for a single item by ID and type (entity, contract, idv, vehicle, agency, opportunity, ota, otidv, organization). Use after search or resolve to drill into a specific record. Optional include_related enriches with related data (e.g. entity + contracts + socioeconomic; contract + subawards). |
Configuration¶
- API key vs OAuth: Send your Tango API key in the
X-Tango-API-Keyheader, or useAuthorization: Bearer <token>with an OAuth access token from tango.makegov.com. - Endpoint: The hosted server is at https://govcon.dev; the MCP endpoint is
https://govcon.dev/mcp(HTTP transport).
Troubleshooting¶
424 error from OpenAI — OpenAI can only reach publicly accessible servers. Use the hosted endpoint https://govcon.dev/mcp.
Empty results — Verify your API key is valid. Check that the UEI, NAICS code, or other identifiers you are using exist in the Tango database.
502 Bad Gateway / "Failed to open SSE stream" — The server uses HTTP transport and JSON responses, not SSE. If the client expects SSE, use a client that supports JSON mode.
403 when calling the server URL — A proxy or firewall may be blocking the request to https://govcon.dev/mcp. Ensure your client sends the API key or Bearer token as described above.
"Invalid API key or authentication required" — When connecting to https://govcon.dev/mcp, the server must receive either your Tango API key in the X-Tango-API-Key header or an OAuth bearer token in the Authorization: Bearer <token> header. Ensure your MCP client is configured to send one of these.
Get help¶
For API keys, account issues, or MCP connection problems:
- Email: [email protected]
- Tango web interface: tango.makegov.com — sign in to manage your account and API keys.
Privacy¶
Data handling and privacy are described in our Privacy policy.
References¶
- govcon.dev — Hosted Tango MCP server (HTTP transport)
- Model Context Protocol Specification
- MCP Inspector — Interactive testing and debugging for MCP servers
- OpenAI MCP Documentation
- Tango API
Changelog¶
This is the most up-to-date change log for Tango and the Tango API.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased¶
Added¶
Changed¶
Breaking¶
Fixed¶
[3.34.5] - 2026-03-12¶
- No user-facing changes
[3.34.4] - 2026-03-12¶
Changed¶
- API (Opportunities): Improved search performance — full-text and attachment search queries now use UNION for independent index usage
- API (Opportunities):
office(*)expand unchanged in output but now backed by unified Organization model for faster responses
[3.34.3] - 2026-03-11¶
Added¶
- API: Text search parameters (
search,recipient,agency,name, etc.) now require at least 2 characters — single-character queries return a400with a descriptive error message (refs #1725)
Changed¶
- API (Protests): Improved entity resolution confidence for near-exact name matches — names differing only by pluralization or punctuation now produce higher confidence scores (refs #1702)
Fixed¶
- API (Protests): Entity resolution no longer times out on candidate queries (fixes #1700, #1701)
[3.34.2] - 2026-03-11¶
Added¶
- API (CALC Rates): New
/api/idvs/{key}/lcats/endpoint for GSA CALC labor category pricing data scoped to a specific IDV (refs #1703) - API (CALC Rates): New
/api/entities/{uei}/lcats/endpoint for CALC rates scoped to an entity - API (CALC Rates): Filters: vendor_name, labor_category, price range, education_level, experience, worksite, business_size, sin, category, full-text search
- API (CALC Rates): Response shaping with
idv(key,piid,award_date),recipient(uei,display_name), andbusiness_size(code,description)expansions - API (CALC Rates): Default shape applied automatically;
?flat=trueworks without an explicit?shape=parameter - API: New
RequiresAccessLevelgeneric tier-based permission class for endpoint gating - API: New
PremiumQueryThrottlefor premium query rate limiting on expensive endpoints
Fixed¶
- API (Entities): Fixed an issue that could prevent the
past_performanceexpansion data from refreshing correctly (fixes #1710) - API (Protests):
?flat=truewithout an explicit?shape=now works on/api/protests/(fixes #1711)
[3.34.0] - 2026-03-10¶
Added¶
- API (Shaping): Bracket parameter syntax — expansions now accept
[key=value]parameters for server-side configuration (e.g.,past_performance[top=10](*)). Parameters are validated with type checking and range enforcement. - API (Entities): New
past_performanceexpansion on/api/entities/— aggregated contract history showing top agencies, NAICS/PSC codes, and obligation totals. Use?shape=uei,past_performance(*)for defaults orpast_performance[top=10](summary,top_agencies)to control how many agencies are returned (default 5, max 100). (refs #1587) - API (Organizations): The organization detail endpoint now accepts either an integer
fh_keyor a UUIDkeyas the URL parameter. Historicalfh_keyredirects (301) are preserved on the integer path. (refs #1548)
Breaking¶
- API: Date range filters now return HTTP 400 for invalid date formats (non-
YYYY-MM-DD) and inverted ranges (start > end). Previously, some endpoints returned HTTP 200 with an error message in the response body. Affected endpoints: contracts, IDVs, OTAs, OTIDVs, opportunities, notices, grants, forecasts, protests (fixes #1690)
Fixed¶
- API: Date filter validation is now consistent across all endpoints. Invalid dates and inverted ranges always return a clear 400 error identifying the problematic parameter and value (fixes #1690)
[3.33.0] - 2026-03-09¶
Added¶
- API (Protests): Entity and organization resolution — use
?shape=...,resolved_protester(*)to see which canonical entity a protester name maps to (by UEI), and?shape=...,resolved_agency(*)for the matched organization (by UUID key). Each includesmatch_confidence("confident"or"review") and a human-readablerationale. Low-confidence matches returnnull. - API: Paginated endpoints that use approximate counts (contracts, IDVs, opportunities, notices) now support
?exact=trueto request an exact count instead of an estimate. On endpoints that already use exact counts, the parameter is accepted but has no effect. See Result counts. - API: All paginated list responses now include an
X-Results-CountTypeheader (exactorapproximate) indicating whether the count is exact or estimated.
Breaking¶
- API: The
count_typefield has been removed from paginated response bodies. Count exactness is now reported exclusively via theX-Results-CountTyperesponse header.
Fixed¶
- API:
X-Results-CountTypeheader now correctly reportsexactwhen the count is known to be exact, instead of always reportingapproximate. - API: Fixed a rare bug where paginated list endpoints could return empty results (
count: 0) when database statistics were stale. - API: Fixed a performance issue where certain paginated list requests could trigger expensive full-table evaluations instead of optimized counting.
- API (Shaping):
?show_shapes=trueschema discovery now includes expand names in thefieldslist. Previously, expand-only names (e.g.,recipient,awarding_office) appeared underexpandsbut were missing fromfields, giving clients an incomplete view of valid shape keys. (fixes #1685)
[3.32.2] - 2026-03-08¶
Added¶
- Opportunities: New
/api/opportunities/attachment-search/endpoint — search across opportunity attachment text using semantic + keyword hybrid search. Requires a Medium plan or higher. (refs #1645) - Forecasts: Support 7 new forecast agencies — DOI, DOL, DOT, VA, NRC, DOE, Treasury. Forecast data from these agencies is now loaded and available via the API.
Changed¶
- API: Tier-related error responses and upgrade hints now display user-facing plan names (Free, Micro, Medium, Enterprise) instead of internal tier codes.
[3.32.1] - 2026-03-08¶
Added¶
- API (Opportunities): The opportunity detail endpoint (
/api/opportunities/{id}/) now resolves notice UUIDs to their parent opportunity. If you pass a notice UUID, you get a 302 redirect to the parent opportunity instead of a 404. (refs #1592)
Breaking¶
- API (Vehicles): Vehicle orders endpoint (
/api/vehicles/:uuid/orders/) now uses standard page-number pagination (?page=&limit=) instead of cursor-based pagination (?cursor=&limit=). This fixes broken backward pagination and simplifies the endpoint. (fixes #1653)
Fixed¶
- API (Opportunities/Notices): 32-byte hex UUID redirects now preserve query string parameters (
?shape=,?show_shapes=,?flat=, etc.). Previously, requesting an opportunity or notice by its undashed UUID with shaping parameters would silently drop those parameters during the redirect.
[3.32.0] - 2026-03-06¶
Added¶
- API (IDVs): IDV list and detail responses now use response shaping by default. All fields from the IDV serializers are available via
?shape=, including 42 premium detail fields (competition details, fee ranges, ordering procedures, etc.). Choice fields (idv_type,multiple_or_single_award_idv,type_of_idc) can be expanded to{code, description}objects.period_of_performance(*)now includeslast_date_to_order. New shapeable expands:naics(code,description),psc(code,description),set_aside(code,description),competition(*),officers(*),legislative_mandates(*). (refs #1601) - API (Vehicles): Vehicle list and detail responses now use response shaping by default, providing consistent structured output. (refs #1601)
- API (OTAs): Full response shaping support.
type_of_ot_agreement,extent_competed, andaward_typeare now expandable to{code, description}via?shape=.award_typeuses OTA-specific choices ("O" = Other Transaction Non-Research, "R" = Other Transaction for Research). New shapeable expands:psc(code,description). Added fields:consortia_uei,dod_acquisition_program,non_governmental_dollars,non_traditional_government_contractor_participation,parent_award_modification_number. Note: OTAs do not have anaics_codefield ornaicsexpand. (refs #1600) - API (OTIDVs): Full response shaping support.
type_of_ot_agreementandextent_competedare now expandable to{code, description}via?shape=. New shapeable expands:psc(code,description). Added fields:consortia_uei,dod_acquisition_program,non_governmental_dollars,non_traditional_government_contractor_participation. Note: OTIDVs do not have anaics_codefield ornaicsexpand. (refs #1600) - Docs: Documented
wildcard_fieldsproperty inavailable_fieldsschema — whentrue, the expansion accepts arbitrary field names (freeform JSON likeraw_data(*)); whenfalse, only the listed fields are valid. (refs #1600) - API (Subawards): Subaward list and detail endpoints (
/api/subawards/,/api/subawards/{id}/) now use a default response shape by default — no?shape=parameter needed. Responses include key award fields, recipient/awarding agency info, and officer lists with canonical agency names. Custom shapes via?shape=still work as before. (refs #1602)
Fixed¶
- API (Shaping):
wildcard_fieldsinavailable_fieldsschema was serialized as the string"False"instead of JSONfalsein 400 error responses (e.g., invalid shape requests). The?show_shapes=truepath was unaffected. All shaped endpoints are now consistent. (refs #1600) - API (IDVs): Pagination
counton/api/idvs/{key}/awards/now returns an exact value instead of an EXPLAIN-based estimate, which could be inaccurate for queries with subquery predicates. (refs #1601) - API (Vehicles): Pagination
counton/api/vehicles/{uuid}/awardees/now returns an exact value instead of an EXPLAIN-based estimate. (refs #1601) - API (Vehicles):
?exact=trueon/api/vehicles/{uuid}/orders/no longer creates a separate cache entry — counts on this endpoint are always exact, so the parameter is now a no-op for caching purposes. (refs #1601)
[3.31.5] - 2026-03-05¶
Added¶
- API: Tier-based access control — responses from gated endpoints now include
meta.upgrade_hintslisting fields or filters that require a higher plan tier. Free-tier users hitting a gated filter (e.g., full-text search on opportunities) receive a structured 403 with upgrade information instead of an opaque error. (refs #1598) - Opportunities:
extracted_textin attachment expansions is now gated to pro+ plans. Full-text search filters on opportunities and notices are gated to pro+ plans. (refs #1598)
[3.31.4] - 2026-03-05¶
Fixed¶
- API (Vehicles): Fixed 504 gateway timeouts on
/api/vehicles/{uuid}/orders/. Requests with?exact=truewere triggering a slowCOUNT(*)across a 3-table join; the endpoint now uses an indexed subquery and should be significantly faster. (fixes TANGO-R15) - API (Vehicles): Fixed a bug where passing
?page=1to/api/vehicles/{uuid}/orders/would bypass the fast path, causing ~15s response times and inaccurate counts. Thepageparameter is now ignored (this endpoint uses cursor pagination). (refs #1624)
[3.31.3] - 2026-03-04¶
Added¶
- API (Shaping):
?show_shapes=trueon any shaped endpoint appends a_shapingkey at the bottom of the response containingavailable_fields— the full schema of fields and expansions available for that endpoint. Truthy values:true,1,yes,on. (refs #1545) - API (Shaping): 400 error responses for invalid shapes now always include
available_fieldsat the top level, so clients can see what's valid without a successful request. (refs #1545) - Docs: Added "Discovering available fields" section to Response Shaping documenting
?show_shapesand the_shapingresponse block. (refs #1545)
Breaking¶
- Entities API:
relationshipsis no longer included in the default list response for/api/entities/. Clients that need relationships on list results can opt in via response shaping:?shape=...,relationships(*). The detail endpoint (/api/entities/{uei}/) still includesrelationshipsby default. (closes #1579)
Fixed¶
- API (Forecasts): The forecast detail endpoint (
/api/forecasts/{id}/) now correctly supports response shaping via?shape=. Previously, the?shape=parameter was silently ignored on the detail endpoint — it only worked on the list endpoint. The detail response now uses the shaping pipeline by default, including adisplayexpand with normalized display fields. - API: Error responses now return correct HTTP status codes (404 for invalid resources, 400 for bad query parameters) instead of always returning 200. Affects
NotFound, validation errors, field errors, and search errors. (fixes #1349) - API (Awards): Invalid date format parameters (
award_date,award_date_gte,award_date_lte) now return HTTP 400 with a descriptive error message instead of silently returning empty results. (fixes #1349) - API (Entities): Fixed intermittent 504 timeouts on entity detail requests (
/api/entities/{uei}/) caused by cold-cache stampedes on the underlying database view. Entity obligation data now caches for longer and is pre-populated when entities appear in list responses. (fixes #1344)
[3.31.2] - 2026-03-03¶
Fixed¶
- API: Fixed an edge case where certain error responses could fail to render when raised outside normal request processing (e.g. middleware exceptions). (fixes #1608)
[3.31.1] - 2026-03-03¶
Added¶
- API (Protests): New
/api/protests/endpoint for GAO bid protest data — list and detail views with filter, search, and response shaping. Detail endpoint keyed bycase_id. Use?shape=...,dockets(*)to expand docket-level data. Gated behindPROTESTS_APIfeature flag.
[3.31.0] - 2026-03-03¶
Breaking¶
- Awards: removed the deprecated IDV summary endpoints (
GET /api/idvs/{identifier}/summary/andGET /api/idvs/{identifier}/summary/awards/). Use the Vehicles API (GET /api/vehicles/andGET /api/vehicles/{uuid}/) instead. (closes #1365)
[3.30.4] - 2026-03-03¶
Added¶
- Docs: Added MCP (AI agents) documentation — covers connecting Claude Desktop, Cursor, and the OpenAI Responses API to the hosted Tango MCP server at
govcon.dev; includes tool reference, auth options (API key and OAuth), and troubleshooting. (refs #1571) - API (Opportunities):
/api/opportunities/now has a default shape — all responses go through the shaping pipeline. List responses return core fields withmeta(*),office(*),place_of_performance(*)expanded by default. Detail responses additionally includeattachments(*),description,notice_history(*),primary_contact(*). (refs #1530, part of #1524) - API (Opportunities):
set_asideis now expandable to{code, description}via?shape=set_aside(code,description)orset_aside(*)— consistent with the awards shaping pattern. (refs #1530, fixes makegov/tango-public#44) - API (Opportunities): New shaping expansions:
notice_history(...)(opportunity timeline),primary_contact(...),secondary_contact(...). Available via?shape=on both list and detail. - API (Opportunities): Additional shapeable fields and expansions:
latest_notice_id,archive_date,agency_id,department_id,office_id, plusagency(*),department(*), andlatest_notice(notice_id,link). - API (Notices):
/api/notices/now has a default shape — all responses go through the shaping pipeline. List responses expandaddress(*),meta(*),office(*),opportunity(*),place_of_performance(*)by default. Detail responses additionally includearchive(*),primary_contact(*),secondary_contact(*). (refs #1530, part of #1524) - API (Notices):
set_asideis now expandable to{code, description}via?shape=set_aside(*). New expansions:archive(date,type),opportunity(opportunity_id,link),secondary_contact(...),set_aside(code,description). (refs #1530) - API (Notices):
award_numberis now available as a shapeable field (previously only in serializer output). (refs #1530) - API (Notices):
opportunity_idis now available as a shapeable field. - Docs: Updated Opportunities API Reference and Notices API Reference with Response Shaping sections — available fields, expansions, default shapes (list vs. detail), and SDK examples.
- API (Organizations):
/api/organizations/now has a default shape — all responses go through the shaping pipeline, returningkey, fh_key, name, short_name, type, level, is_active, code, fpds_code, cgac, canonical_code, parent_fh_key, full_parent_path_nameby default. (refs #1543, part of #1524) - API (Organizations):
fh_keyis now returned as a zero-padded 9-character string (e.g.,"000000001") everywhere — root fields, expands, and alll{n}_fh_keyfields. Previously returned as a raw integer. (refs #1543) - API (Organizations): New root fields available via shaping:
canonical_code,fpds_org_id,aac_code,start_date,end_date,logo,summary,l1_fh_keythroughl8_fh_key,total_obligations,tree_obligations. (refs #1543) - API (Organizations): New
department(code, name, abbreviation)andagency(code, name, abbreviation)expands let you retrieve legacy-compatible department/agency data from any organization. Returnsnullwhen not applicable (e.g., a department doesn't have a department above it). Safe to use in list responses with mixed hierarchy levels. (refs #1543) - API (Organizations): Enriched
ancestorsexpand now includesleveland cachedshort_name.parentandchildrenexpands now includecodeandcgac. (refs #1543) - Docs: Updated Organizations API Reference and Organizations Data Dictionary with all new fields, expands, and default shape details.
- API (Reference Data): Five reference data endpoints now support the
?shape=query parameter for response shaping:/api/business_types/,/api/mas_sins/,/api/naics/,/api/psc/, and/api/assistance_listings/. Default responses are backward-compatible. (refs #1527, part of #1524) - API (NAICS):
size_standardsandfederal_obligationsare now available as shaping expansions on/api/naics/. Use?shape=code,description,size_standards(*),federal_obligations(*)instead of the legacy?show_limits=1parameter. Detail responses include both expansions by default. (refs #1527) - API (Agencies): Legacy agency endpoints (
/api/departments/,/api/agencies/,/api/offices/) now support the?shape=query parameter for response shaping, letting clients select specific fields per request. (refs #1526, part of #1524) - Docs: API reference pages for Departments, Agencies, and Offices now include Response Shaping sections with available fields, expansions, default shapes, and examples.
Changed¶
- API (Organizations):
fh_keytype changed from integer to zero-padded string in all API responses. If you parsefh_keyas a number, this is a format change. The integer value is preserved (e.g.,"000000001"→1). (refs #1543) - API (Organizations): Detail endpoint now returns inactive organizations directly — active-only filtering only applies to list requests. Previously,
GET /api/organizations/{fh_key}/returned 404 for inactive orgs unlessinclude_inactive=truewas passed. (refs #1543) - API (Agencies): The
organizationfield has been removed from/api/departments/and/api/agencies/responses. This was an internal FK that leaked an opaque identifier and was never part of the documented API contract. (refs #1526) - API (NAICS): The
?show_limits=1parameter is now deprecated in favor of?shape=code,description,size_standards(*),federal_obligations(*). The legacy parameter still works but has been removed from the OpenAPI/Swagger docs. (refs #1527) - API (Awards): Default
parent_awardin contract and IDV responses is now a minimal{key, piid}reference — no database query required. To get the full parent award object, use theshapeparameter withparent_award(key,piid)orparent_award(*). OTIDV endpoints are unchanged. (refs #1576)
Breaking¶
- API (Financial assistance): Removed the
financial_assistanceapp and the assistance transactions API surface. CFDA reference data viaAssistanceListingremains (e.g./api/assistance_listings/is unchanged). (refs #1567)
Fixed¶
- API (Shaping): Bare relation-backed expand names requested as leaf fields (e.g.
?shape=opportunity) are now treated asfield(*)to prevent 500s caused by non-JSON-serializable ORM objects. - API (Shaping): Leaf auto-promotion no longer interferes with
field_map-backed leaf fields (e.g. Grantsstatus). - API (Vehicles): Vehicle full-text search now includes solicitation title. Vehicles can be found by common name (e.g. "CIO-SP3") as well as solicitation identifier. (closes #1573)
[3.30.3] - 2026-03-02¶
Added¶
- Docs: Added MCP (AI agents) documentation — covers connecting Claude Desktop, Cursor, and the OpenAI Responses API to the hosted Tango MCP server at
govcon.dev; includes tool reference, auth options (API key and OAuth), and troubleshooting. (refs #1571) - API (Organizations): Fixed
childrenexpand performance — now uses prefetch instead of per-row queries. (refs #1543) - API (NAICS): Improved performance for
federal_obligationsexpansion on list endpoints — now uses a single batched query instead of per-item lookups. (refs #1527) - API (Agencies): Fixed
Organization is not JSON serializableerror when requesting/api/agencies/without a?shape=parameter. (refs #1526)
[3.30.2] - 2026-03-01¶
Fixed¶
- API (Entities): Fixed a crash (
AttributeError) whenfederal_obligationsdata isNonefor an entity. Shaping builders now safely handle missing obligation data. (fixes #1562)
[3.30.1] - 2026-03-01¶
Added¶
- API (Entities): Entities now default to the shaping pipeline — responses render through shaping even without
?shape=. List and detail endpoints return action-aware default shapes with all previously-available fields. (refs #1531, part of #1524) - API (Entities): New expandable fields via shaping:
business_types(code,description),sba_business_types(code,description,entry_date,exit_date),naics_codes(code,sba_small_business),federal_obligations(total,active),highest_owner(cage_code,legal_business_name,uei),immediate_owner(cage_code,legal_business_name,uei). (refs #1531) - API (Entities):
federal_obligationsis now an expand-only field supporting child selection — usefederal_obligations(*)for bothtotalandactive, orfederal_obligations(total)for just one section. (refs #1531) - API (Entities): Many additional detail fields now available via shaping:
uuid,dodaac,evs_source,last_update_date,uei_status,uei_expiration_date,uei_creation_date,public_display_flag,exclusion_status_flag,exclusion_url,entity_division_name,entity_division_number,entity_start_date,fiscal_year_end_close_date,submission_date, entity structure/type/profit/organization/incorporation codes and descriptions. (refs #1531) - API (Forecasts): Forecasts now default to the shaping pipeline with action-aware default shapes. (refs #1531, part of #1524)
- API (Grants): Grants now default to the shaping pipeline with action-aware default shapes. (refs #1531, part of #1524)
- Docs: Updated Entities Data Dictionary, Entities API Reference, and Response Shaping with full field list, expand definitions, normalization details, and examples.
- Docs: Updated Forecasts and Grants API reference and data dictionary docs with default shaping information.
Changed¶
- API (Entities): Entity address keys (
physical_address,mailing_address) are now normalized to snake_case when expanded via shaping. Entities loaded from DSBS previously had camelCase keys (addressLine1,zipCode,stateOrProvinceCode); these are now consistentlyaddress_line1,zip_code,state_or_province_code. SAM-loaded entities (the majority) already used snake_case and are unaffected. (refs #1531) - API (Entities):
business_typesexpanded viabusiness_types(*)now always returns[{code, description}]arrays. Previously, DSBS-sourced entities could return{"2X": true, "F": true}dict format. Descriptions are looked up from in-memory reference maps (entities.loaders.maps). (refs #1531) - API (Entities):
sba_business_typesexpanded viasba_business_types(*)now always returns[{code, description, entry_date, exit_date}]arrays, with the same dict-to-array normalization asbusiness_types. (refs #1531) - API (Entities):
naics_codesexpanded vianaics_codes(*)now always returns[{code, sba_small_business}]objects. Previously, some entities stored plain string arrays (["541512", ...]); these are automatically normalized. (refs #1531) - API (Entities): Code/description pairs (
entity_structure,entity_type,profit_structure,organization_structure,state_of_incorporation,country_of_incorporation,purpose_of_registration) are now structured{code, description}expands instead of separate_code/_descleaf fields. Description fallbacks by field:entity_structure→ENTITY_STRUCTURE_MAP;entity_type,profit_structure,organization_structure→BUSINESS_TYPE_MAP;country_of_incorporation→django-genc(GENC country names);purpose_of_registration→PURPOSE_OF_REGISTRATION_MAP;state_of_incorporation→ model value only. (refs #1531)
Fixed¶
- API (Grants):
statusas a root leaf field now correctly maps to the underlyingopportunity_statusmodel attribute. (refs #1531) - API (Grants):
attachmentsexpand fixed for correct query behavior (was using invalidselect_relatedon a reverse FK). (refs #1531) - API (Grants): Removed
attachment_idfrom grant attachments — field does not exist on the model. Useresource_idas the attachment identifier. (refs #1531) - API (Grants):
important_dates,funding_details,grantor_contact, andadditional_infoexpands now support sub-field selection (e.g.,important_dates(posted_date,response_date),funding_details(award_ceiling)) instead of being opaque. (refs #1531)
Internal / Infra¶
- Bulk builders for
relationships(entities) andcfda_numbers(grants) — list-endpoint batch fetching reduces query count significantly. - Business type description lookups now use in-memory maps instead of database queries for faster response times.
- Forecast
display_datamemoized to prevent redundant parsing on list pages. - Tests: removed 9 fragile list-endpoint assertions across reference data, agency, and organization tests that relied on
ApproximatePaginator(pg_class.reltuples), which returns 0 in CI test databases. Detail tests andTestInvalidShapeFieldparametrized tests already cover the same shaping logic without pagination sensitivity.
[3.30.0] - 2026-02-28¶
Added¶
- API (Organizations):
/api/organizations/now has a default shape — all responses go through the shaping pipeline, returningkey, fh_key, name, short_name, type, level, is_active, code, fpds_code, cgac, canonical_code, parent_fh_key, full_parent_path_nameby default. (refs #1543, part of #1524) - API (Organizations):
fh_keyis now returned as a zero-padded 9-character string (e.g.,"000000001") everywhere — root fields, expands, and alll{n}_fh_keyfields. Previously returned as a raw integer. (refs #1543) - API (Organizations): New root fields available via shaping:
canonical_code,fpds_org_id,aac_code,start_date,end_date,logo,summary,l1_fh_keythroughl8_fh_key,total_obligations,tree_obligations. (refs #1543) - API (Organizations): New
department(code, name, abbreviation)andagency(code, name, abbreviation)expands let you retrieve legacy-compatible department/agency data from any organization. Returnsnullwhen not applicable (e.g., a department doesn't have a department above it). Safe to use in list responses with mixed hierarchy levels. (refs #1543) - API (Organizations): Enriched
ancestorsexpand now includesleveland cachedshort_name.parentandchildrenexpands now includecodeandcgac. (refs #1543) - Docs: Updated Organizations API Reference and Organizations Data Dictionary with all new fields, expands, and default shape details.
- API (Reference Data): Five reference data endpoints now support the
?shape=query parameter for response shaping:/api/business_types/,/api/mas_sins/,/api/naics/,/api/psc/, and/api/assistance_listings/. Default responses are backward-compatible. (refs #1527, part of #1524) - API (NAICS):
size_standardsandfederal_obligationsare now available as shaping expansions on/api/naics/. Use?shape=code,description,size_standards(*),federal_obligations(*)instead of the legacy?show_limits=1parameter. Detail responses include both expansions by default. (refs #1527) - API (Agencies): Legacy agency endpoints (
/api/departments/,/api/agencies/,/api/offices/) now support the?shape=query parameter for response shaping, letting clients select specific fields per request. (refs #1526, part of #1524) - Docs: API reference pages for Departments, Agencies, and Offices now include Response Shaping sections with available fields, expansions, default shapes, and examples.
- Docs: Reorganized API Reference and Data Dictionary navigation — Organizations moved under "Reference data"; legacy agency endpoints moved to "Shared" section with deprecation notices; new data dictionary pages for Agencies, Departments, and Offices.
- Docs: Response Shaping promoted to top-level documentation — now includes field references for Organizations, GSA eLibrary contracts, Forecasts, and Grants.
- Docs: Added "Guides" section to docs navigation with Quick Start, Authentication, Rate Limits, and Vehicles.
Changed¶
- API (Organizations):
fh_keytype changed from integer to zero-padded string in all API responses. If you parsefh_keyas a number, this is a format change. The integer value is preserved (e.g.,"000000001"→1). (refs #1543) - API (Organizations): Detail endpoint now returns inactive organizations directly — active-only filtering only applies to list requests. Previously,
GET /api/organizations/{fh_key}/returned 404 for inactive orgs unlessinclude_inactive=truewas passed. (refs #1543) - API (Agencies): The
organizationfield has been removed from/api/departments/and/api/agencies/responses. This was an internal FK that leaked an opaque identifier and was never part of the documented API contract. (refs #1526) - API (NAICS): The
?show_limits=1parameter is now deprecated in favor of?shape=code,description,size_standards(*),federal_obligations(*). The legacy parameter still works but has been removed from the OpenAPI/Swagger docs. (refs #1527)
Fixed¶
- API (Organizations): Fixed
childrenexpand performance — now uses prefetch instead of per-row queries. (refs #1543) - API (NAICS): Improved performance for
federal_obligationsexpansion on list endpoints — now uses a single batched query instead of per-item lookups. (refs #1527) - API (Agencies): Fixed
Organization is not JSON serializableerror when requesting/api/agencies/without a?shape=parameter. (refs #1526)
[3.29.2] - 2026-02-26¶
Added¶
- Docs: API Reference Shared page documenting shared response objects (set_aside, office) for shaping.
- Docs: Set-aside codes reference page (Data Dictionary → Reference data); replaces undocumented constant reference (refs makegov/tango-public#44).
- Docs: OpenAPI spec at a stable URL (api/openapi.json) for tools and AI. Single-page HTML at docs/print_page/. Combined markdown at docs/all.md (all public docs in one file). Docs homepage and page head link to the OpenAPI spec for discoverability.
Fixed¶
- API (IDVs): Shaped responses now include
last_date_to_orderunderperiod_of_performancewhen requested viashape=...period_of_performance(start_date,last_date_to_order)(fixes makegov/tango-public#45). - API: Opportunities shaping now supports
set_aside(code,description)expansion (previously only contracts did). Docs no longer reference an undocumented constant; set-aside code list and common response shapes are documented (refs makegov/tango-public#44).
[3.29.0] - 2026-02-25¶
Internal / Infra¶
- Documentation and tooling updates (Cursor agents, session artifacts, docproc).
[3.28.7] - 2026-02-25¶
Added¶
- Opportunities: Change provenance (CDC and field-level source tracking) for opportunity notices and opportunities; source authority:
sam_api,sam_csv,sam_history_api,tango_enrichment.
[3.28.6] - 2026-02-22¶
Fixed¶
- API: Agencies endpoint no longer 500s on cache hits when a cached response entry is malformed; the cache entry is evicted and recomputed. (fixes #1487)
- API: Contracts endpoint no longer 500s on pagination cache hits; cached paginated responses now include renderer metadata so they can be rendered safely. (fixes #1486)
Internal / Infra¶
[3.28.5] - 2026-02-22¶
Added¶
Changed¶
Breaking¶
- API: Contract/award
parent_awardpayload no longer includesawarding_office;idv_typeis now returned as{code, description}.
Fixed¶
- API: Contract/OTA/OTIDV list endpoints avoid unnecessary joins (organizations, offices, recipients, parent awards, place of performance) in default list responses, reducing query time and row width.
- API: Cold-cache list responses do less database work when expanding related fields (recipient, place of performance, parent award, subawards summary), reducing per-row query cost.
Internal / Infra¶
[3.28.4] - 2026-02-21¶
Added¶
- Docs: Index page now links to API Reference and Data Dictionary so readers can discover them without relying on the top nav only.
- Docs: Public documentation pages can be requested with a
.mdextension (e.g./docs/getting-started/response-shaping.md) to receive raw markdown, for easier consumption by LLMs and tools.
Fixed¶
- API: Contract and award list endpoints no longer time out when filtering by awarding or funding agency (e.g.
awarding_agency=CMS). Filtering now uses organization UUIDs under the hood with a legacy fallback for awards that have only office data; response shape forawarding_office/funding_officeis unchanged.
[3.28.2] - 2026-02-19¶
Added¶
- Docs: Documentation pages are available as raw Markdown at stable
/docs/...URLs withContent-Type: text/markdownand 1-day cache for LLM and crawler consumption (refs #1466).
Fixed¶
- API: Read-only endpoints (organizations, departments, agencies, offices, business types, MAS SINs) now apply API key rate limits when
X-API-KEYis sent; previously they did not authenticate API keys and throttled only by anonymous/IP (refs #1469).
[3.28.1] - 2026-02-18¶
Changed¶
- API: Contract and award search now use PostgreSQL
websearch_to_tsqueryfor the search parameter, supporting OR (e.g.cyber OR security), quoted phrases (e.g."cyber security"), and negation (-word). Unquoted words are ANDed. (refs #1405)
Fixed¶
- API: Contract and OTA list endpoints are faster when filtering by UEI, recipient, or PSC with default ordering (refs #1404).
- API: Contract (and award) search no longer times out (504) when the full-text search returns no matches: the fast path now returns an empty result set instead of falling back to a slow LIKE scan. (fixes #1405)
[3.28.0] - 2026-02-15¶
Added¶
- Data: New SAM Awards data pipeline. With FPDS.gov decommissioning on February 24, 2026, Tango is transitioning contract award ingestion from the FPDS Atom feed to SAM.gov's Contract Awards API. The new pipeline runs side-by-side with the existing FPDS loader during the transition period, with full cutover planned for later in FY 2026.
Changed¶
Breaking¶
Fixed¶
Internal / Infra¶
[3.27.8] - 2026-02-13¶
Fixed¶
- API: Keyset (cursor) pagination now returns 400 Bad Request when the cursor contains invalid values (e.g. non-date strings for date fields), instead of a 500 server error. (fixes #1183)
- API: Pagination
next/previouslinks now respect reverse-proxy TLS (viaSECURE_PROXY_SSL_HEADER) so they usehttpswhen the public API is served over HTTPS. (fixes #1436)
[3.27.7] - 2026-02-13¶
Fixed¶
- API: The
shapeparameter is now validated consistently: invalid/malformed shapes return 400 Bad Request with a structured error (error,issues) instead of 500, and endpoints without shaping support return 400 instead of ignoringshape. (fixes #1351)
[3.27.6] - 2026-02-13¶
Added¶
- Signup: Optional marketing communications opt-in checkbox on the complete signup page. (closes #1431)
Internal / Infra¶
- Docs conformance: expanded API reference filter documentation across awards/opportunities/grants/forecasts and aligned docs parsing with runtime filters. (refs #1439)
[3.27.5] - 2026-02-12¶
Added¶
- IDVs API: Expose GSA eLibrary enrichment on IDV list/detail responses and via response shaping (
gsa_elibrary(...)). (refs #1416) - GSA eLibrary API: Add direct endpoints for persisted GSA eLibrary contract metadata at
/api/gsa_elibrary_contracts/(filters + ordering + shaping). Responses includerecipient(cached entity basics) and best-effortidvbasics, and pagination uses exact counts. (refs #1416)
Breaking¶
- GSA eLibrary: Remove
last_updatedfrom GSA eLibrary response payloads (including IDVgsa_elibraryenrichment and shaping). - GSA eLibrary API:
/api/gsa_elibrary_contracts/filters changed — removeexternal_idandlast_updated_*; renameidv_key/idv_piidtokey/piid.
[3.27.4] - 2026-02-10¶
Added¶
- Docs: add a comprehensive rate limits guide and align header/429 examples with runtime behavior. (refs #1425)
- Docs: add external references for NAICS and PSC pages. (refs #1425)
[3.27.3] - 2026-02-09¶
Added¶
- Reference data API: Add MAS SINs reference endpoint at
/api/mas_sins/and loader-backed reference table for normalized SIN metadata. (refs #1417) - Account onboarding: new
/welcome/page used as the authenticated home experience, with quick links and a compact plan summary + upgrade/change CTA. (refs #1412)
Fixed¶
- Social signup: more reliable redirect behavior after first-time social signup (avoid landing on profile due to
next=propagation). (refs #1412) - UI: improve help-text contrast for USWDS hint styling on signup/account pages. (refs #1412)
[3.27.1] - 2026-02-07¶
Fixed¶
- Opportunities API:
notice_historyandmeta.notices_countnow reflect the best-available notice history for an opportunity (preferlatest_notice, otherwise fall back to the most recently refreshed notice), avoiding undercounting whenfirst_noticehas stale history. (fixes #1418)
[3.27.0] - 2026-02-05¶
Fixed¶
- sync_organizations: Improve scheduled runs so failures surface properly, add durable loader error logging, and reduce alias rebuild churn.
[3.26.11] - 2026-02-04¶
Added¶
- IDVs API: IDV list/detail responses now include
vehicle_uuid(UUID of the Tango Vehicle the IDV is grouped under) for easier linking to/api/vehicles/{uuid}/. (refs #1406)
[3.26.10] - 2026-02-03¶
Added¶
- Entities API: New filters on the entity list endpoint:
total_awards_obligated_gte– entities with total obligations ≥ value (USD)total_awards_obligated_lte– entities with total obligations ≤ value (USD)- Total obligated is derived from the entities_awards_totals materialized view (contracts + subawards only; IDV/OTA/OTIDV obligations are not included). The filter is MV-backed for performance.
- Invalid range (e.g. gte > lte) returns a
BadSearchRequesterror. (refs #1146)
[3.26.9] - 2026-02-02¶
Added¶
- Organizations API: Lookup by historical
fh_key(e.g. after an organization merge) now resolves to the merged organization. When the requestedfh_keyis not the current one, the API returns 301 Moved Permanently to the canonical URL/api/organizations/<current_fh_key>/, preserving query parameters. (refs #1146) - sync_organizations: Federal Hierarchy (FH) input can be provided via
--local-fileor--s3-object(FileMixin). Each FH file is processed by a dedicated loader and recorded in File Processing History (FPH) and per-file results. (refs #1146) - Docs: add Data Dictionary + API Reference landing pages, plus new filtering/ordering reference pages for Contracts, Entities, IDVs, and Vehicles. (refs #1396)
- Docs: expand API Reference pages to cover most endpoint groups (excluding
assistance), including organizations/agencies/opportunities/notices/forecasts/grants, awards (OTAs/OTIDVs/subawards), and reference data (business_types,assistance_listings, NAICS, PSC). (refs #1396) - Docs: add a “Report an issue with this page” link at the bottom of every docs page, prefilled to create a GitHub issue for the current page URL. (refs #1396)
- Docs: add project rule and validate-docs checklist to keep MkDocs, Swagger/OpenAPI, and code aligned (
.cursor/rules/documentation.mdc,.cursor/commands/validate-docs.md). (refs #1396)
Changed¶
- Docs: API Reference overview page reorganized to match nav (Awards, Organizations, Opportunities, Other, Reference data). (refs #1396)
- Docs build: make MkDocs overrides + custom CSS first-class (
docs/overrides/,docs/stylesheets/extra.css) and improvebuild_docspath resolution across Docker bind-mount layouts. (refs #1396)
[3.26.8] - 2026-02-01¶
Added¶
- Subawards: support ordering by
last_modified_dateon/api/subawards/and contract-scoped subaward lists. (closes #1297)
Breaking¶
- API: the
orderingquery param is now strictly validated; invalid/unsupported ordering values return HTTP 400 instead of being ignored or causing 500s. (closes #1297) - Forecasts API: ordering is now limited to
anticipated_award_date,fiscal_year, andtitle. (closes #1297)
[3.26.7] - 2026-01-30¶
Changed¶
- API docs: add admin control to Swagger schema visibility. (closes #1314)
[3.26.6] - 2026-01-29¶
Fixed¶
- Vehicles API: fixed shaped vehicle responses so
descriptionsnever containsnullelements when some member IDVs havedescription = NULL. (fixes #1369)
[3.26.5] - 2026-01-28¶
Changed¶
- Docs: the Webhooks Partner Guide now uses the canonical hyphenated path under
/docs/webhooks-user-guide/(instead of the older underscore form).
Breaking¶
- API: removed the deprecated
/api/subscriptions/endpoints. Use/api/webhooks/subscriptions/instead. (closes #1246)
[3.26.4] - 2026-01-28¶
Added¶
- Vehicles API: new
GET /api/vehicles/{uuid}/orders/endpoint returns all task orders (contracts) issued against all IDVs within a vehicle. Supports pagination, response shaping, filtering, search, and transaction expansion. Task orders are ordered by-award_date, -uuid(newest first) by default, with support for custom ordering via?ordering=parameter (e.g.,?ordering=-obligated,?ordering=recipient_name). (closes #1356) - Vehicles API: you can now sort vehicles by activity metrics using the
?ordering=query parameter. Available fields: vehicle_obligations- Sort by total obligations across all IDVs in the vehiclelatest_award_date- Sort by the most recent IDV award date in the vehicle- Use
-prefix for descending order (e.g.,?ordering=-vehicle_obligations) - Combine multiple fields (e.g.,
?ordering=-vehicle_obligations,-latest_award_date) - Default ordering (when no
?ordering=is provided) remains unchanged. (closes #1357)
Fixed¶
- Vehicles API: fixed inconsistency where the default response includes a
descriptionfield, but theshapeparameter only accepteddescriptions. Both field names are now accepted in shaping requests (e.g.,?shape=descriptionor?shape=descriptions). (closes #1362) - API: fixed case-sensitivity issue with
recipientfilter parameter. The filter now works case-insensitively, so searches like?recipient=Deloitte,?recipient=deloitte, and?recipient=DELOITTEall return the same results. This affects/api/contracts,/api/subawards, and other endpoints using recipient filtering. (fixes #1345)
[3.26.3] - 2026-01-27¶
Fixed¶
- Awards: contract obligation time-series metrics are now attributed to the transaction month (instead of the award date), improving trend accuracy for NAICS/PSC and recipient rollups. (fixes #1268)
[3.26.0] - 2026-01-25¶
Added¶
- Data provenance & auditing (Organizations + Entities): Tango now records field-level provenance and per-row audit logs for key datasets so we can answer “where did this value come from?” and “when did it last change?” more reliably.
- Covered models so far: Organizations and Entities (including entity relationships).
- This work is currently not exposed via the API (no new endpoints/fields), but it improves our ability to debug discrepancies, explain changes, and harden future data quality guarantees.
- Read more: Provenance & auditing.
Fixed¶
- Entities ingestion is more robust to inconsistent upstream typing for certification date fields.
- Entities ingestion is now robust to SAM certification date “vector” formats (e.g.
2024-09-17~2024-09-17,null~null), preventing ingestion failures for affected rows. - Entities: fixed recipient filter to enable partial name matching for single-word and short multi-word queries (e.g., "HARVARD" now matches "PRESIDENT AND FELLOWS OF HARVARD COLLEGE"). Previously, exact matching was attempted first, which could skip full-text search and return incomplete results. (fixes #1333)
[3.25.0] - 2026-01-20¶
Added¶
- Awards: new Vehicles API endpoints under
/api/vehicles/to discover and inspect solicitation-based "vehicles" built from IDVs. (closes #1313) GET /api/vehicles/: full-text search via?search=(vehicle-level).GET /api/vehicles/{uuid}/: detail endpoint supports response shaping, includingawardees(...)expansion of the underlying IDVs.- Vehicles are stable: the
uuidis deterministic from \(solicitation_identifier, agency identifier derived from the IDVkey\) so it remains consistent across refreshes. - Optional:
?search=on the detail endpoint filters expanded awardees (not the vehicle itself) whenshapeincludesawardees(...). - Exposes
organization_id(best-effort mapping into/api/organizations/) to support consistent agency filtering and joins.
Fixed¶
- Awards: fixed Swagger/OpenAPI documentation for IDV summary endpoints (closes #1312)
- Removed duplicate
identifierpath parameter declarations - Fixed example generator to correctly detect list vs retrieve actions
- Fixed Swagger examples to use realistic values and proper pagination structure
Internal / Infra¶
- Awards: added a vehicles refresh pipeline (
refresh_vehicles) that rebuildsawards_vehicle,awards_vehicle_award, andawards_vehicle_stats_mvfromawards_idvand reuses existing award search vectors for vehicle search. (refs #1313)
[3.24.1] - 2026-01-12¶
Internal / Infra¶
- Awards: ETL now refreshes awards search tables for contracts, IDVs, OTAs, and OTIDVs via
refresh_awards_search. (closes #1294) - Subawards: add
award_uuidfor deterministic association to prime awards; populate on ingest. (closes #1298)
[3.24.0] - 2026-01-10¶
Internal / Infra¶
- Awards: infrastructure and performance improvements to support faster, more consistent search behavior across award types (contracts, IDVs, OTAs, OTIDVs). (refs #1278)
[3.23.2] - 2026-01-08¶
Added¶
- Account: your account page now shows your daily requests remaining (and when it resets).
- Account: improved signup emails (welcome email + admin notifications) with updated branding. (closes #280)
Changed¶
- Account: API keys now explicitly note that they share the same account rate limits.
[3.23.1] - 2026-01-08¶
Added¶
- Account: manage API keys from your account page (create, revoke, delete) to support key rotation. (closes #1269)
[3.23.0] - 2026-01-07¶
Added¶
- Webhooks: expanded webhook coverage beyond awards to include entities, opportunities, grants, and forecasts (including new/create-style events for opportunities, grants, and forecasts). See the Webhooks partner guide.
- Webhooks: entities now emit explicit new entity events (
entities.new_entity) when a new entity appears (in addition toentities.updated). - Webhooks: subscriptions now support richer filtering via subjects (e.g. entity UEI, award key, agency, notice ID, notice type), so you can subscribe more precisely.
- Webhooks: new discovery endpoint to list supported event types and subject types (
GET /api/webhooks/event-types/).
Changed¶
- Webhooks: improved “data is ready” guarantees; events are published only once the underlying data is queryable via the API (including publishing opportunity updates at the end of loading, not during maintenance processing).
- Webhooks: legacy immediate-dispatch buffering has been removed; webhooks are now produced via the outbox + publish pipeline.
- Webhooks: duplicate subscription configurations are now rejected per endpoint (prevents accidentally subscribing to the same thing twice).
- Webhooks: sample payload endpoint now returns Tango-shaped sample deliveries for all supported event types and includes copy/paste subscription examples.
Breaking¶
- Webhooks:
GET /api/webhooks/endpoints/sample-payload/has a new contract. It now accepts?event_type=<event_type>and returnssample_delivery/sample_subjects/sample_subscription_requests(the legacyentity_type/change_typequery params and response shape are no longer supported). - Webhooks: award events no longer include legacy
resource_id, and award identifiers are now delivered asaward_key(notaward_id). Update any webhook handlers that were reading the old fields. - Webhooks (legacy): subscriptions that use
event_type: "entity_awards"will not match v2 award events. Migrate toawards.new_award/awards.new_transactionwithsubject_type: "entity"(UEI).
Deprecated¶
- Webhooks: The
/api/subscriptions/endpoints are deprecated and will be removed in a future release. Please migrate to/api/webhooks/subscriptions/instead. The deprecated endpoints remain functional but are no longer documented in Swagger.
[3.22.7] - 2025-12-31¶
Fixed¶
- Fixed an internal opportunities ingestion failure when rebuilding notice history could encounter NULL IDs. (fixes #1257)
- Awards: ensure deterministic ordering for smart-filtered award queries by appending
-keyas a tiebreaker when ordering byaward_date. (fixes #1254)
[3.22.5] - 2025-12-30¶
Added¶
- Cursor pagination now supports backwards navigation via
previouslinks. (closes #1097) - Add
obligated_gteandobligated_ltefilters to/api/contracts/. (closes #1138)
Changed¶
- Opportunities ingestion is now faster, improving update freshness. (addresses #1248)
- Admin: bulk enable/disable API maintenance rules. (closes #1241)
Fixed¶
- Fixed duplicate
WHERE ... IN (...)predicates in contract queries when filtering by awarding/funding agency. (fixes #1247) - Improved DSBS enrichment reliability/performance and reduced lock contention with entity loads. (fixes #1238) (closes #1239) (fixes #1240) (addresses #949)
[3.22.4] - 2025-12-24¶
Changed¶
- Improved the “Get API access” sign-in page to make account creation and sign-in clearer. (closes #1233)
Fixed¶
- Social sign-in now preserves redirect destinations more reliably (e.g.
?next=...). (fixes #1233)
[3.22.3] - 2025-12-23¶
Added¶
- Improved contract search performance for large result sets via a new count estimation helper.
Fixed¶
- API requests now fail fast with a clean 504 when Postgres statement/lock timeouts are hit, instead of timing out at the proxy.
- Opportunities rollups avoid spurious updates when incoming values are NULL, and notice status maintenance is faster via a single-pass UPSERT.
[3.22.2] - 2025-12-22¶
Changed¶
- Internal improvements to organization management and data synchronization.
[3.22.0] - 2025-12-21¶
Added¶
- Organizations: a unified federal organization hierarchy (departments, agencies, and offices) with powerful search and filtering via
/api/organizations/. - Better organization identifiers: stable organization UUIDs (
key), SAM Federal Hierarchy keys (fh_key), and operational codes like CGAC / FPDS codes (when available), so you can reliably map transaction data to the right org. - Organization rollups: obligation rollups for organizations (including descendants) to support exploration and analytics.
Changed¶
- Agency/org consistency: agency-related behavior across the API now uses the unified Organizations hierarchy, improving hierarchy consistency and organization matching across endpoints.
Documentation¶
- Organizations endpoint data dictionary: Organizations
- Background on the federal hierarchy + why org matching is hard: Federal agency hierarchy
[3.21.11] - 2025-12-16¶
Added¶
- NAICS and PSC descriptions now available in awards endpoint response shapes
Fixed¶
- Redis connection stability issues
[3.21.10] - 2025-12-15¶
Fixed¶
- Cache warming CROSSSLOT key hashing errors
- Bulk entities endpoint post-caching changes
[3.21.0] - 2025-12-09¶
Added¶
- API key authentication caching with 1-hour TTL and cache reconstruction
Changed¶
- API authentication reconstructs APIKey and User objects from cache to avoid database queries
- API pagination cache keys standardized for more consistent caching
[3.20.9] - 2025-11-28¶
Added¶
- Officer expand configuration in response shaping
[3.20.4] - 2025-11-23¶
Added¶
- Quick-start documentation (
docs/getting-started/quick-start.md) with response shaping examples
[3.18.11] - 2025-11-11¶
Fixed¶
- Critical fix for
generate_unique_award_keyfunction
[3.18.10] - 2025-11-07¶
Changed¶
- Pagination enhanced with search hit ordering
[3.18.6] - 2025-10-27¶
Added¶
ApiMaintenanceRulemodel for endpoint-level maintenance control- API maintenance middleware
[3.17.16] - 2025-10-10¶
Added¶
cursorproperty now included in paginated responses
Fixed¶
- Cache pagination edge cases
- Caching and cursor interaction conflict
[3.17.12] - 2025-10-07¶
Changed¶
- Pagination
nulls_lastparameter handling for nullable vs non-nullable fields
[3.17.7] - 2025-10-01¶
Added¶
- Webhooks are now ordered predictably for pagination
Changed¶
- Webhook delivery timeout configuration added (30s connect, 60s read/write)
Fixed¶
- Missing
sam_urlfield in opportunities response shaping
[3.17.0] - 2025-09-26¶
Added¶
- Response shaping system: clients can now customize API response fields using the
shapequery parameter
[3.14.0] - 2025-08-08¶
Fixed¶
- Broken cache key for opportunity attachments
- Invalid
select_relatedfield in OTIDV API endpoint
[3.13.9] - 2025-08-07¶
Changed¶
- Performance improvements in agencies and recipients endpoints
[3.13.4] - 2025-08-01¶
Changed¶
- Opportunity endpoint performance
[3.13.0] - 2025-07-28¶
Added¶
- GitHub OAuth social authentication
[3.12.5] - 2025-07-23¶
Changed¶
- Pagination ordering logic in opportunities
[3.11.2] - 2025-06-29¶
Changed¶
- API filters for agency search performance
[3.10.2] - 2025-06-19¶
Added¶
- Webhook system improvements
Changed¶
- Webhook delivery improvements
Fixed¶
- G2X wrapper bug (hotfix)
[3.10.0] - 2025-06-17¶
Added¶
- Webhook delivery includes retry logic and error handling
- Webhook subscriptions can filter by entity type and entity IDs
- Webhook buffering and deduplication to prevent duplicate deliveries
Changed¶
- Award and entity updates now trigger webhook events on data changes
- Award transaction updates now emit webhook events
[3.7.6] - 2025-05-25¶
Fixed¶
- Swagger documentation routing (corrected
/api/apipath)
[3.7.5] - 2025-05-22¶
Fixed¶
- Bulk entities endpoint tweaks
[3.7.4] - 2025-05-20¶
Added¶
- Swagger docs now include realistic API response examples
- Swagger docs now include examples for agencies, awards, entities, grants, and opportunities
- OpenAPI schema customization improvements
- Swagger documentation organization improvements
Changed¶
- API viewsets now use generated examples for Swagger UI instead of static/hardcoded data
[3.7.0] - 2025-05-12¶
Added¶
- Grant pagination system with cursor support
[3.6.0] - 2025-05-02¶
Fixed¶
- Notice and opportunity loading deduplication and data integrity issues
[3.5.0] - 2025-04-27¶
Changed¶
- Metrics models rebuilt with consistent schema across NAICS, PSC, and entities
[3.4.0] - 2025-04-23¶
Changed¶
- API serializers updated with improved field selection logic
[3.3.1] - 2025-04-21¶
Fixed¶
- PSC detail endpoint query logic
[3.2.0] - 2025-04-11¶
Added¶
- Entity display name ordering index
Changed¶
- Pagination responses now include consistent
count,next,previous,resultsstructure across all endpoints
Fixed¶
- Entity ordering and caching logic edge cases
[3.1.0] - 2025-04-04¶
Changed¶
- Subaward field mapping aligned with USASpending schema changes
[3.0.4] - 2025-03-27¶
Added¶
- API key authentication
- Automatic default API key creation for new users
Changed¶
- Accounts page updated with API key management
[3.0.0] - 2025-03-25¶
Added¶
- Keyset (cursor-based) pagination system for awards with
cursorandlimitquery parameters - Cursor encoding/decoding using Base64-encoded composite keys (date + unique key)
Changed¶
- Pagination now supports approximate counts via
get_approximate_countfor performance - Cached pagination increased to 30-day TTL for static models (NAICS, PSC) with 10K max page size
[2.6.21] - 2025-03-18¶
Added¶
- Entities endpoint includes summary metrics
[2.6.20] - 2025-03-15¶
Added¶
- NAICS and PSC code metrics endpoints
[2.6.19] - 2025-03-14¶
Added¶
- Basic entity metrics API support
[2.6.13] - 2025-02-18¶
Added¶
psc_codefiltering oncontractsendpoint
[2.6.11] - 2025-02-03¶
Added¶
- New aggregate view for aggregated award data (for faster API responses)
[2.6.10] - 2025-01-26¶
Added¶
- More fields on
assistance_transactionsendpoint
[2.6.6] - 2025-01-03¶
Fixed¶
- Filtering by NAICS/PSC combo
[2.6.1] - 2024-12-01¶
Fixed¶
- Date filters returning incorrect opportunities
[2.6.0] - 2024-11-28¶
Added¶
related_entitiesendpointbase_notice_type_codeadded to API responses
[2.5.0] - 2024-11-25¶
Added¶
- Entity summary endpoint
[2.1.5] - 2024-11-22¶
Changed¶
- Opportunity management API improvements
[2.0.0] - 2024-11-11¶
Changed¶
- Opportunities schema updates for improved structure and usability
[1.5.1] - 2024-11-04¶
Added¶
- Ordering parameters added to
contractsandidvsendpoints
Changed¶
- Default ordering for
contractsandidvsendpoints changed toaward_date
[1.4.5] - 2024-10-11¶
Added¶
assistance_listingsendpointversionendpoint
Changed¶
business_typesdetail endpoint now properly accepts business type codes- Breaking:
last_updated_timerenamed tolast_updatedonnoticesandopportunitiesendpoints
[1.4.0] - 2024-09-27¶
Added¶
pscparameter (endpoints:notices,opportunities)place_of_performanceparameter (endpoints:notices,opportunities)- Disjunctive search for
agency,naics,office,psc(endpoints: all)
Changed¶
- Breaking: Standardized all API endpoints to use
limit(replacingpage_sizewhere applicable) - Breaking: Renamed
naics_codetonaicsfornoticesandopportunitiesendpoints - Removed alphabetical sorting of parameters (endpoints: all)