Skip to content

Commit 8745189

Browse files
committed
Updated the contracts endpoint to reflect real filters
1 parent 00aaba8 commit 8745189

21 files changed

+2056
-88
lines changed

README.md

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -106,30 +106,50 @@ contracts = client.list_contracts(
106106
limit=25,
107107
# Filter parameters
108108
keyword="software",
109-
awarding_agency="GSA",
109+
awarding_agency="4700", # GSA agency code
110110
award_date_gte="2023-01-01",
111-
award_amount_gte=100000,
111+
fiscal_year=2024,
112112
naics_code="541511"
113113
)
114114

115115
# Filter by specific agency
116116
contracts = client.list_contracts(
117-
awarding_agency="DOD",
117+
awarding_agency="4700", # GSA
118118
limit=50
119119
)
120120
```
121121

122122
**Available Filter Parameters:**
123123

124-
- `keyword` - Text search
125-
- `award_date_gte`, `award_date_lte` - Date range filters
126-
- `award_amount_gte`, `award_amount_lte` - Amount filters
127-
- `awarding_agency`, `funding_agency` - Agency filters
128-
- `recipient_name`, `recipient_uei` - Recipient filters
129-
- `naics_code`, `psc_code` - Classification codes
130-
- `place_of_performance_state`, `place_of_performance_zip` - Location filters
131-
- `fiscal_year` - Fiscal year filter
132-
- `contract_type`, `award_type`, `set_aside_type`, `extent_competed` - Type filters
124+
**Text Search:**
125+
- `keyword` - Search contract descriptions (mapped to 'search' API param)
126+
127+
**Date Filters:**
128+
- `award_date_gte`, `award_date_lte` - Award date range
129+
- `pop_start_date_gte`, `pop_start_date_lte` - Period of performance start date range
130+
- `pop_end_date_gte`, `pop_end_date_lte` - Period of performance end date range
131+
- `expiring_gte`, `expiring_lte` - Contract expiration date range
132+
133+
**Party Filters:**
134+
- `awarding_agency`, `funding_agency` - Agency codes
135+
- `recipient_name`, `recipient_uei` - Vendor/recipient filters
136+
137+
**Classification:**
138+
- `naics_code`, `psc_code` - Industry/product codes
139+
- `set_aside_type` - Set-aside type
140+
141+
**Type Filters:**
142+
- `fiscal_year`, `fiscal_year_gte`, `fiscal_year_lte` - Fiscal year filters
143+
- `award_type` - Award type code
144+
145+
**Identifiers:**
146+
- `piid` - Procurement Instrument Identifier
147+
- `solicitation_identifier` - Solicitation ID
148+
149+
**Sorting:**
150+
- `sort`, `order` - Sort results (e.g., `sort="award_date"`, `order="desc"`)
151+
152+
**Response Options:**
133153
- `shape`, `flat`, `flat_lists` - Response shaping options
134154

135155
### Entities (Vendors/Recipients)

ROADMAP.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# ROADMAP
2+
3+
## Now
4+
5+
- [ ] Align existing API to the SDK
6+
- [ ] Add in existing IDV endpoint
7+
- [ ] Add in existing OTA endpoint
8+
- [ ] Add in existing OTIDV endpoint
9+
- [ ] Add in existing financial assistance endpoint
10+
- [ ] Add in account usage endpoint
11+
- [ ] Add in webhooks endpoint
12+
- [ ] Add in subawards endpoint
13+
- [ ] Better Filter DX
14+
- [ ] Dataclasses for search validation and typing
15+
- [ ] Docs improvements
16+
- [ ] Document each endpoint separately to allow for easier information
17+
- [ ] Some more targeted examples
18+
19+
## Next
20+
21+
- Better support for MCPs
22+
23+
## Later
24+
25+
-
26+
27+
## Maybe Someday
28+
29+
- CLI support

docs/API_REFERENCE.md

Lines changed: 73 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -114,24 +114,37 @@ contracts = client.list_contracts(
114114
flat=False,
115115
flat_lists=False,
116116
# Filter parameters (all optional)
117-
keyword=None,
117+
# Text search
118+
keyword=None, # Mapped to 'search' API param
119+
# Date filters
118120
award_date_gte=None,
119121
award_date_lte=None,
120-
award_amount_gte=None,
121-
award_amount_lte=None,
122+
pop_start_date_gte=None,
123+
pop_start_date_lte=None,
124+
pop_end_date_gte=None,
125+
pop_end_date_lte=None,
126+
expiring_gte=None,
127+
expiring_lte=None,
128+
# Party filters
122129
awarding_agency=None,
123130
funding_agency=None,
124-
recipient_name=None,
125-
recipient_uei=None,
126-
naics_code=None,
127-
psc_code=None,
128-
place_of_performance_state=None,
129-
place_of_performance_zip=None,
131+
recipient_name=None, # Mapped to 'recipient' API param
132+
recipient_uei=None, # Mapped to 'uei' API param
133+
# Classification
134+
naics_code=None, # Mapped to 'naics' API param
135+
psc_code=None, # Mapped to 'psc' API param
136+
set_aside_type=None, # Mapped to 'set_aside' API param
137+
# Type filters
130138
fiscal_year=None,
131-
contract_type=None,
139+
fiscal_year_gte=None,
140+
fiscal_year_lte=None,
132141
award_type=None,
133-
set_aside_type=None,
134-
extent_competed=None,
142+
# Identifiers
143+
piid=None,
144+
solicitation_identifier=None,
145+
# Sorting
146+
sort=None, # Combined with 'order' into 'ordering' API param
147+
order=None, # 'asc' or 'desc'
135148
)
136149
```
137150

