Keys & scoping

Last updated Aug 12, 2026View as MarkdownAgent setup

Two kinds of key, one hard rule: money is server-authoritative.

sk_live_ (server)pk_live_ (public)
Behavioral events✓ (rate-limited)
payment events
/v1/objects (subscriptions)
Read APIs

pk_live_ keys are designed to ship inside binaries: Expo bundles, Swift apps, Electron builds. Assume they will be extracted; that's fine, because a public key can only ever write behavioral events. Nobody who pulls your key out of an IPA can touch the revenue or MRR you show your investors.

Revenue never legitimately originates client-side: your server (or your biller's webhook) is where money truth lives, so that's the only place that can write it.

Rotation: revoke in the dashboard; propagation to the edge takes ≤60 seconds. Keys are shown in full exactly once, at creation.

Test and live are separate environments

Every key also carries an environment, baked into the same prefix: sk_test_ / pk_test_ for test, sk_live_ / pk_live_ for live. The capability rules above hold unchanged inside each one: an sk_test_ key writes payment events in test, and a pk_test_ key is behavioral-only and just as safe to ship as pk_live_.

What the prefix buys you is isolation. Test keys write to, and test reads come from, a different project_id than live. The boundary is structural, not conventional: a request is routed to its plane by the key's own material, server-side, so a test key can never touch live data and a live key can never touch test. There is no environment flag to pass, and none to get wrong.

Test data follows the same retention as live: events age out at 90 days, payments are kept. The test environment is org-shared, not per-developer, and provisioned lazily: it comes into being the first time you switch an app into test mode or mint a test key, and stays empty until you send it a first event.

To read test metrics over the API, an sk_test_ key is scoped to the app's test plane, so the project is implied. A dg_test_ + metrics:read control token is org-scoped, so it names the test project explicitly: ?project=proj_... (the test project's id). A dg_live_ token reads live projects only (see below).

Control tokens are a third class

sk_live_ and pk_live_ are app-scoped data-plane keys: they send events and read metrics for one app. Managing apps and keys themselves is a separate credential: the org-scoped dg_ control token, which mints those keys over HTTP. It carries explicit scopes and never touches ingest. See the Control API.

Control tokens are plane-confined, the same as data keys. A dg_live_ token reads live metrics and mints live keys; a dg_test_ token, minted from the dashboard in test mode, reads only test metrics and mints only test keys. Neither crosses into the other plane, and a dg_test_ token cannot create apps (apps are created with a live token, and their first key is an sk_live_).