# Keys and limits

> API keys and allowed origins for tiles, the monthly tile allowance per plan, the per-visitor tile rate limit, and the error codes of the tile API.

Tiles use the same keys, plans and errors as the geocoding API. Tile requests count against their own monthly allowance (India tile set today; planet tiles in development), separate from geocoding.

## Keys

| Kind        | Prefix   | Use for tiles                                                     |
| ----------- | -------- | ----------------------------------------------------------------- |
| Publishable | `gc_pk_` | Web maps. Answers only the origins listed on the key              |
| Secret      | `gc_sk_` | Servers and scripts, for example a tile cache or a print renderer |

A browser sends the `Origin` (or `Referer`) header on tile requests, so a publishable key in a TileJSON or tile URL works with no extra code. A publishable key with no allowed origins answers nothing. Details: [API keys](/search/hosted/keys).

## Monthly allowances

| Plan    | Price      | Map tiles a month | Geocoding requests a month |
| ------- | ---------- | ----------------- | -------------------------- |
| Free    | $0         | 200,000           | 50,000                     |
| Starter | $19/month  | 2,000,000         | 500,000                    |
| Growth  | $99/month  | 10,000,000        | 2,500,000                  |
| Scale   | $299/month | 30,000,000        | 7,500,000                  |

Each tile response counts once. TileJSON requests are not counted. Over the allowance, tile requests stop with `429 quota_exceeded` and `error.product` `tiles` until the month (UTC) ends or you upgrade; there are no overage charges. Every tile answer carries `X-Quota-Product: tiles`, `X-Quota-Limit` and `X-Quota-Remaining`.

The allowance is per account: all projects and keys of the account share it. Free accounts together also share a daily ceiling; when it is used up, free tile requests stop for the rest of the UTC day with `quota_exceeded` and `error.reason` `free_daily_ceiling`.

## Rate limits

| Requests                                            | Limit                                                                       |
| --------------------------------------------------- | --------------------------------------------------------------------------- |
| Tiles and TileJSON with a publishable key           | 20 a second per visitor (the key and the visitor's IP address)              |
| Tiles and TileJSON with a secret key or OAuth token | The plan's rate per key: Free 10, Starter 25, Growth 50, Scale 100 a second |

Every visitor of a web page shares its publishable key, so tile requests from a publishable key are limited per visitor, not per key. A map view asks for about 30 tiles at once; 20 a second holds two of the largest map sessions measured. Over the limit, the answer is `429 rate_limited` with `Retry-After: 1`.

## Errors

Errors are JSON with a stable `code`:

```json
{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded (20 tile requests per second per visitor)."
  }
}
```

| Status | Code                 | When                                                               |
| ------ | -------------------- | ------------------------------------------------------------------ |
| 400    | `tile_error`         | `x` or `y` is out of range for `z`                                 |
| 401    | `missing_api_key`    | No key or token                                                    |
| 401    | `invalid_api_key`    | Malformed, unknown or revoked key                                  |
| 403    | `origin_not_allowed` | Publishable key from an origin it does not list                    |
| 404    | `not_found`          | Unknown tile set                                                   |
| 429    | `rate_limited`       | Over the per-second rate                                           |
| 429    | `quota_exceeded`     | The monthly tile allowance is used up (`error.product` is `tiles`) |

An empty tile is not an error: it answers `204 No Content`.
