Authentication
Every request to the Mountaya developer platform carries an API key that identifies your organization and scopes what it may do. Most surfaces also require a short-lived session token. This page covers both, the query-parameter fallbacks for browser navigations, and how rate limiting surfaces.
API keys
Keys come in a pair. Choose which to use by where the request runs.
Publishable keypk_…
Safe to ship in a browser or mobile app. Authorizes Map Embedding and the Tile and Data APIs (subject to scopes), and is restricted to the origins you allow. Sent in the X-API-Key header.
Secret keysk_…
Authorizes privileged operations, most importantly minting session tokens. Keep it on a server you control and never expose it to a browser. Sent in the X-API-Key header of the session-minting call.
Scopes
Each key carries scopes, and each scope authorizes exactly one product surface. A key grants nothing beyond what you enable on it, so enable only what an integration needs.
Every operation states the scope it requires: in the REST references as an x-pkey-scope on the operation and a line in its description, and in the Data API schema as a @pkeyScope directive on the field.
embeddingPermission to embed Map Studio in an iframe, and to reach the studio-only surfaces behind it — the AI agent, real-time collaboration, layers and activities. Enabling it also enables tiles and resources, since the studio renders tiles and edits itineraries.
tilesAccess to the Tile API: overlay specifications and {z}/{x}/{y} tiles.
resourcesRead and write access to itineraries, collections, zones and everything hanging off them over the Map Studio API. This is the scope a server-side integration needs, with no iframe involved.
dataAccess to the Data API for routing, places, and geometry analysis. It does not grant MCP access.
mcpPermission for MCP clients to reach your data through the Mountaya connector. It does not grant direct Data API access — the two are separate products, and a connector's session is bound to the MCP surface when it is minted.
managementAdministration of the organization: publishable and secret keys, billing, members, settings, AI configuration and usage. Never enable it on a key that ships in client-side code — a publishable key is public by construction, and this is the one scope that reaches your credentials and your billing.
Session tokens
A session token (sess_…) is a short-lived credential derived from your key pair. The Data API requires one on every request. Map Embedding requires one whenever your organization enables session enforcement (require_session_token); organizations without their own backend can leave it off and embed with just a publishable key and origin validation.
1
Call POST /v1/sessions on internal.mountaya.com. The secret key authorizes the call in the X-API-Key header; the publishable key the token is minted for goes in the body.
2
A successful call returns 201 Created with the token and the moment it expires.
Tokens live for 5 minutes. Mint a fresh one before it expires; minting is cheap and reuses a cached token within its validity window.
3
Pass the session token in the X-Session-Token header alongside your publishable key. Both headers are required on every Data API request.
What a bare publishable key reaches
A publishable key sent with no session token is the credential an embed carries when your organization leaves require_session_token off. What it reaches depends on whether you are opening one resource or listing what exists:
- By id, the key reads its own organization's resources whatever their privacy, plus any other organization's public resources. That is what lets an embed with no backend render its own private itinerary.
- By listing, the key is public-only. A private resource is never enumerable with a publishable key, so reaching one means already holding its id.
Design your client around that asymmetry: a private resource stays out of every listing, while one whose id you already hold stays embeddable. A session token narrows a request to the organization it belongs to.
Listing collections
Two Map Studio API operations list collections, and a bare publishable key reaches both:
Both listings report viewer as each collection's role. A key holds no membership of its own, so it never inherits the role of whoever created the collection. A private collection appears in neither listing, and reaching one takes a session token.
Identifying the user on a write
A publishable key identifies an organization, not a person. That is enough to read, but every write on the Map Studio API — POST, PUT, PATCH, DELETE — is attributed to a member, so those requests carry one more header.
X-User-Iduuid
The organization member the write is attributed to. Required on every write request authorized by a publishable key. Reads ignore it and run as a synthetic user with no identity of their own.
The id must name a member of the organization the key belongs to, holding a write-capable role: owner, admin, or contributor. A viewer cannot write. Two failures are worth telling apart:
- A missing or unparseable header answers
400 Bad Request. You sent nothing usable. - A well-formed id that names no member, or names one whose role is viewer, answers
403 Forbidden. The header was read and the answer is no.
X-User-Id sits in the CORS allowlist alongside X-API-Key and X-Session-Token, so a browser request may send all three.
Share links
A share token is a fourth credential, and the only one that is not about an organization. It carries no key, no session and no user, and it grants read-only access to one resource. It is share_ followed by 32 hex characters, sent as the X-Share-Token header or the ?share_token= query parameter.
You mint one for a specific resource, and what the token reaches depends on what it was minted for:
The two kinds look identical on the wire — same prefix, same length — so a token does not tell you which kind you hold. A collection link is the one Mountaya credential that reaches more than one resource, and it follows the folder: anything filed into that collection later becomes readable through the same link, without the link changing. That is worth knowing before you hand one out.
Properties to design around:
- Read-only.
GET,HEADandOPTIONSonly. Any other method is refused. - Privacy-independent. A share token reads a private resource. That is the point of it — the link, not the privacy flag, is the gate.
- Uniformly opaque on failure. Malformed, unknown, disabled and rotated tokens all answer
401. You cannot tell "revoked" from "never existed", by design, so do not branch on the difference. - Revocable, and revocation is the only control. Rotating a link (
POST .../share/rotate) issues a new token and invalidates the old URL; disabling it (DELETE .../share) invalidates the link entirely. The studio labels rotation Reset link — same operation, same endpoint. There is no expiry and no per-recipient scoping, so a link survives membership changes until someone rotates or disables it. - Not usable for management. Minting, rotating and disabling a link all require a signed-in Mountaya user. A share token cannot mint another one, and neither can a publishable key.
OAuth for MCP connectors
The MCP server accepts a second, interactive authentication path built for AI assistants: instead of sending keys, you connect once over OAuth. The assistant discovers Mountaya's OAuth server from the connector URL and registers itself (no app to create), you sign in with your Mountaya account, and on a consent screen you choose which publishable key the assistant should act with. From then on the assistant carries an access token, scoped to that key's organization, and you never paste a key into its config. This is the path Claude, ChatGPT, and similar assistants use; see connect your assistant over OAuth for the full flow.
The same MCP endpoint also accepts the pk_/sk_ header pair for non-interactive clients. A client you script yourself can skip OAuth entirely and send a publishable key in X-API-Key and a secret key in X-Secret-Key on each request, and the server brokers a session token for it, exactly as the MCP server page documents. Use OAuth for an assistant a person signs into; use the key pair for an unattended client.
Query-parameter fallbacks
Some browser navigations, such as an <iframe src> or a download <a href>, cannot set custom headers. For those cases the publishable key and session token may travel as query parameters instead of headers:
?publishable_key=pk_…is accepted in place of theX-API-Keyheader.?session_token=sess_…is accepted in place of theX-Session-Tokenheader.?share_token=share_…is accepted in place of theX-Share-Tokenheader, on the surfaces that accept share links at all.
The header form always takes precedence when both are present.
Because the middleware reads them as credentials, publishable_key, session_token, share_token and auth_token are reserved query-parameter names. Never use one as a filter or an application parameter on a Mountaya request: it will be read as a credential and change how the request authenticates.
Errors and rate limits
This section covers what authentication itself can go wrong with. The shared envelope, the sixteen error codes, and what each status means across both APIs are on the errors page.
Rate limiting
Quotas are applied per organization, per API, per minute, across every key the organization owns. A second publishable key does not add quota. The defaults are 60 requests per minute for the Data API and 600 requests per minute for the Tile API, and both are configurable per organization.
Those two are the only per-organization quotas. The Map Studio API is not quota-limited, so none of its operations answers with a quota 429 — with the one exception below.
When you exceed a limit, the API responds with 429 Too Many Requests. The response carries no Retry-After header, so back off on your own schedule: retry after a couple of seconds, widen the gap if it happens again, and wait out the remainder of the minute if a large burst exhausted the window.
Creating a session token
POST /v1/sessions does not consume the tile or data quota. It is still bounded, because it is the one public endpoint that runs before any credential has been resolved, and it guards itself with two per-minute counters:
Neither counter is keyed on the organization, because the organization is only known once the secret key has been looked up — which is exactly the work these bounds exist to limit.
A working integration never reaches the per-key counter, since it only counts failures. If you hit it, the key is revoked, mistyped, or belongs to another organization; backing off will not help, because the retry fails the same way. The per-IP limit is generous against real traffic: a cached token is reused for most of its five-minute life, so one backend needs roughly one mint per publishable key every few minutes, and a fleet behind a single address stays well under 60.
Both counters fail open. If the counter store is unavailable the endpoint keeps minting rather than refusing, so a limiter outage never stops a visitor from loading a map.
GraphQL errors
The Data API is GraphQL, so it answers with 200 OK even when a query fails and reports problems in an errors array. Each entry carries a human-readable message, the response path it applies to, and an extensions object with machine-readable detail such as an error code.
Inspect errors on every Data API response, not just the HTTP status. A partial result can return both data and errors together. Rate limiting still surfaces as a 429 at the transport layer, before a GraphQL response is produced.