Hierarchical and cross-account access

DotID lets you grant access along an organization’s shape, not just one account at a time. Two capabilities cover this, both under the identity and organizations API families.

Resolve your organization

Every org-scoped route below needs an {orgId} in the path. If you only know your account id (for example the account_id claim on your token), resolve the organization your account belongs to:

GET /identity/v1/accounts/{accountId}/organization
{
  "account_id": "9a33e1b6-…",
  "organization_id": "7b39dd74-…",
  "name": "BROIT Portal",
  "role": "management",
  "ou_id": "5642e5b0-…",
  "ou_name": "Root",
  "ou_path": "root",
  "mgmt_account_id": "9a33e1b6-…"
}

An account belongs to at most one organization — and resides in exactly one OU within it — so the result is unambiguous. The response also tells you where the account sits in the tree: ou_id, ou_name, and ou_path (the hierarchy as a dotted path, e.g. root.city.store-3; a management account resides in its org’s Root OU). The call is self-scoped: you may resolve only the organization of the account your credential is bound to (the accountId must match your access key’s account, or your token’s account_id claim) — otherwise 403. An account that belongs to no organization returns 404. Feed the returned organization_id into the {orgId} routes below.

OU-scoped permission assignment

Assign a permission set to a group on an organizational unit (OU) instead of on a single account. The grant then applies to every account in that OU’s subtree — including accounts you add later — so you don’t re-assign each account by hand.

# Assign permission set PS to group G on an OU; it cascades to accounts under that OU.
POST /identity/v1/organizations/{orgId}/ous/{ouId}/assignments
{ "group_id": "…", "permission_set_id": "…" }

# List / remove OU-scoped assignments
GET    /identity/v1/organizations/{orgId}/ous/{ouId}/assignments
DELETE /identity/v1/organizations/{orgId}/ous/{ouId}/assignments/{id}

An account is covered when the assigned OU is one of its ancestors. An account outside that subtree is not granted anything by the assignment.

Transitive account-to-account delegation

An account can consent to another account exercising a set of its permission sets on its resources. These consent edges compose transitively: a store city area HQ chain of delegations lets a principal in the top account act on the bottom account’s resources.

# Delegate scope you hold to another account
POST /identity/v1/accounts/{accountId}/delegations
{ "delegatee_account_id": "…", "scope_permission_set_ids": ["…"] }

# List delegations you granted / received; revoke one
GET    /identity/v1/accounts/{accountId}/delegations
GET    /identity/v1/accounts/{accountId}/delegations/received
DELETE /identity/v1/accounts/{accountId}/delegations/{delegationId}

Rules that keep delegation safe:

  • Scope only narrows. The effective scope is the intersection of the permission sets across every hop — a chain can never grant more than its weakest link.

  • You can only delegate what you hold. Each permission set in scope_permission_set_ids must be assigned to the delegating account, or the request is rejected (422).

  • Bounded depth. Chains longer than the configured maximum are rejected (422); a cycle is rejected (422).

  • Immediate revocation. DELETE on an edge takes effect on the very next authorization — there is no cached grant.

Access is evaluated per request: a valid, in-scope, non-revoked chain authorizes the action; anything else falls through to the normal deny.

These /identity/v1/accounts/{accountId}/delegations calls are reachable over AK/SK, authorized for the delegating account itself or its organization’s management account — any other caller gets a 403. To make one account a manager for a whole company’s accounts (an OU subtree, current and future), the organization’s management account uses the OU → Manager delegation surface — see Scoped delegation.