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

# Your credentials

> How your API key and webhook signing secret are issued, why each is shown only once, and how rotation works.

Your integration holds up to four values. Two of them are secrets that the platform shows you
exactly once — this page explains why, and what to do about it.

| Value                  | Looks like                      | Secret?                     | Shown                 |
| ---------------------- | ------------------------------- | --------------------------- | --------------------- |
| API key                | `pk_...`                        | **Yes**                     | Once, at issue        |
| Brand ID               | `brd_...`                       | No                          | Always visible        |
| Webhook signing secret | `psig_...`                      | **Yes**                     | Once, at registration |
| Publishable brand key  | `pub_test_...` / `pub_live_...` | No — browser-safe by design | Once, at issue        |

<Warning>
  **`pk_` is the secret one.** Some payment tools use a `pk_` prefix for their browser-safe key. This
  platform does not, and issues no `sk_` key at all: here `pk_` marks the server-side API key, and the
  browser-safe credential is the publishable brand key below. A `pk_` value in browser code, a public
  repository, or a prompt pasted into a code-generation tool is a disclosed secret — rotate it.
</Warning>

## How your API key is issued

Your API key is created by our onboarding team when your account is set up — there is no
self-serve key generation. You receive the key value **exactly once**, at the moment it is
issued. Store it in your secret manager immediately.

The platform does not keep your key. What we store is a one-way fingerprint — enough to
recognize the key when your requests present it, never enough to reconstruct it. That means:

* **Nobody can read your key back.** Not through the API, not from a dashboard, and not by
  asking us — the value no longer exists on our side.
* **A breach of our storage does not leak a usable key.** The fingerprint cannot be turned back
  into the credential.
* **A lost key is replaced, not recovered.** See rotation below.

Your brand ID (`brd_...`) travels with the key on every request as the `X-Brand-Id` header. It
is an identifier, not a secret — it appears in your dashboard views and can always be read back.

## Rotation: the only recovery

If a key is lost, or you suspect it has been exposed, ask your onboarding contact to rotate it.
Rotation issues a **new** key — shown once, like the first — and **revokes every previous key in
the same act**. There is no overlap window by default: plan the swap so your servers pick up the
new value promptly. Requests presenting a revoked key receive the same `401` as an unknown key.

<Warning>
  **Revocation is fast, not instant — budget 30 seconds.** The platform caches credential
  resolutions for up to **30 seconds**, and that window is the upper bound on how long a revoked or
  rotated key can still be accepted. A key you have just replaced may keep answering until the window
  closes.

  This matters most in the case you are most likely to be in when you read it: if a key has leaked,
  rotating it starts the clock rather than stopping it. Treat the old value as live for 30 seconds
  after you rotate, and if the exposure is serious do not rely on rotation alone to end it.
</Warning>

Rotate immediately if a key ever lands anywhere it should not: a repository, a log file, a chat
message, browser code, or a crash report.

## Your publishable brand key

The publishable key is the one credential meant to live in a public page bundle. It is issued per
**brand** — not per client — and it reaches exactly two read-only operations: your brand's
storefront price read and its readiness read. Every other operation, and every write, is refused.

It is shown once at issue, like the API key, and replacing it is the same act: a new key is minted
for the brand and every previous key for that brand is revoked. As with the API key, that takes
effect **within one 30-second cache window** rather than instantly — a replaced publishable key can
still be accepted until the window closes. It is not a secret, so a leaked
value is not an incident — but it is still brand-scoped capability, so replace it if it ends up
somewhere you did not intend.

A publishable key only works from an origin registered on your brand's browser-origin allowlist.
[Authentication](/pages/authentication) covers both halves.

## Your webhook signing secret

When a webhook endpoint is registered — either during onboarding or by your own call to
`POST /v1/webhooks/registrations` — the platform generates a signing secret (`psig_...`) and
returns it **once, in the creation response**. Every delivery to your endpoint carries a
signature computed with it, so your receiver can verify that events really come from the
platform.

The same show-once rule applies: registration reads (`GET /v1/webhooks/registrations`) confirm a
secret exists but never return its value. To replace a signing secret, delete the registration
and create a new one — you get a fresh secret in that creation response, and signatures made
with the old one stop being produced.

## Handling rules

* Keep both secrets **server-side only**: environment variables or a secret manager, never
  browser code, mobile apps, or public repositories.
* Scope access narrowly — the API key authenticates your whole client account.
* Log request outcomes, not credentials. If your framework logs headers, redact
  `Authorization`.
* Use your test-scoped credentials everywhere except your production deployment.
