> ## Documentation Index
> Fetch the complete documentation index at: https://usefoil.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Authenticate Foil API requests with publishable and secret keys, including Bearer token usage, key scopes, environments, rotation, and revocation.

Foil uses `Authorization: Bearer <token>` for every authenticated request. The token format signals what the key is for and what it can do.

## Key types

Three 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.

| Prefix                   | Lives in                           | Authorizes                                                                                                                              |
| ------------------------ | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `pk_live_*`, `pk_test_*` | Browser bundles (public by design) | The Collect API path that the browser SDK uses to open a session, stream observation batches, and mint a sealed handoff.                |
| `sk_live_*`, `sk_test_*` | Your server only                   | All authenticated REST: durable session and fingerprint readback, organization and API-key management, Gate business backend endpoints. |
| `agt_*`                  | Gate CLI / agent contexts          | Starting a fresh dashboard login session via `POST /v1/gate/login-sessions`. Issued by Gate on signup.                                  |

Plus a small set of Gate workflow credentials — one-time polling tokens (`gtpoll_*`), approval tokens, and login codes — that are scoped to a single Gate session and documented on the [Gate](/api-reference/gate-sessions) pages.

<Warning>
  Secret keys (`sk_*`) have broad read access to your session history and visitor fingerprint data. Never commit one to git, send it over a non-TLS channel, or ship it in a client bundle. If a secret key is ever exposed, [rotate it immediately](#rotating-a-key).
</Warning>

## Using a key

Send the key as a Bearer token on every request.

<CodeGroup>
  ```bash cURL theme={"dark"}
  curl https://api.usefoil.com/v1/sessions/sid_... \
    -H "Authorization: Bearer sk_live_..."
  ```

  ```javascript Node.js theme={"dark"}
  const { Foil } = require("@abxy/foil-server");
  const client = new Foil({ secretKey: process.env.FOIL_SECRET_KEY });

  const session = await client.sessions.get("sid_...");
  ```

  ```python Python theme={"dark"}
  from foil_server import Foil
  import os

  client = Foil(secret_key=os.environ["FOIL_SECRET_KEY"])
  session = client.sessions.get("sid_...")
  ```

  ```go Go theme={"dark"}
  import foil "github.com/abxy-labs/foil-server-go"

  client := foil.New(foil.Config{SecretKey: os.Getenv("FOIL_SECRET_KEY")})
  session, err := client.Sessions.Get(ctx, "sid_...")
  ```

  ```ruby Ruby theme={"dark"}
  require "foil/server"

  client = Foil::Server::Client.new(secret_key: ENV["FOIL_SECRET_KEY"])
  session = client.sessions.get("sid_...")
  ```

  ```php PHP theme={"dark"}
  use Foil\Server\Client;

  $client = new Client(["secret_key" => getenv("FOIL_SECRET_KEY")]);
  $session = $client->sessions()->get("sid_...");
  ```
</CodeGroup>

## Scopes — what each key can do

Foil's authorization model is prefix-driven rather than scope-based: the endpoint decides which key type it accepts, and the key type decides which endpoint group it reaches.

### Publishable keys (`pk_*`)

Allowed to call only the Collect API path the browser SDK needs. A publishable key can:

* `POST /v1/collect/sessions` — open a durable encrypted transport session
* `GET /v1/collect/pings/:pingId` — RTT timing measurement during session setup
* `POST /v1/collect/sessions/:sessionId/batches` — stream observation batches
* `POST /v1/collect/sessions/:sessionId/results` — mint a sealed handoff for the current session
* `POST /v1/collect/network-checks` — compare HTTP and WebSocket network identity
* `GET /v1/gate/registry`, `GET /v1/gate/registry/:serviceId` — read public Gate service metadata

A publishable key **cannot** read verdict data, list sessions, inspect durable fingerprints, or touch any management surface. There is no escalation path from `pk_*` to `sk_*` — the keys are fully partitioned.

### Secret keys (`sk_*`)

Allowed to call every authenticated endpoint on the public REST surface:

| Endpoint group          | Path pattern                                                                                      | Typical use                                                                                                                                                                                           |
| ----------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Sessions                | `/v1/sessions`, `/v1/sessions/:sessionId`                                                         | Durable session readback for backend verification, audit, and reconciliation                                                                                                                          |
| Fingerprints            | `/v1/fingerprints`, `/v1/fingerprints/:visitorId`                                                 | Cross-session visitor correlation — promo abuse, KYC farming, etc.                                                                                                                                    |
| Organizations           | `/v1/organizations`, `/v1/organizations/:id`                                                      | Create, read, update organizations                                                                                                                                                                    |
| API keys                | `/v1/organizations/:id/api-keys`, including rotations and revocation                              | Key lifecycle                                                                                                                                                                                         |
| Gate — services         | `/v1/gate/services`, `/v1/gate/services/:serviceId`                                               | Register and manage Gate services your organization owns                                                                                                                                              |
| Gate — business backend | `/v1/gate/agent-tokens/verify`, `/v1/gate/agent-tokens/revoke`, `/v1/gate/login-sessions/consume` | Verify Gate-issued agent tokens and consume dashboard login codes                                                                                                                                     |
| Webhooks and events     | `/v1/organizations/:id/webhooks/endpoints`, `/v1/organizations/:id/events`                        | Manage webhook endpoints, rotate signing secrets, send test events, and browse event history with delivery diagnostics. Reads require the `webhooks:read` scope; mutations require `webhooks:manage`. |

Secret keys on test mode (`sk_test_*`) and live mode (`sk_live_*`) authorize the same endpoints but operate on separate data.

### Agent tokens (`agt_*`)

A narrow credential issued by Gate when a developer completes a signup flow. Its only privileged use on the public API is `POST /v1/gate/login-sessions`, which exchanges an agent token for a short-lived dashboard login handoff. Agent tokens are designed to be stored in long-lived CLI or shell environments where developers expect re-entry without re-signing-in.

Your backend verifies agent tokens via `POST /v1/gate/agent-tokens/verify` using your `sk_*`, and revokes them via `POST /v1/gate/agent-tokens/revoke`. See [Agent tokens](/api-reference/gate-tokens) for the details.

## 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 with `sk_live_*`, and vice versa.
* Organization, billing, and member state is the same across both environments. Sessions, fingerprints, and Gate state 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.

Use test mode for automated integration tests, development, and CI. Use live mode when you ship.

## Origin restrictions

Publishable keys can be narrowed to a list of allowed origins in the dashboard. A `pk_live_*` limited to `https://yourdomain.com` will be rejected when presented from any other origin, so a leaked key is only as dangerous as the origins it's allowed to speak for.

Restrict every production publishable key to the exact hostnames you load `t.js` from. Allow wildcards only on test keys.

<Note>
  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.
</Note>

## Rotating a key

Rotation issues a new version of a key while allowing the old version to continue functioning through a grace window. This lets you roll new secrets into deployment before revoking the old one — no flight of 401s during the overlap.

```bash theme={"dark"}
curl -X POST https://api.usefoil.com/v1/organizations/org_.../api-keys/key_.../rotations \
  -H "Authorization: Bearer sk_live_..."
```

Recommended rotation flow:

1. Call the rotation endpoint. You receive the new key material in the response.
2. Deploy the new key to all environments that use the old one.
3. Verify the new key is in use (e.g. by inspecting logs or a dashboard request count).
4. Revoke the old key.

See [API keys](/api-reference/organizations) for the full request and response shapes.

## Revoking a key

Revocation is immediate and unconditional — the key stops working on the next request.

```bash theme={"dark"}
curl -X DELETE https://api.usefoil.com/v1/organizations/org_.../api-keys/key_... \
  -H "Authorization: Bearer sk_live_..."
```

If you believe a secret key has been exposed, revoke first and investigate second. The rotation flow above is for planned, graceful transitions; revocation is for incidents.

## Rate limits

Rate limits are applied at the edge per organization and key type, then returned in response headers. Defaults:

* Publishable keys (`pk_*`): `120` requests per window
* Secret keys (`sk_*`): `600` requests per window

Foil support can configure organization-level overrides when a production integration needs more headroom. Every authenticated response carries:

* `X-RateLimit-Limit` — the ceiling for this organization and key type
* `X-RateLimit-Remaining` — requests left in the current window

Rate-limited responses are `429 Too Many Requests` and include a `Retry-After` header. See [Errors](/api-reference/errors) for the full error envelope shape.

## What's next

<CardGroup cols={2}>
  <Card title="Errors" icon="triangle-alert" href="/api-reference/errors">
    Error envelope shape, status codes, and retry semantics.
  </Card>

  <Card title="Pagination" icon="list-ordered" href="/api-reference/pagination">
    How list endpoints paginate and filter.
  </Card>

  <Card title="Security and privacy" icon="lock" href="/privacy-and-data">
    How keys are protected end-to-end.
  </Card>

  <Card title="Sessions" icon="monitor" href="/api-reference/sessions">
    First authenticated endpoint most integrations hit.
  </Card>
</CardGroup>
