PlanyDocs
API reference

IamService

api.plany.cloud:443Global23 methods

Sign in, manage API keys and service accounts, and decide who may do what. Exchange a password or an API key for a short-lived token with IssueToken, and use that token on every other call. Access is granted by binding roles to people and service accounts on an account, a project or a single resource; CheckPermissions tells you which actions a caller may take.

RegisterUser

plany.iam.v1.IamService/RegisterUser

Registers a new user and signs them in, returning tokens as well as the user so no second call is needed.

Plany is invitation-only, so this is refused unless registration is open. An invited user signs in with the password they were emailed and then sets their own with ChangePassword.

Parameters

  • emailstringRequired
  • passwordstringRequired

    Plaintext, hashed with Argon2id before storage and never persisted or logged. Length is checked but composition is not: length is what actually resists guessing, and composition rules mostly produce predictable substitutions.

  • display_namestring
  • create_accountbool

    Create an account owned by the new user, and grant them roles/account.owner on it.

    The common case: someone signing up to host a game server needs an account before they can create anything, and making that a second call means every client reimplements the same two-step dance.

  • account_display_namestring

    Display name for that account. Defaults to the user's own display name.

Returns

RegisterUserResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"email": "",
"password": ""
}' \
api.plany.cloud:443 plany.iam.v1.IamService/RegisterUser
Example response
{
"user": "",
"email": "",
"account": "accounts/",
"tokens": {
"access_token": "",
"refresh_token": "",
"expire_time": "2026-10-04T12:00:00Z",
"scopes": [
""
],
"principal": {
"name": "",
"type": "PRINCIPAL_TYPE_USER",
"account": "accounts/",
"display_name": "My server",
"email": "",
"scopes": [
""
],
"project_restrictions": [
""
],
"credential_id": "my-credential",
"expire_time": "2026-10-04T12:00:00Z"
},
"account_warning": "",
"password_change_required": false,
"email_verification_required": false
}
}

ChangePassword

plany.iam.v1.IamService/ChangePassword

Replaces a user's password, proving they hold the current one.

The other half of InviteUser: an invitee signs in with a token that can do nothing but this, and gets a full one back. It is also the ordinary change-your-password call for anybody else.

Parameters

  • current_passwordstringRequired

    The password being replaced.

    Required even for a credential that must change: the token an invitee holds was issued to whoever read the invitation email, and without this a forwarded message would be a full account takeover.

  • new_passwordstringRequired

Returns

ChangePasswordResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"current_password": "",
"new_password": ""
}' \
api.plany.cloud:443 plany.iam.v1.IamService/ChangePassword
Example response
{
"tokens": {
"access_token": "",
"refresh_token": "",
"expire_time": "2026-10-04T12:00:00Z",
"scopes": [
""
],
"principal": {
"name": "",
"type": "PRINCIPAL_TYPE_USER",
"account": "accounts/",
"display_name": "My server",
"email": "",
"scopes": [
""
],
"project_restrictions": [
""
],
"credential_id": "my-credential",
"expire_time": "2026-10-04T12:00:00Z"
},
"account_warning": "",
"password_change_required": false,
"email_verification_required": false
}
}

RequestPasswordReset

plany.iam.v1.IamService/RequestPasswordReset

Emails a single-use link that sets a new password.

Unauthenticated: it is for somebody who cannot sign in. It answers the same way whether or not the address has an account, so it cannot be used to find out which addresses do — the email is the only place the answer goes. Repeated requests for one address within a minute send one email.

Parameters

  • emailstringRequired

Returns

Empty.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"email": ""
}' \
api.plany.cloud:443 plany.iam.v1.IamService/RequestPasswordReset
Example response
{}

ResetPassword

plany.iam.v1.IamService/ResetPassword

Sets a new password with the token from a reset email, and signs in.

Unauthenticated, like IssueToken: the token is the credential. It works once, for an hour, and only while the account's email is still the address it was sent to. Every existing session is revoked, and holding the link proves the inbox, so the address is marked confirmed too.

Parameters

  • tokenstringRequired

    From the reset link. Single-use, valid for an hour.

  • new_passwordstringRequired

    At least twelve characters, as everywhere else.

Returns

ResetPasswordResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"token": "",
"new_password": ""
}' \
api.plany.cloud:443 plany.iam.v1.IamService/ResetPassword
Example response
{
"tokens": {
"access_token": "",
"refresh_token": "",
"expire_time": "2026-10-04T12:00:00Z",
"scopes": [
""
],
"principal": {
"name": "",
"type": "PRINCIPAL_TYPE_USER",
"account": "accounts/",
"display_name": "My server",
"email": "",
"scopes": [
""
],
"project_restrictions": [
""
],
"credential_id": "my-credential",
"expire_time": "2026-10-04T12:00:00Z"
},
"account_warning": "",
"password_change_required": false,
"email_verification_required": false
},
"email": ""
}

SendEmailVerification

plany.iam.v1.IamService/SendEmailVerification

Sends the signed-in user a link that confirms their email address.

Registration sends the first one itself; this is "send it again". Until the address is confirmed, a registered user's token carries a single scope and is refused by every service, so this and VerifyEmail are the two calls such a session exists to make.

Parameters

No parameters.

Returns

Empty.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
api.plany.cloud:443 plany.iam.v1.IamService/SendEmailVerification
Example response
{}

VerifyEmail

plany.iam.v1.IamService/VerifyEmail

Confirms an email address with the token from a verification email.

Unauthenticated, because the link is often opened somewhere other than where the person registered — a phone, a different browser. It confirms the address and nothing else: it is not a sign-in link, so it returns no tokens. A session issued before confirmation is widened on its next refresh.

Parameters

  • tokenstringRequired

    From the verification link. Single-use, valid for a day.

Returns

VerifyEmailResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"token": ""
}' \
api.plany.cloud:443 plany.iam.v1.IamService/VerifyEmail
Example response
{
"email": ""
}

IssueToken

plany.iam.v1.IamService/IssueToken

Exchanges a credential — a password or an API key — for a short-lived token.

This is the one call that accepts a raw credential. Everything else on Plany takes the token it returns.

