Skip to Content
SecurityAPI keys

API keys

Three kinds of credentials, three threat models.

pk_ — Publishable

  • Designed to ship to the browser. Sent as the X-Client-ID header on every signed B2B request, also embedded in the SDK bundle for client-side checkout opens.
  • Can identify your account; cannot create sessions, read other merchants’ data, or trigger anything destructive.
  • A leaked publishable key is a low-severity event.

sk_ — Secret (HMAC signing key)

  • The HMAC-SHA256 signing key for all B2B API calls — see Authentication.
  • Never travels over the wire. Only its derived per-request signature does. So you only have to worry about leaks at the storage layer (env vars, git, logs), not at the transport layer.
  • Server-only. Should never appear in a browser bundle, public repo, screenshot, or chat message.
  • A leaked secret is a high-severity event.

whsec_ — Webhook signing secret

  • Used to verify the signature on inbound webhook deliveries from us to your server. See Signature verification.
  • Separate per webhook endpoint — if you have 3 registered endpoints, you have 3 distinct whsec_ secrets. Environment is encoded in the prefix: whsec_live_… / whsec_test_….
  • Server-only. Like sk_, never travels over the wire — only used to verify HMACs locally.
  • Rotation has a 24-hour grace window. Click Rotate and the previous secret stays accepted for 24h alongside the new one (deliveries carry both X-Signature and X-Signature-Prev), so you can redeploy your verifier without holding traffic.
  • Reveal-existing-secret is available, gated by fresh 2FA and recorded in the audit log — for the case where the secret was lost and rotation isn’t acceptable. The dashboard’s default posture is “rotate, don’t reveal”.
  • A leaked webhook secret lets an attacker fake events to your URL. Medium-to-high severity depending on how much you trust the event payload.

Scopes

Secret keys are scoped. The dashboard lets you mint keys with one of these scope bundles:

ScopeCan doUsed for
readList/read orders, sessions, refunds, balancesRead-only integrations (analytics, BI)
write_orderAll read + create sessions, create orders, cancel ordersStorefront backend
write_refundAll read + create refunds, mark refunds executedCustomer support tools
webhook_manageAll read + manage webhook endpointsDevOps tooling

A default-mint “full access” key gets all four. Minting per-purpose keys is still good hygiene — it documents intent and gets you ready for enforcement when it lands — but read the caveat below before you treat scope as a security boundary.

Scopes are advisory today — they are not enforced at the gateway. The gateway verifies the key’s HMAC signature and injects your merchant identity (X-Merchant-ID / X-Merchant-Domain) to downstream services, but it does not propagate or check the key’s scope. In practice that means a leaked sk_ of any scope can call any /b2b/v1/* endpoint for your merchant — a read key is not actually prevented from creating a refund. So narrow scopes do not limit blast radius yet: for breach planning treat every secret key as full-access, and rely on fast rotation + revocation (below) as your real containment. Per-scope enforcement is on the roadmap.

Rotation

  1. Generate a new key. Dashboard → Developers → API keys+ Add key. Pick scope. The dashboard displays the secret once — store it immediately.
  2. Roll your env vars to the new value across all environments. Deploy.
  3. Verify traffic. Dashboard shows per-key request counts in real time. Wait for the old key’s count to drop to zero.
  4. Revoke the old key. Same screen → kebab menu → Revoke.

There is no automatic overlap window today — once you revoke a key, any in-flight request signed with it gets 401. Plan your rotation accordingly: deploy the new key first, drain traffic from the old, then revoke.

Emergency revocation

If a key has leaked (in git history, in a public bundle, in a logged stack trace, in a partner’s pen-test report) — revoke it immediately, even at the cost of some failed requests. Better to fail loudly than to let an attacker hold a valid credential.

Steps:

  1. Dashboard → Developers → API keys → [key] → Revoke now. Effect is instant; no grace period.
  2. Mint a replacement and deploy.
  3. Audit recent activity — dashboard shows the last 30 days of requests per key with IPs and endpoints hit.

If you suspect the breach is broader than one key, contact [email protected] to:

  • Get a full audit log export for your merchant account
  • Rotate webhook secrets in bulk
  • Optionally freeze the account while you investigate

Storage best practices

  • Env vars only. Never commit secrets to git, even in a .env.example that says “REPLACE ME”.
  • Per-environment keys. Different sk_test_… and sk_live_… for dev/staging/prod, sourced from your secrets manager (AWS Secrets Manager, Vault, Doppler, …).
  • Restrict env var access. In Kubernetes, mount as a Secret, not a ConfigMap. In Vercel/Netlify, use environment-variable scoping not project-wide globals.
  • Don’t log requests with bodies. Even when debugging — your HMAC signature in X-Signature is single-use but your business payload may include PII.

What’s NOT supported today

  • IP allowlisting for secret keys. On the roadmap.
  • OAuth-style scoped per-user tokens. The current key model is per-merchant, not per-user.
  • Automatic key rotation (e.g. weekly rotation enforced by the platform). Manual today.

What’s next