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)
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).
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?stringOptional; 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.
uuidapplication/json- body
Payload for creating an API token, mirroring the API token creation form.
name*stringToken name — lowercase letters, numbers and hyphens, 2–63 chars, e.g. "ci-deploy-pipeline".
^[a-z0-9][a-z0-9-]{1,62}$scopes*array<>Permission scopes to grant; must be a non-empty subset of the scope catalogue.
1 <= itemsexpiry*stringExpiry policy — fixed window in days, no expiration, or a custom date.
"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.
dateipAllowlist?array<string>Allowed source IPs / CIDR ranges; empty or omitted = no restriction.
Token created; the full secret is included in this response only and never again.
application/json- 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*stringThe 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"}