Parameters

  • grant_typeGrantTypeRequired
    GRANT_TYPE_PASSWORDGRANT_TYPE_API_KEYGRANT_TYPE_REFRESH_TOKENGRANT_TYPE_SERVICE_ACCOUNT_ASSERTIONGRANT_TYPE_OIDC_ASSERTION
  • credentialstring

    The credential, interpreted according to grant_type: the API key, the refresh token, or the signed assertion. Unset for PASSWORD, which uses the email/password fields.

  • emailstring
  • passwordstring
  • mfa_codestring

    One-time code, when the account has multi-factor authentication enabled.

  • scopesrepeated string

    Narrow the issued token below what the credential could otherwise do. Requesting a scope the credential lacks fails rather than silently downgrading.

  • accountstring

    Bind the token to one account, for a user belonging to several.

    Optional, and resolved automatically when the user holds a role on exactly one account — the ordinary case. With several, sign-in fails with FAILED_PRECONDITION naming them rather than guessing, because every service decides tenancy by comparing against this claim and a wrong guess silently scopes the session to the wrong tenant.

    Checked, not trusted: naming an account the user holds no role on is refused.

  • requested_lifetimeDuration

    Requested lifetime, capped by policy. Zero takes the default.

Returns

IssueTokenResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"grant_type": "GRANT_TYPE_PASSWORD"
}' \
api.plany.cloud:443 plany.iam.v1.IamService/IssueToken
Example response
{
"access_token": "",
"refresh_token": "",
"expire_time": "2026-10-04T12:00:00Z",
"scopes": [
""
],
"principal": {
"name": "",
"type": "PRINCIPAL_TYPE_USER",
"account": "accounts/",
"display_name": "My server",
"email": "",
"scopes": [
""
],
"project_restrictions": [
""
],
"credential_id": "my-credential",
"expire_time": "2026-10-04T12:00:00Z"
},
"account_warning": "",
"password_change_required": false,
"email_verification_required": false
}

RevokeToken

plany.iam.v1.IamService/RevokeToken

Revokes a token or an entire credential's token family before expiry.

Parameters

  • tokenstring

    The token to revoke. Mutually exclusive with credential_name.

  • credential_namestring

    Revoke every unexpired token minted from this credential, e.g. accounts/a/apiKeys/k. The blast radius control for a leaked key.

Returns

Empty.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
api.plany.cloud:443 plany.iam.v1.IamService/RevokeToken
Example response
{}

GetPublicKeys

plany.iam.v1.IamService/GetPublicKeys

Returns the public keys that verify Plany-issued tokens, as a JSON Web Key Set. Keys are published before they are used, so a cached copy never misses a rotation.

Parameters

No parameters.

Returns

GetPublicKeysResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
api.plany.cloud:443 plany.iam.v1.IamService/GetPublicKeys
Example response
{
"keys": [
{
"kid": "",
"kty": "",
"alg": "",
"use": "",
"crv": "",
"x": "",
"y": "",
"n": "",
"e": ""
}
],
"cache_duration": "300s"
}

CheckPermissions

plany.iam.v1.IamService/CheckPermissions

Decides whether a principal may perform permissions on a resource.

Returns the subset of permissions that are allowed rather than a bare boolean, so a UI can grey out actions with one round trip.

Parameters

  • resourcestringRequired

    Resource being acted on, e.g. projects/p1 or projects/p1/locations/eu-west-2/instances/i1.

  • permissionsrepeated stringRequired

    Permissions to test, in service.resource.verb form.

  • principalPrincipal

    Principal to test. Omitted means the caller, which is the normal case. Supplying one requires the caller to hold iam.policies.check on the resource, so this cannot be used to enumerate others' access.

    Show child attributes
    • namestringRequired

      Resource name of the underlying identity: users/{user} accounts/{account}/serviceAccounts/{service_account} accounts/{account}/apiKeys/{api_key} services/{service}

    • typePrincipalTypeRequired
      PRINCIPAL_TYPE_USERPRINCIPAL_TYPE_SERVICE_ACCOUNTPRINCIPAL_TYPE_API_KEYPRINCIPAL_TYPE_SERVICEPRINCIPAL_TYPE_OPERATOR
    • accountstring

      Account this principal acts on behalf of, accounts/{account}. Empty only for PRINCIPAL_TYPE_SERVICE. All spend and quota consumption is attributed here.

    • display_namestring

      Display name for audit logs and UIs. Never used for authorization.

    • emailstring

      Verified email, for USER principals only.

    • scopesrepeated string

      Scopes the presented credential carries, which upper-bound what the principal may do in this call regardless of its granted roles. An API key restricted to microvm.instances.read cannot delete an instance even if its owner is an account admin.

    • project_restrictionsrepeated string

      Projects the credential is restricted to, as projects/{project} names. Empty means every project in the account, subject to role checks.

    • credential_idstring

      Opaque id of the credential used, for audit correlation and revocation. For a JWT this is the jti claim.

    • expire_timeTimestamp

      When the presented credential stops being valid. Calls made after this are refused.

Returns

CheckPermissionsResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"resource": "",
"permissions": []
}' \
api.plany.cloud:443 plany.iam.v1.IamService/CheckPermissions
Example response
{
"permissions": [
""
]
}

GetIamPolicy

plany.iam.v1.IamService/GetIamPolicy

Parameters

  • resourcestringRequired

Returns

Policy.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"resource": ""
}' \
api.plany.cloud:443 plany.iam.v1.IamService/GetIamPolicy
Example response
{
"resource": "",
"bindings": [
{
"role": "roles/my-role",
"members": [
""
]
}
],
"etag": "W/\"1\""
}

SetIamPolicy

plany.iam.v1.IamService/SetIamPolicy

Parameters

  • resourcestringRequired
  • policyPolicyRequired
    Show child attributes
    • resourcestringRequired

      Resource the policy attaches to, accounts/{account} or projects/{project}.

    • Show child attributes
      • rolestringRequired

        roles/{role}.

      • membersrepeated stringRequired

        Principal names the role is granted to. Also accepts the special member allAccountMembers, which covers every member of the owning account.

    • etagstring

      Opaque concurrency token. SetIamPolicy fails with ABORTED if it does not match the stored value, which makes read-modify-write safe without holding a lock.

  • update_maskFieldMask

