Control API
Everything you can do in the dashboard — create an app, mint its keys, set a webhook secret — you can do over HTTP. An agent can run the whole loop headlessly: create an app, get a key, send events, read the numbers back.
The dg_live_ token
The control plane uses a third credential class, separate from the data-plane
keys. A dg_live_ token is org-scoped: it manages
every app in one organization. It is not an sk_live_ key and does not work on
ingest; an sk_live_ key does not work here.
You mint the first one in the dashboard, at Organization → Control API keys.
It is shown in full exactly once. Store it in a secret; there is no way to read
it back. dg_test_ is reserved for a future test mode.
curl -X POST https://api.datagauge.dev/v1/apps \
-H "Authorization: Bearer $DATAGAUGE_CONTROL_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"My SaaS"}'Endpoints
| Method | Path | Scope | Returns |
|---|---|---|---|
POST | /v1/apps | apps:write | 201 app + sk_key (once) |
GET | /v1/apps | apps:read | 200 app list |
GET | /v1/apps/{id} | apps:read | 200 app |
PATCH | /v1/apps/{id} | apps:write | 200 app |
POST | /v1/apps/{id}/keys | keys:write | 201 {key_id, key} (once) |
GET | /v1/apps/{id}/keys | keys:read | 200 masked keys |
DELETE | /v1/apps/{id}/keys/{key_id} | keys:write | 204 (revoke) |
PUT | /v1/apps/{id}/webhooks/{provider} | webhooks:write | 204 |
Rotating a key is POST a new one, then DELETE the old. The webhook endpoint
is write-only: provider is stripe or polar, and the secret is never read
back, here or anywhere.
Scopes
A token carries an explicit scope set, fixed when you mint it. Scopes never
imply one another — apps:write does not grant keys:write. The full set:
| Scope | Grants |
|---|---|
apps:read | list and read apps |
apps:write | create apps and change their settings |
keys:read | list an app's ingest keys (masked) |
keys:write | mint and revoke ingest keys |
webhooks:write | set Stripe / Polar signing secrets |
metrics:read | read /v1/metrics/* for any app in the org |
You can only mint a token carrying scopes your own role already holds. A wrong
scope returns 403.
Key material is shown once
POST /v1/apps returns an sk_key and POST /v1/apps/{id}/keys returns a
key. That is the only time you ever see the full value. Every read path
returns a masked form. Lose it and the only fix is to mint a replacement and
revoke the old one.
404, not 403
An app that belongs to another org, an id that never existed, and a malformed
id all return the same 404 — as does a key id that belongs to a different app.
This is deliberate: a 403 would confirm the id is real, which turns the API
into an existence oracle. If you are sure an id is right, check that your token
belongs to the org that owns the app.
The whole control plane, with request and response schemas, is in
/openapi.json (OpenAPI 3.1).