Organization Permission Management

Manage protected owners, permission groups, group membership, direct assignments, and authorized policy reads.

PixService separates the organization membership shell from protected ownership, permission groups, direct assignments, and the organization's entitlement ceiling. Membership alone does not grant access to protected resources.

Discover the permission catalog

Call GET /v1/permissions/catalog before building permission controls. The catalog is code-owned and describes each stable capability key, binary or tiered assignment values, valid organization/cluster/location scopes, optional document-path support, evaluation contexts, hierarchy and visibility gates, delegation metadata, entitlement controllability, valid ceilings, cleanup actions, platform-only actions, and typed operational limits.

validMutationValues includes Inherit so clients can represent removal of a manual override separately from the stored assignment values. Do not invent a capability, scope, or value that is absent from the catalog.

Inspect your effective permissions

Use GET /v1/orgs/{organizationId}/permissions/effective to render actions for the current user without permission-management authority. Supply contextType=Organization, Cluster, Location, Bundle, Document, or Job. Every context except Organization also requires its exact resourceId. An organization, cluster, or location request may include a case-preserving documentPath; the API normalizes separators and redundant slashes before evaluating longest-path inheritance.

For example, this lookup evaluates a location and path:

GET /v1/orgs/{organizationId}/permissions/effective?contextType=Location&resourceId={locationId}&documentPath=/Contractor/Uploads
Authorization: Bearer {token}

Bundle, Document, and Job identifiers are lookup contexts. The API resolves their organization, cluster, location, and stored document path; it does not create or report an individual-resource ACL. A visible cluster remains inspectable when ClusterView survives even if OrganizationView does not. Hidden, foreign, and nonexistent contexts all return the same 404 response.

The response reports the normalized context and, for each relevant capability, the ordinary ACL result after principal-local visibility gates, the exact organization entitlement ceiling, the current credential or PAT maximum, the final value, blockedByEntitlement, visibility-gate outcomes, allowed actions, and safe reason codes. Freshness includes permission and policy versions, exact entitlement definition/version identity, operational usage markers, evaluation time, and validUntilUtc. It never lists contributing groups, direct assignments, another principal, internal reason messages, or raw credential IDs. Even a permission manager uses the separate management endpoints below to inspect assignments; current-user introspection does not change shape based on management authority.

To evaluate an operation-dependent limit, optionally send storagePool with requestedAdditionalBytes, requestedLogicalJobs, requestedLifetimeLogicalJobs, requestedClusters, and/or requestedLocations. Cluster and Location counts are organization-wide, including when the evaluated Location belongs to one specific Cluster. Detailed consumed, reserved, and remaining usage is included only when OrganizationUsageView is present in the evaluated organization context. An ordinary caller whose own operation is denied receives only the typed limit or UTC reset boundary needed to explain that denial.

Use POST /v1/permissions/effective/batch for up to 100 contexts across one or more organizations. Each item carries a unique correlationId and the same context and optional operational fields as the single lookup:

{
  "items": [
    {
      "correlationId": "11111111-1111-4111-8111-111111111111",
      "organizationId": "22222222-2222-4222-8222-222222222222",
      "contextType": "Location",
      "resourceId": "33333333-3333-4333-8333-333333333333",
      "documentPath": "/Contractor/Uploads"
    }
  ]
}

Results retain request order. A hidden item returns only its correlation and isOpaque: true, with no normalized resource metadata. PAT organization scope and capability maxima are evaluated independently for every item. Both lookup forms are advisory for client rendering; every protected operation evaluates current permissions again when it executes.

Inspect a member's organization-scope defaults

An authorized organization permission manager can inspect the backend-rendered organization-scope defaults for one selected member:

GET /v1/orgs/{organizationId}/permissions/effective/users/{userId}
Authorization: Bearer {token}