Returns

Policy.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"resource": "",
"policy": {
"resource": ""
}
}' \
api.plany.cloud:443 plany.iam.v1.IamService/SetIamPolicy
Example response
{
"resource": "",
"bindings": [
{
"role": "roles/my-role",
"members": [
""
]
}
],
"etag": "W/\"1\""
}

ListRoles

plany.iam.v1.IamService/ListRoles

Parameters

  • Return only roles bindable at this scope.

    SCOPE_ACCOUNTSCOPE_PROJECTSCOPE_BOTH
  • page_sizeint32
  • page_tokenstring

Returns

ListRolesResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"page_size": 50
}' \
api.plany.cloud:443 plany.iam.v1.IamService/ListRoles
Example response
{
"roles": [
{
"name": "roles/my-role",
"display_name": "My server",
"description": "",
"included_permissions": [
""
],
"scope": "SCOPE_ACCOUNT",
"operator_only": false
}
],
"next_page_token": ""
}

CreateApiKey

plany.iam.v1.IamService/CreateApiKey

Creates an API key. The plaintext key is returned only here and never again; the service stores a hash.

Parameters

  • parentstringRequired
  • api_keyApiKeyRequired
    Show child attributes
    • display_namestringRequired
    • namestringIdentifier

      accounts/{account}/apiKeys/{api_key}.

    • scopesrepeated string

      Permission scopes this key may exercise, upper-bounding the roles held by the identity it acts as. Empty means every scope that identity has, which callers should avoid for keys deployed to game servers.

    • project_restrictionsrepeated string

      Projects this key may touch. Empty means all projects in the account.

    • allowed_ip_rangesrepeated string

      CIDR ranges the key may be presented from. Empty means anywhere. Worth setting for a key baked into a fixed fleet.

    • subjectstring

      Identity this key authenticates as. Usually a service account; a key acting as a user inherits that user's roles and is discouraged.

    • expire_timeTimestamp

      When the key stops working. Empty means it never expires, which the API permits but the console warns about.

  • api_key_idstring

    Client-chosen id. Empty generates one.

Returns

CreateApiKeyResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"parent": "accounts/",
"api_key": {
"display_name": "My server"
}
}' \
api.plany.cloud:443 plany.iam.v1.IamService/CreateApiKey
Example response
{
"api_key": {
"name": "accounts//apiKeys/my-api-key",
"display_name": "My server",
"key_prefix": "",
"state": "STATE_ACTIVE",
"scopes": [
""
],
"project_restrictions": [
"projects/"
],
"allowed_ip_ranges": [
""
],
"subject": "",
"create_time": "2026-10-04T12:00:00Z",
"expire_time": "2026-10-04T12:00:00Z",
"last_use_time": "2026-10-04T12:00:00Z",
"creator": "",
"token_expire_time": "2026-10-04T12:00:00Z"
},
"key_string": ""
}

GetApiKey

plany.iam.v1.IamService/GetApiKey

Parameters

  • namestringRequired

Returns

ApiKey.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"name": "accounts//apiKeys/my-api-key"
}' \
api.plany.cloud:443 plany.iam.v1.IamService/GetApiKey
Example response
{
"name": "accounts//apiKeys/my-api-key",
"display_name": "My server",
"key_prefix": "",
"state": "STATE_ACTIVE",
"scopes": [
""
],
"project_restrictions": [
"projects/"
],
"allowed_ip_ranges": [
""
],
"subject": "",
"create_time": "2026-10-04T12:00:00Z",
"expire_time": "2026-10-04T12:00:00Z",
"last_use_time": "2026-10-04T12:00:00Z",
"creator": "",
"token_expire_time": "2026-10-04T12:00:00Z"
}

ListApiKeys

plany.iam.v1.IamService/ListApiKeys

Parameters

  • parentstringRequired
  • page_sizeint32
  • page_tokenstring
  • filterstring

    AIP-160 filter, e.g. state = "ACTIVE".

Returns

ListApiKeysResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"parent": "accounts/",
"page_size": 50
}' \
api.plany.cloud:443 plany.iam.v1.IamService/ListApiKeys
Example response
{
"api_keys": [
{
"name": "accounts//apiKeys/my-api-key",
"display_name": "My server",
"key_prefix": "",
"state": "STATE_ACTIVE",
"scopes": [
""
],
"project_restrictions": [
"projects/"
],
"allowed_ip_ranges": [
""
],
"subject": "",
"create_time": "2026-10-04T12:00:00Z",
"expire_time": "2026-10-04T12:00:00Z",
"last_use_time": "2026-10-04T12:00:00Z",
"creator": "",
"token_expire_time": "2026-10-04T12:00:00Z"
}
],
"next_page_token": ""
}

UpdateApiKey

plany.iam.v1.IamService/UpdateApiKey

Parameters

  • api_keyApiKeyRequired
    Show child attributes
    • display_namestringRequired
    • namestringIdentifier

      accounts/{account}/apiKeys/{api_key}.

    • scopesrepeated string

      Permission scopes this key may exercise, upper-bounding the roles held by the identity it acts as. Empty means every scope that identity has, which callers should avoid for keys deployed to game servers.

    • project_restrictionsrepeated string

      Projects this key may touch. Empty means all projects in the account.

    • allowed_ip_rangesrepeated string

      CIDR ranges the key may be presented from. Empty means anywhere. Worth setting for a key baked into a fixed fleet.

    • subjectstring

      Identity this key authenticates as. Usually a service account; a key acting as a user inherits that user's roles and is discouraged.

    • expire_timeTimestamp

      When the key stops working. Empty means it never expires, which the API permits but the console warns about.

  • update_maskFieldMaskRequired

Returns

ApiKey.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"api_key": {
"display_name": "My server"
},
"update_mask": "display_name"
}' \
api.plany.cloud:443 plany.iam.v1.IamService/UpdateApiKey
Example response
{
"name": "accounts//apiKeys/my-api-key",
"display_name": "My server",
"key_prefix": "",
"state": "STATE_ACTIVE",
"scopes": [
""
],
"project_restrictions": [
"projects/"
],
"allowed_ip_ranges": [
""
],
"subject": "",
"create_time": "2026-10-04T12:00:00Z",
"expire_time": "2026-10-04T12:00:00Z",
"last_use_time": "2026-10-04T12:00:00Z",
"creator": "",
"token_expire_time": "2026-10-04T12:00:00Z"
}

