create-service-account-token
dci create-service-account-token [body] [flags]
Mints an API token for the service account and returns its accessToken once. The token
inherits the service account's permissions as they stand at creation; there is no per-token
scoping. Returns 409 when the service account already has a token of the same name, and
422 at the cap of 10 tokens.
dryRun=true checks the name bounds only, then returns a preview without creating anything.
It does not verify that the service account exists, that the name is unused, or that the
account is under the token cap, so a dry run can succeed where the real create then returns
404, 409 or 422. Requires the serviceAccountCreator permission.
Pass the request body as name: value arguments or pipe JSON on stdin — see Command structure.
The accessToken in the create response is the credential that authenticates as the service
account. It is returned only by this operation and can never be retrieved again, so store it
somewhere safe on receipt and treat it like a password. Later get and list calls never
include it; if it is lost, create a new token and delete the old one.
name is required (1-100 characters, no leading or trailing whitespace) and unique among
the account's tokens (409). The token inherits the service account's permissions as they
stand at creation; there is no per-token scoping. An account holds at most 10 tokens (422
at the cap). Requires the serviceAccountCreator permission, and the API requires an
Idempotency-Key on every real call.
--dry-run sends the API's dryRun=true, which checks only the name bounds: it does not
verify that the service account exists, that the name is unused, or that the account is
under the cap, so a dry run can succeed where the real create returns 404, 409 or 422.
The preview response has accessToken as an empty string.
Examples
# Mint a token that expires on a given date. Run it with --output json and store the `accessToken` in a secret manager at once.
dci create-service-account-token <service-account-id> name: ci-pipeline-prod, expiresTime: "2027-09-01T08:00:00Z" --idempotency-key "$(uuidgen)" --output json
# Mint a token with the server's default expiry.
dci create-service-account-token <service-account-id> name: ci-pipeline-prod --idempotency-key "$(uuidgen)"
# Check the name server-side first; nothing is created.
dci create-service-account-token <service-account-id> name: ci-pipeline-prod --dry-run
Request
Content-Type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Name, unique among the service account's tokens. Leading or trailing whitespace returns 400. |
expiresTime | string (date-time) | When the token should stop authenticating. Omit to let the server set the default expiry. |
Example body (JSON)
{
"name": "ci-pipeline-prod",
"expiresTime": "2027-09-01T08:00:00Z"
}
Raw JSON schema
{
"type": "object",
"description": "Fields of a new API token.",
"required": [
"name"
],
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "Name, unique among the service account's tokens. Leading or trailing whitespace returns `400`.",
"example": "ci-pipeline-prod"
},
"expiresTime": {
"type": "string",
"format": "date-time",
"description": "When the token should stop authenticating. Omit to let the server set the default expiry.",
"example": "2027-09-01T08:00:00Z"
}
}
}
Flags
| Flag | Type | Default | Example | Description |
|---|---|---|---|---|
--dry-run | boolean | false | If true, validates the request and returns the would-be result without applying it. The response then carries the X-Dry-Run header. |
Every command also accepts the CLI-wide flags for output shaping — see Output formats and Table output options.
Output
OK - Dry run only (dryRun=true). The name passed its bounds check and nothing was created; id and createTime are null and accessToken is an empty string. Not a guarantee that a real create would succeed — see the operation description.
By default dci renders the result as a table. Use --output json to get the full structure described below — see Output formats.
| Field | Type | Description |
|---|---|---|
accessToken | string (password) | The token credential, and the secret that authenticates as this service account. Returned only by this operation and never retrievable again, so store it somewhere safe on receipt; an empty string on a dry-run create. Treat it like a password. |
id | string | API token ID. null only on a dry-run create. |
serviceAccountId | string | ID of the service account that owns the token. |
customerId | string | ID of the customer whose service account the token belongs to. |
name | string | Name, unique among the service account's tokens. |
state | string | The token's stored state: active while it is enabled, disabled once it has been turned off. This is not a liveness signal — a token whose expiresTime has passed stops authenticating but keeps the state it was stored with, so active here does not by itself mean the token still works; compare expiresTime. Only these two values can be set. One of: "active", "disabled". |
createTime | string (date-time) | When the token was created. null only on a dry-run create. |
expiresTime | string (date-time) | When the token stops authenticating. null when it does not expire. |
lastUsedTime | string (date-time) | When the token last authenticated a request. null until it is first used. |
Example response (--output json)
{
"id": null,
"serviceAccountId": "Lq3nO9rM5wS2tU0xY4zA",
"customerId": "Kp2mN8qL4vR0sT1wX3yZ",
"name": "ci-pipeline-prod",
"state": "active",
"createTime": null,
"expiresTime": "2027-09-01T08:00:00Z",
"lastUsedTime": null,
"accessToken": ""
}
Raw JSON schema
{
"description": "A newly created API token, together with the credential that authenticates as it.",
"allOf": [
{
"type": "object",
"description": "An API token of a service account. It authenticates with the service account's permissions, and carries no secret material after the create response.",
"required": [
"id",
"serviceAccountId",
"customerId",
"name",
"state",
"createTime",
"expiresTime",
"lastUsedTime"
],
"properties": {
"id": {
"type": "string",
"nullable": true,
"readOnly": true,
"description": "API token ID. `null` only on a dry-run create.",
"example": "Mr0sN7pQ4tU2vW5xY8zC"
},
"serviceAccountId": {
"type": "string",
"readOnly": true,
"description": "ID of the service account that owns the token.",
"example": "Lq3nO9rM5wS2tU0xY4zA"
},
"customerId": {
"type": "string",
"readOnly": true,
"description": "ID of the customer whose service account the token belongs to.",
"example": "Kp2mN8qL4vR0sT1wX3yZ"
},
"name": {
"type": "string",
"description": "Name, unique among the service account's tokens.",
"example": "ci-pipeline-prod"
},
"state": {
"type": "string",
"enum": [
"active",
"disabled"
],
"description": "The token's stored state: `active` while it is enabled, `disabled` once it has been turned off. This is not a liveness signal — a token whose `expiresTime` has passed stops authenticating but keeps the state it was stored with, so `active` here does not by itself mean the token still works; compare `expiresTime`. Only these two values can be set.",
"example": "active"
},
"createTime": {
"type": "string",
"format": "date-time",
"nullable": true,
"readOnly": true,
"description": "When the token was created. `null` only on a dry-run create.",
"example": "2026-09-01T08:00:00Z"
},
"expiresTime": {
"type": "string",
"format": "date-time",
"nullable": true,
"description": "When the token stops authenticating. `null` when it does not expire.",
"example": "2027-09-01T08:00:00Z"
},
"lastUsedTime": {
"type": "string",
"format": "date-time",
"nullable": true,
"readOnly": true,
"description": "When the token last authenticated a request. `null` until it is first used.",
"example": "2026-09-20T14:31:00Z"
}
}
},
{
"type": "object",
"required": [
"accessToken"
],
"properties": {
"accessToken": {
"type": "string",
"format": "password",
"readOnly": true,
"description": "The token credential, and the secret that authenticates as this service account. Returned only by this operation and never retrievable again, so store it somewhere safe on receipt; an empty string on a dry-run create. Treat it like a password.",
"example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.example.signature"
}
}
}
]
}
Errors
On failure, dci prints a single error message — with a hint when one is available — and exits with a typed code your scripts can branch on. See Errors and exit codes for the full contract.
HTTP status to exit code mapping
| HTTP status | Exit code | Error code | Meaning |
|---|---|---|---|
| 400, 422 | 30 | VALIDATION_ERROR | The arguments or request body were rejected. Review the command's flags and payload. |
| 401 | 10 | AUTHENTICATION_FAILED | Not signed in, or the API token is invalid. Run dci login or check DCI_API_KEY. |
| 403 | 11 | PERMISSION_DENIED | The DoiT user or the active customer context does not have access. |
| 404 | 20 | RESOURCE_NOT_FOUND | The requested resource does not exist. Check the identifier argument. |
| 409 | 21 | RESOURCE_CONFLICT | The operation conflicts with the resource's current state. |
| 500 | 40 | API_SERVER_ERROR | The API failed to process the request. Retryable; contact DoiT support if it persists. |
Related
- list-service-account-tokens — List API tokens for a service account
- get-service-account-token — Get an API token
- update-service-account-token — Enable or disable an API token
- delete-service-account-token — Delete an API token
- create-service-account — Create a service account
- API reference: POST /iam/v1/service-accounts/{serviceAccountId}/api-tokens
Aliases: createserviceaccounttoken