This endpoint requires ManageOrganizationPermissions. It evaluates the selected user as an ordinary interactive user. For every catalog capability assignable at organization scope—including Cluster, Location, Document, and Bundle capabilities whose final authorization requires a concrete resource—it combines protected-owner, direct-user, and group values at organization scope and applies the exact entitlement ceiling. The response intentionally excludes cluster, location, and path overrides. It is an administration projection of defaults, not proof of final access to any concrete resource; normal protected operations still evaluate the resolved resource context and its visibility gates. The endpoint does not reveal contributing assignment rows. A user without a normal membership in the organization returns 404.

To label the result with current group membership, list the organization's permission groups and their /{groupId}/members subresources. Do not combine those rows with direct assignments in client code to infer effective access; the selected-member endpoint remains the authoritative rendered result. Clients must treat an unexpectedly omitted catalog capability as unevaluated, not as an implicit None decision.

Understand asynchronous actor boundaries

Requester-visible background outputs—document-folder ZIPs, Bundle archive imports, and generated report PDFs—must retain an explicit requester or exact external-link actor. A system or migration identity cannot execute those task types. Their handlers still recheck current access before a result is attached where finalization attaches durable data, and every result retrieval rechecks current access before returning a URL or artifact.

Search indexing/backfills, search asset synchronization, chat synchronization, thumbnail derivation, organization-derived provisioning, and ZIP cleanup are maintenance task types. They cannot publish a direct task output URL or artifact pointer. When one is enqueued with a system identity, the credential ID and bounded policy key must match that exact maintenance type; process identity is never treated as a user.

Authorization-sensitive scheduled entitlement expiry and transition execution use separate code-owned system credentials and policy keys, each scoped to the single target organization. A differently keyed credential, another organization scope, or an unbounded System actor is rejected before the mutation. These system operations emit audit/outbox state but cannot create a requester-visible result.

Treat authorization cache identities as bounded evidence

Within one request, PixService can reuse only an exact stable permission evaluation. Its identity includes the user and credential, PAT scope ceilings or bounded service policy, external-link authorization snapshot where applicable, organization permission version, exact immutable entitlement version and policy-catalog fingerprint, normalized resource/path context, and the earliest credential or entitlement validity boundary.

Storage, current Cluster/Location count, and monthly or lifetime Job usage are evaluated after that stable stage. Derived-result identities include their usage versions and freshness timestamps when those results are relevant. A cache identity never extends validUntilUtc, and durable permission/policy events remain the invalidation source for longer-lived projections.

Each delivered permission event advances durable, organization-scoped generations for evaluator decisions, authorized queries, ZIP/archive, thumbnail, report, search, chat/realtime, notification, and directory surfaces. Duplicate delivery of the same outbox generation is idempotent; operator replay advances a new generation. Long-lived caches and projection workers use the generation for their own surface, while request-scoped reads still evaluate the current permission and entitlement versions. Search suggestion and typo-vocabulary cache identities already include the durable Search generation, so a permission change cannot reuse a pre-change entry on another API process.

The invalidation generation is only a freshness marker, never authorization. Requester-bound generation/finalization and result retrieval continue to check the current actor, PAT, entitlement, resource, and capacity state. This also means a previously generated physical archive, thumbnail, or report may remain stored while current delivery is denied; stale storage never restores access.

The default operational objectives are 30 seconds from a committed change to durable invalidation for a change that may revoke access, and 120 seconds for general asynchronous propagation. Both values are deployment configuration and must be reviewed before Enforced cutover. Until a change is known to be expansion-only, it is measured against both objectives. These windows do not delay protected API reads or background finalization: those operations apply current authorization immediately on their next check.

Document-folder ZIPs use a different safe reuse rule: the cache correlation is derived from the exact authorized document set and each file revision, and the background payload stores those exact IDs. Two requesters may reuse the same archive only when that complete authorized snapshot is identical; a broader or newer set produces another archive identity.

Handle protected-operation denials