RotateApiKey

plany.iam.v1.IamService/RotateApiKey

Issues a replacement key while leaving the old one usable for a grace period, so a fleet can roll over without downtime.

Parameters

  • namestringRequired
  • grace_periodDuration

    How long the old key keeps working. Zero takes the default of 24 hours.

Returns

CreateApiKeyResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"name": "accounts//apiKeys/my-api-key"
}' \
api.plany.cloud:443 plany.iam.v1.IamService/RotateApiKey
Example response
{
"api_key": {
"name": "accounts//apiKeys/my-api-key",
"display_name": "My server",
"key_prefix": "",
"state": "STATE_ACTIVE",
"scopes": [
""
],
"project_restrictions": [
"projects/"
],
"allowed_ip_ranges": [
""
],
"subject": "",
"create_time": "2026-10-04T12:00:00Z",
"expire_time": "2026-10-04T12:00:00Z",
"last_use_time": "2026-10-04T12:00:00Z",
"creator": "",
"token_expire_time": "2026-10-04T12:00:00Z"
},
"key_string": ""
}

DeleteApiKey

plany.iam.v1.IamService/DeleteApiKey

Parameters

  • namestringRequired

Returns

Empty.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"name": "accounts//apiKeys/my-api-key"
}' \
api.plany.cloud:443 plany.iam.v1.IamService/DeleteApiKey
Example response
{}

CreateServiceAccount

plany.iam.v1.IamService/CreateServiceAccount

Parameters

  • parentstringRequired
  • service_accountServiceAccountRequired
    Show child attributes
    • namestringIdentifier

      accounts/{account}/serviceAccounts/{service_account}.

    • service_account_idstringImmutable

      Stable, human-readable id unique within the account, e.g. "fleet-controller". Chosen at creation and immutable.

    • display_namestring
    • descriptionstring
    • disabledbool

      Disabled service accounts fail authentication but keep their bindings, so access can be suspended without losing the grant history.

  • service_account_idstringRequired

Returns

ServiceAccount.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"parent": "accounts/",
"service_account": {
"display_name": "My server"
},
"service_account_id": "my-service-account"
}' \
api.plany.cloud:443 plany.iam.v1.IamService/CreateServiceAccount
Example response
{
"name": "accounts//serviceAccounts/my-service-account",
"service_account_id": "my-service-account",
"display_name": "My server",
"description": "",
"disabled": false,
"create_time": "2026-10-04T12:00:00Z",
"managed_by": ""
}

GetServiceAccount

plany.iam.v1.IamService/GetServiceAccount

Parameters

  • namestringRequired

Returns

ServiceAccount.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"name": "accounts//serviceAccounts/my-service-account"
}' \
api.plany.cloud:443 plany.iam.v1.IamService/GetServiceAccount
Example response
{
"name": "accounts//serviceAccounts/my-service-account",
"service_account_id": "my-service-account",
"display_name": "My server",
"description": "",
"disabled": false,
"create_time": "2026-10-04T12:00:00Z",
"managed_by": ""
}

ListServiceAccounts

plany.iam.v1.IamService/ListServiceAccounts

Parameters

  • parentstringRequired
  • page_sizeint32
  • page_tokenstring

Returns

ListServiceAccountsResponse.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"parent": "accounts/",
"page_size": 50
}' \
api.plany.cloud:443 plany.iam.v1.IamService/ListServiceAccounts
Example response
{
"service_accounts": [
{
"name": "accounts//serviceAccounts/my-service-account",
"service_account_id": "my-service-account",
"display_name": "My server",
"description": "",
"disabled": false,
"create_time": "2026-10-04T12:00:00Z",
"managed_by": ""
}
],
"next_page_token": ""
}

DeleteServiceAccount

plany.iam.v1.IamService/DeleteServiceAccount

Parameters

  • namestringRequired

Returns

Empty.

grpcurl -H "authorization: Bearer $PLANY_API_KEY" \
-d '{
"name": "accounts//serviceAccounts/my-service-account"
}' \
api.plany.cloud:443 plany.iam.v1.IamService/DeleteServiceAccount
Example response
{}

The Binding object

Binding grants one role to a set of members on one resource.

Attributes

  • rolestringRequired

    roles/{role}.

  • membersrepeated stringRequired

    Principal names the role is granted to. Also accepts the special member allAccountMembers, which covers every member of the owning account.

Binding
{
"role": "roles/my-role",
"members": [
""
]
}

The GetPublicKeysResponse.Jwk object

One JSON Web Key.

Attributes

  • kidstring
  • ktystring
  • algstring
  • usestring
  • crvstring

    EdDSA/ECDSA curve parameters. Plany signs with EdDSA (Ed25519), so crv is "Ed25519" and x carries the public key.

  • xstring
  • ystring
  • nstring

    RSA parameters, populated only for legacy RS256 keys.

  • estring
GetPublicKeysResponse.Jwk
{
"kid": "",
"kty": "",
"alg": "",
"use": "",
"crv": "",
"x": "",
"y": "",
"n": "",
"e": ""
}

The Principal object

Principal is the resolved identity of a caller: who a credential belongs to, and what it may do.

Attributes

  • namestringRequired

    Resource name of the underlying identity: users/{user} accounts/{account}/serviceAccounts/{service_account} accounts/{account}/apiKeys/{api_key} services/{service}

  • typePrincipalTypeRequired
    PRINCIPAL_TYPE_USERPRINCIPAL_TYPE_SERVICE_ACCOUNTPRINCIPAL_TYPE_API_KEYPRINCIPAL_TYPE_SERVICEPRINCIPAL_TYPE_OPERATOR
  • accountstring

    Account this principal acts on behalf of, accounts/{account}. Empty only for PRINCIPAL_TYPE_SERVICE. All spend and quota consumption is attributed here.

  • display_namestring

    Display name for audit logs and UIs. Never used for authorization.

  • emailstring

    Verified email, for USER principals only.

  • scopesrepeated string

    Scopes the presented credential carries, which upper-bound what the principal may do in this call regardless of its granted roles. An API key restricted to microvm.instances.read cannot delete an instance even if its owner is an account admin.

  • project_restrictionsrepeated string

    Projects the credential is restricted to, as projects/{project} names. Empty means every project in the account, subject to role checks.

  • credential_idstring

    Opaque id of the credential used, for audit correlation and revocation. For a JWT this is the jti claim.

  • expire_timeTimestamp

    When the presented credential stops being valid. Calls made after this are refused.

