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.
Assign the role to a principal at a scope
Grants this role to a principal (user or service account) at a chosen scope level ("Add assignment"
in the role detail page assignments tab — choose a principal and scope). On acceptance the assignment
appears in the role's assignment table (principal, type, scope type, scope) and in the principal's
role list, and the role's member count increases.
Validation: the role must exist and be visible (else 404 NOT_FOUND); principalId must reference
an accessible user or service account in the tenant (unknown → 404 NOT_FOUND); scopeKind must be
one of subscription|project and included in the role's assignableScopes; scopeId must
reference an accessible subscription or project — violations → 422 VALIDATION_FAILED; an
identical principal+scope assignment for this role already existing → 409 CONFLICT.
Async & state: Asynchronous; returns 202 with an Operation (action iam.role.assignment.create)
progressing PENDING → RUNNING → SUCCEEDED once the grant is written and propagated to enforcement
points (FAILED on error). A resource.updated SSE frame with kind iam.role carries the updated
member count; the new assignment row is then visible to subsequent reads.
Errors: 401 unauthenticated; 403 when the caller lacks iam:manage at the target scope; 404 when
the role or principal does not exist; 409 CONFLICT for a duplicate principal+scope assignment;
422 for an invalid scope kind, a scope level outside the role's assignableScopes, or an inaccessible
scope reference; 500 on internal failure.
Idempotency/Concurrency: Idempotency-Key is required; replaying the same key returns the original
202 Operation without granting twice. No If-Match applies to assignment creation.
Step-up: granting an owner-ranked role (built-in owner, or a custom role that
ranks as owner) from 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). Other roles, and an owner row the member already holds, are not
affected.
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.
roleId*stringIdentifier of the role being assigned.
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
Payload for "Add assignment" — grant this role to a principal at a scope.
principalId*stringIdentifier of the user or service account receiving the role.
scopeKind*stringScope level the grant applies to; must be within the role's assignableScopes.
"tenant""subscription""project"scopeId*stringIdentifier of the target subscription or project.
Assignment accepted; returns the tracking Operation.
application/json- response
A long-running operation record. GET /operations/{operationId} returns its current state.
id*stringOperation identifier, unique platform-wide.
action*stringCanonical action id that started this operation, e.g. compute.instance.create.
state*OperationStateState machine for long-running operations. PENDING and RUNNING are transitional; the rest are terminal.
"PENDING""RUNNING""SUCCEEDED""FAILED""CANCELLED"resourceKind?|Kind of the target resource (matches RealtimeEvent.kind), null for resource-less actions.
resourceId?|Identifier of the target resource; null until the resource is allocated.
resourceName?|Human-readable name of the target resource captured when the operation was opened; null when unknown or the resource has been deleted (clients fall back to resourceId).
principalId?|Subject id (user id/email or service-account id) of the actor that initiated this operation, captured at the create chokepoint; null on internal/worker paths with no request-scoped principal or for historical rows. This is the real actor the Activity feed renders.
sourceIp?|Source IP address of the request that initiated this operation; null when unavailable (internal/worker paths, historical rows).
progressPercent?|Best-effort progress; null when the action does not report progress.
0 <= value <= 100error?|nullPopulated only when state is FAILED (or CANCELLED with partial rollback notes).
warning?|nullNon-fatal degradation recorded on an operation that still SUCCEEDED - the primary action completed but something explicitly requested could not be delivered (e.g. publicIp was requested at instance create but no floating IP could be assigned). On a CANCELLED create it reports that the provider resource had already been created and was kept (live and billed until deleted; details.disposition = left_in_place). Same code+message shape as error so clients render both uniformly; null when the operation ran without degradation.
startedAt?|When the worker began executing; null while PENDING.
finishedAt?|When a terminal state was reached; null while transitional.
createdAt*stringupdatedAt*stringcurl -X POST "https://example.com/scopes/string/iam/roles/string/assignments" \ -H "Idempotency-Key: 497f6eca-6276-4993-bfeb-53cbbbba6f08" \ -H "Content-Type: application/json" \ -d '{ "principalId": "string", "scopeKind": "tenant", "scopeId": "string" }'{ "id": "string", "action": "string", "state": "PENDING", "resourceKind": "string", "resourceId": "string", "resourceName": "string", "principalId": "string", "sourceIp": "string", "progressPercent": 0, "error": { "code": "string", "message": "string", "field": "string", "details": {}, "retryable": false }, "warning": { "code": "string", "message": "string", "field": "string", "details": {}, "retryable": false }, "startedAt": "string", "finishedAt": "string", "createdAt": "string", "updatedAt": "string"}