Build on GlobalGov
Connect AI assistants and back-end systems to 9.9M+ government procurement records — solicitations, tenders, RFPs and grants. National procurement sources in 60 countries and records from 193 in total, updated daily. Start with the live MCP server or the REST API.
X-API-Key. Live now.ggk_ keys, OpenAPI. Live now.Getting started
Who can access the API
The MCP server has a genuinely free tier — https://freemcp.globalgov.io/mcp, no key, no sign-in (see Connect an assistant). Full programmatic access (the AI brief, live feed, full-depth pagination, all regions, and the REST + Developer API) is a paid add-on:
- The API & MCP add-on is $400/mo, available only on the Global and Enterprise+ plans.
- It is not included in any plan. Even Global and Enterprise+ purchase it separately as an add-on; it is not bundled and it is not free.
- Scout, Essentials, Intelligence are not eligible. Upgrade to Global or Enterprise+ to add it.
All 5 MCP tools work with no key at all at teaser depth (platform stats, search, factual record lookups, related opportunities) — see Free tier vs. paid tier.
Get an API key
- Sign in and open Settings → API & MCP Access (
/settings/api). - Click Buy API Access to add the add-on. No plan includes it, so this step applies to every account.
- Click Generate API key. Your key (format
gg_…) is shown once — copy it immediately. It is stored hashed and can never be shown again; lose it and you regenerate.
Keys can be regenerated (rotated) or revoked at any time from the same page. Revoking a key breaks any assistant or integration still using it.
Base URLs & authentication
| Surface | Base URL | Auth |
|---|---|---|
| MCP server (free — start here) | https://freemcp.globalgov.io/mcp | None — no sign-in, 5 tools at teaser depth |
| MCP server (full access) | https://mcp.globalgov.io | OAuth ("Sign in with GlobalGov") or X-API-Key |
| MCP (keyless twin of full host) | https://mcp.globalgov.io/public | None — anonymous teaser |
| REST API | https://globalgov.io/api/v1 | X-API-Key header |
AI assistants authenticate over OAuth ("Sign in with GlobalGov"). For direct REST / BYO callers, authenticate every request with your key in the X-API-Key header:
X-API-Key: gg_your_key_here
All access is over HTTPS. Never embed a key in client-side/browser code or a public repository — treat it like a password.
MCP connector guide
The Model Context Protocol (MCP) is the open standard AI assistants use to connect to external tools and data. GlobalGov runs a remote MCP server so an assistant can search and read procurement intelligence on your behalf — no glue code required.
| Endpoint | https://mcp.globalgov.io |
|---|---|
| Transport | Streamable HTTP (stateless JSON), JSON-RPC 2.0 |
| Protocol | 2025-06-18 (also negotiates 2025-03-26, 2024-11-05) |
| Methods | initialize, ping, tools/list, tools/call |
| Auth | OAuth 2.1 ("Sign in with GlobalGov") or an X-API-Key header. See Connect an assistant. |
Start free. https://freemcp.globalgov.io/mcp needs no sign-in and no key — add it to any MCP client and all 5 tools appear at teaser depth. For the AI brief on each record, the live opportunity feed, full-depth pagination, and all your subscribed regions, use https://mcp.globalgov.io and sign in with GlobalGov (or send an X-API-Key header). https://mcp.globalgov.io/public is the same free teaser on the paid host. All are POST-only; GET/DELETE return 405, and JSON-RPC batching is not supported.
Connect an assistant
Start with the free URL https://freemcp.globalgov.io/mcp — no account, no key, no sign-in. It works on every client below that supports remote MCP. To unlock full depth (AI briefs, live feed, full pagination, all regions), swap in https://mcp.globalgov.io and either "Sign in with GlobalGov" (OAuth, zero-config via Dynamic Client Registration) or send an X-API-Key header. Verified against each vendor's current docs (2026).
Free, no sign-in
- Customize → Connectors → Add custom connector
- Remote MCP server URL:
https://freemcp.globalgov.io/mcp - Free plan allows one custom connector. Claude Code:
claude mcp add --transport http globalgov https://freemcp.globalgov.io/mcp - For full depth, use
https://mcp.globalgov.ioand "Sign in with GlobalGov" (leave OAuth Client ID / Secret blank — auto-registration)
- Add a remote Streamable HTTP MCP server
- URL:
https://freemcp.globalgov.io/mcp(Windsurf/Cline: typestreamable-http) - Full depth: add a
headersentryX-API-Key: gg_your_keyand point athttps://mcp.globalgov.io
- Command Palette → MCP: Open User Configuration
- Add
"globalgov": { "type": "http", "url": "https://freemcp.globalgov.io/mcp" } - OAuth for the full-access URL is handled automatically (browser opens on first connect)
gemini mcp add --transport http globalgov https://freemcp.globalgov.io/mcp- Or add
"globalgov": {"httpUrl": "https://freemcp.globalgov.io/mcp"}undermcpServers
- Connectors → add MCP connector
- URL:
https://freemcp.globalgov.io/mcp(HTTPS, no auth)
Paid-plan assistants
- Turn on Developer mode in Settings
- Connectors/Apps → create → paste URL
https://freemcp.globalgov.io/mcp - Free ChatGPT cannot add custom remote connectors
grok.com/connectors→ New Connector → Custom- URL:
https://freemcp.globalgov.io/mcp
- Connectors → add custom connector
- Transport Streamable HTTP, auth None, URL
https://freemcp.globalgov.io/mcp - Full depth: choose auth API Key and paste your
X-API-Key
Every path hits the same tools. The free URL is the zero-config default; X-API-Key and OAuth on https://mcp.globalgov.io unlock full depth for scripts and assistants respectively.
Prefer the command line? With MCP tooling you can smoke-test the server directly:
npx @modelcontextprotocol/inspector # URL: https://mcp.globalgov.io (runs the OAuth "Sign in with GlobalGov" flow) # or the keyless public twin: https://mcp.globalgov.io/public # or add an X-API-Key header to https://mcp.globalgov.io for BYO-key access
Free tier vs. paid tier
Access is resolved from your X-API-Key:
| Tool | No key (free) | Key with API access |
|---|---|---|
get_platform_stats | ✓ | ✓ |
search_solicitations | Teaser: page 1, up to 5 results | Full results, 20/page, pagination |
get_solicitation | — | ✓ |
get_related_solicitations | — | ✓ |
get_live_opportunity_feed | — | ✓ |
Access is resolved live on every call from your identity (OAuth sign-in or X-API-Key): a plan with API access gets all 5 tools, a free/trial account gets the 2 teaser tools. Calling a paid tool without a qualifying plan returns a tool error error="unavailable_for_tier" (not a crash). Anonymous callers on the public twin get the teaser too. Entitlement is never frozen in the token — downgrading a plan drops it back to the teaser immediately.
Free search shares the public site's per-visitor budget (a handful of searches per 24h); a paid key lifts that and is governed by the per-key hourly limit instead. See Rate limits.
The five tools
| Tool | Access | Parameters |
|---|---|---|
search_solicitations | Free tier | query* (2–200), country (ISO-2), category (enum), page |
get_platform_stats | Free tier | none |
get_solicitation | API key | slug_or_id* (slug or UUID) |
get_related_solicitations | API key | slug* |
get_live_opportunity_feed | API key | none |
* required. Category enum: DEFENSE_SECURITY, INFRASTRUCTURE, HEALTH_SERVICES, ENERGY, TECHNOLOGY, PROFESSIONAL_SERVICES, CONSTRUCTION, LOGISTICS, HUMANITARIAN, ENVIRONMENTAL, RESEARCH_DEVELOPMENT, EDUCATION, OTHER.
search_solicitations
Full-text search over the corpus. Free callers get a teaser (teaser=true, up to 5 results, page 1) with the true match total; keyed callers get 20/page with pagination. If total_degraded=true, the exact count timed out and total is a floor.
POST https://mcp.globalgov.io
Content-Type: application/json
X-API-Key: gg_your_key_here
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "search_solicitations",
"arguments": { "query": "cybersecurity training", "country": "US", "page": 1 }
}
}The result carries JSON in both the text content block and structuredContent:
{
"results": [
{
"id": "6a3b7032-4989-4691-8465-9829d3306151",
"title": "Cybersecurity Awareness Training Services",
"agency_name": "Department of Homeland Security",
"country_code": "US",
"value_usd": 1250000.0,
"currency": "USD",
"deadline": "2026-08-15T17:00:00+00:00",
"category": "DEFENSE_SECURITY",
"slug": "dhs-cybersecurity-awareness-training-...",
"description": "...",
"rank": 0.8213
}
],
"total": 3184,
"page": 1,
"has_more": true,
"total_degraded": false
}get_platform_stats
Canonical coverage numbers, pre-computed and served from cache. No arguments. Every field:
| Field | Type | What it is |
|---|---|---|
solicitations_total | int | Full searchable corpus. Records, not open opportunities. |
countries_with_national_source | int | Countries whose own procurement system is indexed. The figure to cite. |
countries_with_any_record | int | Countries holding any record, including those reached only through multilateral feeds. Breadth, not coverage. |
countries_measured_at | date | When both country counts were derived. |
countries_definition | string | States which codes are counted and which are excluded by rule. |
source_systems_with_data | int | Distinct source systems carrying records. |
languages_supported | int | Distinct languages held and normalized to English on read. |
languages_measured_at | date | When that count was measured. |
languages_definition | string | States what the count folds and what it excludes. |
vendors_indexed | int | Canonical (deduplicated) vendor records. |
forecasts_tracked | int | Tracked forecast / pre-solicitation records. |
agencies_total | int | Recounted live on every refresh. The example prints the last governed figure, so a live call reads higher. |
solicitations_open_confirmed_deadline | int | Recounted. Tenders carrying a confirmed future closing date. This is the figure to cite. |
solicitations_open_including_inferred | int | Recounted. The above plus tenders with no published deadline seen in the last 90 days. |
countries_with_open | int | Recounted. Countries with anything open. |
open_pipeline_measured_at | date | When the open pipeline was last computed. |
open_pipeline_definitions | object | One prose definition per open figure, stating what share of the wider number is inferred rather than confirmed. |
stats_verified_at | timestamp | When the figures were MEASURED. |
data_freshness | object | When source data last arrived, read from ingestion runs. Compute staleness against this, never against generated_at. |
generated_at | timestamp | When this response was assembled. Moves on every cache refresh and says nothing about the age of the data. |
retired_stats | object | Fields withdrawn for being inaccurate, listed by name with the reason, so a consumer gets an explanation instead of a KeyError. |
{ "jsonrpc": "2.0", "id": 2, "method": "tools/call",
"params": { "name": "get_platform_stats", "arguments": {} } }An abridged response. The key set is complete and in order; the two long prose objects are shortened here and given in full by the live call:
{
"solicitations_total": 10364022,
"countries_with_national_source": 60,
"countries_with_any_record": 193,
"countries_measured_at": "2026-08-26",
"countries_definition": "Countries with a national procurement source, and countries holding any record. The second includes countries reached only through multilateral feeds. …",
"source_systems_with_data": 70,
"languages_supported": 40,
"languages_measured_at": "2026-08-21",
"languages_definition": "Distinct languages present in the corpus and normalized to English on read. …",
"vendors_indexed": 2958399,
"forecasts_tracked": 1849,
"agencies_total": 184564,
"solicitations_open_confirmed_deadline": …,
"solicitations_open_including_inferred": …,
"countries_with_open": …,
"open_pipeline_measured_at": "2026-08-15",
"open_pipeline_definitions": { "…": "…" },
"stats_verified_at": "2026-08-14T00:00:00+00:00",
"data_freshness": { "available": true, "…": "…" },
"generated_at": "2026-08-23T02:06:56+00:00",
"retired_stats": {
"fields": ["solicitations_active",
"solicitations_open_for_bidding",
"open_with_confirmed_deadline",
"countries_live_coverage",
"source_systems_active",
"market_coverage_usd"],
"retired_on": "2026-08-14",
"reason": "Withdrawn for being inaccurate, not stale. …"
}
}The four … counts are recounted on every refresh, so they are described in the table rather than frozen into an example that would be wrong by the time you read it. The other figures are the governed values measured on the dates the response itself carries. Nothing in this response is a number we cannot show you the derivation of, which is the point of stats_verified_at, data_freshness and retired_stats all being separate fields.
get_solicitation API key
Full record by slug (preferred) or UUID — original + English title, agency, country, value/currency, deadline, status, category, NAICS/CPV, source_url, full description, and (when available) an AI-generated brief. Returns error="not_found" for unknown ids.
{ "jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": { "name": "get_solicitation",
"arguments": { "slug_or_id": "dhs-cybersecurity-awareness-training-..." } } }get_related_solicitations API key
Up to 5 open solicitations related to a record (matched by country + NAICS, nearest deadline first). Argument: slug.
get_live_opportunity_feed API key
A random sample of 12 records from the curated live feed of open opportunities. No arguments. Served from a background-refreshed cache; if cold, returns a retryable warming_up error rather than an empty list.
Honest degraded states
GlobalGov never fakes an empty result. When a cache is cold or the database is under load, a tool returns an isError result whose JSON payload has a machine error code and a retryable flag:
error | Meaning | Retryable |
|---|---|---|
unavailable_for_tier | Tool needs a key on a plan with API access | No |
warming_up | Backing cache cold / warm scheduled | Yes |
computing | Stats being recalculated | Yes |
rate_limit_exceeded | Access-level limit hit (carries reset_at) | Yes |
not_found | Unknown slug/id | No |
REST API reference
The REST API serves the same corpus over plain HTTPS for back-end integrations. Two surfaces are live today:
- Public read endpoints — no key required, rate-limited per visitor. These power the MCP search tools.
- Key-authenticated endpoints — an
X-API-Keyon a plan with API access lifts the anonymous limits and unlocks the list endpoints below.
Base URL: https://globalgov.io/api/v1. All responses are JSON.
Building a new integration? Prefer the Developer API (REST v1) at https://globalgov.io/api/public/v1 — it's the versioned, contract-stable surface with explicit schemas, opaque IDs, cursor pagination, and scoped ggk_ keys, and it's live now. The endpoints below remain available for existing callers.
Authentication
Send your key in the X-API-Key header. Public /public/* read endpoints work without one.
curl "https://globalgov.io/api/v1/solicitations?limit=25" \ -H "X-API-Key: gg_your_key_here"
Rate limits
| Caller | Limit | On exceed |
|---|---|---|
Anonymous /public/search | ~7 searches / 24h per visitor | 429 with reset_at |
API key on /api/v1/* | 1,000 requests / hour | 429 with Retry-After header |
Error format
Errors use the standard FastAPI shape with an HTTP status and a detail field:
// 429 — anonymous search budget exhausted
{ "detail": { "error": "rate_limit_exceeded",
"searches_remaining": 0,
"reset_at": "2026-07-21T00:19:59+00:00" } }
// 401 invalid key · 403 no API access · 404 not found
{ "detail": "Invalid API key" }The Developer API (REST v1) uses the richer RFC 9457 problem+json error format with stable machine codes and a request_id — it is live now.
Public endpoints Free tier
No authentication. Rate-limited per visitor.
/public/statsPlatform coverage numbers (same payload as the get_platform_stats MCP tool).
curl "https://globalgov.io/api/v1/public/stats"
/public/searchFull-text search. Query params: q* (2–200), country (ISO-2), category (enum), page (≥1), limit (1–20, default 20). Returns { results[], total, page, has_more, total_degraded }; each result has id, title, agency_name, country_code, value_usd, currency, deadline, category, slug, description, rank.
curl "https://globalgov.io/api/v1/public/search?q=cybersecurity&country=US&limit=5"
/public/solicitations/{slug}One full record by slug or UUID — includes original + English title, agency, country, value, deadline, status, NAICS/CPV, source_url, description, and an ai_brief when available. 404 if unknown.
curl "https://globalgov.io/api/v1/public/solicitations/ted-pl-poland-medical-consumables-...-291518-2025"
/public/solicitations/{slug}/relatedUp to 5 related open solicitations (by country + NAICS). Returns { related: [{ slug, title, country_name, agency_name, deadline, status }] }.
curl "https://globalgov.io/api/v1/public/solicitations/{slug}/related"Key-authenticated endpoints API key
Require an X-API-Key on a plan with API access. List endpoints accept limit (≤100, default 25) and offset, and return { data: [...], total, has_more }.
| Method | Path | Returns |
|---|---|---|
| GET | /solicitations | Active solicitations (paged) |
| GET | /solicitations/{id} | One solicitation by UUID |
| GET | /awards | Contract awards (paged) |
| GET | /vendors | Vendors (paged) |
| GET | /agencies | Agencies (paged) |
| GET | /pipeline | Your organization's pipeline (paged) |
curl "https://globalgov.io/api/v1/solicitations?limit=25&offset=0" \ -H "X-API-Key: gg_your_key_here"
These endpoints return the full record objects. For a field-explicit, versioned contract with opaque IDs and cursor pagination, use the Developer API (REST v1) — live now — or the public / MCP surfaces.
Developer API (REST v1)
A versioned, read-only REST API over the full corpus — live now. Explicit response schemas (never raw records), opaque non-sequential IDs, cursor pagination, and RFC 9457 errors.
| Base URL | https://globalgov.io/api/public/v1 |
|---|---|
| Auth | Authorization: Bearer ggk_live_… (scoped API key) |
| OpenAPI | openapi.json · interactive Swagger UI |
| Access | Requires the API & MCP add-on ($400/mo, Global or Enterprise+ plans) |
Get a key
In Settings → API & MCP Access generate a key (shown once, format ggk_live_…) — or a rate-limited sandbox key (environment: "test"). Keys carry least-privilege scopes: solicitations:read, awards:read, vendors:read, agencies:read. Keys are stored hashed, verified by an indexed O(1) lookup, and independently revocable.
curl "https://globalgov.io/api/public/v1/solicitations?limit=25&country=US" \ -H "Authorization: Bearer ggk_live_your_key"
Endpoints
Every resource has a cursor-paginated list and a by-id lookup. IDs are opaque and non-sequential.
| Method | Path | Scope |
|---|---|---|
| GET | /solicitations · /solicitations/{id} | solicitations:read |
| GET | /awards · /awards/{id} | awards:read |
| GET | /vendors · /vendors/{id} | vendors:read |
| GET | /agencies · /agencies/{id} | agencies:read |
| GET | /ping | any |
List params: limit (1–100, default 25), cursor (opaque), plus per-resource filters (e.g. country, naics, posted_after, active). Response envelope: { "data": […], "next_cursor": "…", "has_more": true }. Corpus results are scoped to your subscribed regions; no personal contact data is ever returned.
Errors & rate limits
Errors are application/problem+json (RFC 9457) with a stable machine code and a request_id: unauthorized, invalid_key, insufficient_scope, insufficient_tier, not_found, validation_error, rate_limited. Every response carries RateLimit-Limit/Remaining/Reset; live keys default to 1,000 req/hr, sandbox keys 60 req/hr.
On the roadmap
Live today: the four read resources above, scoped keys, sandbox keys, cursor pagination, and the OpenAPI spec. Still coming: Python/TypeScript SDKs, write access to your own pipeline/watchlist, a dedicated api.globalgov.io host, and a published 6-month deprecation policy. Tell us what you need next.
Support
Questions, a key that isn't working, or a feature request? Contact us or manage your key anytime in Settings → API & MCP Access.