update-service-account
dci update-service-account [body] [flags]
Partially updates a service account with an application/merge-patch+json body (RFC 7396). Omitted or null fields stay unchanged; an explicit empty string clears description. permissions replaces the whole list, and [] removes every permission. With dryRun=true the request goes through the same checks as a real update (If-Match, name bounds and uniqueness, permission names, caller scope) and returns the service account as it would look after the patch, without changing anything. Requires the serviceAccountManager permission.
Pass the request body as name: value arguments or pipe JSON on stdin — see Command structure.
Send any of name, description and permissions; the body is a JSON Merge Patch, so
omitted or null fields stay unchanged. An empty string clears description, and
permissions replaces the whole list ([] removes every permission). Requires the
serviceAccountManager permission.
The API requires If-Match with the current ETag, from the etag field of dci get-service-account or of a create or update response. A stale value returns 412:
re-read the account and retry with the new ETag. It also requires an Idempotency-Key
(retrying with the same key returns the stored response; keys are kept for 24 hours).
--dry-run sends the request with the API's dryRun=true and runs the same checks as a real
update (If-Match, name bounds and uniqueness, permission names, caller scope). When you
omit --idempotency-key under --dry-run, the CLI generates a throwaway one.
Examples
# Replace the permissions, passing the ETag from `dci get-service-account` (the list you send is the whole new list).
dci update-service-account <service-account-id> permissions: [cloudAnalyticsReadOnly] --if-match <etag> --idempotency-key "$(uuidgen)"
# Preview the result server-side first; the response shows the account as it would look and nothing changes.
dci update-service-account <service-account-id> name: terraform-prod --if-match <etag> --dry-run
# Clear the description.
dci update-service-account <service-account-id> description: "" --if-match <etag> --idempotency-key "$(uuidgen)"
Request
Content-Type: application/merge-patch+json
| Field | Type | Required | Description |
|---|---|---|---|
name | string | New name, unique among the customer's service accounts. Leading or trailing whitespace returns 400. | |
description | string | New free-text description. null leaves it unchanged; an explicit empty string clears it. | |
permissions | array of string | Replaces the whole permission list. An unknown name returns 422. |
Example body (JSON)
{
"permissions": [
"cloudAnalyticsReadOnly"
]
}
Raw JSON schema
{
"type": "object",
"description": "Fields to change on a service account, as a JSON Merge Patch document.",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "New name, unique among the customer's service accounts. Leading or trailing whitespace returns `400`.",
"example": "terraform-ci"
},
"description": {
"type": "string",
"nullable": true,
"description": "New free-text description. `null` leaves it unchanged; an explicit empty string clears it.",
"example": "Manages DoiT resources from CI"
},
"permissions": {
"type": "array",
"nullable": true,
"description": "Replaces the whole permission list. An unknown name returns `422`.",
"items": {
"type": "string"
}
}
}
}
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 - Service account updated, or previewed when dryRun=true (the body is the merged result, and etag is still the current one).
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 |
|---|---|---|
id | string | Service account ID. null only on a dry-run create. |
customerId | string | ID of the customer that owns the service account. |
name | string | Name, unique among the customer's service accounts. |
description | string | Free-text description. |
permissions | array of string | Platform permission names in camelCase, as shown in the DoiT console role editor. |
createdBy | string | Display name of the user who created the service account. null when unknown or when the service account was created with a service account token. |
createdByEmail | string | Email of the user who created the service account. null when unknown or when the service account was created with a service account token. |
createdByUserId | string | ID of the user who created the service account. null when unknown or when the service account was created with a service account token. |
createTime | string (date-time) | When the service account was created. |
updateTime | string (date-time) | When the service account was last changed. |
etag | string | Current version of the service account. Send it in If-Match to update or delete. |
Example response (--output json)
{
"id": "Lq3nO9rM5wS2tU0xY4zA",
"customerId": "Kp2mN8qL4vR0sT1wX3yZ",
"name": "terraform-ci",
"description": "Manages DoiT resources from CI",
"permissions": [
"cloudAnalyticsReadOnly"
],
"createdBy": "Jane Doe",
"createdByUserId": "Ab1cD2eF3gH4iJ5kL6mN",
"createTime": "2026-09-01T08:00:00Z",
"updateTime": "2026-09-02T09:30:00Z",
"etag": "9b2e4d6f8a0c1e3b5d7f9a1c3e5b7d9f1a3c5e7a9b1d3f5a7c9e1b3d5f7a9c1e"
}
Raw JSON schema
{
"type": "object",
"description": "A non-human identity owned by a customer. Its API tokens authenticate with exactly the permissions listed here.",
"required": [
"id",
"customerId",
"name",
"description",
"permissions",
"createdBy",
"createdByEmail",
"createdByUserId",
"createTime",
"updateTime",
"etag"
],
"properties": {
"id": {
"type": "string",
"nullable": true,
"readOnly": true,
"description": "Service account ID. `null` only on a dry-run create.",
"example": "Lq3nO9rM5wS2tU0xY4zA"
},
"customerId": {
"type": "string",
"readOnly": true,
"description": "ID of the customer that owns the service account.",
"example": "Kp2mN8qL4vR0sT1wX3yZ"
},
"name": {
"type": "string",
"description": "Name, unique among the customer's service accounts."
},
"description": {
"type": "string",
"description": "Free-text description."
},
"permissions": {
"type": "array",
"description": "Platform permission names in camelCase, as shown in the DoiT console role editor.",
"items": {
"type": "string"
}
},
"createdBy": {
"type": "string",
"nullable": true,
"readOnly": true,
"description": "Display name of the user who created the service account. `null` when unknown or when the service account was created with a service account token."
},
"createdByEmail": {
"type": "string",
"nullable": true,
"readOnly": true,
"description": "Email of the user who created the service account. `null` when unknown or when the service account was created with a service account token."
},
"createdByUserId": {
"type": "string",
"nullable": true,
"readOnly": true,
"description": "ID of the user who created the service account. `null` when unknown or when the service account was created with a service account token."
},
"createTime": {
"type": "string",
"format": "date-time",
"nullable": true,
"readOnly": true,
"description": "When the service account was created."
},
"updateTime": {
"type": "string",
"format": "date-time",
"nullable": true,
"readOnly": true,
"description": "When the service account was last changed."
},
"etag": {
"type": "string",
"nullable": true,
"readOnly": true,
"description": "Current version of the service account. Send it in `If-Match` to update or delete."
}
}
}
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. |
| 412, 415, 428 | 1 | API_ERROR | The request failed; the printed error message has details. |
| 500 | 40 | API_SERVER_ERROR | The API failed to process the request. Retryable; contact DoiT support if it persists. |
Related
- get-service-account — Get a service account
- list-service-accounts — List service accounts
- create-service-account — Create a service account
- delete-service-account — Delete a service account
- list-service-account-tokens — List API tokens for a service account
- API reference: PATCH /iam/v1/service-accounts/{id}
Aliases: updateserviceaccount