Identity & Access Management

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 an API token (secret revealed once)

POST
/scopes/{scopeId}/iam/api-tokens

Token callers: a pc_live_ token (needs iam:write) may only mint a token whose scopes it holds itself -- otherwise 403 FORBIDDEN with details.reason TOKEN_SCOPE_MISSING and the excess scopes in missingTokenScopes, before any row is written. The child must also stay inside the minting token's fences: it expires no later (never only when the minting token never expires) and, when the minting token has an ipAllowlist, carries a non-empty allowlist inside it -- otherwise 403 FORBIDDEN TOKEN_FENCE_EXCEEDED (tokenFence: expiry | ipAllowlist | identity). Creates a new API token for programmatic access (HTTP API, CI/CD) using the API token creation form: token name, one or more permission scopes from the scope catalogue, an expiry policy (30/60/90 days, never, or a custom date), and an optional IP/CIDR allowlist (the "Add range" control). On success the token is persisted in ACTIVE status, becomes discoverable in the scoped token list, and the response carries the full secret exactly once — it is never retrievable again from any read endpoint, only the prefix is. Validation: name must match ^[a-z0-9][a-z0-9-]{1,62}$ (lowercase letters, digits, hyphens, 2–63 chars) and be unique within the scope (duplicate → CONFLICT 409); scopes must be a non-empty subset of the token scope catalogue (e.g. compute:read, billing:read); expiry must be one of 30|60|90|never|custom, and customDate is required (a future ISO date) when expiry=custom and may be at most 365 days from today (UTC; the platform's api_token_max_lifetime_days) — a later date is VALIDATION_FAILED (422, field: customDate, details.reason: token_lifetime_exceeds_maximum, with details.maxLifetimeDays / details.latestCustomDate); never stays allowed; each ipAllowlist entry must be a valid IPv4 address or CIDR block; violations map to VALIDATION_FAILED (422). The caller must hold a role permitted to mint tokens (owner|admin|contributor). Async & state: Synchronous create returning 201 with { token, secret }; the token is born ACTIVE with lastUsedAt/lastUsedIp null. A resource.updated SSE frame with kind: iam.api_token announces the new resource to open list views (the secret is never present in SSE frames). Errors: 401 unauthenticated; 403 caller lacks token-creation permission; 409 duplicate token name in the scope (and 409 QUOTA_EXCEEDED semantics if the scope's token quota is exhausted); 422 invalid name, empty scopes, bad expiry/custom date, or malformed CIDR; 500 on backend failure. Idempotency/Concurrency: Idempotency-Key is optional (recommended) for safe retries: a replay with the same key returns the original 201 body — including the original secret — instead of minting a second token.

Step-up: from a console session whose account has two-factor authentication, the factor must have been verified in the last 5 minutes, otherwise 403 MFA_STEP_UP_REQUIRED (verify with POST /auth/step-up, then retry). An API token is not asked; a service-account key is refused (403 INTERACTIVE_SESSION_REQUIRED: a service-account key never performs an IAM write).

Authorization

bearerToken
headerAuthorizationBearer <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.

Path Parameters

scopeId*string

Opaque ownership+authorization scope resolving to tenant + subscription + project.

Header Parameters

Idempotency-Key?string

Optional; recommended for safe retries. When sent, the same key+body within 24h replays the original result and the same key with a different body is 409 CONFLICT; keys are unique per tenant. When an API token or service-account (bearer) caller omits it, the request is applied once with no replay protection (a retry may apply it again). A console session gets one from the edge.

Formatuuid

Request Body

application/json
  1. body

Payload for creating an API token, mirroring the API token creation form.

name*string

Token name — lowercase letters, numbers and hyphens, 2–63 chars, e.g. "ci-deploy-pipeline".

Match^[a-z0-9][a-z0-9-]{1,62}$
scopes*array<>

Permission scopes to grant; must be a non-empty subset of the scope catalogue.

Items1 <= items
expiry*string

Expiry policy — fixed window in days, no expiration, or a custom date.

Value in"30""60""90""never""custom"
customDate?|

Custom expiry date; required when expiry is "custom", otherwise ignored. Must be a future date at most 365 days from today (UTC) — a later date is a 422 VALIDATION_FAILED with details.reason: token_lifetime_exceeds_maximum.

Formatdate
ipAllowlist?array<string>

Allowed source IPs / CIDR ranges; empty or omitted = no restriction.

Response Body

Token created; the full secret is included in this response only and never again.

application/json
  1. response

Create result — the persisted token plus the one-time-reveal secret.

token*

A scoped programmatic API token. The full secret is never present on this schema.

secret*string

The full token secret. Shown exactly once in this response; never retrievable again.

curl -X POST "https://example.com/scopes/string/iam/api-tokens" \  -H "Content-Type: application/json" \  -d '{    "name": "string",    "scopes": [      "compute:read"    ],    "expiry": "30"  }'
{  "token": {    "id": "string",    "name": "string",    "description": "string",    "prefix": "string",    "scopes": [      "string"    ],    "createdBy": "string",    "createdAt": "2019-08-24T14:15:22Z",    "expiresAt": "2019-08-24T14:15:22Z",    "lastUsedAt": "2019-08-24T14:15:22Z",    "lastUsedIp": "string",    "ipAllowlist": [      "string"    ],    "status": "ACTIVE"  },  "secret": "string"}