Authentication
Every /v1 endpoint except GET /healthz and the signed file URLs requires an API key.
Key format
Section titled “Key format”A key looks like this:
glr_sk_8Qd1nR7xKpV2sYbL4mTf9Uaeglr_sk_ followed by 24 random bytes in base64url. The API stores only the SHA-256 of the key
plus its first 13 characters (glr_sk_8Qd1nR7) for display. The plaintext exists on the one
response that issued it and nowhere else.
The two accepted headers
Section titled “The two accepted headers”The API reads Authorization first and falls back to X-API-Key.
| Header | Example | Notes |
|---|---|---|
Authorization | Authorization: Bearer glr_sk_… | Preferred. The Bearer prefix is matched case-insensitively. |
Authorization | Authorization: glr_sk_… | Also accepted — a value with no Bearer prefix is used as the key verbatim. |
X-API-Key | X-API-Key: glr_sk_… | Used only when Authorization is absent or empty. |
curl -sS https://api.galleyrender.com/v1/templates \ -H "Authorization: Bearer $GALLEY_API_KEY"
curl -sS https://api.galleyrender.com/v1/templates \ -H "X-API-Key: $GALLEY_API_KEY"The MCP server takes different headers
Section titled “The MCP server takes different headers”https://mcp.galleyrender.com/mcp accepts Authorization: Bearer glr_sk_…, X-Galley-Api-Key
or X-API-Key. It also understands X-Galley-Client-Id.
| Header | Purpose |
|---|---|
X-Galley-Api-Key: glr_sk_… | The key or trial token to use for this call. |
X-Galley-Client-Id: <8–200 chars> | An opaque, stable identity for the keyless trial, so the same agent gets the same trial account back across IP changes. |
A bearer token that does not begin with glr_sk_ is ignored rather than forwarded — an OAuth
token from some other server falls through to the keyless trial instead of producing a 401.
With no key and no client id, the trial identity is derived from a salted hash of your IP and
User-Agent.
The 401 body
Section titled “The 401 body”No key at all:
{ "error": { "type": "authentication_error", "message": "Missing API key.", "docs_url": "https://galleyrender.com/docs/errors/authentication_error", "details": { "how_to_authenticate": "Send `Authorization: Bearer glr_sk_…` or `X-API-Key: glr_sk_…`.", "get_a_key": "https://galleyrender.com/docs/quickstart" } }}A key that is unknown, mistyped or revoked:
{ "error": { "type": "authentication_error", "message": "Invalid or revoked API key.", "docs_url": "https://galleyrender.com/docs/errors/authentication_error", "details": { "header": "Authorization: Bearer glr_sk_…", "get_a_key": "https://galleyrender.com/docs/quickstart" } }}The API does not distinguish “never existed” from “revoked”, on purpose.
Trial tokens are real keys
Section titled “Trial tokens are real keys”The token in trial.trial_token from a keyless MCP render call is an ordinary API key on an
ordinary account. It authenticates against https://api.galleyrender.com exactly like a key you
signed up for. The only difference is on the account: a trial carries a lifetime ceiling of
50 billable units rather than a monthly allowance.
curl -sS https://api.galleyrender.com/v1/usage \ -H "Authorization: Bearer glr_sk_8Qd1nR7xKpV2sYbL4mTf9Uae"When the ceiling is reached, every render returns quota_exceeded
with details.trial: true. Calling create_account with an email clears the ceiling on that
same account, so nothing you built during the trial is lost.
Key hygiene
Section titled “Key hygiene”Keys are server-side only. The REST API sends no CORS headers at all, so a browser cannot
call it from page JavaScript — a fetch from a web page will be blocked by the browser before
it sees a response. That is deliberate: there is no configuration that makes a Galley key safe
in a browser bundle, a mobile app or anything else a user can read.
Browser-based clients should talk to the MCP endpoint instead, which does send CORS headers
(https://mcp.galleyrender.com/mcp), or go through your own backend.
- Put the key in an environment variable (
GALLEY_API_KEY), a secret manager, or your platform’s secret store. Never in source control. - Give each deployment its own key, so you can revoke one without taking down the others.
- The API never logs key values. Neither should you — log the
x-request-idresponse header instead when you need to report something. - Signed render URLs carry no key and are safe to hand to a user. They expire in an hour.
Rotating a key
Section titled “Rotating a key”Keys are issued once and cannot be read back. To rotate:
- Issue a new key for the account.
- Deploy it everywhere the old one is used.
- Revoke the old key. A revoked key produces the “Invalid or revoked API key.” 401 above on its very next request.
The /v1 REST surface has no key-management endpoints today: creating and revoking keys happens
through the account dashboard (https://galleyrender.com/dashboard/keys, linked from the
create_account tool’s own response) or by writing to support@galleyrender.com. If you think a
key has leaked, revoke it first and ask questions second — see Security.