Centralized action enforcement returns 403 Forbidden with code: "permission_action_denied" when the caller may know the target exists but the current operation is not authorized. The response keeps requirement classes separate so a client does not present an entitlement, PAT policy, or capacity failure as an assignable ACL:

  • missingOrdinaryCapabilities contains capability keys and required/current values.
  • entitlementCeilings contains the organization policy ceiling separately.
  • personalAccessTokenCeilings contains PAT organization/scope or capability narrowing reasons.
  • deploymentFeatures, storageCapacity, currentResourceCounts, monthlyJobAdmission, and lifetimeJobAdmission contain their typed prerequisite failures. Storage, Cluster, Location, monthly Job, and lifetime Job denials use the distinct stable codes storage_capacity_exceeded, cluster_limit_exceeded, location_limit_exceeded, monthly_job_limit_exceeded, and lifetime_job_limit_exceeded. A depleted UTC-month allowance uses monthly_job_limit_exceeded and includes the bounded limit, remaining state, and reset boundary needed to explain the denied operation. Current resource counts and lifetime Job use never report a reset boundary.
  • context contains only the normalized organization, cluster, location, resource, and path identifiers that are safe for that caller.

The denial does not include contributing groups, direct assignments, PAT IDs, other principals, or detailed storage/job consumption. If confirming the target would violate visibility, the same operation returns a metadata-free 404 instead: there is no denial code, context, missing-capability list, or development exception marker to distinguish the target from a nonexistent resource.

External share-link preflight uses the same safe ordinary, entitlement, and credential distinction for every visible member of the proposed closure. It does not report storage, current-resource, or Job admission because creating or replacing share-link metadata consumes none of those limits. Operations that do consume capacity expose those families through effective-permission probes and the structured known-resource 403 response instead.

Query the permission audit log

Use GET /v1/orgs/{organizationId}/permission-audit to read immutable audit events for one organization. The caller must be a protected owner or have a final PermissionAuditLogView value of Allow; ordinary organization membership and a platform administrator identity do not bypass that organization capability. A personal access token is also narrowed by its live organization and capability scopes.

Results use a deterministic newest-first order: occurredAtUtc descending, then event id descending. Set limit from 1 through 200. When nextCursor is present, pass it unchanged as after with the same filters:

GET /v1/orgs/{organizationId}/permission-audit?result=Denied&capabilityKey=DelegatePermissionManagement&limit=100
Authorization: Bearer {token}
GET /v1/orgs/{organizationId}/permission-audit?result=Denied&capabilityKey=DelegatePermissionManagement&limit=100&after={nextCursor}
Authorization: Bearer {token}

Filtering occurs after audit-read authorization and before page boundaries. Available filters cover:

  • fromUtc and toUtc as inclusive UTC timestamps;
  • actorSource (User, System, Migration, or ExternalLink), actorUserId, actorCredentialKind, actorCredentialId, and personalAccessTokenId;
  • targetType and targetId for the recorded target entity or principal;
  • capabilityKey, entitlementDefinitionId, entitlementDefinitionKey, entitlementVersionId, and policyDescriptorKey;
  • scopeType, scopeId, and the ordinal case-sensitive documentPath for the affected organization, cluster, location, or path resource;
  • provenanceId for a SharedResourceAccess workflow target;
  • action, result, correlationId, permissionVersion, and policyVersion.

Each event reports actor and credential identity, target, capability/policy and resource context, action/result/reason, correlation, safe before/after JSON, and version markers when recorded. External-link events have no actorUserId; their actorCredentialId is the exact link identity. Raw idempotency keys and internal disclosure markers are not part of the response.

Audit events are retained indefinitely and cannot be updated or deleted through the application. Raw idempotency keys are stored only as SHA-256 values. Before and after payloads keep bounded operational identifiers, names, paths, values, counts, and outcomes while credential material, tokens, secrets, passwords, contact/network identifiers, and URLs are removed before persistence. Malformed or oversized payloads are replaced by an explicit redaction marker. Keep audit reasons free of secrets; denied attempts receive an additional stricter redaction and rate-limit policy.

