Preview — pending review
This reference is generated from the platform API contract and is still under review. Operations, fields, and descriptions can change before publication.
Create a service account (optionally minting an initial key)
Key scopes: with createKey: true the initial key carries keyScopes (optional;
omitted = the default key scopes, i.e. the whole ApiTokenScope catalogue minus iam:write). An explicit
empty list is 422 VALIDATION_FAILED (field keyScopes); iam:write is never grantable to a
service-account key (422 VALIDATION_FAILED, field keyScopes, details.reason
iam_write_not_grantable_to_service_account_key). keyScopes is ignored when createKey is false.
Token callers: createKey: true from a pc_live_ token may only request
keyScopes (explicit or defaulted) the token holds itself -- otherwise 403 FORBIDDEN TOKEN_SCOPE_MISSING
(missingTokenScopes), no account created. A key has no IP allowlist, so a token with an ipAllowlist
cannot mint one (403 TOKEN_FENCE_EXCEEDED); a key minted by an expiring token expires with it. Initial
roleIds stay capped by the creator's current role. A service-account key calling this operation gets
403 INTERACTIVE_SESSION_REQUIRED (an SA key never performs an IAM write).
Creates a new machine identity in the active scope from the service account creation form: a lowercase
DNS-label account name (becomes the immutable local part of the email-style ID), an optional description,
an optional set of initial role bindings from the role catalog scoped to the current project, and an
optional "create a key and download the credential" flag. When createKey is true the response carries the
one-time private-key credential exactly once; it can never be retrieved again. On acceptance the account
becomes discoverable in the scoped list.
Validation: name must match ^[a-z]([a-z0-9-]{1,28}[a-z0-9])?$ (3–30 chars, lowercase DNS label) else
422 VALIDATION_FAILED; name must be unique within the tenant else 409 CONFLICT ("An account with this name
already exists"); each entry in roleIds must exist in the role catalog else 422; caller must hold an IAM
admin-capable role (owner|admin) in the scope else 403; per-scope service-account quota is enforced → 409
QUOTA_EXCEEDED.
Async & state: Asynchronous create — returns 202 with the resource in its transitional enabled state
while provisioning completes (or 201 when provisioning is immediate). Emits resource.updated SSE frames
(kind: iam.service_account, patch: {status, keyCount, bindingCount}) as the account, optional initial key and
bindings materialize.
Errors: 401 unauthenticated; 403 caller lacks create permission; 404 scope not found; 409 duplicate name
(CONFLICT) or quota exceeded (QUOTA_EXCEEDED); 422 invalid name/description/roleIds; 500 provisioning failure.
Idempotency/Concurrency: Idempotency-Key required; replaying the same key returns the original result
(including the same one-time credential envelope) without creating a duplicate account.
Step-up: with createKey: true or an owner-ranked roleIds entry, a console
session whose account has two-factor authentication needs the factor verified in the last 5
minutes, otherwise 403 MFA_STEP_UP_REQUIRED (verify with POST /auth/step-up, then retry).
bearerTokenAuthorizationBearer <token>An API token (pc_live_…) or a service-account key (sak_live_…), created in Identity & Access Management and sent as Authorization: Bearer <token>. Requests are rate limited per credential and per tenant: every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, and a refused request gets 429 RATE_LIMITED with Retry-After.
scopeId*stringOpaque ownership+authorization scope resolving to tenant + subscription + project.
Idempotency-Key*stringRequired: this operation creates a new resource asynchronously, so a retry without the key would create a second one. Same key+body within 24h replays the original result; the same key with a different body is 409 CONFLICT. Keys are unique per tenant (the same key in two tenants is two different requests). An API token or service-account (bearer) caller MUST send it -- a request without it is refused with 400 IDEMPOTENCY_KEY_REQUIRED (ErrIdempotencyKeyRequired); reuse the same key on every retry of one logical request. A console session gets one from the edge.
uuidapplication/json- body
The service account creation form payload.
name*stringLowercase DNS label, 3-30 chars; becomes the local part of the email-style ID and cannot be changed later.
^[a-z]([a-z0-9-]{1,28}[a-z0-9])?$description?stringWhat the account is for and who owns it; shown in lists.
length <= 255roleIds?array<string>Initial role bindings granted on the current project, chosen from the role catalog.
createKey?booleanWhen true, mint an initial key and return its one-time credential in the response.
falsekeyScopes?array<>Scopes of the initial key -- optional; omitted with createKey: true = the default key scopes (the ApiTokenScope catalogue minus iam:write); an explicit empty list is 422; ignored when createKey is false. iam:write is never grantable to a service-account key (422).
Service account created synchronously. credential is present only when createKey was true — it is shown exactly once.
application/json- response
Create response. credential is present only when createKey was true and is shown exactly once.
serviceAccount*Machine identity with email-style ID, long-lived keys and scoped role bindings.
key?Long-lived key metadata. Private key material is never present here — it is revealed exactly once at creation.
credential?One-time private-key credential JSON. Returned ONLY by service-account create (with createKey) and key create; never retrievable afterwards and never present in GET/list/export responses.
curl -X POST "https://example.com/scopes/string/iam/service-accounts" \ -H "Idempotency-Key: 497f6eca-6276-4993-bfeb-53cbbbba6f08" \ -H "Content-Type: application/json" \ -d '{ "name": "string" }'{ "serviceAccount": { "id": "string", "name": "string", "email": "string", "arn": "string", "uniqueId": "string", "description": "string", "status": "enabled", "createdAt": "2019-08-24T14:15:22Z", "createdBy": "string", "lastUsedAt": "2019-08-24T14:15:22Z", "keyCount": 0, "bindingCount": 0, "oldestKeyAgeDays": 0, "auth24h": 0, "denied24h": 0 }, "key": { "id": "string", "fingerprint": "string", "createdAt": "2019-08-24T14:15:22Z", "lastUsedAt": "2019-08-24T14:15:22Z", "expiresAt": "2019-08-24T14:15:22Z", "status": "active", "ageDays": 0, "scopes": [ "compute:read" ] }, "credential": { "type": "service_account", "account": "string", "account_id": "string", "private_key_id": "string", "private_key": "string", "secret": "string", "token_uri": "string", "auth_provider": "string", "universe_domain": "string", "region": "string" }}