> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useshipd.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Service account tokens

> shipd_sa_ token format, scopes, binding, expiry, and audit attribution.

## Overview

Control-plane credentials for automation. Distinct from management keys (`shipd_mgmt_`) and SDK keys (`shipd_sdk_`).

Related: [Create a service account](/enterprise/service-accounts).

## Format

```
shipd_sa_{base64url}
```

The secret is returned only once on create. Store it securely; a lost token cannot be recovered.

Send it as `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

| Binding | Effect |
| - | - |
| None | Org-wide. Pass `--project` / `--env` (or `SHIPD_PROJECT` / `SHIPD_ENV`) for commands that need them. |
| Project | Requests that name another project are `403`. |
| Project + environment | Requests that name another environment are `403`. |

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

| State | Auth result |
| - | - |
| Revoked | `401` |
| Expired | `401` |
| Account disabled | `401` |

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 record `actorType: 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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.