Principal
{
"name": "",
"type": "PRINCIPAL_TYPE_USER",
"account": "accounts/",
"display_name": "My server",
"email": "",
"scopes": [
""
],
"project_restrictions": [
""
],
"credential_id": "my-credential",
"expire_time": "2026-10-04T12:00:00Z"
}

The Role object

roles/{{role}}

Role is a named bundle of permissions granted on an account or a project.

Plany ships predefined roles only. Custom roles are a B2B/studio ask that the model already supports — a Role resource with an explicit permission list — but exposing them is deferred until there is demand.

Attributes

  • namestringIdentifier

    roles/{role}, e.g. roles/project.editor.

  • display_namestringOutput only
  • descriptionstringOutput only
  • included_permissionsrepeated stringOutput only

    Permissions in service.resource.verb form, e.g. microvm.instances.create. A permission may end in * to cover a family.

  • scopeRole.ScopeOutput only
    SCOPE_ACCOUNTSCOPE_PROJECTSCOPE_BOTH
  • operator_onlyboolOutput only

    Whether this role is granted only by Plany.

    You can see such a role and remove a binding of it, but SetIamPolicy refuses adding it or adding members to it. It is listed so that you can see what it is, rather than having it missing from the catalogue.

Role
{
"name": "roles/my-role",
"display_name": "My server",
"description": "",
"included_permissions": [
""
],
"scope": "SCOPE_ACCOUNT",
"operator_only": false
}

ApiKey

ApiKey is a long-lived credential owned by an account, for scripts, CI and anything else that cannot sign in as a person.

Exchange it for a short-lived token with IssueToken. Revoking a key takes effect within that token's lifetime.

Only the key's hash is stored: the plaintext is returned exactly once, from CreateApiKey.

  • display_namestringRequired
  • namestringIdentifier

    accounts/{account}/apiKeys/{api_key}.

  • key_prefixstringOutput only

    The key's public prefix, e.g. "pk_live_7Fq2". Shown in UIs and logs so a key can be identified without revealing it, and used to index the lookup so verification is one hash comparison rather than a table scan.

  • stateApiKey.StateOutput only
    STATE_ACTIVESTATE_DISABLEDSTATE_EXPIREDSTATE_ROTATINGSTATE_REVOKED
  • scopesrepeated string

    Permission scopes this key may exercise, upper-bounding the roles held by the identity it acts as. Empty means every scope that identity has, which callers should avoid for keys deployed to game servers.

  • project_restrictionsrepeated string

    Projects this key may touch. Empty means all projects in the account.

  • allowed_ip_rangesrepeated string

    CIDR ranges the key may be presented from. Empty means anywhere. Worth setting for a key baked into a fixed fleet.

  • subjectstring

    Identity this key authenticates as. Usually a service account; a key acting as a user inherits that user's roles and is discouraged.

  • create_timeTimestampOutput only
  • expire_timeTimestamp

    When the key stops working. Empty means it never expires, which the API permits but the console warns about.

  • last_use_timeTimestampOutput only

    Last successful use, updated at most once a minute to keep the write rate bounded. Drives "unused key" hygiene warnings.

  • creatorstringOutput only

    Principal that created the key, for audit.

  • token_expire_timeTimestampOutput only

    Lifetime granted to JWTs minted from this key. Zero requests the platform default of one hour. Shorter lifetimes tighten the revocation window at the cost of more token exchanges.

ChangePasswordResponse

  • A fresh, unrestricted token pair.

    Returned because the token that made this call may not have been able to do anything else — a credential awaiting a change is issued a token scoped to this one permission — so a client with only that would have changed the password and still be unable to use the platform.

    Every other token minted from the old password is revoked first.

    Show child attributes
    • access_tokenstring

      Signed JWT. Presented as authorization: Bearer <token>.

    • refresh_tokenstring

      Refresh token, issued only for interactive grants. Rotates on each use so a captured refresh token is detectable.

    • expire_timeTimestamp
    • scopesrepeated string

      Scopes actually granted, which may be narrower than requested.

    • principalPrincipal

      The identity the token authenticates as, saved from a round trip.

      Show child attributes
      • namestringRequired

        Resource name of the underlying identity: users/{user} accounts/{account}/serviceAccounts/{service_account} accounts/{account}/apiKeys/{api_key} services/{service}

      • typePrincipalTypeRequired
        PRINCIPAL_TYPE_USERPRINCIPAL_TYPE_SERVICE_ACCOUNTPRINCIPAL_TYPE_API_KEYPRINCIPAL_TYPE_SERVICEPRINCIPAL_TYPE_OPERATOR
      • accountstring

        Account this principal acts on behalf of, accounts/{account}. Empty only for PRINCIPAL_TYPE_SERVICE. All spend and quota consumption is attributed here.

      • display_namestring

        Display name for audit logs and UIs. Never used for authorization.

      • emailstring

        Verified email, for USER principals only.

      • scopesrepeated string

        Scopes the presented credential carries, which upper-bound what the principal may do in this call regardless of its granted roles. An API key restricted to microvm.instances.read cannot delete an instance even if its owner is an account admin.

      • project_restrictionsrepeated string

        Projects the credential is restricted to, as projects/{project} names. Empty means every project in the account, subject to role checks.

      • credential_idstring

        Opaque id of the credential used, for audit correlation and revocation. For a JWT this is the jti claim.

      • expire_timeTimestamp

        When the presented credential stops being valid. Calls made after this are refused.

    • account_warningstring

      Set when the credential is valid but the account needs attention before it can spend — for instance a zero credit balance. The token is still issued so the console can render the top-up flow.

    • password_change_requiredbool

      The password must be replaced before anything else can be done.

      Set for a credential IAM generated — an alpha invitation — and cleared by ChangePassword. It is advisory to the client and not what enforces the change: the token issued alongside it carries a single scope, so it is refused everywhere the change-password call is not. A console that ignored this field would render a session that could read nothing.

    • email_verification_requiredbool

      The email address must be confirmed before anything else can be done.

      Set for a user who registered and has not yet followed the link in their verification email. Advisory, exactly as password_change_required is: the token issued alongside it carries a single scope, so it is refused by every service until the address is confirmed and the session refreshed.

