Skip to content
Docs/API

API keys

Sapient issues two kinds of API key. They look similar and they are not interchangeable — each one works on exactly one API and is rejected on the other.

PublishableSecret
Looks likedfpk_…dfsk_…
Belongs inyour browser bundleyour server, and nowhere else
Used bythe bug-reporting API (/ingest/v1/*)the contacts API (/api/v1/*)
Sent asX-Sapient-Key header, or ?key=Authorization: Bearer (or X-Sapient-Key) — never a query parameter
Bound tothe website origins you listnothing — it works from any server, so treat it like a password
If it leaksannoying: revoke and re-issueserious: revoke immediately
  • “I want errors and user feedback from my website.” → publishable key, bug reporting.
  • “My backend needs to push contacts/leads into the CRM.” → secret key, contacts.
  • “I’m writing a script that runs on my laptop / in CI.” → that’s a server. Secret key.
  • “I want to call the contacts API from a web page.” → you don’t. The contacts API refuses any request that carries a browser Origin header, precisely so a secret key can’t end up in client code and quietly keep working. Put the call behind your own endpoint.

Settings → API keys in the control room, where the two types have their own cards. Or from the CLI, against a factory you administer.

Creating a key requires the factory.update permission, and both creation and revocation are recorded in your factory’s audit log.

Give the key a name and list the website origins allowed to use it — https://app.acme.com, https://acme.com. Requests from anywhere else are rejected. Leaving the list empty means “any origin”; that’s fine while you’re wiring things up locally and a bad idea in production.

Give the key a name. That’s all — there is no origin list, because a browser origin is not a server-side control and pretending otherwise would imply a protection that doesn’t exist. (If you pass one anyway, the API returns an error rather than silently dropping it.)

At creation you get the full key exactly once. Sapient stores only a SHA-256 hash of it, so nobody — including us — can show it to you again. Copy it into your secret manager before you close the dialog.

If you lose it, revoke it and create another. That’s cheaper than any alternative.

The keys list shows a display prefix (dfsk_ab12cd34…), when the key was last used, and whether it’s been revoked. Those are safe to share; the key itself never is.

  • Environment variable or a secret manager. Not in your repository, not in a client bundle, not in a URL.
  • Query strings end up in access logs, proxy logs, and Referer headers — which is why the contacts API doesn’t read keys from them at all. A key passed that way isn’t a weak credential; it’s simply not authentication, and you’ll get a 401.
  • One key per system that calls us — your API server, your CRM sync job, your CI — so you can revoke one without taking down the rest.

Revoke from the same Settings card. A revoked key stops working within a minute — immediately on most requests, and at worst after a short cache window (up to 60 seconds) on servers that had recently seen the key. It never comes back.

If a key is actively being abused, revoke it and rotate whatever it could reach; don’t wait on the window.

Revoke when: someone leaves, a key appears in a log or a screenshot, a key shows up in a client bundle, or you simply don’t know where a key is anymore. Revocation is free.

Each key has its own budget, and there are separate per-IP limits.

Default
Publishable key6,000 requests/minute (100/s)
Secret key30,000 requests/minute (500/s)

Exceeding a limit returns 429 with a Retry-After header telling you how many seconds until the window rolls over. Honor it — see errors and limits.

Both key types are data-plane only. A key authenticates one documented API for one factory, and nothing else: it can’t read your control room, can’t manage other keys, can’t act as you, and can’t reach any other factory. Even a secret key is far less powerful than your own login — which is the point. Key management itself always requires a signed-in human.