Authorization: Bearer <token> for every authenticated request. The token format signals what the key is for and what it can do.
Key types
Two distinct credential types exist on the public API. Each has a different prefix, lives in a different place, and authorizes a different set of endpoints.
A few endpoints need no key:
GET /v2/collect/pings/:pingId and POST /v2/collect/network-checks.
Using a key
Send the key as a Bearer token on every request.Authorization header is missing, the API returns 401 with auth.missing_api_key. If the header is malformed, or the key is unrecognized, revoked, or past the end of its rotation grace window, the API returns 401 with auth.invalid_api_key.
Scopes
Publishable keys are limited to the Collect API, and secret keys are limited by scope. The endpoint decides which key type it accepts, and for secret keys it also decides which scope the key must carry.Publishable keys (pk_*)
A publishable key can call only the Collect API endpoints that the SDKs need:
POST /v2/collect/sessions- open or resume an encrypted unified sessionPOST /v2/collect/sessions/:sessionId/documents/:documentId/batches- stream observation batchesPOST /v2/collect/sessions/:sessionId/documents/:documentId/results- mint a sealed handoff for the current session
403 with auth.secret_key_required. There is no escalation path from pk_* to sk_* - the keys are fully partitioned.
Native publishable keys
Each publishable key has aclient_target: browser (the default), native-ios, or native-android. A native key works only with the matching Foil mobile SDK on the /v2/collect/sessions endpoints. Any other use of a native key, including a request from a different client or to a different path, returns 403 with auth.native_key_not_allowed. Origin restrictions apply to browser keys only, and native keys can’t define allowed origins.
Secret keys (sk_*)
Each secret key carries a list of scopes, and each endpoint requires one scope. A request to an endpoint whose scope the key doesn’t carry returns 403 with auth.insufficient_scope, and the error message names the missing scope. The scope * grants all current and future scopes.
A secret key with no stored scopes receives the default scopes sessions:read, sessions:update, and fingerprints:read. The defaults don’t include sessions:list or fingerprints:list, so add those scopes if your integration lists sessions or fingerprints.
Foil accepts secret keys only on the REST endpoints in this table. Calling a Collect API endpoint with a secret key returns
403 with auth.secret_key_not_allowed.
The /v1/organizations/:organizationId/... endpoints work only for the organization that owns the calling key. A request for any other organization returns 403 with auth.organization_access_denied. See Organizations for the full list of scopes.
Secret keys on test mode (sk_test_*) and live mode (sk_live_*) authorize the same endpoints but operate on separate data.
Live and test environments
Each organization has separate live and test key pairs. They share the same REST surface but are fully isolated:- Sessions minted under
pk_test_*cannot be read back withsk_live_*, and vice versa. - Organization, billing, and member state is the same across both environments. Sessions and fingerprints are separate.
- Test-mode sessions may expose richer debug detail in internal tooling and the dashboard; the public browser handoff stays opaque regardless of environment.
Origin restrictions
Browser publishable keys can be narrowed to a list of allowed origins in the dashboard or through the API keys endpoints. Apk_live_* limited to https://yourdomain.com is rejected with auth.origin_not_allowed when presented from any other origin, or without an Origin header, so a leaked key is only as dangerous as the origins it’s allowed to speak for. A key with no allowed origins accepts any origin.
Restrict every production publishable key to the exact hostnames you load t.js from. Allow wildcards only on test keys.
Secret keys are not origin-restricted - they’re meant for server-to-server traffic where the caller’s “origin” is your infrastructure. Control where they’re used by keeping them on the server side and not shipping them into the browser.
Rotating a key
Rotation issues a new key with the same type, environment, name, origins, client target, and scopes. The old key keeps working for a 24-hour grace window. This lets you roll new secrets into deployment before the old one stops - no flight of 401s during the overlap.rotating, and its grace_expires_at field shows when it stops working. When the window ends, Foil revokes the old key automatically.
Recommended rotation flow:
- Call the rotation endpoint. You receive the new key material in the response.
- Deploy the new key to all environments that use the old one.
- Verify the new key is in use (e.g. by inspecting logs or a dashboard request count).
- Optionally revoke the old key without waiting for the grace window to end.
Revoking a key
Revocation is unconditional, but it isn’t instantaneous. Foil caches successful key verifications for up to about 15 seconds, so a revoked key can keep working for that long. Changes to a key’s scopes or allowed origins take the same time to apply.Rate limits
Foil applies rate limits per organization and key type. The limit belongs to the organization and key type, not to an individual key. By default, all of an organization’s secret keys share one limit of600 requests per 60-second window, and all of its publishable keys share one limit of 3000 requests per 60-second window. Foil support can configure organization-level overrides when a production integration needs more headroom.
Responses carry X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Cost headers. Rate-limited responses are 429 Too Many Requests and include a Retry-After header. See Rate limits for how the window works, what counts against it, and how to retry.
What’s next
Errors
Error envelope shape, status codes, and retry semantics.
Pagination
How list endpoints paginate and filter.
Security and privacy
How keys are protected end-to-end.
Sessions
First authenticated endpoint most integrations hit.