Cluster Sharing and Permissions
The workflow for provisioning cluster shares and handling read and write access across spatial scopes.
Spatial clusters contain locations and their related documents, bundles, and annotations. Cluster lifecycle authority and shared read/write access are separate decisions.
Cluster Lifecycle
Create an organization-owned cluster with POST /v1/spatial/clusters. Set
the JSON ownerType to the number 1 (Org), not the string "Org"; new user-owned clusters are rejected. New locations must
also belong to an organization-owned cluster. Creation requires the current
credential's final ClusterCreate=Allow decision in that organization. An
organization role or membership does not independently authorize creation, and
the final decision remains subject to the exact organization entitlement
version and any personal-access-token organization and capability ceilings.
Use PATCH /v1/spatial/clusters/{clusterId} to change cluster metadata and
DELETE /v1/spatial/clusters/{clusterId} to remove a cluster and its documents.
Update requires final ClusterUpdate=Allow, while delete independently requires
final ClusterDelete=Allow. Being allowed to update never implies delete
authority.
Known-resource lifecycle authorization failures return the stable structured
403 Forbidden permission-denial payload. Its categories distinguish an
ordinary missing capability from an organization entitlement ceiling, a PAT
ceiling, and any applicable operational prerequisite. A missing cluster
returns 404 Not Found.
List Visibility
GET /v1/spatial/clusters requires final ClusterView=Read for every returned
cluster. The API evaluates group and direct assignments, protected-owner and
legacy Contributor sources, the exact organization entitlement version, and
the current credential ceiling. It removes unauthorized clusters before
search, sorting, and offset/limit pagination. Hidden matches therefore do not
change the returned page or hasNextPage.
Supplying ownerType and ownerId only narrows the authorized result; owner
membership by itself does not make a cluster visible. Personal access tokens
are also restricted to their current organization bindings and capability
maximums.
GET /v1/spatial/clusters/{clusterId} applies the same final
ClusterView=Read decision to cluster detail. An active, verified direct-user
Contributor compatibility row can still supply that cluster-local read source,
but it does not grant ClusterUpdate or ClusterDelete.
Discover Shared Clusters Across Organizations
Use GET /v1/spatial/shared-clusters for a current-user picker that contains
only clusters marked as shared. The request does not need an active
organization or cluster selection. It unions active shared-resource workflows
with still-unmigrated direct-user Contributor compatibility rows, deduplicates
the same cluster across those sources, and runs the current evaluator before
offset/limit pagination. Revoked provenance, stale grants, and candidates that
no longer have final ClusterView=Read are omitted without shortening the
authorized page.
Each item contains safe organization and cluster display data, including the
cluster color fields, plus a provenance summary. isSharedAccessGuest means
that the active shared-resource workflow originally created the user's
zero-permission membership shell; it is presentation metadata and never grants
access. hasLegacyContributorCompatibility identifies a still-active legacy
candidate. The effectiveCapabilities collection reports the current final
value, entitlement-blocked state, and allowed actions for every capability
evaluated in the cluster context. These values already include the owning
organization's exact entitlement version and any PAT organization/capability
ceilings.
GET /v1/spatial/shared-clusters?offset=0&limit=100Resolve a share target
Before creating a share, search the central privacy-aware user directory:
GET /v1/users?search=person&limit=20&includeProfilePicture=trueThree or more trimmed characters search every active, non-rejected account.
Accounts known through an organization roster the caller may view can match and
return their authorized profile/contact fields. External accounts match only by
username and return only id, username, isKnown: false, and an optional
temporary profilePicture; all other profile fields are blank or null.
Use the selected result's id as targetUserId in the shared-Cluster create
request. Cluster and Document-folder pickers use this same directory. Creation
still revalidates exact resource authority, invitation/membership, delegation,
entitlement, concurrency, and target state.
The former
GET /v1/spatial/shared-clusters/targets?organizationId=...&clusterId=...
route is deprecated and remains temporarily available for client compatibility.
Create and manage authenticated shared access
Use POST /v1/spatial/shared-clusters to share one organization-owned Cluster
with an existing active user. Supply a stable client-generated workflowId;
that ID is the idempotency identity for an ambiguous retry. The request also
contains the owning organizationId, clusterId, targetUserId, and the exact
ordinary permission contributions selected by the sharing interface:
{
"workflowId": "11111111-1111-4111-8111-111111111111",
"organizationId": "22222222-2222-4222-8222-222222222222",
"clusterId": "33333333-3333-4333-8333-333333333333",
"targetUserId": "44444444-4444-4444-8444-444444444444",
"grants": [
{
"capabilityKey": "ClusterView",
"scopeType": "Cluster",
"scopeId": "33333333-3333-4333-8333-333333333333",
"parentClusterId": "33333333-3333-4333-8333-333333333333",
"value": "Read"
}
]
}Every workflow requires exact ClusterView=Read for the shared Cluster. Other
selected grants must be ordinary delegable resource permissions inside that
Cluster subtree. Administrative permissions, exact-target cleanup actions,
unrelated resources, entitlement versions, product grants, storage overrides,
and Cluster/Location/Job capacity changes are rejected.
The actor must be able to manage and delegate every requested contribution.
When the target has no organization membership, the actor also needs
OrganizationMembersInvite; PixService creates a zero-permission Viewer-valued
compatibility shell and records that this workflow owns its membership purpose.
An existing membership and its role are preserved. In both cases, the target's
final access remains capped by the owning organization's current entitlement
version, PAT ceiling, and organization-wide operational limits.
An exact retry with the same workflow ID and contributions returns the current workflow without incrementing the permission version or creating another membership, assignment, audit event, or outbox event. Reusing the workflow ID or the same organization/user/Cluster identity with different create content returns a conflict instead of silently changing access.
Use PUT /v1/spatial/shared-clusters/{workflowId} to replace the set of
contributions owned by that workflow. Include expectedAccessConcurrencyVersion
and the complete desired grants collection. Removed workflow origins are
revoked, but a canonical assignment remains when a manual, invitation,
migration, or another shared workflow origin still needs it. An exact update
retry is a no-op even when it carries the pre-update expected version.
Use DELETE /v1/spatial/shared-clusters/{workflowId} with
expectedAccessConcurrencyVersion and an optional bounded reason to revoke
the workflow. Revocation removes only its origins. If the workflow originally
created the membership, guarded cleanup removes that shell only when no other
active shared workflow, direct grant, permission group, protected-owner
relation, active invitation, or promoted role still needs it. An exact retry of
the same terminal revocation returns the current revoked state.
Lifecycle responses include the workflow and resource identities, status,
createdMembership, presentation-only isSharedAccess and
isSharedAccessGuest, access concurrency version, committed permission
version, and the normalized contribution set for create/update. Create, update,
revoke, and membership cleanup have distinct audit/outbox event types.
Before rendering a manager's existing workflow list, call
GET /v1/spatial/shared-clusters/managed?organizationId={organizationId}&clusterId={clusterId}.
This is an authorized Cluster-management read, not recipient discovery. It
returns only active workflows for that exact Cluster, including target user,
access concurrency version, membership-purpose flag, and active normalized
contributions. Use those versions for subsequent PUT or DELETE requests and
refresh the list after 409 Conflict.
Read Effective Access
Call GET /v1/spatial/clusters/{clusterId}/permissions to retrieve independent
final capability decisions projected as compatibility flags:
canReadrequiresClusterView=Read.canUploadrequiresClusterDocuments=Write.canManageClusterrequiresClusterUpdate=Allow.canManageSharesrequiresManageResourcePermissions=Allowat the cluster.- the applicable legacy
shareRole, when present
The flags are not inferred from one broad role or write boolean. For example,
a user can manage cluster metadata without being allowed to manage access, or
can read cluster documents without being allowed to upload them. A returned
legacy shareRole describes the compatibility source; it does not bypass the
final evaluator decisions. Use these values to guide the interface, but treat
the API response to each mutation as authoritative.
Authenticated Cluster Shares
The authenticated sharing routes under
/v1/spatial/clusters/{clusterId}/shares are deprecated. Their OpenAPI
operations are marked deprecated and clients should move access provisioning to
organization membership plus group/direct permission management.
Legacy share rows are now read-only:
GET /v1/spatial/clusters/{clusterId}/sharesremains available for compatibility inventory.POST /v1/spatial/clusters/{clusterId}/sharesrejects all new legacy share rows.PATCH /v1/spatial/clusters/{clusterId}/shares/{shareId}rejects legacy role changes.DELETE /v1/spatial/clusters/{clusterId}/shares/{shareId}remains available to revoke an exact existing row as access-reducing cleanup.
Only existing direct-user Contributor rows remain compatibility authorization sources. They retain their current cluster read/write behavior, including the existing job and external-link write paths, without cluster lifecycle or share-management authority. Viewer and organization-target legacy rows are not authorization or migration sources. Do not build new integrations around these deprecated routes.
External anonymous links are a separate mechanism. Do not add a user to an organization merely because they opened an external link.