Manage permission groups

Use /v1/orgs/{organizationId}/permission-groups for group lifecycle and the /{groupId}/members subresource for enrollment:

  • GET /state returns the current permission, policy, and authorization-state concurrency versions required before the first optimistic mutation.
  • GET lists groups with offset and limit.
  • POST creates a group.
  • GET /{groupId} reads one group.
  • PUT /{groupId} renames it.
  • POST /{groupId}/delete-preview returns the member and assignment impact and every safely reportable validation issue.
  • DELETE /{groupId} revalidates and deletes the complete group atomically.
  • GET, PUT /{userId}, and DELETE /{userId} list, add, and remove group members.

Mutations require an idempotencyKey plus the current organization authorization concurrency version. Rename and delete also require the current group concurrency version; membership changes require the group's current permission version. Refresh state after 409 Conflict instead of retrying with stale versions.

Group lifecycle requires OrganizationGroupsManage; enrollment uses the separate OrganizationGroupMembershipsManage capability. If the group contains administrative assignments, the caller must already hold every resulting administrative capability at an equal or broader scope. This rule applies when the actor enrolls another user or themselves, so a self-enrollment cannot manufacture administrative authority. Delegating permission-management authority also requires DelegatePermissionManagement at the affected scope.

Deletion authority follows the complete impact, not only the group row. A populated group also requires OrganizationGroupMembershipsManage, and the caller must be allowed to remove every assignment contributed by the group. The delete-preview response reports member/assignment counts and all safely reportable missing authority. Commit repeats the preview against current group, authorization, assignment, and membership versions and deletes nothing when any part has changed.

Manage assignments

Use /v1/orgs/{organizationId}/permission-assignments to list, read, create, update, reset, and delete assignments for User and Group principals. Filtering supports principal type and ID, capability, scope type and ID, and an ordinal case-sensitive document path.

Persisted assignment targets are limited to Organization, Cluster, and Location. Bundle, document, and Job IDs are evaluation contexts, not ACL targets. Document permissions use the matching organization, cluster, or location Documents capability and may add a normalized path. Organization Document paths address only the organization library; Cluster Document paths may be organization defaults or cluster rules; Location Document paths may be organization defaults, cluster defaults, or exact location rules. Paths are anchored literal subtree prefixes, preserve case, and compare ordinally, so /A matches /A and /A/B but not /AB or /a. Leading, trailing, repeated, and backslash separators canonicalize to a slash-trimmed key. Empty/root-only, . or .. traversal, and overlong paths are rejected before assignment validation probes any resource. Glob and regular-expression syntax has no special matching behavior; path prefixes are always literal.

Creating a path assignment atomically materializes any missing logical ancestor and managed-root folders in every currently applicable concrete library. Exact rules from multiple principals or origins reuse the same case-sensitive folder with independent bindings, so removing one rule cannot unlock a root still referenced by another. Folder creation is policy structure only and does not grant access beyond the assignment's final evaluated value. New organization-owned clusters and locations apply the relevant organization and cluster defaults in the same database transaction that creates the resource, so the library is never reported writable before its managed roots exist.

Folder list responses expose isPermissionManaged, isLocked, and lockReason. An exact root referenced by one or more path assignments returns both flags as true with lockReason: "permission_managed_path". Ancestors created only to complete that path remain unlocked unless another assignment binds the ancestor itself. Document-derived folders without an explicit folder record also return both flags as false and no lock reason.

Ordinary folder rename, move, and delete endpoints reject a managed root with HTTP 409 and code: "permission_managed_path"; change the corresponding permission path instead. This lock protects the root structure, not its contents: authorized document operations may still move files into, within, or out of the managed subtree.

Rename, reconcile, and unlock managed paths

A permission-policy rename runs a case-sensitive collision and authority preflight over every affected assignment and concrete document library before changing state. Renaming /A can rewrite exact /A rules and path-segment descendants such as /A/B only when the renamed folder and every affected rule cover the same complete library set. It never rewrites a substring such as /AB, never merges /A with case-distinct /a, and never silently splits a partially overlapping rule. A surviving exact binding or unsafe broader/partial coverage rejects the complete rename.

