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

# Public and Secret Keys

> Public Key, Private API Key, Secret Key, and webhook secrets: what each ShieldLabs credential authenticates and where it belongs.

Every domain you add to ShieldLabs gets a **public key**, a **secret key**, and a **private API key**. They are scoped to that single domain and serve different purposes.

| Key                        | Format                 | Where it lives               | What it does                                                                                  | Safe in the browser? |
| -------------------------- | ---------------------- | ---------------------------- | --------------------------------------------------------------------------------------------- | -------------------- |
| **Public key**             | 32-char hex            | The snippet URL on your site | Identifies the domain so the server knows which account a fingerprint belongs to              | Yes                  |
| **Private API key**        | `sec_xxx-xxx-xxx`      | Your server only             | Authenticates [History API](/api/server-api) calls on `account.shieldlabs.ai`                 | No, never            |
| **Secret key**             | 32-char hex            | Your server only             | Authenticates the [Management API](/api/server-api) on `api.shieldlabs.ai` (profile, balance) | No, never            |
| **Webhook signing secret** | `whsec_…` per endpoint | Your server only             | Verifies the `X-Shield-Signature` header on incoming webhooks                                 | No, never            |

## Public key

The public key is the only credential that ships to the browser, and exposing it there is by design.

```
a3f8c2d1e9b0476a8c5d2f1e0b9a8c7d
```

* Goes in the snippet URL as the `?publicKey=` query parameter.
* Tells `rest.shieldlabs.ai` which domain a fingerprint belongs to.
* Safe to expose. It is visible in your page source and cannot read data, change settings, or authenticate against any server API.
* The request is only accepted when the public key matches the domain it is served from (resolved from the `Origin`, `Referer`, or `Host`). A public key lifted from your page will not work on someone else's domain.

```html theme={null}
<script type="module">
  const mod = await import('https://cdn.shieldlabs.ai/snippet.js?publicKey=a3f8c2d1e9b0476a8c5d2f1e0b9a8c7d');
  mod.checkAnonymous();
</script>
```

[Install the snippet](/setup/snippet) covers the full client setup.

## Private API key

The **Private API Key** is the credential for the recommended [History API](/api/server-api). Find it in the dashboard **API** tab for your domain.

```
sec_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
```

* Send it as `Authorization: Bearer sec_…` to `account.shieldlabs.ai/api/v1/…`.
* Used to read scored snapshots by `request_id`, `device_id`, and other identifiers.
* Does **not** go in the snippet or the browser.
* Rotate it independently from the public/secret key pair from the dashboard **API** tab.

```bash theme={null}
curl "https://account.shieldlabs.ai/api/v1/history/request_id/550e8400-e29b-41d4-a716-446655440000?limit=1" \
  -H "Authorization: Bearer sec_your_private_api_key"
```

## Secret key

The secret key authenticates the **Management API** on `api.shieldlabs.ai` — profile, balance, and the alternate billed History path.

```
9b74c98e1a3f0d2c5b6a7e8f10293847
```

<CardGroup cols={2}>
  <Card title="Management API auth" icon="key" href="/api/server-api">
    Recommended: `X-Shield-Domain` + `Authorization: Bearer` headers on `api.shieldlabs.ai/v1/…`.
  </Card>

  <Card title="Webhook verification" icon="signature" href="/setup/webhooks">
    Webhooks are **not** signed with the Secret Key. Each endpoint you register in the dashboard **Webhooks** tab gets its own `whsec_…` signing secret. Verify the `X-Shield-Signature` header over the raw request body with that secret.
  </Card>
</CardGroup>

<Warning>
  Never put the secret key or private API key in client-side code, a snippet, a mobile app bundle, a public repository, or any place a browser can reach. Store them in environment variables or a secrets manager. Store each webhook `whsec_…` the same way.
</Warning>

## Keys are masked once issued

The full secret key is shown **only at the moment it is created or rotated**, in the dashboard. After that, you cannot read it back in plaintext anywhere.

The free [Profile endpoint](/api/server-api) on `api.shieldlabs.ai` returns the public and secret keys masked to the last four characters, so you can confirm *which* key a domain is using without exposing it. It costs 0 requests.

```bash theme={null}
curl "https://api.shieldlabs.ai/v1/profile" \
  -H "X-Shield-Domain: myshop.com" \
  -H "Authorization: Bearer YOUR_SECRET_KEY"
```

If you lose the secret key, rotate the key set and update your server. The Private API Key can be rotated separately from the **API** tab.

## Rotating keys

| Key                      | Where to rotate                                | What breaks if you forget to update              |
| ------------------------ | ---------------------------------------------- | ------------------------------------------------ |
| Public + Secret key pair | **Snippet** tab (public), **API** tab (secret) | Snippet stops working; Management API auth fails |
| Private API key          | Dashboard **API** tab                          | History API calls return `401`                   |
| Webhook `whsec_…`        | Dashboard **Webhooks** tab                     | Signature verification fails for that endpoint   |

After rotating the public/secret pair:

<Steps>
  <Step title="Update the snippet">
    Replace the `?publicKey=` value in your snippet (or the environment variable that feeds it) with the new public key.
  </Step>

  <Step title="Update your server">
    Swap the secret used for Management API auth to the new secret. Keep it in your secrets manager, not in code. Webhook endpoint secrets (`whsec_…`) are managed separately in the dashboard **Webhooks** tab.
  </Step>

  <Step title="Confirm with Profile">
    Call the [Profile endpoint](/api/server-api) and check that the masked tails match the new keys.
  </Step>
</Steps>

<Note>
  Rotate keys whenever a credential may have been exposed (a leaked log, a committed `.env`, an offboarded teammate) and on a routine schedule for sensitive domains.
</Note>

## Where to find your keys

Open [app.shieldlabs.ai](https://app.shieldlabs.ai/), select your domain:

* **Snippet** tab — Public Key
* **API** tab — Private API Key (History API)
* **API** tab — Secret Key (Management API)

## Next steps

Wire the public key into the [snippet](/setup/snippet), register webhook endpoints and verify each endpoint's `whsec_…` secret per the [webhooks](/setup/webhooks) guide, and read scored results through the [History API](/api/server-api).
