Start here
Authentication
Every call sends your API key in the Authorization header. Create and revoke keys in the console, and keep them on your server.
Send your key
Put the key in the Authorization header, after the word Bearer and a space:
Authorization: Bearer gm_…That header is the only place we look for it. There's no X-API-Key header, and we never read a key from the URL, because URLs end up in logs.
To check that a key works, ask for your usage. It's free and changes nothing. The SDK sends the header for you once you give it the key:
curl https://api.gmaps.dev/v1/usage \
-H "Authorization: Bearer $GMAPS_API_KEY"Create a key
Create keys in the console, under API keys. Name each one after where it will run, such as “production server” or “Claude on my laptop”, so you know which one to revoke later.
We show a key once, when you create it. We don't keep the key itself, so we can't show it again: if you lose it, create another. The console lists the start of each key and when it was last used, so you can tell them apart.
How many keys you can have at once depends on your plan. Revoked keys don't count:
| Plan | Keys at once |
|---|---|
| Free | 2 |
| Starter | 5 |
| Pro | 10 |
| Scale | 20 |
At the limit, revoke a key you no longer use, or move to a bigger plan.
More keys don't give you more requests. The per-minute limit counts your whole account, whichever key sends the call. Limits has the numbers.
Revoke a key
A key works until you revoke it. Revoke it in the console when you stop using it, or when it may have leaked. It stops working at once, and you can't undo that. What it spent stays on the Usage page.
To replace a key without a gap, create the new key first, move your code to it, then revoke the old one.
Keep keys secret
A key spends your credits, so treat it like a password:
- Keep it out of your code and out of git. Read it from an environment variable, as the examples here do.
- Keep it out of web pages and apps you hand out, where anyone can read it. Call the API from your server. Web pages on other sites can't call it anyway: the API only takes calls from browsers on gmaps.dev.
- Give each place that runs your code its own key. Then you can revoke one without stopping the rest.
When a key is refused
A refused call changes nothing and costs nothing. The answer says what went wrong:
| Status | Code | Why | What to do |
|---|---|---|---|
| 401 | UNAUTHORIZED | There's no Authorization header, or it doesn't start with Bearer. | Send the header as shown above. |
| 401 | INVALID_TOKEN | The key is wrong, it was revoked, or it isn't an API key, such as a console sign-in token. | Copy the key again, or create a new one. |
| 403 | FORBIDDEN | The key is fine, but the account is suspended, deleted or waiting to be deleted. | Sign in to the console to cancel a deletion, or write to us. |
| 429 | RATE_LIMIT_EXCEEDED | Too many calls this minute. | Wait the number of seconds in the retry-after header, then try again. |
A wrong key and a revoked one get the same answer.
Every error has the same shape. This is the answer to a call with no key, and Errors lists every code:
{
"error": {
"code": "UNAUTHORIZED",
"message": "Send your API key as \"Authorization: Bearer gm_…\". Create one at https://console.gmaps.dev/keys, then retry.",
"messageKey": "serverErrors.unauthorized"
}
}MCP uses the same key
An AI agent connected over MCP sends the same header with the same key. Its calls count against the same limits and cost the same credits as calls from your code. Listing the tools needs no key, so an agent can see what it could do before it has one.
When you create a key, the console shows your agent's MCP settings with the key already in them, ready to paste.
Calls that need no key
These answer without a key:
GET /v1/attributions: the open-source projects we build on, and their licenses.GET /v1/exports/{id}/download: an export's file. The token in its link is what opens it, so share the link only with people who should have the file. It works for 24 hours. Exports has more.GET /openapi.json: the whole API, described for tools that generate clients.GET /health: whether the API is up.
Keep the request id
Every answer carries an x-request-id header. Keep it with your own logs. When something goes wrong, send it to support, and we can find that exact call.
You can also send an x-request-id of your own, up to 64 letters, digits, dots, dashes and underscores. We use yours instead of making one up, so your logs and ours share one id. If yours doesn't follow those rules, we use one of ours.
In the SDK, an error from the API carries it as requestId.
For each call, the API logs the id, the method, the path, the status and how long it took. The web server in front of it also logs the full URL, query string included, your IP address and your headers except Authorization, and keeps them for 30 days. Neither one logs your key or the request body.