CheckPermissionsResponse

  • permissionsrepeated string

    The subset of the requested permissions that are granted.

CreateApiKeyResponse

  • api_keyApiKey
    Show child attributes
    • display_namestringRequired
    • namestringIdentifier

      accounts/{account}/apiKeys/{api_key}.

    • key_prefixstringOutput only

      The key's public prefix, e.g. "pk_live_7Fq2". Shown in UIs and logs so a key can be identified without revealing it, and used to index the lookup so verification is one hash comparison rather than a table scan.

    • stateApiKey.StateOutput only
      STATE_ACTIVESTATE_DISABLEDSTATE_EXPIREDSTATE_ROTATINGSTATE_REVOKED
    • scopesrepeated string

      Permission scopes this key may exercise, upper-bounding the roles held by the identity it acts as. Empty means every scope that identity has, which callers should avoid for keys deployed to game servers.

    • project_restrictionsrepeated string

      Projects this key may touch. Empty means all projects in the account.

    • allowed_ip_rangesrepeated string

      CIDR ranges the key may be presented from. Empty means anywhere. Worth setting for a key baked into a fixed fleet.

    • subjectstring

      Identity this key authenticates as. Usually a service account; a key acting as a user inherits that user's roles and is discouraged.

    • create_timeTimestampOutput only
    • expire_timeTimestamp

      When the key stops working. Empty means it never expires, which the API permits but the console warns about.

    • last_use_timeTimestampOutput only

      Last successful use, updated at most once a minute to keep the write rate bounded. Drives "unused key" hygiene warnings.

    • creatorstringOutput only

      Principal that created the key, for audit.

    • token_expire_timeTimestampOutput only

      Lifetime granted to JWTs minted from this key. Zero requests the platform default of one hour. Shorter lifetimes tighten the revocation window at the cost of more token exchanges.

  • key_stringstring

    The plaintext key, returned exactly once. Not recoverable afterwards.

GetPublicKeysResponse

  • Show child attributes
    • kidstring
    • ktystring
    • algstring
    • usestring
    • crvstring

      EdDSA/ECDSA curve parameters. Plany signs with EdDSA (Ed25519), so crv is "Ed25519" and x carries the public key.

    • xstring
    • ystring
    • nstring

      RSA parameters, populated only for legacy RS256 keys.

    • estring
  • cache_durationDuration

    How long a client may cache this set. Kept short enough that an emergency rotation propagates quickly.

IssueTokenResponse

  • access_tokenstring

    Signed JWT. Presented as authorization: Bearer <token>.

  • refresh_tokenstring

    Refresh token, issued only for interactive grants. Rotates on each use so a captured refresh token is detectable.

  • expire_timeTimestamp
  • scopesrepeated string

    Scopes actually granted, which may be narrower than requested.

  • principalPrincipal

    The identity the token authenticates as, saved from a round trip.

    Show child attributes
    • namestringRequired

      Resource name of the underlying identity: users/{user} accounts/{account}/serviceAccounts/{service_account} accounts/{account}/apiKeys/{api_key} services/{service}

    • typePrincipalTypeRequired
      PRINCIPAL_TYPE_USERPRINCIPAL_TYPE_SERVICE_ACCOUNTPRINCIPAL_TYPE_API_KEYPRINCIPAL_TYPE_SERVICEPRINCIPAL_TYPE_OPERATOR
    • accountstring

      Account this principal acts on behalf of, accounts/{account}. Empty only for PRINCIPAL_TYPE_SERVICE. All spend and quota consumption is attributed here.

    • display_namestring

      Display name for audit logs and UIs. Never used for authorization.

    • emailstring

      Verified email, for USER principals only.

    • scopesrepeated string

      Scopes the presented credential carries, which upper-bound what the principal may do in this call regardless of its granted roles. An API key restricted to microvm.instances.read cannot delete an instance even if its owner is an account admin.

    • project_restrictionsrepeated string

      Projects the credential is restricted to, as projects/{project} names. Empty means every project in the account, subject to role checks.

    • credential_idstring

      Opaque id of the credential used, for audit correlation and revocation. For a JWT this is the jti claim.

    • expire_timeTimestamp

      When the presented credential stops being valid. Calls made after this are refused.

  • account_warningstring

    Set when the credential is valid but the account needs attention before it can spend — for instance a zero credit balance. The token is still issued so the console can render the top-up flow.

  • password_change_requiredbool

    The password must be replaced before anything else can be done.

    Set for a credential IAM generated — an alpha invitation — and cleared by ChangePassword. It is advisory to the client and not what enforces the change: the token issued alongside it carries a single scope, so it is refused everywhere the change-password call is not. A console that ignored this field would render a session that could read nothing.

  • email_verification_requiredbool

    The email address must be confirmed before anything else can be done.

    Set for a user who registered and has not yet followed the link in their verification email. Advisory, exactly as password_change_required is: the token issued alongside it carries a single scope, so it is refused by every service until the address is confirmed and the session refreshed.

