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¶
Internal / Infra¶
[4.6.1] - 2026-05-13¶
Fixed¶
GET /api/vehicles/?search=matches text from member-IDV descriptions. Vehicles whosesolicitation_identifieris a single run-on token (e.g.RFPCMS2016SPARC) now match substring queries like?search=SPARCvia the underlying IDV descriptions. The endpoint's default ordering (solicitation_identifier, agency_id, uuid) is unchanged. (issue #2224)
[4.6.0] - 2026-05-12¶
Added¶
- Shape aliases:
naics_code(...)andpsc_code(...)now work as expand forms.?shape=naics_code(code,description)is accepted as a synonym fornaics(...)on/api/contracts/and/api/idvs/(the only award endpoints with a NAICS expand).?shape=psc_code(code,description)is accepted as a synonym forpsc(...)across all award endpoints (/api/contracts/,/api/idvs/,/api/otas/,/api/otidvs/). The expanded object comes back under the canonical key (naics/psc). Bare scalarnaics_code/psc_codeis unchanged — it still returns the raw code value. (issue #2257) POST /api/webhooks/endpoints/test-delivery/now acceptsendpoint. The canonical field name matchesPOST /api/webhooks/subscriptions/, so SDKs and docs can use one identifier across both calls. The legacyendpoint_idfield is still accepted as a deprecated alias; if both are provided,endpointwins.endpoint_idwill be removed in the next major release. (issue #2252)POST /api/webhooks/alerts/accepts an optionalendpoint(UUID) field. Multi-endpoint accounts can disambiguate without dropping to/api/webhooks/subscriptions/; single-endpoint accounts can still omit it. (issue #2256)
Breaking¶
- Subject-based webhook subscriptions removed (#2267). Subscriptions now match by saved filters (
/api/webhooks/alerts/) only —subject_type,subject_ids, and the legacyresource_ids/entity_type/entity_ids/change_typesfields are no longer accepted byPOST /api/webhooks/subscriptions/(orPATCH). Existing integrations that still send these fields will see them silently dropped. See the alerts guide on docs.makegov.com for migration.
Fixed¶
- OpenAPI now matches runtime for
ordering./api/notices/no longer advertisesordering(the endpoint never accepted it — every value 400s), and/api/subawards/advertises itsorderingenum aslast_modified_date/-last_modified_dateonly. SDKs generated from the schema no longer surface anorderingkwarg on notices, and the subawards kwarg is typed to the actual allowlist. (issue #2254) - OpenAPI
orderingnow has a realenumon the remaining endpoints. Completes the schema/runtime parity work started in #2258:/api/contracts/,/api/idvs/,/api/opportunities/,/api/forecasts/,/api/vehicles/,/api/vehicles/{uuid}/orders/, and/api/gsa_elibrary_contracts/now declare an explicitenummatching each viewset's runtime allowlist (ordering_fields∪ordering_fields_map.keys()+ their-variants). SDK generators emit a typed kwarg instead of a free-formstr, so invalid values fail at type-check time rather than as a runtime 400. (issue #2262) POST /api/webhooks/alerts/no longer returns a sibling endpoint's subscription row when the same user has the same filter(query_type, filters)on two different endpoints. The post-create lookup is now scoped by the resolved endpoint instead of user — a latent dedup bug that became reachable once multi-endpoint disambiguation was added. (issue #2256)GET /api/webhooks/endpoints/sample-payload/no longer 500s. The endpoint previously referenced a subject-type attribute that was removed when subject-based webhooks were deprecated. Returns the alert-only sample set as expected.
[4.5.2] - 2026-05-11¶
Changed¶
- Public docs moved to docs.makegov.com. The in-app MkDocs site at
tango.makegov.com/docs/*is gone; legacy URLs 301-redirect to the new host path-preserving (/docs/getting-started/pricing/→docs.makegov.com/getting-started/pricing/, etc.). Bookmarks keep working. Pricing-tier upgrade responses (upgrade_url) and the welcome-email "Docs" CTA now point at the new host directly.
Fixed¶
/api/otas/and/api/otidvs/pagination no longer 400s on page 2. Cursor-based pagination on these endpoints used to return HTTP 400 whenever the page-1 anchor row had a NULLaward_date— common on OTAs/OTIDVs because many leading rows have no resolvable award date. Page 2 now succeeds and returns the next slice as expected. No client changes required. (issue #2139)
[4.5.1] - 2026-05-09¶
Changed¶
/api/notices/:?shape=office(organization_id)is now valid. The office payload on notices gainsorganization_idas a 7th key, matching the surface already exposed on/api/opportunities/and the awards endpoints. The other six keys (office_code,office_name,agency_code,agency_name,department_code,department_name) are unchanged.
Performance¶
/api/notices/is materially faster. Theofficeexpand no longer fetches fullOrganizationrows on every request. Uncached?limit=100drops from ~0.36 s to ~0.07–0.1 s. No query parameter changes needed; same shapes work faster. (issue #2236)
[4.5.0] - 2026-05-09¶
Fixed¶
?shape=case_id,docketsno longer 500. Namingdocketsas a leaf in the protests shape — without an inner expand likedockets(case_number)— used to raise an internal serializer error. The leaf is now equivalent todockets(*)and returns the default docket projection. Detail endpoint mirrors list. (issue #2222)
Performance¶
- Five more endpoints are materially faster. The organization expand on
/api/forecasts/,/api/grants/,/api/itdashboard/,/api/opportunities/(theofficeexpand), and awards (/api/contracts/,/api/idvs/,/api/otas/,/api/otidvs/) no longer fetches fullOrganizationrows from the database. Uncached?limit=100timing across eight endpoints: ~8.7 s total → ~1.9 s total (−78%); opportunities alone 3.4 s → 0.4 s (−88%), forecasts 2.1 s → 0.15 s (−93%). No query parameter changes needed — same shapes work faster. (issue #2225, PR #2233)
/api/contracts/,/api/idvs/,/api/otas/,/api/otidvs/:?shape=awarding_office(organization_id)and?shape=funding_office(organization_id)are now valid. The office payload gainsorganization_idas a 7th key (the other six —office_code,office_name,agency_code,agency_name,department_code,department_name— are unchanged). Rows that hit the legacy JSON fallback return{"organization_id": null, ...}.
/api/protests/is materially faster. End-to-end on a default?limit=100request, latency drops from ~3.8 s to ~80 ms. No API changes; same response shape.
[4.4.0] - 2026-05-08¶
Added¶
- Agency filter accepts more identifier forms. The
agency/awarding_agency/funding_agencyfilters on every endpoint that exposes one now resolve the same way: hand them a name, abbreviation, or code (CGAC, FPDS, AAC, and others) and Tango figures out the matching agency subtree. See the new Agency search guide. (issue #2207)
Changed¶
- Trimmed
?ordering=whitelist on/api/vehicles/. Removedawardee_countandvehicle_contracts_valuefrom the v4.3.0 ordering surface — both wereSubqueryannotations onVehicleStatswith no backing index, and their matching*_min/maxfilters were intentionally deferred. The remaining surface isvehicle_obligations,latest_award_date,total_obligated,award_date,last_date_to_order,fiscal_year,idv_count,order_count. (issue #2202 follow-up)
Breaking¶
- Comma
,is no longer anANDseparator in filter values; multi-value uses|only. Across every endpoint that accepts smart-text filter values (naics,psc, set-asides, business types, entity / agency text searches, etc.), a comma is now a literal character in the token value rather than anANDseparator.?awarding_agency=HHS,DODwas previously treated asHHS AND DOD(which was always empty — a single record can't equal two different values) and is now treated as a single literal value"HHS,DOD"(also always empty, but for the literal reason). For union semantics use|:?awarding_agency=HHS|DODreturns rows in either subtree. For intersection semantics, repeat the query parameter or use multiple separate filter parameters —AND-joining values inside one parameter has no clear use case in this API. Mixed inputs like?field=A,B|Cno longer raise a400 "Cannot combine AND and OR in the same query"error; they're parsed as"A,B"OR"C". The change also fixes the long-standing footgun where federal entity / agency names containing literal commas ("ENERGY, DEPARTMENT OF","GENERAL DYNAMICS, INC.") silently produced empty results when pasted into a filter. Out of scope:/api/gsa_elibrary_contracts/?sin=,?uei=,?search=continue to honor the prior comma-as-AND grammar (separate code path). (issue #2214)
Removed¶
- AND-via-comma is fully removed from documentation, swagger, and help text. Comma-as-AND no longer works anywhere downstream of
BaseSmartFilter/BasePerformantFilterand the swagger / public docs no longer advertise it. Multi-value uses|(OR) only. Consumers using,for intersection semantics should migrate to multiple distinct query parameters (e.g.?naics=541511&fiscal_year=2024rather than trying to AND values inside a single param). The swagger description-builder (make_description) now raisesValueErrorif a future internal call site passes"conjunctive": True, so the option cannot be reintroduced silently. Public docs (docs/guides/patterns/agency-search.md,docs/webhooks-user-guide.md,docs/index.md, forecasts API user guide) rewritten to drop OR-vs-AND framing in favor of OR-only language. (issue #2214)
Fixed¶
- Multi-value
?agency=A|Breturned zero results. Pipe-separated values onagency/awarding_agency/funding_agencynow correctly return the union of both subtrees (?awarding_agency=HHS|DODreturns rows from either) on every endpoint. Single-value queries are unchanged. (issue #2210, also reported externally asmakegov/tango-public#51)
- Numeric Federal Hierarchy keys (
fh_key) now resolve to the canonical agency. Previously, passing an L2fh_key(e.g. NIH's100019747) could resolve to a deep descendant office (an L3 within NIH whose name happened to contain "AGENCY") instead of NIH itself. The agency now picks the canonical match and the subtree expansion gives the full agency's records. Same behavior change applies to numeric CGAC-style codes when the leading zero is stripped (?agency=89now resolves to DOE rather than a sub-office under DOE).
- Long pipe-separated agency queries no longer return HTTP 400 on award endpoints.
?awarding_agency=DOD|HHS|VA|DHS|DOE|TREAS|USDA|DOJ|DOT|GSA(and similar 10-token OR queries) now return HTTP 200 with the union of every named department's awards on/api/contracts/,/api/idvs/, and other award endpoints. Empty / pipe-only inputs (|||) and all-unresolvable inputs (FAKE1|FAKE2|FAKE3) likewise return HTTP 200 with an empty result set rather than 400. A single typo'd agency name still returns 400 (e.g.?awarding_agency=DEPRTMENTOFENERGY).
- Single-word agency abbreviations no longer accidentally match an unrelated office. Some L3+ offices in the Federal Hierarchy data have a
nameliterally equal to a department abbreviation (e.g. an L3 office named"HHS"); previously, querying?agency=HHScould match that office instead of the canonical L1 HHS department, returning a narrow result set. Abbreviations now consistently resolve to the canonical agency. Multi-word canonical names like?agency=ENERGY, DEPARTMENT OFare unchanged.
?agency=A|Bon/api/forecasts/,/api/grants/,/api/protests/no longer over-matches via partial-text fallback. Where a token resolves cleanly to an agency, only that agency's subtree is matched. The previous behavior fell back to a partial-text match on the legacy text column when paired with multi-value input, which over-matched compound codes (e.g.?agency=HHS|...on grants matched every grant with"HHS-..."in itsagency_code— 1500+ instead of 40). Unresolvable tokens still fall back to the legacy text column as before.
[4.3.0] - 2026-05-07¶
Added¶
- Vehicle list filtering (
/api/vehicles/). New query parameters cover enum / code fields (vehicle_type,type_of_idc,contract_type,set_aside,who_can_use), reference codes (naics_code,psc_code,program_acronym), org hierarchy (agency,organization_id), numeric ranges (total_obligated_min/max,idv_count_min/max,order_count_min/max), and dates (fiscal_year,award_date_after/before,last_date_to_order_after/before).vehicle_type,type_of_idc, andcontract_typeaccept pipe-separated multi-value selections via theORsmart-filter grammar (e.g.?vehicle_type=A|B|C). The?ordering=whitelist is expanded withtotal_obligated,award_date,last_date_to_order,fiscal_year,idv_count,order_count,awardee_count, andvehicle_contracts_valuealongside the existingvehicle_obligationsandlatest_award_date. Examples:GET /api/vehicles/?vehicle_type=A,GET /api/vehicles/?vehicle_type=A|B,GET /api/vehicles/?naics_code=541512&total_obligated_min=1000000,GET /api/vehicles/?ordering=-total_obligated. (issue #2202) - Awardee search (
/api/vehicles/{uuid}/awardees/?search=). Filter the awardees response by entity-aware full-text search across IDV fields (PIID, key, solicitation identifier, NAICS, PSC) and the recipient entity (legal name, address, etc.). Examples:GET /api/vehicles/{uuid}/awardees/?search=ACCENTURE,GET /api/vehicles/{uuid}/awardees/?search=GS-35F-0119Y. The response count reflects filtered results. (issue #2202) /api/forecasts/: neworganizationshape expand. Each forecast row is now linked to a canonicalagencies.Organizationresolved deterministically from the existingagencytext field (12 distinct production acronyms —HHS,DHS,DOI,GSA,DOE,DOT,VA,DOL,NRC,NSF,COMMERCE,TREASURY). Use?shape=organization(*)for the canonical 7-key office payload (organization_id,office_code,office_name,agency_code,agency_name,department_code,department_name). Theorganizationexpand is also in the default response shape (no?shape=needed). The legacyagencytext field and filter are unchanged./api/grants/: neworganizationshape expand. Each grant opportunity is now linked to a canonicalagencies.Organizationresolved from the free-textagency_codefield — the resolver walks compound codes likeHHS-NIH11/HHS-FDA/HHS-CDC-GHC/DOS-ECA/USDOJ-OJP-BJAsegment-wise to the most-specific aliased sub-agency (NIH, FDA, CDC, the State Dept bureau, BJA, etc.) rather than collapsing to the parent department. Codes whose only recognizable token is the dept prefix (DOS-MEXcountry codes, etc.) resolve to the L1 department.?shape=organization(*)returns the canonical 7-key office payload;organizationis in the default response shape. The legacyagencytext field and filter are unchanged./api/itdashboard/: neworganizationshape expand (free tier — same gating asagency_name). Each IT Dashboard investment is now linked to a canonicalagencies.Organization, resolved deterministically from(agency_code, bureau_code)(preferred) and(agency_name, bureau_name)(fallback).?shape=organization(*)returns the canonical 7-key office payload. A small minority of investments (e.g., U.S. Army Corps of Engineers) currently resolve tonulldue to gaps in the canonical org data — tracked in #2176./api/protests/: neworganizationshape expand (free tier — same gating as the existingagencytext field). Each protest case is now linked to a canonicalagencies.Organizationresolved deterministically from the free-textagencyfield — handles hierarchical names (Department of the Army : NAVSEA : Surface Warfare), DoD branches (Army / Navy / Air Force resolve to their AGENCY-typed orgs under DoD, not to DoD itself), and synthetic GAO buckets (Independent Government Entities/Legislative Agenciesskip the dept lookup).?shape=organization(*)returns the canonical 7-key office payload. The deterministic FK is the canonical "what agency is this protest against?" signal — distinct from (and complementary to) the existing Bayesian?shape=resolved_agency(*)expand which returns a best-guess match with confidence and rationale. Both signals can be requested in the same call.
Changed¶
organizationis now in the default response shape for/api/forecasts/,/api/grants/,/api/itdashboard/, and/api/protests/. Previously opt-in via?shape=organization(*); now always present. Renders as the canonical 7-key office payload — same shape asawards,opportunities, andvehicles. Droporganizationfrom your?shape=parameter if you don't want it./api/opportunities/officepayload now includesorganization_id(was 6 keys, now 7). Additive change — same UUID is resolvable as before, just no longer requires a separate query to round-trip from the office to the underlying Organization. Other six keys (office_code,office_name,agency_code,agency_name,department_code,department_name) unchanged.- Bare
?shape=<expand-name>syntax now works on every dataset that has the expand registered withrelation="select"or"prefetch". Previously rejected with a 400unknown_fielderror on most endpoints —?shape=organizationreturns 200 on forecasts / grants / itdashboard / protests / vehicles / opportunities. The parens form (organization(*)) was always working and is unchanged.
Breaking¶
Fixed¶
[4.2.2] - 2026-05-05¶
Fixed¶
?shape=opportunity(...)on/api/vehicles/now returns the full Opportunity shape instead of a 400. The v4.2.1 implementation shipped a 4-field stub that only allowedopportunity_id,solicitation_title,solicitation_description, andsolicitation_date. Any consumer requesting a field the pre-cutovervehicle.opportunityFK exposed —title,sam_url,first_notice_date,office(...), or any other Opportunity field — received a 400 from shape validation. The fix resolves the fullOpportunitybysolicitation.opportunity_idand routes through the complete Opportunity shape so every field and nested expand (includingoffice(office_code,office_name,agency_code,agency_name,department_code,department_name)andset_aside(code,description)) works as it did pre-cutover. Available on both list and retrieve; opt-in via?shape=opportunity(...)(not in the default response shape). On list pages, all Opportunity rows for the page are fetched in a single batched query, soopportunity(...)is safe to request alongside other shapes. Closes #2193.solicitation_identifierno longer leaks the internalACRO:storage prefix on synthetic GWAC vehicles. Previously, certain GWAC vehicles returned values like"solicitation_identifier": "ACRO:SEWP". TheACRO:prefix is an internal storage detail (collision avoidance with real solicitation numbers in the unique index); the API response now strips it, so SEWP-family vehicles surface as"SEWP","SEWP IV","SEWP V", etc. Useis_synthetic_solicitation(boolean) andprogram_acronym(string) to identify GWAC-recovery vehicles. Refs #2193.
Changed¶
Deprecation: trueHTTP header removed from/api/vehicles/. v4.2.1 added an unconditionalDeprecation: trueheader on every list and retrieve response, advertising deprecation ofagency_details,competition_details, and?shape=opportunity(...). We're walking it back: there are no committed first-class replacements foragency_details.funding_officeor for uniquecompetition_detailskeys (extent_competed,set_aside,solicitation_procedures,number_of_offers_received), no sunset date, and?shape=opportunity(...)is now restored to full pre-cutover parity. The fields continue to work; tooling that was watching for the header should expect it to be absent until we publish a real migration plan.
Breaking¶
?shape=opportunity(solicitation_title)/opportunity(solicitation_description)/opportunity(solicitation_date)no longer validate. These three fields are top-level Vehicle fields, not Opportunity model fields — the v4.2.1 stub erroneously accepted them insideopportunity(...). Use?shape=solicitation_title,solicitation_description,solicitation_date(top-level, no nesting) instead — these come back in the default list shape and are cheaper than the fullopportunity(...)expand.opportunity(opportunity_id)continues to work —opportunity_idis also an Opportunity model field, AND it's available as a top-level Vehicle field. SDK consumers (tango-python,tango-node) verified clean. If you adopted the v4.2.1 stub shape between #2177 and #2193 landing, move the three companion fields to top-level.
[4.2.1] - 2026-05-03¶
Added¶
/api/vehicles/responses now includeis_synthetic_solicitation(boolean). True for a small set of GWAC vehicles where the underlying IDVs lacked a real solicitation identifier but had a recognizableprogram_acronym(8ASTARS,SEWP IV,COMMITS NEXGEN, etc.) — the API keys the vehicle off the program acronym so these GWACs surface in results instead of being dropped. SAM enrichment (solicitation_title/description/date/opportunity_id) is always null on synthetic rows. Use this flag to distinguish them in your own filtering or display logic./api/vehicles/responses now include three new top-level fields on both list and retrieve:program_acronym(the vehicle's program acronym, e.g."OASIS+", when present),idv_count(number of IDVs in the vehicle),total_obligated(sum of obligations across the vehicle's IDVs). Retrieve responses also include a nestedmetricsobject with 12 new metrics:competed_rate,award_concentration_hhi,order_concentration_hhi,top_recipient_share,avg_offers_received,avg_order_value,max_order_value,using_agency_count,recent_obligations_24mo,recent_orders_24mo,days_since_last_order,obligation_to_ceiling_ratio. Request the bag via?shape=metrics(*)or specific keys via?shape=metrics(competed_rate,top_recipient_share).organizationfield on/api/vehicles/list and retrieve responses — the awarding Organization expanded to the canonical 7-key office payload (organization_id,office_code,office_name,agency_code,agency_name,department_code,department_name). The same payload now also populatesagency_details.awarding_officeon both list and detail responses (was previously null on list and sometimes null on detail when per-IDV office signals were missing). Cached for 1 year per Organization.description(string) anddescriptions(array) on/api/vehicles/are populated again. Both had been returning null since v4.2.0; that's now fixed. The legacy compose-a-single-string behavior (descriptionreturns the longest common substring acrossdescriptions) is unchanged.
Changed¶
- Response keys are now alphabetized at every nesting level on
/api/vehicles/list and detail. Leaves and nested expand objects interleave by key name. The order is stable and independent of the order keys appear in your?shape=parameter —?shape=uuid,organizationand?shape=organization,uuidproduce the same JSON. Affects every shape-using endpoint (vehicles, contracts, opportunities, entities, etc.) — if you've been relying on response-key order, switch to explicit key access. The OpenAPI schema (Swagger UI) and SDK type definitions are unchanged.
Changed (internal data path; API surface preserved)¶
/api/vehicles/{uuid}/agency_detailsandcompetition_detailsJSON blobs and the?shape=opportunity(...)expand are now recomputed at request time (from the vehicle's IDVs and theawards_vehicle_solicitationcompanion respectively) instead of being stored columns. No deprecation announced: see the #2193 / 4.2.2 entry for the walk-back. The fields keep working. List responses includeagency_details.awarding_officepopulated from the same source as the top-levelorganizationfield —agency_details.funding_officeis null at the vehicle grain (see below).- Top-level
organization_idon/api/vehicles/retrieve responses is dropped from the default shape — it's redundant withorganization.organization_id(the same UUID, nested inside the office payload). Still requestable explicitly via?shape=organization_id, but the default response no longer surfaces it. - Funding-side organization signal removed from vehicles.
agency_details.funding_officeis null at the vehicle grain. Vehicles are not the right grain for funding-org analysis: a single vehicle is funded by many agencies via task orders, and task-order data already carries funding-side detail. Consumers needing funding-org rollups should query/api/vehicles/<uuid>/orders/and aggregate from there.
[4.2.0] - 2026-04-30¶
Added¶
- G2X integration (#1881): new
/api/news/and/api/events/endpoints (G2X User group required), a/api/company/rag/endpoint for unified company/people/news lookups, andg2x_about/g2x_ai_summary/g2x_employee_countfields available via?shape=on/api/entities/when a linked G2X profile exists - eBuy opportunities now available on
/api/opportunities/via?domain=ebuy(eBuy only) or?domain=sam,ebuy(union with SAM). eBuy results are served live from the G2X GraphQL API — no stored snapshot; filter byrequest_type,contract_type,set_aside_type,buyer_department,closes_after, orsearch. On upstream outage,?domain=sam,ebuydegrades to SAM-only with anupstream_warningsfield so SAM queries stay up vehicleis now available as a shape expand on/api/contracts/. Use?shape=vehicle(uuid,solicitation_title)to attach the contract's parent vehicle to each result, or?shape=vehicle(*)for the curated field set (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). Contracts without a parent IDV — or whose parent IDV is not part of any vehicle — returnnull. For richer vehicle detail (awardees, opportunity, totals), follow the returneduuidto/api/vehicles/{uuid}/. Resolution adds one query per page, not per row.
Changed¶
Breaking¶
Fixed¶
[4.1.1] - 2026-04-27¶
Added¶
cageis now an alias forcage_codeacross the API. Query entities with?cage=or?cage_code=(sending both is rejected — pick one). Awardrecipientshapes accept either key:recipient(cage)returnscage,recipient(cage_code)returnscage_code, andrecipient(*)returnscage_codeonly. If you want the shortcagekey, ask for it explicitly (refs #1350).
Fixed¶
- Filtering subawards by
?awarding_agency=<name|code>or?funding_agency=<name|code>now uses the same hierarchical resolution as the contracts and opportunities endpoints. Department queries (e.g.?awarding_agency=DOE,?awarding_agency=089) return all subawards under that department's subtree; agency codes (e.g.?awarding_agency=8900for DOE,?awarding_agency=7530for CMS) return that agency's subtree; abbreviations (e.g.?awarding_agency=CMS) resolve via the canonical alias table. Result counts will shift compared to the previous literal-code-match behavior — most notably, name-based queries that previously returned 0 (e.g.?awarding_agency=CMS) now return the full agency subtree, semantically aligned with/api/contracts/?awarding_agency=.... Closes #2076.
[4.1.0] - 2026-04-26¶
Internal / Infra¶
- Internal ETL pipeline rewrite for awards data freshness. No API surface or query-behavior changes (refs #2082).
[4.0.14] - 2026-04-26¶
Changed¶
- Latency spikes on
/metrics/endpoints during scheduled refreshes should be noticeably smaller after an internal pipeline rewrite. API surface is unchanged — the same/metrics/endpoints with?group_by=agency/?group_by=departmentparameters continue to work. - Filtering opportunities or notices by
?agency=<name|code>now uses the same hierarchical resolution as the contracts agency filter. Department queries (e.g.?agency=DOE,?agency=089) return the whole department subtree; agency codes (e.g.?agency=8900for DOE,?agency=8960for FERC) return just that agency's subtree. Result counts will shift compared to the previous full-text-search behavior — the new counts are semantically correct subtree matches rather than token co-occurrence. Closes #2058.
Fixed¶
- Forecasts loader: reduced log noise and false Sentry alerts.
sanitize_yeardata-quality events are now DEBUG-level; empty records is a no-op rather than an error; partial validation failures log as warnings (visible in admin, no Sentry alert). Closes #1974, closes #1935. - Filtering contracts by a department's full legal name (e.g.
?awarding_agency=ENERGY, DEPARTMENT OF) now correctly returns the whole department's contracts instead of 0 results. The embedded comma in federal inverted names was being misinterpreted as a target/context separator. Queries for?awarding_agency=DOEand the numeric CGAC/FPDS codes are unchanged. Closes #2079. - Filtering contracts by
awarding_agencyorfunding_agencyusing a real (but currently inactive) agency code such as5706,8933, or8944now returns an HTTP 200 response with the matching contracts, instead of an HTTP 400 "No agency found matching" error. Queries for agency codes that don't exist at all continue to return 400 as before. Closes #2057. - Filtering contracts by a numeric agency code (e.g.
awarding_agency=8900,funding_agency=8900) now returns the correct subtree of contracts instead of narrowing to a single sub-office. A 4-digit FPDS code resolves to that agency and its descendants; a 3-digit CGAC code resolves to the whole department (matching whatawarding_agency=DOEreturns). Name queries are unchanged. Closes #2056. - Filtering opportunities or notices by a numeric agency code (e.g.
?agency=8900) now resolves to the correct subtree instead of matching agencies whose search index happens to contain that token. Fixes over-broad matches for short numeric queries and makes sibling-agency queries (like DOE8900vs FERC8960under the same department) correctly distinct. Closes #2058.
[4.0.12] - 2026-04-22¶
Added¶
- The
/welcome/page now displays your active API key(s) with copy-to-clipboard and visibility toggle — no longer need to navigate to your profile to find your key after signing up
Changed¶
- The welcome page's API keys card now matches the richer layout used on your profile: full-width card at the top of the page with your daily requests remaining, per-key name + "Active" badge, click-to-copy, show/hide, and created date + rate limits. "Your plan" and "Quick links" now sit side-by-side below it so nothing important is hidden below the fold
[4.0.11] - 2026-04-21¶
- No user-facing changes
[4.0.10] - 2026-04-21¶
- No user-facing changes
[4.0.9] - 2026-04-20¶
- No user-facing changes
[4.0.8] - 2026-04-20¶
- No user-facing changes
[4.0.7] - 2026-04-18¶
- No user-facing changes
[4.0.6] - 2026-04-17¶
- No user-facing changes