@@ -145,36 +158,42 @@ contracts = client.list_contracts(
145158
**Filter Parameters:**
146159

147160
**Text Search:**
148-
- `keyword` - Search contract descriptions and titles
161+
- `keyword` - Search contract descriptions (automatically mapped to API's 'search' parameter)
149162

150163
**Date Filters:**
151164
- `award_date_gte` - Awarded on or after date (YYYY-MM-DD)
152165
- `award_date_lte` - Awarded on or before date (YYYY-MM-DD)
153-
154-
**Amount Filters:**
155-
- `award_amount_gte` - Minimum award amount
156-
- `award_amount_lte` - Maximum award amount
166+
- `pop_start_date_gte` - Period of performance start date ≥
167+
- `pop_start_date_lte` - Period of performance start date ≤
168+
- `pop_end_date_gte` - Period of performance end date ≥
169+
- `pop_end_date_lte` - Period of performance end date ≤
170+
- `expiring_gte` - Expiring on or after date
171+
- `expiring_lte` - Expiring on or before date
157172

158173
**Party Filters:**
159-
- `awarding_agency` - Agency code awarding the contract
160-
- `funding_agency` - Agency code funding the contract
161-
- `recipient_name` - Vendor/recipient name (partial match)
162-
- `recipient_uei` - Vendor UEI (exact match)
174+
- `awarding_agency` - Agency code (e.g., "4700" for GSA)
175+
- `funding_agency` - Funding agency code
176+
- `recipient_name` - Vendor/recipient name (mapped to 'recipient' API param)
177+
- `recipient_uei` - Vendor UEI (mapped to 'uei' API param)
163178

164179
**Classification:**
165-
- `naics_code` - NAICS industry code
166-
- `psc_code` - Product/Service code
167-
168-
**Location:**
169-
- `place_of_performance_state` - State code (e.g., "CA", "NY")
170-
- `place_of_performance_zip` - ZIP code
180+
- `naics_code` - NAICS industry code (mapped to 'naics' API param)
181+
- `psc_code` - Product/Service code (mapped to 'psc' API param)
182+
- `set_aside_type` - Set-aside type (mapped to 'set_aside' API param)
171183

172184
**Type Filters:**
173-
- `fiscal_year` - Federal fiscal year
174-
- `contract_type` - Type of contract
175-
- `award_type` - Award type
176-
- `set_aside_type` - Small business set-aside type
177-
- `extent_competed` - Competition extent
185+
- `fiscal_year` - Federal fiscal year (exact match)
186+
- `fiscal_year_gte` - Fiscal year ≥
187+
- `fiscal_year_lte` - Fiscal year ≤
188+
- `award_type` - Award type code
189+
190+
**Identifiers:**
191+
- `piid` - Procurement Instrument Identifier (exact match)
192+
- `solicitation_identifier` - Solicitation ID
193+
194+
**Sorting:**
195+
- `sort` - Field to sort by (e.g., "award_date", "obligated")
196+
- `order` - Sort order: "asc" or "desc" (default: "asc")
178197

179198
**Returns:** [PaginatedResponse](#paginatedresponse) with contract dictionaries
180199

@@ -186,7 +205,13 @@ contracts = client.list_contracts(limit=10)
186205

187206
# Filter by agency
188207
contracts = client.list_contracts(
189-
awarding_agency="GSA",
208+
awarding_agency="4700", # GSA agency code
209+
limit=50
210+
)
211+
212+
# Text search
213+
contracts = client.list_contracts(
214+
keyword="software development",
190215
limit=50
191216
)
192217

@@ -197,25 +222,34 @@ contracts = client.list_contracts(
197222
limit=100
198223
)
199224

200-
# Amount range
225+
# Expiring contracts
201226
contracts = client.list_contracts(
202-
award_amount_gte=100000,
203-
award_amount_lte=1000000,
227+
expiring_gte="2025-01-01",
228+
expiring_lte="2025-12-31",
204229
limit=50
205230
)
206231

207232
# Multiple filters
208233
contracts = client.list_contracts(
209-
awarding_agency="DOD",
210-
naics_code="541511", # IT services
234+
keyword="IT services",
235+
awarding_agency="4700", # GSA
211236
fiscal_year=2024,
237+
naics_code="541511",
212238
limit=100
213239
)
214240

215241
# With shaping for performance
216242
contracts = client.list_contracts(
217243
shape="key,piid,recipient(display_name),total_contract_value,award_date",
218-
awarding_agency="GSA",
244+
awarding_agency="4700",
245+
fiscal_year=2024,
246+
limit=100
247+
)
248+
249+
# Sorting results
250+
contracts = client.list_contracts(
251+
sort="award_date",
252+
order="desc",
219253
limit=100
220254
)
221255
```

tango/client.py

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -396,27 +396,73 @@ def list_contracts(
396396
flat_lists: If True, flatten arrays using indexed keys (e.g., items.0.field)
397397
filters: Optional SearchFilters object or dict for backward compatibility.
398398
Filter parameters can also be passed as keyword arguments.
399-
**kwargs: Filter parameters (keyword, award_date_gte, award_date_lte,
400-
award_amount_gte, award_amount_lte, awarding_agency, funding_agency,
401-
recipient_name, recipient_uei, naics_code, psc_code,
402-
place_of_performance_state, place_of_performance_zip, cfda_number,
403-
contract_type, award_type, set_aside_type, extent_competed,
404-
fiscal_year, sort, order)
399+
**kwargs: Filter parameters
400+
401+
Text search:
402+
- keyword: Search contract descriptions (mapped to 'search' API param)
403+
404+
Date filters:
405+
- award_date_gte: Award date >= (YYYY-MM-DD)
406+
- award_date_lte: Award date <= (YYYY-MM-DD)
407+
- pop_start_date_gte: Period of performance start date >=
408+
- pop_start_date_lte: Period of performance start date <=
409+
- pop_end_date_gte: Period of performance end date >=
410+
- pop_end_date_lte: Period of performance end date <=
411+
- expiring_gte: Expiring on or after date
412+
- expiring_lte: Expiring on or before date
413+
414+
Party filters:
415+
- awarding_agency: Awarding agency code (e.g., "4700" for GSA)
416+
- funding_agency: Funding agency code
417+
- recipient_name: Vendor/recipient name (mapped to 'recipient' API param)
418+
- recipient_uei: Vendor UEI (mapped to 'uei' API param)
419+
420+
Classification filters:
421+
- naics_code: NAICS code (mapped to 'naics' API param)
422+
- psc_code: PSC code (mapped to 'psc' API param)
423+
- set_aside_type: Set-aside type (mapped to 'set_aside' API param)
424+
425+
Type filters:
426+
- fiscal_year: Fiscal year (exact match)
427+
- fiscal_year_gte: Fiscal year >=
428+
- fiscal_year_lte: Fiscal year <=
429+
- award_type: Award type code
430+
431+
Identifiers:
432+
- piid: Procurement Instrument Identifier
433+
- solicitation_identifier: Solicitation ID
434+
435+
Sorting:
436+
- sort: Field to sort by (combined with 'order')
437+
- order: Sort order ('asc' or 'desc', default 'asc')
405438
406439
Examples:
407440
>>> # Simple usage
408441
>>> contracts = client.list_contracts(limit=10)
409442
410443
>>> # With keyword arguments
411444
>>> contracts = client.list_contracts(
412-
... awarding_agency="GSA",
445+
... awarding_agency="4700", # GSA
413446
... award_date_gte="2023-01-01",
414447
... limit=25
415448
... )
416449
417-
>>> # With SearchFilters object
418-
>>> filters = SearchFilters(keyword="IT", awarding_agency="GSA")
450+
>>> # Text search
451+
>>> contracts = client.list_contracts(keyword="software development")
452+
453+
>>> # With SearchFilters object (legacy)
454+
>>> filters = SearchFilters(
455+
... keyword="IT",
456+
... awarding_agency="4700",
457+
... fiscal_year=2024
458+
... )
419459
>>> contracts = client.list_contracts(filters=filters)
460+
461+
>>> # Using new date range filters
462+
>>> contracts = client.list_contracts(
463+
... expiring_gte="2025-01-01",
464+
... expiring_lte="2025-12-31"
465+
... )
420466
"""
421467
# Start with explicit parameters
422468
params: dict[str, Any] = {"page": page, "limit": min(limit, 100)}
@@ -471,21 +517,31 @@ def list_contracts(
471517
# Map Python parameter names to API parameter names
472518
# The API may expect different parameter names than our Python interface
473519
api_param_mapping = {
474-
"naics_code": "naics", # API expects 'naics' not 'naics_code' for filtering
520+
"naics_code": "naics", # API expects 'naics' not 'naics_code'
521+
"keyword": "search", # API expects 'search' not 'keyword'
522+
"psc_code": "psc", # API expects 'psc' not 'psc_code'
523+
"recipient_name": "recipient", # API expects 'recipient' not 'recipient_name'
524+
"recipient_uei": "uei", # API expects 'uei' not 'recipient_uei'
525+
"set_aside_type": "set_aside", # API expects 'set_aside' not 'set_aside_type'
475526
}
476527

528+
# Handle sort + order → ordering conversion
529+
# API expects single 'ordering' parameter with '-' prefix for descending
530+
sort_field = filter_params.pop("sort", None)
531+
sort_order = filter_params.pop("order", None)
532+
if sort_field:
533+
# Prefix with '-' for descending order
534+
prefix = "-" if sort_order == "desc" else ""
535+
filter_params["ordering"] = f"{prefix}{sort_field}"
536+
477537
# Apply parameter name mapping and process values
478538
api_params = {}
479539
for key, value in filter_params.items():
480540
if value is None:
481541
continue # Skip None values
482542
# Map to API parameter name if needed
483543
api_key = api_param_mapping.get(key, key)
484-
# Convert Decimal/numeric values to strings for award amounts
485-
if key in ("award_amount_gte", "award_amount_lte"):
486-
api_params[api_key] = str(value)
487-
else:
488-
api_params[api_key] = value
544+
api_params[api_key] = value
489545

490546
# Update params with all filter parameters
491547
# This is the same pattern as other endpoints use

0 commit comments

Comments
 (0)