ListApiKeysResponse

  • Show child attributes
    • display_namestringRequired
    • namestringIdentifier

      accounts/{account}/apiKeys/{api_key}.

    • key_prefixstringOutput only

      The key's public prefix, e.g. "pk_live_7Fq2". Shown in UIs and logs so a key can be identified without revealing it, and used to index the lookup so verification is one hash comparison rather than a table scan.

    • stateApiKey.StateOutput only
      STATE_ACTIVESTATE_DISABLEDSTATE_EXPIREDSTATE_ROTATINGSTATE_REVOKED
    • scopesrepeated string

      Permission scopes this key may exercise, upper-bounding the roles held by the identity it acts as. Empty means every scope that identity has, which callers should avoid for keys deployed to game servers.

    • project_restrictionsrepeated string

      Projects this key may touch. Empty means all projects in the account.

    • allowed_ip_rangesrepeated string

      CIDR ranges the key may be presented from. Empty means anywhere. Worth setting for a key baked into a fixed fleet.

    • subjectstring

      Identity this key authenticates as. Usually a service account; a key acting as a user inherits that user's roles and is discouraged.

    • create_timeTimestampOutput only
    • expire_timeTimestamp

      When the key stops working. Empty means it never expires, which the API permits but the console warns about.

    • last_use_timeTimestampOutput only

      Last successful use, updated at most once a minute to keep the write rate bounded. Drives "unused key" hygiene warnings.

    • creatorstringOutput only

      Principal that created the key, for audit.

    • token_expire_timeTimestampOutput only

      Lifetime granted to JWTs minted from this key. Zero requests the platform default of one hour. Shorter lifetimes tighten the revocation window at the cost of more token exchanges.

  • next_page_tokenstring

ListRolesResponse

  • Show child attributes
    • namestringIdentifier

      roles/{role}, e.g. roles/project.editor.

    • display_namestringOutput only
    • descriptionstringOutput only
    • included_permissionsrepeated stringOutput only

      Permissions in service.resource.verb form, e.g. microvm.instances.create. A permission may end in * to cover a family.

    • scopeRole.ScopeOutput only
      SCOPE_ACCOUNTSCOPE_PROJECTSCOPE_BOTH
    • operator_onlyboolOutput only

      Whether this role is granted only by Plany.

      You can see such a role and remove a binding of it, but SetIamPolicy refuses adding it or adding members to it. It is listed so that you can see what it is, rather than having it missing from the catalogue.

  • next_page_tokenstring

ListServiceAccountsResponse

  • service_accountsrepeated ServiceAccount
    Show child attributes
    • namestringIdentifier

      accounts/{account}/serviceAccounts/{service_account}.

    • service_account_idstringImmutable

      Stable, human-readable id unique within the account, e.g. "fleet-controller". Chosen at creation and immutable.

    • display_namestring
    • descriptionstring
    • disabledbool

      Disabled service accounts fail authentication but keep their bindings, so access can be suspended without losing the grant history.

    • create_timeTimestampOutput only
    • managed_bystringOutput only

      The service that created this identity for a resource of its own — e.g. playpute.plany.cloud for a game server's, sandbox.plany.cloud for a sandbox's. Empty for an identity a customer created.

      A managed identity is created, bound and deleted by the service that owns it, alongside the one resource it exists for. Attaching it to anything else would tie a second resource to a lifetime nobody chose for it, so pickers offer only identities with no managed_by. Set by IAM from the caller that created it, never from the request.

  • next_page_tokenstring

Policy

Policy is the complete set of bindings on one resource.

  • resourcestringRequired

    Resource the policy attaches to, accounts/{account} or projects/{project}.

  • Show child attributes
    • rolestringRequired

      roles/{role}.

    • membersrepeated stringRequired

      Principal names the role is granted to. Also accepts the special member allAccountMembers, which covers every member of the owning account.

  • etagstring

    Opaque concurrency token. SetIamPolicy fails with ABORTED if it does not match the stored value, which makes read-modify-write safe without holding a lock.

RegisterUserResponse

  • userstring

    users/{user}.

  • emailstring
  • accountstring

    The account created when create_account was set, accounts/{account}.

  • Credentials for the new user, so registration signs them in.

    Show child attributes
    • access_tokenstring

      Signed JWT. Presented as authorization: Bearer <token>.

    • refresh_tokenstring

      Refresh token, issued only for interactive grants. Rotates on each use so a captured refresh token is detectable.

    • expire_timeTimestamp
    • scopesrepeated string

      Scopes actually granted, which may be narrower than requested.

    • principalPrincipal

      The identity the token authenticates as, saved from a round trip.

      Show child attributes
      • namestringRequired

        Resource name of the underlying identity: users/{user} accounts/{account}/serviceAccounts/{service_account} accounts/{account}/apiKeys/{api_key} services/{service}

      • typePrincipalTypeRequired
        PRINCIPAL_TYPE_USERPRINCIPAL_TYPE_SERVICE_ACCOUNTPRINCIPAL_TYPE_API_KEYPRINCIPAL_TYPE_SERVICEPRINCIPAL_TYPE_OPERATOR
      • accountstring

        Account this principal acts on behalf of, accounts/{account}. Empty only for PRINCIPAL_TYPE_SERVICE. All spend and quota consumption is attributed here.

      • display_namestring

        Display name for audit logs and UIs. Never used for authorization.

      • emailstring

        Verified email, for USER principals only.

      • scopesrepeated string

        Scopes the presented credential carries, which upper-bound what the principal may do in this call regardless of its granted roles. An API key restricted to microvm.instances.read cannot delete an instance even if its owner is an account admin.

      • project_restrictionsrepeated string

        Projects the credential is restricted to, as projects/{project} names. Empty means every project in the account, subject to role checks.

      • credential_idstring

        Opaque id of the credential used, for audit correlation and revocation. For a JWT this is the jti claim.

      • expire_timeTimestamp

        When the presented credential stops being valid. Calls made after this are refused.

    • account_warningstring

      Set when the credential is valid but the account needs attention before it can spend — for instance a zero credit balance. The token is still issued so the console can render the top-up flow.

    • password_change_requiredbool

      The password must be replaced before anything else can be done.

      Set for a credential IAM generated — an alpha invitation — and cleared by ChangePassword. It is advisory to the client and not what enforces the change: the token issued alongside it carries a single scope, so it is refused everywhere the change-password call is not. A console that ignored this field would render a session that could read nothing.

    • email_verification_requiredbool

      The email address must be confirmed before anything else can be done.

      Set for a user who registered and has not yet followed the link in their verification email. Advisory, exactly as password_change_required is: the token issued alongside it carries a single scope, so it is refused by every service until the address is confirmed and the session refreshed.

