API keys: scopes, expiry, revocation
Everything against sandbox-api.k8s.tangovision.dev authenticates with an org-scoped tvk_… bearer token. You mint keys in the developer portal; the plaintext is shown exactly once. This page is the reference for how keys behave.
Two invariants first:
- A key can never mint another key. Minting requires a signed-in portal session, so a leaked key can't multiply itself.
- Up to 5 active keys per org. Revoked and expired keys don't count — revoke what you don't use.
Scopes
Every key carries one scope, chosen at mint time:
| Scope | Allows | Use it for |
|---|---|---|
sandbox (default) | The sandbox lifecycle API (/api/v1/sandboxes*): create, list, extend, reset, delete | Day-to-day module development, CI that provisions sandboxes |
publish | The module-publish surface (arrives with tv-sdk publish; no endpoint accepts it yet) | Release pipelines, once publishing ships |
full | Everything above, plus key listing and revocation over the API | Break-glass automation; prefer the narrower scopes |
A request outside your key's scope fails with 403 and the error code SCOPE_DENIED — mint a key with the right scope rather than widening an existing workflow's key. Keys minted before scopes existed behave as full.
Expiry
Self-service keys always expire — after 90 days by default. Minting through the API instead of the portal, you can pick the lifetime:
curl -X POST https://sandbox-api.k8s.tangovision.dev/api/v1/keys \
-H "Authorization: Bearer $PORTAL_JWT" \
-H "Content-Type: application/json" \
-d '{"label": "ci", "scope": "sandbox", "expiresInDays": 30}'expiresInDays accepts 1–365. An expired key gets 401 on its next request; mint a replacement in the portal (the key list shows each key's expiry date, and its status flips to expired). Non-expiring keys exist only as operator-minted credentials — ask developers@tango.vision if a service genuinely needs one.
Revocation
Revoke in the portal, or over the API:
curl -X DELETE https://sandbox-api.k8s.tangovision.dev/api/v1/keys/<keyId> \
-H "Authorization: Bearer $PORTAL_JWT"Revocation is effective on the key's next request — every request re-checks the key store directly, with no cache in between, so the observed propagation delay is however long your next request takes to arrive. (The platform's formal commitment is under 5 minutes globally; in practice it's seconds.) If a key leaks, revoke it immediately and mint a replacement — and tell us, so we can check the audit trail with you.
Audit trail
Every key event is recorded: issuance (who minted, which scope, what expiry), use (each authenticated request: key, route, source IP, user agent), denials (revoked/expired/unknown keys, scope violations), and revocation. Records are kept for 18 months.
From a portal session you can query your org's trail:
curl "https://sandbox-api.k8s.tangovision.dev/api/v1/keys/audit?limit=50" \
-H "Authorization: Bearer $PORTAL_JWT"Filters: action (key.issued | key.used | key.revoked), keyId, limit (≤ 500). The audit log is readable only from a signed-in portal session — an API key can't read it, deliberately: the rows contain IP addresses, which have no business sitting behind a CI secret.