# HTTP: endpoints, auth parameters and headers

The endpoints of the server, and the request parameters and headers outside the map description: authentication, URL signatures, caching and limits. Entries marked *keys* apply only when the server runs with API keys (`WHEREBOX_AUTH=keys`, the hosted service).

## Endpoints

Every `GET` endpoint also answers `HEAD`. Parameters and responses of the map and lookup endpoints are in [openapi.json](/docs/openapi.json). The hosted service also serves the account console (sign-in, API keys, usage), which is a website, not an API.

| Endpoint | What it does | SDK method (TypeScript / Python) |
|---|---|---|
| GET `/v1/map` | Render a map from query parameters | Same as `/v1/map.{ext}`; the SDKs' `url` always writes the format as the extension. |
| GET `/v1/map.{ext}` | Render a map; the extension picks the format | `url` / `url` (builds the URL) |
| POST `/v1/map` | Render a map from a JSON MapSpec | `render` / `render`<br>`renderJson` / `render_json` (`response=json`) |
| GET `/v1/images/{key}` | Fetch a cached image by content hash | The `url` that `renderJson` returns: a public, immutable link for `<img>` or any HTTP client. |
| GET `/v1/areas/search` | Search areas by name (with hierarchy context for disambiguation) | `searchAreas` / `search_areas` |
| GET `/v1/areas/{id}` | Get one area | `getArea` / `get_area` |
| GET `/v1/places/search` | Search named places (cities, peaks, mountain ranges…) | `searchPlaces` / `search_places` |
| GET, POST, DELETE `/mcp` | MCP server (Streamable HTTP) for AI agents: render maps, search areas and places | Spoken by MCP clients (Claude, `@wherebox/mcp`), not by the REST SDKs. |
| GET `/openapi.json` | OpenAPI 3.1 document of this API | For tools and code generators. |
| GET `/playground` | Interactive playground (a redirect to the website's playground when a site URL is configured) | Browser page. |
| GET `/` | Redirects to `/playground` | Browser entry point. |
| GET `/healthz` | Liveness check | For load balancers and orchestrators. |
| GET `/readyz` | Readiness: database reachable, data and render versions, render queue | For load balancers and orchestrators. |
| GET `/metrics` | Prometheus metrics (disabled unless a metrics token is configured) | For the operator's monitoring. |
| GET `/.well-known/oauth-authorization-server` | OAuth authorization server metadata (RFC 8414) | For OAuth clients (connected apps, MCP); the SDKs authenticate with keys. |
| GET `/.well-known/oauth-protected-resource/mcp` | Protected resource metadata of `/mcp` (RFC 9728) | For OAuth clients (connected apps, MCP); the SDKs authenticate with keys. |
| GET `/.well-known/oauth-protected-resource/v1` | Protected resource metadata of `/v1` (RFC 9728) | For OAuth clients (connected apps, MCP); the SDKs authenticate with keys. |
| POST, OPTIONS `/oauth/register` | Dynamic client registration (RFC 7591) | For OAuth clients (connected apps, MCP); the SDKs authenticate with keys. |
| GET, POST `/oauth/authorize` | Consent page; the POST records the user's decision | For OAuth clients (connected apps, MCP); the SDKs authenticate with keys. |
| POST, OPTIONS `/oauth/token` | Token endpoint (authorization code with PKCE, refresh token) | For OAuth clients (connected apps, MCP); the SDKs authenticate with keys. |
| POST, OPTIONS `/oauth/revoke` | Token revocation (RFC 7009) | For OAuth clients (connected apps, MCP); the SDKs authenticate with keys. |

## Query parameters

Accepted on every `/v1/map` request in addition to the [map parameters](/docs/reference/parameters.md).

| Parameter | Description | Example |
|---|---|---|
| <a id="param-apikey"></a>`apikey` | Publishable key (`pk_…`) for `<img>` embeds. Only valid together with `sig`. Secret keys (`sk_…`) are rejected in URLs. | `apikey=pk_8fK2aQ1mZr9TbL0x4WcYvN3sHd7uJe6p` |
| <a id="param-sig"></a>`sig` | URL signature: HMAC-SHA256 of the canonical request with the key's signing secret (see the signing guide). Proves the URL was created by the key owner, so a leaked `pk_` cannot be reused for other maps. | `sig=Jx3w0b2kQnVt9yRmZsLc4u8hAe1pDfGo` |
| <a id="param-exp"></a>`exp` | Optional expiry of a signed URL (Unix seconds). Covered by the signature. | `exp=1798761600` |

## Request headers

| Header | Description | Example |
|---|---|---|
| <a id="header-authorization"></a>`Authorization` *keys* | Secret key for server-to-server calls (`Bearer sk_…`), or an OAuth access token from a connected app (`Bearer wba_…`). | `Bearer sk_…` |
| <a id="header-x-provider-key"></a>`X-Provider-Key` | Key for a commercial basemap style (`style=`); kept out of URLs and logs. | `your-maptiler-key` |
| <a id="header-x-routing-key"></a>`X-Routing-Key` | Key for openrouteservice / GraphHopper routing; kept out of URLs and logs. | `your-ors-key` |
| <a id="header-x-request-id"></a>`X-Request-Id` | Optional id for this request (letters, digits, `._:-`, ≤ 64 chars), e.g. from your proxy; otherwise the server generates one. | `3f2c9a1e-…` |
| <a id="header-if-none-match"></a>`If-None-Match` | Send a previous `ETag` to get `304 Not Modified` when the image is unchanged. | `"e1b4…png"` |

## Response headers

| Header | Description | Example |
|---|---|---|
| <a id="header-etag"></a>`ETag` | Content hash of the image (also its cache key). SDKs: `etag` / `etag` of the `render` result. | `"e1b4d02…7b6.png"` |
| <a id="header-cache-control"></a>`Cache-Control` | Rendered maps may be cached for a day; `/v1/images/{key}` is immutable. | `public, max-age=86400` |
| <a id="header-x-cache"></a>`X-Cache` | `HIT` when served from the image cache, `MISS` when rendered for this request. SDKs: `cached` / `cached` of the `render` result. | `HIT` |
| <a id="header-x-render-ms"></a>`X-Render-Ms` | Render time in milliseconds (on a `MISS`). | `212` |
| <a id="header-x-image-width"></a>`X-Image-Width` | Final pixel width. Can exceed `w × scale` when `neighborfit=extend` grew the image. SDKs: `width` / `width` of the `render` result. | `556` |
| <a id="header-x-image-height"></a>`X-Image-Height` | Final pixel height. SDKs: `height` / `height` of the `render` result. | `296` |
| <a id="header-retry-after"></a>`Retry-After` | Seconds to wait after a `503 busy` or `429` response. | `2` |
| <a id="header-x-ratelimit-limit"></a>`X-RateLimit-Limit` *keys* | Requests per minute allowed for this key's plan (without a key: the anonymous demo allowance, per client network). | `120` |
| <a id="header-x-ratelimit-remaining"></a>`X-RateLimit-Remaining` *keys* | Requests left in the current window. | `117` |
| <a id="header-x-ratelimit-reset"></a>`X-RateLimit-Reset` *keys* | Unix seconds when the window is full again. | `1798761660` |
| <a id="header-www-authenticate"></a>`WWW-Authenticate` *keys* | On `401` when OAuth is enabled: where OAuth clients find the authorization server (RFC 9728), with `error="invalid_token"` when a presented access token was rejected (expired, revoked, or issued for another resource). | `Bearer resource_metadata="https://app.wherebox.dev/.well-known/oauth-protected-resource/v1"` |
| <a id="header-x-quota-remaining"></a>`X-Quota-Remaining` *keys* | Renders left this calendar month (UTC). Cache hits do not count. Without a key (anonymous demo allowance): renders left today (UTC) for your network, or for all anonymous visitors together when that is lower. | `24120` |
| <a id="header-x-request-id-response"></a>`X-Request-Id` | Id of this request; also in every error body as `requestId` and in the server logs. Quote it in support requests. | `3f2c9a1e-7b1d-4c0e-9a55-0d2f6e8b1c44` |
| <a id="header-x-attribution"></a>`X-Attribution` | The data credits for this image, as drawn in its corner (items joined with " · "). Always sent, also with `attribution=none`, when you must show this text next to the image yourself. HTTP headers are ASCII, so `%` and every character outside printable ASCII are percent-encoded as UTF-8 (`©` is `%C2%A9`): decode with `decodeURIComponent` (JavaScript) or `urllib.parse.unquote` (Python). SDKs: `attribution` / `attribution` of the `render` result. | `OpenFreeMap %C2%B7 %C2%A9 OpenStreetMap` |
| <a id="header-access-control-allow-origin"></a>`Access-Control-Allow-Origin` | CORS: images and JSON can be fetched from any origin. | `*` |
| <a id="header-access-control-expose-headers"></a>`Access-Control-Expose-Headers` | CORS: lets browser code read these headers on a cross-origin `fetch` (`X-Attribution` in particular). | `X-Attribution, X-Cache, X-Image-Width, X-Image-Height, X-Request-Id` |
