Sell to State — Government Contracts Data API
Version 0.4.0
# Sell to State Data API
Programmatic access to **government tenders and contract awards in 73 countries**, from official procurement sources: open tenders with bid deadlines, awards with the winner and the amount, public buyers and suppliers. Built for analysts, vendors, and **AI agents**. The [countries page](https://www.selltostate.com/countries/) lists each country and its sources.
The same data behind the public [selltostate.com](https://selltostate.com) site and the [app](https://app.selltostate.com/search), available as JSON, CSV, and an **MCP server** your AI assistant can call directly.
## Base URL
```
https://app.selltostate.com
```
> The API is served from `https://app.selltostate.com` at the documented paths — use this host today. A dedicated `https://api.selltostate.com` machine-API host is planned for GA but is **not yet deployed** (it currently returns 404); do not target it until it is announced.
## 60-second quickstart
1. Create a free account at [app.selltostate.com](https://app.selltostate.com) and start a subscription (or trial).
2. Generate an API key under **Account → API keys** (`app.selltostate.com/account/keys`). It is shown **once** — store it.
3. Call the API:
```bash
curl -s https://app.selltostate.com/api/v1/awards?q=cybersecurity&page_size=5 \
-H "x-api-key: sts_xxxxxxxx"
```
Open tenders in Mexico published in the last 30 days:
```bash
curl -s "https://app.selltostate.com/api/v1/search?scope=tenders&country=mexico&lifecycle=open&published_days=30" \
-H "x-api-key: sts_xxxxxxxx"
```
Without an active subscription every data call returns **`402 Payment Required`** with a `payment_link` (and, for agents, a `machine_payment` affordance) — see **Subscriptions & the paywall** below.
## Authentication
Two credential types, both resolved to one entitlement check:
| Type | Header | Who | Get one |
|---|---|---|---|
| **API key** | `x-api-key: sts_…` | Humans / your backend | Dashboard → Account → API keys |
| **OAuth 2.1 access token** | `Authorization: Bearer <access_token>` | MCP clients: Claude, ChatGPT, Claude Code, Gemini CLI | Sign-in and consent (see *Connect flow*) |
| **Machine client** | `Authorization: Bearer client:<client_id>` | Autonomous agents | Self-register via DCR (`POST /api/oidc/register`) |
- API keys are `sts_` + 48 hex chars, shown once, stored only as a SHA-256 hash, and revocable from the dashboard.
- Machine clients self-register with no human in the loop (RFC 7591). A freshly registered client has **zero data scopes** until it subscribes — registration returns a `payment_link`, and the client can also pay autonomously via `POST /api/v1/pay`.
- MCP clients sign in with OAuth 2.1 (the `OAuth2` scheme below): authorization code with PKCE (S256) and dynamic client registration at `POST /api/auth/mcp/register`. The user signs in and allows access on a consent page. See *Connect flow* below.
## Subscriptions & the paywall
Data is gated by a single flat subscription (read live pricing at `GET /api/v1/price`). Until the caller's subject (`user:<id>` for a key, `client:<id>` for an agent) is active, **every data endpoint returns `402`**:
```json
{
"error": "payment_required",
"message": "An active subscription is required to access award data.",
"payment_link": "https://app.selltostate.com/checkout",
"plan": "data-monthly",
"machine_payment": {
"endpoint": "https://app.selltostate.com/api/v1/pay",
"method": "POST",
"accepts": ["payment_method_token", "customer"],
"scopes_granted": ["data:read", "data:export"]
},
"price": "$49/mo",
"currency": "usd"
}
```
The `402` also carries a header advertising both paths:
```
WWW-Authenticate: Bearer realm="data", charge="…/checkout", charge_automated="…/api/v1/pay"
```
- **Humans** open `payment_link` (hosted Stripe Checkout).
- **Agents** `POST /api/v1/pay` with a Stripe payment-method token and are charged off-session — no browser. On success the agent's very next data call returns `200`.
**Plans & caps:** a 2-day trial is capped at **20 rows** per export/page; a paid plan returns up to **5,000 rows**. v1 entitlement is all-or-nothing — an active subscription grants every data scope.
## Scopes
`data:read` (read awards), `data:export` (CSV export), `data:bulk` (bulk access). In v1 an active subscription grants all three.
## Pagination
List endpoints take `page` (default 1) and `page_size` (default 100; hard-capped by your plan — 20 trial / 5,000 paid). Responses echo `total`, `page`, and `pageSize`.
## Filter errors (400)
A bad filter value, an unknown param name, or an unknown country / sector slug is a `400`. Nothing runs and nothing is dropped in silence: the body lists every problem.
```json
{ "error": "invalid_filter", "errors": [{ "code": "invalid_filter", "param": "lifecycle", "value": "live", "allowed": ["open", "awarded", "cancelled", "planned"] }] }
```
Codes: `invalid_filter`, `unknown_param`, `unknown_country`, `unknown_sector`, `invalid_country`. Values of a fixed list match in any case (`Open`, `TRUE`). MCP returns the same body as the JSON-RPC error `data` (code `-32602`).
## Rate limits
- **Data calls:** 120 requests/minute per credential (per API key or machine client; anonymous/`402` traffic is limited per source IP).
- **Client registration:** 10 registrations/hour per IP.
Over the limit → `429` with a `Retry-After` (seconds) header.
## Using the API from an AI agent (MCP)
This API is a **Model Context Protocol (MCP) server**. Point any MCP-capable client (Claude Desktop, Claude Code, Cursor, your own agent) at the streamable-HTTP endpoint and it can search and export government tenders and contracts in 73 countries. An autonomous agent can also self-register and pay for access with no human in the loop.
**Endpoint**
```
https://app.selltostate.com/api/mcp
```
### Connect flow (OAuth 2.1)
Claude, ChatGPT, Claude Code, Gemini CLI and other spec-compliant clients connect with no API key:
1. **Discover.** The client reads `GET /.well-known/oauth-protected-resource/api/mcp` (RFC 9728). The resource is `https://app.selltostate.com/api/mcp`. Then it reads `GET /.well-known/oauth-authorization-server` (RFC 8414) for the endpoints, PKCE (S256) and the scopes (`data:read`, `data:export`, `data:bulk`).
2. **Register.** The client registers with RFC 7591 Dynamic Client Registration at `POST /api/auth/mcp/register`. A redirect URI must be a loopback URL (`http://localhost:<port>/…`) or the hosted Claude or ChatGPT callback.
3. **Sign in.** The client opens `/api/auth/mcp/authorize`. The user signs in to Sell to State and selects **Allow access** on the consent page. The client gets a token at `/api/auth/mcp/token` and sends `Authorization: Bearer <access_token>` on each MCP call.
4. **Subscribe.** Data tools need an active plan. Without one, `tools/call` returns a `402` with a message and the account link.
`tools/list` is open and needs no credential.
### Autonomous agents (no human)
1. **Register.** `POST /api/oidc/register` returns a `client_id` (zero data scopes) plus a `payment_link`.
2. **Authenticate.** Send `Authorization: Bearer client:<client_id>` on every MCP call.
3. **Subscribe.** Until the client's subject is entitled, every `tools/call` returns the same **`402`** body as REST (see *Subscriptions & the paywall*), with a human `payment_link` and the agent-native `machine_payment` affordance. The agent calls the `pay` tool (`POST /api/v1/pay`) with a Stripe payment-method token, is charged off-session, and its next `tools/call` returns data.
### Tool catalog
`tools/list` returns **26 tools** (as of 0.4.0), each mirroring a REST endpoint 1:1 — search, entity detail, faceted search, lists, and saved searches — plus the autonomous `pay` tool. The full catalog (name · scope · REST endpoint · `requires_user_key`) is the machine-readable **`x-mcp-tools`** extension on this document; treat that as the source of truth. Highlights: `whoami` (ungated self-introspection), `search` (faceted), `get_buyer`/`get_supplier_detail`/`get_sector`/`get_tender` (entity detail; `get_buyer_detail` is a back-compat alias of `get_buyer`), and the owner-scoped `*_list`/`*_saved_search` tools that require a user `x-api-key` (an OIDC client token gets a `requires_user_key` result, mirroring the REST `403`).
### Raw JSON-RPC (manual test)
List the tools (open, no auth):
```bash
curl -s https://app.selltostate.com/api/mcp \
-H "content-type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```
Call a tool (needs an entitled principal, else `402`):
```bash
curl -s https://app.selltostate.com/api/mcp \
-H "content-type: application/json" \
-H "Authorization: Bearer client:<client_id>" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search_awards","arguments":{"q":"cybersecurity","year":2024}}}'
```
### Example agent prompts
Once the connector is attached, a user can simply ask:
- *"Find UK tenders for payroll software that still accept bids."*
- *"Who are the top suppliers of Countess of Chester Hospital NHS Foundation Trust?"*
- *"Which German public contracts did Rohde & Schwarz Cybersecurity win? Export them as CSV."*
- *"Show open tenders in Ireland about cybersecurity from the last 30 days."*
If the agent hits a `402`, the affordance is self-explanatory: it can present the `payment_link` to the user, or — when authorised to spend — call `pay` and continue without interruption.
## Data notes
Award amounts are in their **local award currency** (for example SGD in Singapore, GBP in the United Kingdom). Plan prices are in USD; in euro-area countries, checkout charges in EUR. `description` is the tender description, truncated to 240 chars in list/JSON responses.
## Support
[[email protected]](mailto:[email protected]) · status & changelog below.
---
## What's new, 26 October 2026: sign in from Claude and ChatGPT, skills, n8n and Activepieces
**OAuth 2.1 for MCP clients.** Claude (custom connector) and ChatGPT (custom MCP server) connect to `https://app.selltostate.com/api/mcp` with OAuth: the user signs in and allows access, with no API key. Dynamic client registration accepts loopback redirect URIs and the hosted Claude and ChatGPT callbacks. `GET /.well-known/oauth-protected-resource/api/mcp` names the MCP resource. See *Connect flow* above.
**Agent skills.** `npx skills add getbeton/selltostate-skills` installs 5 skills (open tenders, buyer research, competitor wins, tender alerts, the API reference) for Claude Code, Codex, Cursor, Gemini CLI and other agents that read SKILL.md.
**Packages on npm.** n8n community node `n8n-nodes-selltostate`; Activepieces piece `@selltostate/piece-sell-to-state`; local MCP server `npx -y selltostate-mcp` (stdio, with `STS_API_KEY`).
## What's new, 21 October 2026: polling triggers and MCP annotations
**Polling triggers (`GET /api/v1/search`, MCP `search`).** A trigger in Zapier, n8n or your own job can now ask for the rows that are new since its last run:
| Param | Values |
|---|---|
| `sort` | adds `published_desc` (the newest publish date first) and `added_desc` (the newest rows in Sell to State first). Tenders scope only. |
| `added_after` | unix seconds. Only tenders added to Sell to State after this time. |
| `published_days`, `awarded_days`, `date_days` | add `1` (the last day). `/api/v1/awards` keeps 7, 30, 90 and 365. |
```bash
curl -s "https://app.selltostate.com/api/v1/search?scope=tenders&country=united-kingdom&q=software&sort=added_desc&added_after=1760000000" \
-H "x-api-key: sts_xxxxxxxx"
```
Keep the time of each run. Send it as `added_after` in the next run. Use the tender `slug` to remove duplicates.
**MCP.** `tools/list` gives each tool a `title` and `annotations` (`readOnlyHint`, `destructiveHint`, `openWorldHint`). Data tools are read-only. List and saved-search writes are not read-only. `delete_list`, `remove_from_list` and `delete_saved_search` are destructive. `initialize` returns server `instructions`. A `402` on `tools/call` now has a human `error.message` with the account link. For a signed-in user (API key or OAuth), `error.data` is `{error: payment_required, message, account_url}`. A machine client (`Bearer client:<id>`) still gets the full `402` body with `payment_link` and `machine_payment`.
## What's new, 15 October 2026: strict filters
**A bad filter is now a `400`.** Before, the API dropped a filter that it did not understand and returned the results without it. Now a bad value, an unknown param name, or an unknown country or sector returns `400`, and nothing runs. The body lists every problem (see **Filter errors (400)** above).
| Request | Result |
|---|---|
| `GET /api/v1/search?scope=tenders&lifecycle=live` | `400 invalid_filter`, param `lifecycle` |
| `GET /api/v1/search?scope=tenders&published_days=10` | `400 invalid_filter` (allowed: 7, 30, 90, 365) |
| `GET /api/v1/search?per_page=100` | `400 invalid_filter` (1 to 50) |
| `GET /api/v1/search?foo=1` | `400 unknown_param` |
| `GET /api/v1/search?country=atlantis` | `400 unknown_country` |
| `GET /api/v1/awards?page=0` | `400 invalid_filter` |
Other rules:
- Values of a fixed list match in any case: `lifecycle=Open` and `has_amount=TRUE` work.
- `sort=relevance` is the default order. `sort=deadline` puts the nearest bid deadline first.
- Years are whole numbers: `year_min=2024.5` is a `400`.
**`/api/v1/awards` and `/api/v1/awards.csv`:**
- New filters `supplier_slug` and `agency_slug` (exact match). `supplier` and `agency` still match part of the name.
- New day windows `published_days`, `awarded_days`, `date_days` (7, 30, 90 or 365).
- Paging is stable: a row never shows on two pages. `page` and `page_size` must be whole numbers from 1.
- The rows include open notices. An open notice has no supplier and no `awarded_at`.
**Entity endpoints:** `/api/v1/buyers`, `/buyers/{slug}`, `/suppliers`, `/suppliers/{slug}`, `/sectors/{slug}` and `/tenders/{id}` take `?country=<slug>`. Before, they always returned Singapore. Without `country`, the default is still `singapore`.
**MCP:** the `search` tool lists every filter in its schema, with the allowed values. `search_awards` takes the new `/awards` filters. A bad argument is the JSON-RPC error `-32602`; its `data` is the same body as the REST `400`.
**What to do:** if a call now returns `400`, read `errors`. Each entry names the param and the value that failed.
## What's new in 0.4.0 — REST · MCP · CLI parity
0.4.0 closes the gap between the three machine surfaces so **every capability is reachable the same way from REST, the MCP server, and the official CLI** (`@data-atlas/cli` → the `selltostate` binary). Same auth (`x-api-key` or `Bearer client:<id>`), same paywall, same entitlement caps.
### New REST endpoints (all under `/api/v1`, same machine paywall as `/awards`)
| Endpoint | Returns |
|---|---|
| `GET /api/v1/whoami` | Self-introspection: `{subject, type, active, plan, scopes, export_cap}`. **No 402** — a valid-but-unentitled key returns `200` with `active:false` so an agent can decide to pay *before* doing work. Missing credential → `401`. |
| `GET /api/v1/search` | Faceted full-text (Typesense) search over one `scope` (`tenders\|buyers\|suppliers\|sectors\|countries`): `{hits, found, page, per_page, facets}`. Search-budget rate limit (300/min). |
| `GET /api/v1/buyers` · `GET /api/v1/buyers/{slug}` | Top buyers by spend · buyer detail (summary, yearly trend, sector breakdown, top suppliers). |
| `GET /api/v1/suppliers` · `GET /api/v1/suppliers/{slug}` | Top suppliers by awarded total · supplier detail (summary, yearly trend, sectors, top buyers). |
| `GET /api/v1/sectors` · `GET /api/v1/sectors/{slug}` | Curated sector taxonomy · sector detail (summary, yearly trend, active partners via `?kind=buyers\|suppliers`). |
| `GET /api/v1/tenders/{id}` | Single award by numeric `award_id` **or** public tender page id, with related awards. |
| `GET/POST /api/v1/lists` · `GET/PATCH/DELETE /api/v1/lists/{id}` · `POST/DELETE /api/v1/lists/{id}/items` | Saved award **lists** CRUD. **Owner-scoped: requires an `x-api-key` (user) credential** — OIDC client tokens get `403` (a list belongs to a real user). |
| `GET/POST /api/v1/saved-searches` · `GET/PATCH/DELETE /api/v1/saved-searches/{id}` | Saved **searches** CRUD. Same owner-scoped rule as lists. |
Entity-detail and partner tables are capped to your plan's row cap on trial keys (`table_cap` echoes the applied cap).
### MCP tool catalog (24 tools — `x-mcp-tools` on this document is the machine-readable source of truth)
Every REST capability above has a matching MCP tool. `get_buyer` is canonical; `get_buyer_detail` is a kept back-compat alias. Lists/saved-searches tools require a user `x-api-key` (an OIDC client gets a `forbidden`/`requires_user_key` result, mirroring the REST `403`). `whoami` is ungated.
### Official CLI — `selltostate`
`npm i -g @data-atlas/cli` ships the `selltostate` binary — a thin wrapper over this exact REST surface, 1:1 per command, with `--format table|json|csv`. Authenticate once with `selltostate auth login` (stores an `x-api-key` at `~/.config/selltostate/config.json`, mode `0600`) or pass `STS_API_KEY`. See the `x-cli` extension on this document for the full command map, and the [CLI page](https://selltostate.com/cli/) on the marketing site.
```bash
selltostate auth login # verify + persist your x-api-key via /whoami
selltostate whoami # {subject, active, plan, scopes, export_cap}
selltostate search "cybersecurity" --scope tenders --year-min 2023
selltostate get buyer ministry-of-education
selltostate export --supplier ACME -o awards.csv
```
Data
Search and export awarded government tenders. Requires an active subscription (else 402).
GET /api/v1/awards
Search awards and open notices
Paginated, filterable query over the awards of one country (`country` omitted = singapore), largest awarded amount first; `award_id` breaks ties, so pages never overlap. Requires an active subscription — otherwise returns `402` with a payment link. Row count per page is capped by your plan (20 trial / 5,000 paid). The rows include open notices: an open notice has no supplier and no awarded_at.
Parameters
country in query — Country slug. Omitted means singapore.
q in query — Text in the tender description (substring). A text with boolean syntax (OR, AND, NOT, "a phrase", parentheses, -word) matches whole words of the tender title, buyer and supplier instead, as the search q. At most 40 terms.
agency in query — Buyer slug, or text in the buyer name (substring).
agency_slug in query — Buyer slug, exact match.
supplier in query — Text in the supplier name (substring).
supplier_slug in query — Supplier slug, exact match.
category in query — Sector slug, for example it-software.
year in query — Award year (publication year when the award date is missing).
amount_min in query — Minimum awarded amount.
amount_max in query — Maximum awarded amount.
published_days in query — Published in the last N days (UTC days).
awarded_days in query — Awarded in the last N days (UTC days).
date_days in query — Published or awarded in the last N days (UTC days).
page in query — Page number, from 1.
page_size in query — Rows per page, from 1. Default 100; the plan cap and 1,000 apply.
GET /api/v1/awards.csv
Export awards and open notices as CSV
Same params as `searchAwards`, returned as `text/csv` (attachment `selltostate-awards.csv`). Columns: `country,tender_no,supplier,agency,category,awarded_amt,published_at,awarded_at,description`. The file is the top rows up to the plan cap (20 trial / 5,000 paid). Requires an active subscription; un-entitled callers are redirected to `/checkout`. The rows include open notices: an open notice has no supplier and no awarded_at.
Parameters
country in query — Country slug. Omitted means singapore.
q in query — Text in the tender description (substring). A text with boolean syntax (OR, AND, NOT, "a phrase", parentheses, -word) matches whole words of the tender title, buyer and supplier instead, as the search q. At most 40 terms.
agency in query — Buyer slug, or text in the buyer name (substring).
agency_slug in query — Buyer slug, exact match.
supplier in query — Text in the supplier name (substring).
supplier_slug in query — Supplier slug, exact match.
category in query — Sector slug, for example it-software.
year in query — Award year (publication year when the award date is missing).
amount_min in query — Minimum awarded amount.
amount_max in query — Maximum awarded amount.
published_days in query — Published in the last N days (UTC days).
awarded_days in query — Awarded in the last N days (UTC days).
date_days in query — Published or awarded in the last N days (UTC days).
page in query — Page number, from 1.
page_size in query — Rows per page, from 1. Default 100; the plan cap and 1,000 apply.
GET /api/v1/whoami
Self-introspection — auth, entitlement & scopes
Resolve the *calling* credential's identity, entitlement and granted scopes. **Deliberately different from the data paywall:** a valid-but-unentitled credential returns `200` with `active:false` (so an agent/CLI can decide to pay *before* doing work); a missing/invalid credential returns `401` (not `402`). Granted scopes are all data scopes when active, else empty (v1 is all-or-nothing). Shares the standard 120/min per-caller rate limit.
GET /api/v1/search
Faceted full-text search (one collection)
Faceted Typesense search over a single `scope` collection. Returns hits, total `found`, pagination, and `facets` (counts per facet value). Uses the **search budget** rate limit (300/min) shared with the public `/api/search` route. Behind the same machine paywall as `/awards` — no human-session fallback.
Parameters
q in query — Free text, at most 2,000 characters. Boolean syntax: OR, AND, NOT (uppercase), "a phrase", parentheses, -word (= NOT word). Two words with no operator mean AND. At most 300 terms. A text whose syntax does not parse runs as its plain words. When the top level is an OR of parenthesized groups, rows that match the first group come first.
scope in query — The collection to search. Default tenders.
country in query — Country slug, or comma-separated slugs (OR).
sector in query — Sector slugs (OR), for example it-software.
type in query — Procurement type, for example works, goods or services. Only some countries have it.
status in query — Countries scope only: data (the country has data) or coming_soon.
year_min in query — Earliest year (award year, else publication year).
year_max in query — Latest year (award year, else publication year).
amount_min in query — Minimum amount.
amount_max in query — Maximum amount.
lifecycle in query — Tender lifecycle values (OR).
lifecycle_mode in query — is (default) keeps the lifecycle values; is_not leaves them out.
has_amount in query — true: only rows with an amount. false: only rows without one.
published_days in query — Published in the last N days (UTC days). 1 is the last day, for polling.
awarded_days in query — Awarded in the last N days (UTC days).
date_days in query — Published or awarded in the last N days (UTC days).
accepts_bids in query — true: only open tenders whose bid deadline is still ahead.
sort in query — relevance (default), deadline (the nearest bid deadline first), published_desc (the newest publish date first) or added_desc (the newest rows in Sell to State first). Tenders scope only.
added_after in query — Unix seconds. Only tenders added to Sell to State after this time. With sort=added_desc, a polling trigger keeps the time of its last run and asks for the rows after it.
match in query — Text match mode for the suppliers and buyers scopes.
page in query — Page number, from 1.
per_page in query — Results per page, 1 to 50. Default 25.
GET /api/v1/buyers
Top buyers by spend
Top buying agencies ranked by total awarded spend. `?limit` (default 50, max 500). Trial keys are row-capped (`table_cap`).
Parameters
limit in query — Rows to return (default 50, max 500).
country in query — Country slug. Omitted means singapore. A malformed or unknown slug is a 400.
GET /api/v1/buyers/{slug}
Buyer (agency) detail
Full buyer profile: header summary, yearly spend trend, sector breakdown, and a paginated top-suppliers table (`?sup_page`). `404` when the slug is unknown.
Parameters
slug in path (required) — Buyer slug, e.g. ministry-of-education.
sup_page in query — Top-suppliers page (1-based).
country in query — Country slug. Omitted means singapore. A malformed or unknown slug is a 400.
GET /api/v1/suppliers
Top suppliers by awarded total
Top suppliers ranked by total awarded value. `?limit` (default 50, max 500). Trial keys are row-capped.
Parameters
limit in query — Rows to return (default 50, max 500).
country in query — Country slug. Omitted means singapore. A malformed or unknown slug is a 400.
GET /api/v1/suppliers/{slug}
Supplier detail
Full supplier profile: header summary, yearly awarded trend, sector breakdown, and a paginated top-buyers table (`?buyer_page`). `404` when the slug is unknown.
Parameters
slug in path (required) — Supplier slug.
buyer_page in query — Top-buyers page (1-based).
country in query — Country slug. Omitted means singapore. A malformed or unknown slug is a 400.
GET /api/v1/sectors
Sector taxonomy
The curated sector taxonomy (slug + name). Small reference list — no row cap.
GET /api/v1/sectors/{slug}
Sector detail
Sector profile: header summary, yearly trend, and active partners. `?kind=buyers|suppliers` (default buyers) selects the partner table; `?page` paginates it. `404` when the slug is unknown.
Parameters
slug in path (required) — Sector slug.
kind in query — Partner table: buyers | suppliers (default buyers).
page in query — Partner table page (1-based).
country in query — Country slug. Omitted means singapore. A malformed or unknown slug is a 400.
GET /api/v1/tenders/{id}
Single award (tender) detail
One award resolved by **numeric `award_id` OR public tender page id**, plus related awards (same tender / same buyer). Related lists are pre-capped; no trial row cap applies. `404` when unknown.
Parameters
id in path (required) — Numeric award_id or public tender page id.
country in query — Country slug. Omitted means singapore. A malformed or unknown slug is a 400.