You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit c33db62
Browse filesBrowse the repository at this point in the historyBrowse files
authored
feat(ebuy): add the GSA eBuy requests resource (#70)
* feat(ebuy): add the GSA eBuy requests resource
Adds `list_ebuy_requests()`, `get_ebuy_request()`, `get_ebuy_attachment_url()` and `get_ebuy_access()` over the `/api/ebuy/` resource (Tango API 5.1.0), with `EbuyRequest` / `EbuyAttachment` schemas, an `EbuyAccess` result type and the `EBUY_REQUESTS_MINIMAL` / `EBUY_REQUESTS_COMPREHENSIVE` default shapes.
All fourteen of the API's list filters are explicit named parameters.
`get_ebuy_attachment_url()` reads the download redirect without following it and returns the short-lived signed URL; a link entry raises `TangoValidationError` carrying the link.
The response-status handling in `_request()` moves into `_raise_for_status()` so the attachment method can share it.
`ebuy/requests` is now mapped in both conformance gates, and its unmapped-resource shape-coverage baseline entry is removed.
`ebuy_request` is documented as an alert query type.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(ebuy): raise TangoAttachmentLinkError for link attachments
`get_ebuy_attachment_url()` now raises `TangoAttachmentLinkError`, a `TangoValidationError` subclass exposing the link as `.url`, when the entry is an external link rather than a stored document.
The `agency` filter on `list_ebuy_requests()` documents that it requires Tango API 5.3.0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: V. David Zvenyach <dave@zvenyach.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
8
8
## [Unreleased]
9
9
10
+
### Added
11
+
-**GSA eBuy requests** (Tango API 5.1.0). Four methods over the `/api/ebuy/` resource: `list_ebuy_requests()`, `get_ebuy_request()`, `get_ebuy_attachment_url()` and `get_ebuy_access()`, plus `EbuyRequest` / `EbuyAttachment` schemas, an `EbuyAccess` result type, and the `EBUY_REQUESTS_MINIMAL` / `EBUY_REQUESTS_COMPREHENSIVE` defaults. These are the RFQs, RFPs and RFIs posted to GSA eBuy. All fourteen of the API's filters are explicit named parameters, including `search` (which also matches attachment text), `reference_number`, `sin`, `agency` and `contract_number`.
12
+
13
+
Access is scoped to your account: you see only requests posted under the GSA schedule contracts linked to it, and the endpoints require the Pro tier or above. With no linked contract, `list_ebuy_requests()` returns an empty page rather than an error, so `get_ebuy_access()` reports whether access is enabled, why not (`tier_required` or `no_contract_grant`), and which contracts are linked. `status` is frozen at the last state a request was seen in, because a request that closes stops appearing rather than getting a final row; read `last_seen` for staleness. `get_ebuy_attachment_url()` returns the short-lived signed URL the API redirects to without downloading the document, and raises the new `TangoAttachmentLinkError` (a `TangoValidationError`) with the link on `.url` when the entry is an external link rather than a stored document. The `agency` filter requires Tango API 5.3.0.
14
+
-**`alerts.ebuy_request.match` is an alertable event type.**`create_webhook_alert(query_type="ebuy_request", ...)` works.
Copy file name to clipboardExpand all lines: contracts/shape_coverage_baseline.json
+1-2Lines changed: 1 addition & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -1,11 +1,10 @@
1
1
{
2
2
"description": "Known reverse shape-coverage gaps (Tango exposes, SDK schema lacks), accepted as a tracked backlog. check_shape_coverage.py fails only on gaps NOT listed here. Burn down and regenerate with --update-baseline.",
GSA eBuy requests for quotes, proposals and information (RFQs, RFPs, RFIs), keyed by `rfq_id`.
1609
+
1610
+
**Access is scoped to your account.** You see only requests posted under the GSA schedule contracts linked to your account, and the endpoints require the Pro tier or above (below it they return 403). With no linked contract, `list_ebuy_requests()` returns an empty page rather than an error, and `get_ebuy_request()` raises `TangoNotFoundError` for a request outside your scope, the same as for an id that does not exist. Use `get_ebuy_access()` to tell "no access" from "no matches".
1611
+
1612
+
### list_ebuy_requests()
1613
+
1614
+
List requests with filtering and shaping.
1615
+
1616
+
```python
1617
+
requests = client.list_ebuy_requests(
1618
+
page=1,
1619
+
limit=25,
1620
+
shape=ShapeConfig.EBUY_REQUESTS_MINIMAL,
1621
+
# Filter parameters (all optional)
1622
+
search=None,
1623
+
rfq_id=None,
1624
+
reference_number=None,
1625
+
request_type=None,
1626
+
status=None,
1627
+
sin=None,
1628
+
schedule=None,
1629
+
buyer_agency=None,
1630
+
agency=None,
1631
+
contract_number=None,
1632
+
issue_date_after=None,
1633
+
issue_date_before=None,
1634
+
close_date_after=None,
1635
+
close_date_before=None,
1636
+
ordering=None,
1637
+
)
1638
+
```
1639
+
1640
+
**Filter Parameters:**
1641
+
-`search` - Full-text search over the title, description, reference number, request id and attachment text. Results rank by relevance unless `ordering` is given
1642
+
-`rfq_id` - Exact request id, e.g. `"RFQ1835158"`
1643
+
-`reference_number` - The buyer's own solicitation number; dashes are ignored
1644
+
-`request_type` - `"RFQ"`, `"RFP"` or `"RFI"`
1645
+
-`status` - `"Open"` or `"Cancelled"`, as last seen (see the note below)
1646
+
-`sin` - Special Item Number, e.g. `"54151S"`
1647
+
-`schedule` - GSA schedule
1648
+
-`buyer_agency` - The buyer agency as eBuy names it (free text)
1649
+
-`agency` - A Tango agency name, abbreviation, code or organization key, e.g. `"GSA"`. Matches the whole organization subtree, so a department includes its sub-agencies. Requires Tango API 5.3.0
1650
+
-`contract_number` - Narrow to requests posted under one of your own linked contracts. A contract not linked to your account returns an empty page, not an error
1651
+
-`issue_date_after` / `issue_date_before` - Issue date range (`YYYY-MM-DD`, inclusive)
1652
+
-`close_date_after` / `close_date_before` - Close date range (`YYYY-MM-DD`, inclusive)
1653
+
-`ordering` - `issue_date` (the default, as `-issue_date`), `close_date`, `last_seen` or `modified`; prefix `-` for descending
1654
+
1655
+
String filters accept several values joined with `|` (OR).
1656
+
1657
+
**Returns:**[PaginatedResponse](#paginatedresponse) with request dictionaries
-**`status` is frozen at the last state the request was seen in.** Only currently-active requests are carried, so a request that closes stops appearing rather than getting a final row. `Open` means "open the last time it was seen", not "open now"; read `last_seen` for staleness.
1670
+
- The contract number a request was posted under is never returned in any payload.
1671
+
-`buyer_agency_code` and some other buyer and contact fields are sparse on older requests.
The default shape returns every field plus two expands: `organization` (the buyer office, with the same seven keys as other resources' `organization` expand) and `attachments`. Each attachment carries `doc_seq_num`, `doc_name`, `doc_type`, `doc_path`, `is_link` and `doc_session_date`. `is_link=True` means `doc_path` is an outbound URL with no stored document behind it. `amendments`, `line_items` and `addresses` are lists of objects, served as eBuy publishes them.
1688
+
1689
+
### get_ebuy_attachment_url()
1690
+
1691
+
Get a short-lived download URL for one stored attachment.
**Returns:** The signed URL the API redirects to, as a string. The SDK reads the redirect without following it, so no document is downloaded. The URL expires after about five minutes: fetch it promptly, and call this again rather than storing it.
1698
+
1699
+
**Raises:**
1700
+
-`TangoAttachmentLinkError` (a `TangoValidationError`) - The entry is an external link (`is_link`), not a stored document. The link is on `error.url`
1701
+
-`TangoNotFoundError` - The request is unknown or outside your scope, the attachment does not exist, or its document has not been captured yet
1702
+
1703
+
### get_ebuy_access()
1704
+
1705
+
Check whether your account can read eBuy requests.
1706
+
1707
+
```python
1708
+
access = client.get_ebuy_access()
1709
+
ifnot access.enabled:
1710
+
print(access.reason) # "tier_required" or "no_contract_grant"
1711
+
print(access.contracts) # your own linked contracts, sorted
1712
+
```
1713
+
1714
+
**Returns:**`EbuyAccess` with `enabled` (bool), `reason` (`"tier_required"`, `"no_contract_grant"` or `None`; `tier_required` wins when both apply) and `contracts` (list of str).
1715
+
1716
+
---
1717
+
1605
1718
## Budget
1606
1719
1607
1720
Federal account × fiscal year budget rollups, covering the full budget lifecycle (requested → enacted → apportioned → obligated → outlayed), pre-computed ratios and trends, the contract / assistance / unlinked breakdown, and request-vs-actual spend.
|`CONTRACT_APPEALS_COMPREHENSIVE`|`get_contract_appeal`| The list fields plus docket_raw, docket_source, decision_date_repaired, decision_type_raw, listing_year, first_listed_at, listed, text_status, text_char_count (omits `decision_text`, which needs an Enterprise plan) |
0 commit comments