# Limits and response headers

All REST actions and MCP protocol requests handled by the gateway expose live quota snapshots. REST keys and MCP clients share your user budgets. Key rotation, changing IPs, and switching clients do not reset them.

## Response fields

`RateLimit-Policy` lists timed policies: `"requests";q=120;w=60;qu="requests"` means 120 requests per minute. `RateLimit` lists remaining units and reset delay: `"requests";r=119;t=37`. These follow the May 2026 IETF draft format, not a finalized RFC.

`GTMFree-Limits` is a JSON array covering both timed and concurrency limits. Each item has:

- `name`, `scope`, `unit`: the budget, who shares it, and what it measures.
- `limit`, `remaining`: total allowance and remaining units after admission of this request.
- `window_seconds`: fixed window length; null for concurrency.
- `reset_at`: Unix UTC timestamp of the next window or full token-bucket refill; null when there is no scheduled reset.
- `reset_after`: seconds until that reset; null for concurrency.
- `cost`: allowance required for this action. A rejected action might not have charged this amount. Download cost is null until the requested file size is known.

Read headers on successes and errors, not just 429 responses. A positive remaining allowance is a snapshot, not a reservation or availability guarantee. Concurrent clients may consume it before your next request. `GTMFree-Limits-Status: unavailable` means quota storage could not be read: only known ingress counters are returned. Missing user counters do not mean unlimited access.

For MCP, the same array is also in `result._meta["gtmfree/limits"]`, including tool errors. JSON-RPC protocol errors use `error.data["gtmfree/limits"]`. HTTP authorization/admission errors expose headers. Tool errors with a retry delay also include HTTP `Retry-After` and `structuredContent.error.retry_after`. A tool error may have HTTP 200; inspect `isError`.

## Current action budgets

| Budget | Allowance | Applies to | Reset |
| --- | --- | --- | --- |
| Authenticated requests | 120/minute/user | Every authenticated REST request and MCP protocol message, including submissions and connection openings | Next Unix-aligned minute |
| Submission attempts | 10/minute/user | REST submissions and MCP createGoogleMapsJob attempts, including invalid input | Next Unix-aligned minute |
| New jobs | 20/day/user | Successful admission of new work | Midnight UTC |
| Planned points | 100,000/day/user | New work reserves 50,000 points per job | Midnight UTC |
| Worker time | 7,200 seconds/day/user | New work reserves 3,600 seconds per job | Midnight UTC |
| Download bytes | 4 GiB/hour/user | Full REST export size, requested HTTP byte range or admitted MCP chunk bytes, charged before delivery even if you disconnect | Next Unix-aligned hour |
| Active jobs | 1/user/tool; 8 globally | New job admission | When work finishes; no scheduled reset |
| Event connections | 2/job, 6/user, 32 globally | REST SSE connection openings | On close/expiry; no scheduled reset |
| Downloads | 2/user, 4 globally | Concurrent exports | On close/expiry; no scheduled reset |
| MCP requests in flight | 6/user, 32 globally | Concurrent MCP requests | On completion/expiry; no scheduled reset |
| IP ingress | 10 requests/second, burst 40 | All gateway HTTP requests from the same IP | Continuous refill; header reset is full refill |
| Global ingress | 100 requests/second, burst 200; 64 in flight | All gateway HTTP requests | Refill or completion |

Every authenticated action reports your timed budgets and current job slots. `/api/v1/me` also reports the other connection limits. SSE, download, and MCP actions add their corresponding connection snapshots. Public catalogues and unauthorized requests report ingress limits only; they reveal no user counters.

MCP `getJobResults` uses cursor pagination with a smaller byte budget to keep text, structured output and metadata below the response cap. `getJobExport` returns at most 128 KiB of raw file bytes per base64 chunk (default 64 KiB), sharing download leases and byte counters with REST. Each chunk costs one authenticated request and its admitted raw byte count; repeated chunks are charged again. Both MCP and download connection limits appear in its quota metadata.

