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

# Publishable keys

> The client-safe credential that identifies your organization to the API. Retrieve it with your API key, then embed it in browser code.

A publishable key (`end_pk_live_...`) names your organization and nothing else. It is safe to embed in page source, ship in a bundle, or commit to a public repository.

It exists so a browser can call the API without holding anything sensitive. One endpoint accepts it - `POST /v1/taps`, which exchanges a tap for a session token - and it authorizes nothing on its own: the authority in that exchange is the one-time `e` value from the tap, which cannot be forged and works exactly once.

That endpoint takes an API key too. Same path, same request, same response - the credential you send is what changes, so a page with no backend behind it and a server-side integration use the same call.

## Retrieve your key

List your organization's keys. If you have none yet, one is created on the first call, so you always get something usable.

<CodeGroup>
  ```ts SDK theme={null}
  await endstate.publishableKeys.list();
  ```

  ```bash cURL theme={null}
  curl https://api2.endstate.io/v1/publishable-keys \
    -H "Authorization: Bearer end_sk_..."
  ```
</CodeGroup>

<Accordion title="Response">
  ```json theme={null}
  {
    "publishable_keys": [
      {
        "id": "3f9a1c22-8b7d-4e51-9f10-2c3d4e5f6a7b",
        "key": "end_pk_live_0123456789abcdef0123456789abcdef",
        "mode": "live",
        "name": "Default",
        "created_at": "2026-05-14T10:30:00.000Z"
      }
    ],
    "pagination": {
      "limit": 50,
      "has_more": false,
      "next_cursor": null
    }
  }
  ```
</Accordion>

Retrieving the key requires your secret key, so make this call from your server or your terminal - never from the page that will use it. Read `key` once at build or deploy time and inline the value; there is no reason for a browser to fetch it at runtime.

<ResponseField name="key" type="string">
  The credential itself. Send it as `Authorization: Bearer end_pk_live_...`.
</ResponseField>

<ResponseField name="mode" type="string">
  `live` or `sandbox`. Only `live` keys are issued today.
</ResponseField>

<ResponseField name="name" type="string">
  Display name, to tell keys apart when you have more than one.
</ResponseField>

## What it can and cannot do

|                          | Publishable key      | Secret API key         |
| ------------------------ | -------------------- | ---------------------- |
| Safe in a browser        | Yes                  | **Never**              |
| Reads your catalog       | No                   | Yes                    |
| Writes anything          | No                   | Yes                    |
| Accepted as a credential | `POST /v1/taps` only | Most `/v1/*` endpoints |

Losing control of a publishable key does not expose your data. Someone else holding it can only do what any visitor to your page could already do: exchange a genuine tap they physically performed for a session token scoped to that one chip.

<Warning>
  This is not a lesser API key - it is a different kind of thing. Do not
  substitute one for the other. A secret key in browser code is a full
  compromise of your organization's data; see [Credentials](/credentials).
</Warning>

## Before it works in a browser

A publishable key is only half of browser setup. Browser requests carrying one are matched against your organization's origin allow-list, so add the origins your pages are served from before going live - see [CORS origins](/settings/cors-origins). A request with no `Origin` header is not origin-checked: the allow-list governs where the key may be embedded, not who may call the API. The one-time `e` value from the tap remains the authority.

***

## Next steps

<CardGroup cols={2}>
  <Card title="CORS origins" icon="globe" href="/settings/cors-origins">
    Allow-list the origins your pages are served from.
  </Card>

  <Card title="Host your own verify page" icon="scan-line" href="/guides/host-verify-page">
    Build the post-tap experience on your domain, with or without a backend.
  </Card>
</CardGroup>
