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/ - IT Dashboard:
/api/itdashboard/ - 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.vehicle(uuid,solicitation_identifier,solicitation_title,solicitation_description,agency_id,vehicle_type,type_of_idc,contract_type,who_can_use,solicitation_date,award_date,last_date_to_order,fiscal_year,naics_code,psc_code,set_aside,description)— the contract's parent vehicle, resolved through its parent IDV. Returnsnullwhen the contract has no parent IDV, or when the parent IDV is not part of any vehicle. For richer vehicle detail (awardees, opportunity, totals), follow the returneduuidto/api/vehicles/{uuid}/. Shaping-only.
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(*)
# Parent vehicle (uuid + label)
/api/contracts/?shape=key,piid,vehicle(uuid,solicitation_title)
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)
IT Dashboard /api/itdashboard/¶
IT Dashboard exposes tiered shaping: Free gets basic investment metadata, Micro+ adds the funding and details expansions, and Medium+ adds nested sub-tables (contracts, projects, CIO evaluations, performance metrics, etc.) plus the business_case_html leaf. Fields or expansions above the caller's tier are silently stripped from the response, and removed nodes are listed in meta.upgrade_hints. For the full tier/field matrix, see the IT Dashboard API Reference.
- Leaves (all tiers):
uii,agency_code,agency_name,bureau_code,bureau_name,investment_title,type_of_investment,part_of_it_portfolio,updated_time,url - Medium+ leaf:
business_case_html - Expansions (Micro+):
funding(*)— fiscal-year internal funding and contributions (FY2020–FY2025)details(*)— extended metadata: description, previous/current UII, classification, business case URL, public URLs- Expansions (Medium+):
cio_evaluation(*),contracts(*),projects(*),cost_pools_towers(*),funding_sources(*),performance_metrics(*),performance_actual(*),operational_analysis(*)
Default response (no ?shape=):
- List:
uii,agency_name,bureau_name,investment_title,type_of_investment,part_of_it_portfolio,updated_time,url - Detail: adds
agency_code,bureau_code
# Free tier: basic metadata
/api/itdashboard/?shape=uii,investment_title,agency_name,url
# Micro+ tier: funding and details
/api/itdashboard/?shape=uii,investment_title,funding(*),details(*)
# Medium+ tier: nested sub-tables + business case HTML
/api/itdashboard/{uii}/?shape=uii,investment_title,cio_evaluation(*),performance_metrics(*),business_case_html
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)