The commit updates assignment path literals, logical folders, file-artifact folder paths, bindings, audit state, permission versions, and outbox state as one policy mutation. Object-storage keys are unchanged. Work that must finish across multiple libraries records durable reconciliation state rather than reporting a partially repaired policy as complete. Reconciliation moves through pending/running and terminal succeeded or failed states; the background repair workflow is idempotent for propagation, rename, unlock, and interrupted work.

Removing the final assignment origin for a managed root removes its binding and unlocks the existing folder, but never deletes the folder or its contents. If another exact or overlapping binding still owns that root, the folder remains locked. A later entitlement ceiling of Unavailable makes the assignment dormant but does not remove its binding or unlock its policy structure.

Autocomplete document paths

Use GET /v1/orgs/{organizationId}/permission-document-paths/autocomplete when a permission editor needs folder choices. Required query fields are capabilityKey, scopeType, and scopeId; optional fields are parentPath, the ordinal case-sensitive namePrefix, offset, and limit from 1 through 200.

The capability and scope choose the document libraries:

  • OrganizationDocuments with the matching Organization scope reads that organization's direct document library.
  • ClusterDocuments with Cluster reads that exact cluster library. With Organization, it aggregates administrable cluster libraries.
  • LocationDocuments with Location reads that exact location library. With Cluster or Organization, it aggregates administrable location libraries beneath that scope.

Exact organization requests require ManageOrganizationPermissions; exact cluster and location requests require ManageResourcePermissions. Aggregate requests are bounded before any folder lookup to concrete libraries where the caller has ManageResourcePermissions, so a manager confined to one cluster does not discover another cluster's locations or folder names.

GET /v1/orgs/{organizationId}/permission-document-paths/autocomplete?capabilityKey=LocationDocuments&scopeType=Organization&scopeId={organizationId}&parentPath=/Cases&namePrefix=N&limit=100
Authorization: Bearer {token}

Each item contains the canonical case-preserved fullPath, name, hasChildren, isPermissionManaged, isLocked, lockReason, and coverage. Use fullPath as the next parentPath to traverse one level. Full means the path exists in every authorized library participating in that aggregate; Partial means it exists in only part of that authorized set. The response does not identify or count libraries, locations, files, or documents. Paths are de-duplicated and sorted ordinally before pagination, so /A and /a remain separate results. Invalid traversal and overlong paths are rejected before authorization or folder-storage probes.

Call POST /v1/orgs/{organizationId}/permission-assignments/validate with a mutation kind and candidate before committing. The non-mutating response uses the same principal, resource, concurrency, delegation, and entitlement-ceiling validators as the commit path. It reports the current/prospective canonical value and bounded affected-principal/user counts.

Create and update accept a positive binary or tiered value. Reset requires None. Delete omits value and removes only the manual origin. Every mutation recomputes the canonical assignment from all active manual, invitation, shared-workflow, and migration origins, so deleting a manual origin cannot silently remove independent workflow access. Reads return raw canonical and origin values plus the current ceiling, capped value, and dormant status.

New or increased manual grants above the active entitlement ceiling return 422 Unprocessable Entity with code organization_entitlement_ceiling_exceeded. Reduction, reset, and deletion remain available. Existing above-ceiling assignments stay stored and appear as dormant configuration; a reviewed later entitlement transition can reactivate them.

Manage protected owners

Use /v1/orgs/{organizationId}/owners to list protected owners. Owner changes use POST /validate and POST with mutation kind Add, Transfer, or Remove. They are available only to a current protected owner and cannot be delegated through a group or ordinary assignment. An organization may have multiple protected owners.

