Overview
Control-plane credentials for automation. Distinct from management keys (shipd_mgmt_) and SDK keys (shipd_sdk_).
Related: Create a service account.
Format
Authorization: Bearer shipd_sa_… or x-api-key.
Scopes
Scopes are{ resource: [verbs] } matching the RBAC statement (e.g. { "flag": ["read", "create"] }). Empty scopes are rejected. A token cannot receive verbs the minting admin does not have.
me always works so the CLI can resolve org (and project/environment when bound).
Binding
Environment-bound tokens only receive rows for their environment. They cannot create environments,
perform project-wide flag definition changes, manage organization-wide approval policies, or request
a project-wide snapshot rebuild. Resource IDs are resolved inside the token’s organization and are
checked again against both the project and environment binding.
Lifecycle
Revocation preserves the token’s audit history.
Repeated revoke requests succeed, so callers may safely retry them.
rotateToken atomically creates
a replacement with the same scopes and bindings and revokes the old token. The replacement plaintext
is shown once; use a brief overlap only when the client can install the new credential before revoking
the old one manually.
Rotation
Create a second token with the same minimal scopes and bindings, update the consumer’s secret store, verify one successful authenticated operation, then revoke the old token. Because plaintext is shown only once, a lost token cannot be recovered—rotate it. Disable the service account when every token must stop immediately.Audit
Mutations made with a token recordactorType: service_account and actorId = the service account id. tokenId identifies which token.
Lifecycle events: serviceAccount.created, serviceAccount.updated, serviceAccount.disabled, serviceAccount.enabled, serviceAccount.deleted, serviceAccount.token.created, serviceAccount.token.revoked, serviceAccount.token.rotated.
Successful mutating requests are audited with the token id. Successful authentication also records
serviceAccount.token.used when lastUsedAt advances, at most once per minute. This makes the field
a useful activity signal without turning the audit log into a request counter.
Service-account tokens are control-plane-only. SDK routes accept only shipd_sdk_ credentials.