ResetPasswordResponse

  • A fresh session, so a reset ends signed in.

    Absent — and the password still changed — when the account has a second factor enabled, because an emailed link must not stand in for it, or when the user belongs to several accounts and has to choose one at sign-in.

    Show child attributes
    • access_tokenstring

      Signed JWT. Presented as authorization: Bearer <token>.

    • refresh_tokenstring

      Refresh token, issued only for interactive grants. Rotates on each use so a captured refresh token is detectable.

    • expire_timeTimestamp
    • scopesrepeated string

      Scopes actually granted, which may be narrower than requested.

    • principalPrincipal

      The identity the token authenticates as, saved from a round trip.

      Show child attributes
      • namestringRequired

        Resource name of the underlying identity: users/{user} accounts/{account}/serviceAccounts/{service_account} accounts/{account}/apiKeys/{api_key} services/{service}

      • typePrincipalTypeRequired
        PRINCIPAL_TYPE_USERPRINCIPAL_TYPE_SERVICE_ACCOUNTPRINCIPAL_TYPE_API_KEYPRINCIPAL_TYPE_SERVICEPRINCIPAL_TYPE_OPERATOR
      • accountstring

        Account this principal acts on behalf of, accounts/{account}. Empty only for PRINCIPAL_TYPE_SERVICE. All spend and quota consumption is attributed here.

      • display_namestring

        Display name for audit logs and UIs. Never used for authorization.

      • emailstring

        Verified email, for USER principals only.

      • scopesrepeated string

        Scopes the presented credential carries, which upper-bound what the principal may do in this call regardless of its granted roles. An API key restricted to microvm.instances.read cannot delete an instance even if its owner is an account admin.

      • project_restrictionsrepeated string

        Projects the credential is restricted to, as projects/{project} names. Empty means every project in the account, subject to role checks.

      • credential_idstring

        Opaque id of the credential used, for audit correlation and revocation. For a JWT this is the jti claim.

      • expire_timeTimestamp

        When the presented credential stops being valid. Calls made after this are refused.

    • account_warningstring

      Set when the credential is valid but the account needs attention before it can spend — for instance a zero credit balance. The token is still issued so the console can render the top-up flow.

    • password_change_requiredbool

      The password must be replaced before anything else can be done.

      Set for a credential IAM generated — an alpha invitation — and cleared by ChangePassword. It is advisory to the client and not what enforces the change: the token issued alongside it carries a single scope, so it is refused everywhere the change-password call is not. A console that ignored this field would render a session that could read nothing.

    • email_verification_requiredbool

      The email address must be confirmed before anything else can be done.

      Set for a user who registered and has not yet followed the link in their verification email. Advisory, exactly as password_change_required is: the token issued alongside it carries a single scope, so it is refused by every service until the address is confirmed and the session refreshed.

  • emailstring

    The address the reset was for, so a client can prefill sign-in.

ServiceAccount

ServiceAccount is a non-human identity owned by an account.

It is what a studio's CI, matchmaker or fleet controller authenticates as. Roles are granted to a service account exactly as they are to a user, so the authorization path has no special cases.

  • namestringIdentifier

    accounts/{account}/serviceAccounts/{service_account}.

  • service_account_idstringImmutable

    Stable, human-readable id unique within the account, e.g. "fleet-controller". Chosen at creation and immutable.

  • display_namestring
  • descriptionstring
  • disabledbool

    Disabled service accounts fail authentication but keep their bindings, so access can be suspended without losing the grant history.

  • create_timeTimestampOutput only
  • managed_bystringOutput only

    The service that created this identity for a resource of its own — e.g. playpute.plany.cloud for a game server's, sandbox.plany.cloud for a sandbox's. Empty for an identity a customer created.

    A managed identity is created, bound and deleted by the service that owns it, alongside the one resource it exists for. Attaching it to anything else would tie a second resource to a lifetime nobody chose for it, so pickers offer only identities with no managed_by. Set by IAM from the caller that created it, never from the request.

VerifyEmailResponse

  • emailstring

    The address that is now confirmed.

Enums

ApiKey.State

ValueDescription
STATE_UNSPECIFIED
STATE_ACTIVEUsable.
STATE_DISABLEDManually disabled. Rejected, but retained so it can be re-enabled.
STATE_EXPIREDPast expire_time.
STATE_ROTATINGSuperseded by a rotation and inside its grace period. Still accepted, so a rotation does not require an atomic deploy.
STATE_REVOKEDPermanently revoked. Never accepted again.

GrantType

GrantType names the credential being exchanged in IssueTokenRequest.

ValueDescription
GRANT_TYPE_UNSPECIFIED
GRANT_TYPE_PASSWORDEmail and password, for the console's interactive sign-in.
GRANT_TYPE_API_KEYA raw API key, exchanged for a scoped JWT.
GRANT_TYPE_REFRESH_TOKENA refresh token from an earlier issuance.
GRANT_TYPE_SERVICE_ACCOUNT_ASSERTIONA JWT the service account signed with its own key, proving possession without ever transmitting a shared secret.
GRANT_TYPE_OIDC_ASSERTIONAn OIDC id token from a federated provider (GitHub Actions, Google). Lets a studio's CI authenticate with no stored secret at all.

PrincipalType

PrincipalType is the kind of identity behind a call.

ValueDescription
PRINCIPAL_TYPE_UNSPECIFIED
PRINCIPAL_TYPE_USERA human, authenticated interactively and holding a short-lived JWT.
PRINCIPAL_TYPE_SERVICE_ACCOUNTA non-human identity owned by an account, used by customer automation. Holds a JWT obtained by signing an assertion with its own key.
PRINCIPAL_TYPE_API_KEYA long-lived credential owned by an account, exchanged for a short-lived token with `IssueToken`.
PRINCIPAL_TYPE_SERVICEAn internal Plany service calling another. Authenticated by workload identity (mTLS in-cluster), not by a customer credential.
PRINCIPAL_TYPE_OPERATORA person at Plany acting on an account, for example while answering a support case. Always audited, and never able to spend an account's credit.

Role.Scope

Scope at which a role can be bound.

ValueDescription
SCOPE_UNSPECIFIED
SCOPE_ACCOUNTBindable on an account only.
SCOPE_PROJECTBindable on a project only.
SCOPE_BOTHBindable at either level; a binding on the account is inherited by all of its projects.