Execution reservations can make another budget bind before the daily job count. Unused points/time are refunded after known terminal observations; complete cache hits charge zero points. Unknown execution cost retains the reservation. Definite rejection before acceptance refunds execution reservations. Request and submission-attempt charges remain.

## Polling, events, and recovery

Each accepted submission creates a new job. After a lost response, list your jobs before submitting again. Use job status or an event stream to follow accepted work. A disconnect never cancels a job. An uncertain submission retains its active slot until reconciled.

Honor `Retry-After`: normally two seconds after acceptance or while polling a nonterminal job; on 429 it identifies when the rejected budget can be retried. 503 indicates unavailable service/capacity, not permission to repeat a submission blindly. Concurrency rejection can suggest a retry delay, but that does not promise a slot will be available then.

SSE charges one request per connection, not per event or heartbeat. Its response headers describe the opening snapshot. Streams close after 15 minutes and heartbeat every 15 seconds; reconnect or poll afterward. Downloads last at most 15 minutes and recheck authorization/network policy every 30 seconds. MCP requests have a 30-second deadline. Schema/body/output limits also apply; see the OpenAPI contract.

## Large results

Jobs retain up to 100,000 businesses. Follow every `next_cursor` to retrieve the full set; pages contain at most 100 records and may be shorter to respect their byte budget. A full REST download streams the complete requested JSON/CSV/XLSX file. Resume with `Range: bytes=START-` or `bytes=START-END` (206); unsupported suffix/multipart or out-of-file ranges return 416. MCP uses bounded `getJobExport` chunks and `next_offset`, independent of REST.

Results and exports use disk-backed records, bounded worker transfers and 128 KiB database chunks. REST sends at most 64 KiB at a time. The per-job logical data/export budget is 1 GiB, each business record is capped at 8 KiB, and total retained logical output is capped at 16 GiB with a free-disk reserve. The entity cap produces an explicit failed/partial result, never a silent complete result. Storage or export failures can also retain partial output; inspect `partial` and the available `files`. Boundary layer download/cache limits are separate from business exports.

## Edge protections

Cloudflare Free and NGINX may reject requests before they reach the gateway. Those responses can be non-JSON and cannot report the gateway's user counters. NGINX throttling/capacity errors include `Retry-After` and `GTMFree-Limits-Status: edge`; Cloudflare-generated errors may omit application headers entirely. NGINX also caps connections at 20/IP and 96 globally and ordinary responses/downloads at 2 MiB/second/response. SSE is unbuffered for immediate events and uses its connection, lifetime and message-size limits instead. No edge counter is fabricated as a user allowance.

## Region discovery

REST `/api/v1/regions` and MCP `discoverRegions` require authentication and share 30 lookups per minute per user, plus the ordinary 120 requests/minute allowance. Explicit `load=true` operations have a budget of six starts per UTC day per user; joining an in-flight lookup or its short-lived completed result does not charge another load start. These allowances appear as `region-lookups` and `region-loads` in the same quota headers/MCP metadata as other actions. Catalog leases appear as `region-user`/`region-global`.

Only one catalog operation runs globally; region work has a separate bounded RPC connection so it does not consume the scrape submission/observation connection pool. HTTP/MCP waits at most five seconds, then returns `503 region_loading`, `Retry-After: 5`. Indexing continues without creating a scrape job; retry the same lookup after the delay. The background RPC is capped at 30 minutes and the worker's per-layer limits still apply. Global catalog saturation also returns `region_loading`. Oversized responses return `response_too_large`; narrow the country/level filters or reduce `limit`.

Boundary source: geoBoundaries gbOpen only. Per-layer download ceiling 512 MiB, total private cache 4 GiB, 180-second per-operation worker budget, and at most 600,000 indexed features. Available levels vary by country. Data exceeding these limits fails explicitly; the service does not substitute restricted collections or silently claim a complete search.