Owner changes require a recent interactive login. A refreshed session or a personal access token does not satisfy this step-up check; sign in again and submit the mutation within ten minutes. The API derives this result from the authenticated session—there is no client-controlled stepUpVerified field. The transaction always preserves at least one protected owner. Remove may target only a different current owner; an owner cannot remove their own relationship, even when another owner exists. Use Transfer when the acting owner intends to establish a replacement and remove their own relationship in one atomic transaction.

The organization roster returns isOwner independently of the legacy membership role. Its actions object bounds whether the current caller may present add-owner, remove-owner, or transfer controls for that specific row. Use the roster response's top-level authorizationStateConcurrencyVersion for the owner preview and apply requests; it remains available independently of permission-group administration visibility. Owner status may be displayed beside permission groups as a system chip, but it is not a permission group and must use the protected-owner endpoints. Ordinary member removal is unavailable for protected-owner rows.

Pending invitation rows use the same protected system chip. For a ghost row, isOwner represents owner intent only: it grants no authority and does not change the active owner count. A current owner with a recent interactive login previews and applies the intent through POST /v1/orgs/{organizationId}/owners/invitations/{invitationId}/validate and POST /v1/orgs/{organizationId}/owners/invitations/{invitationId} with isOwner, the row's invitation concurrency version, the roster's authorization concurrency version, and one stable idempotency key. Ordinary group editing preserves this intent. Successful bearer-link acceptance creates the membership shell and protected owner relation atomically for the accepting active account; failed acceptance creates neither.

Read organization policy and usage

GET /v1/orgs/{organizationId}/entitlements requires OrganizationEntitlementsView. It returns the exact active definition/version, activation or expiry, effective capability ceilings, and typed operational limits. This route is read-only and cannot attach policy to a user or group.

GET /v1/orgs/{organizationId}/usage independently requires OrganizationUsageView. It returns effective Document and Bundle storage limits and sources, durable and actively reserved bytes, remaining capacity, organization-wide current and actively reserved Cluster and Location counts, current UTC-month Job use, and non-resetting lifetime Job use. Only monthlyJobs contains periodStartUtc and resetAtUtc; the Cluster, Location, and lifetime ledgers never reset. Ordinary membership does not disclose these details, and neither read capability permits capacity or usage mutation.

Finite Cluster, Location, monthly Job, and lifetime Job limits are part of each published entitlement version, including custom tiers. Lowering a current-count limit below existing usage blocks only additional creates or admissions. It does not remove existing Clusters, Locations, or Jobs, and it does not revoke otherwise-authorized reads, updates, or deletions. A new logical Job admission charges its UTC-month and lifetime ledgers atomically; retries of the same idempotent admission do not consume either allowance twice.

Platform entitlement-definition, version, organization-transition, default, capacity, and reconciliation operations are separate AdminFull workflows and are not assignable organization capabilities.

The organization entitlement-pin administration surface uses one lifecycle for exact version changes, suspension, resume, explicit activation, and expiry changes. Call POST /v1/admin/orgs/{organizationId}/entitlement-pin/validate with the intended lifecycle kind, exact source pin and policy versions, target state, and UTC effective time before creating the transition. Only one pending transition may exist; a new command can explicitly replace it, and its durable status remains readable at GET /v1/admin/orgs/{organizationId}/entitlement-pin/transitions/{transitionId}. Immediate and scheduled execution both use the same stale-source protection. The validation response also reports operationalUsageImpacts for storage, Cluster count, Location count, UTC-month Jobs, and lifetime Jobs against the target version. Every item includes target limit, used/reserved values, remaining allowance, and overage; only the UTC-month Job item has resetAtUtc.

Retired targets cannot be newly selected, scheduled, resumed, reactivated, or extended. An existing active retired pin may remain active until its current expiry and may be shortened immediately. Access expires exactly at validUntilUtc; authorization does not wait for a scheduler, transition write, or notification delivery. A background detector later records exactly one system-source expiry audit event and a correlated policy-cache invalidation for that expiry boundary. Delayed or retried event delivery cannot extend access.

On this page