Every request to the Pivotal API carries an API key in the Authorization header:
Keys are created from Admin > API Keys inside the workspace they should access. There is no OAuth flow, no exchange step, and no signed request scheme — Bearer auth over TLS is the entire mechanism.
The cleartext key is shown exactly once — at create time, in a copy-able banner. Pivotal stores only a PBKDF2-SHA256 hash. Lose the key and you have to create a new one.
The visible key prefix (e.g. pivotal_K8s9) is safe to log and appears on the API Keys page so you can match revoked keys to deployments. The remaining bytes are the secret half.
Common header mistakes that return 401:
Bearer prefix (Authorization: pivotal_…)Bearer: pivotal_…)bearer — Pivotal accepts it, but some intermediaries strip itEvery key is scoped to exactly one workspace (one Pivotal “org”). A key for the vml workspace cannot read or write data in the aurora workspace, and vice versa. There is no cross-workspace key.
Inside a workspace, a key carries full read/write across all resources. There is no per-endpoint or per-resource scoping yet. Treat any key like a workspace admin password.
Pivotal supports concurrent active keys so rotation is zero-downtime:
A revoked key returns 401 authentication_error / api_key_revoked instantly on the next request — there is no grace period.
Don’t:
?api_key=…). The header is the only supported transport, and URL params end up in access logs and referer headers.Do:
dev, staging, prod) so revoking one is surgical.Each key’s row shows last used at, last used IP (where available), and request count. Anything unexpected — a key marked “ci” hitting from a random VPS, a “local-dev” key still active after the laptop was sold — is a signal to revoke.
If a key leaks, revoke first, investigate second. Revoke is one click and reversible (you can re-create a key with the same name); waiting to revoke while you investigate is not.
Outbound webhooks are not yet part of the public API. The placeholder page at Webhooks describes the planned shape. For now, poll the relevant list endpoints with ?cursor= to stay in sync.