API keys
Key format, scope taxonomy, rate-limit tiers, and revocation paths.
An API key authenticates every request you make and decides what that request is allowed to do. One key is scoped to one organization. It carries the rate-limit tier that caps throughput and the allowlist of returnUrl values the OAuth flows will accept. A future scope list will gate individual routes.
Key format
lp_<env>_<key_id>_<secret>envis eitherliveortest. Test keys talk to the same API but their traffic is routed to sandboxed back-ends — no production publishing, no real billing.key_idis a 16-character base32 handle. It's public — safe to log, used for rate-limit attribution, and how we look up the row.secretis a 43-character base64url remainder. Everything after the last underscore.
We store bcrypt(cost=12, secret). The plaintext exists only in your client. If you lose it, you rotate.
The secret is shown exactly once — at the moment of creation. We can't recover it, display it again, or confirm you have the right one. Paste it into your secrets manager before you close the tab.
Sending the key
Primary form: X-Api-Key: <key>. Authorization: Bearer <key> is accepted as a fallback for clients that can't set custom headers. If both are sent, the server prefers X-Api-Key.
GET /v1/whoami HTTP/1.1
Host: api.layers.com
X-Api-Key: lp_live_01HX9Y6K7EJ4T2AB_4QZpN...remainderThe first call any client should make is GET /v1/whoami — it resolves your key to the org it's bound to and lets you fail fast if anything is wrong. Response shape:
{
"organizationId": "2481fa5c-a404-44ed-a561-565392499abc",
"workspaceId": "2481fa5c-a404-44ed-a561-565392499abc",
"organizationName": "Acme Growth",
"scopes": [],
"rateLimitTier": "standard",
"killSwitch": false,
"apiAccessRevoked": false,
"apiKeyId": "c2037bb9-354d-4662-96b7-97a28ad6b6e1"
}Scopes (planned)
Scopes are not yet enforced. Partner keys currently carry org-level access across the whole surface and /v1/whoami returns scopes: []. The table below documents the planned vocabulary so your integration can plan for granular access.
| Scope | Gates |
|---|---|
projects:read / projects:write | Project CRUD. |
ingest:write | GitHub / website / App Store ingestion. |
content:read / content:write / content:approve | Content read, generation, and approval actions. |
social:read / social:write | Social account listing and OAuth flows. |
publish:write | Schedule and publish posts. |
events:read / events:read+pii | SDK event stream. +pii includes unredacted fields. |
metrics:read | Organic and ads metrics. |
ads:read / ads:write | Ads reads today; ads CRUD is planned. |
influencers:write | Influencer create / clone / patch. |
leased:write | Submit and release leased-account requests. |
engagement:write | Patch engagement layer config. |
github:admin | Register and read GitHub App installations. |
jobs:read / jobs:cancel | Read and cancel jobs. |
Rate-limit tiers
Tier is a property of the key, not the endpoint. Buckets are keyed per (key_id, endpoint_class) so a runaway generation loop can't starve your reads. Endpoint classes: read-light, write-light, long-running.
| Tier | Typical provisioning |
|---|---|
standard | Default for every partner key. |
pilot | Higher throughput for early-integration partners — granted by Layers on request. |
partner | Enterprise tier for GA partners with SLAs. |
Every 429 response carries:
Retry-After(seconds)X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-ResetX-RateLimit-Endpoint-Class,X-RateLimit-Tier- Body with
error.details.retryAfterMsanderror.details.endpointClass
See common patterns for a back-off snippet and rate limits for the full bucket policy.
Rotation
You can rotate a key without downtime:
last_used_at on the old key drop to zero.Both keys are active in parallel during the cutover, so there's no flap.
Revocation
Three levers, each stronger than the last:
- Revoke the key.
revoked_atgets stamped. Every subsequent request fails with401 UNAUTHENTICATED. This is the normal path. - Kill switch on the key. Sets
kill_switch = true. Requests fail with503 KILL_SWITCH— a different signal than revoked, so you can tell an incident from a rotation. Clearable without reissuing. - Org-wide kill switch. Flips
organizations.api_access_revoked = true. Every key on the org fails. Reserved for incident response.
Revocation and kill-switch flips take effect on the next request — propagation is effectively immediate.