Joinable collections reference¶
A joinable collection is one people ask to be in, rather than one they match into. This page documents the join policy that controls who may ask and who approves, and the lifecycle a request goes through.
The join policy¶
Every joinable collection has a joinPolicy:
{
"approvalRequired": true,
"approvalGates": [
{ "order": 1, "type": "Collection", "approvers": ["1ee874ac-6c2c-4990-8fd6-e80fbc0b4e33"] },
{ "order": 2, "type": "Manager", "approvers": [] }
],
"joinableBy": {
"collectionIds": ["4fd301f8-0409-4856-bc3d-7f0102231f7a"]
}
}
| Property | Type | Description |
|---|---|---|
approvalRequired |
bool | Whether requests need approving. Required. |
approvalGates |
array | The approval steps, in order. At least one is required when approvalRequired is true. |
joinableBy |
object | Who is eligible to request. Omit for everyone. |
With approvalRequired set to false the collection is open to join — a request is granted immediately and the person becomes a member, and any gates are ignored.
Who may request¶
joinableBy scopes the collection to people who are already members of other collections:
Being in at least one of the listed collections makes someone eligible. If joinableBy is omitted, or its collectionIds is empty, everyone is eligible.
This is what makes the pattern in the introduction work: a criteria collection of everyone whose relationshipType is Employee becomes the scope, so only employees see the collection and can ask to join it.
Approval gates¶
When approval is required, each gate is one step that must be passed. Gates run in ascending order, and each must be approved before the next begins.
| Property | Type | Description |
|---|---|---|
order |
int | Must be greater than zero, and unique within the policy. |
type |
string | Identity, Collection or Manager. |
approvers |
array | Who approves, interpreted according to type. |
type |
approvers holds |
Who can approve |
|---|---|---|
Identity |
Identity ids | Any of the named people |
Collection |
Collection ids | Anyone who is a member of one of those collections |
Manager |
Nothing — leave it empty | The requester's own manager, resolved at approval time |
Manager gates find the manager through the relationship the request was made for, falling back to the manager of that relationship's org unit. Because the manager is resolved per request rather than configured, approvers is left empty. A policy may contain at most one Manager gate.
Two gates — first anyone in a named approver collection, then the requester's own manager — is the arrangement in the example at the top of this page.
Validation¶
The policy is rejected with a clear message if:
approvalRequiredis true and there are no gates- two gates share an
order, or anorderis not greater than zero - there is more than one
Managergate - a gate's
typeis not one of the three values - an
IdentityorCollectiongate has no approvers, or aCollectiongate's approvers are not valid ids
The request lifecycle¶
flowchart LR
A[Requested] --> B[PendingApproval]
A --> J[Joined]
B --> B
B --> J
B --> R[Rejected]
A --> C[Cancelled]
B --> C
J --> L[Left]
| Status | Meaning |
|---|---|
Requested |
Submitted. Where every request starts. |
PendingApproval |
Waiting at a gate. A request sits here once per gate. |
Approved |
Recorded in the history each time a gate passes. |
Rejected |
Turned down at a gate. |
Cancelled |
Withdrawn before a decision. |
Joined |
A member. |
Left |
Was a member and is no longer. |
An open-to-join collection takes a request straight from Requested to Joined. Otherwise the request enters PendingApproval at the first gate; approving a gate that is not the last returns it to PendingApproval at the next one, and approving the last makes the person a member.
Who may do what:
- Approve or reject — only someone who satisfies the gate the request is currently waiting at.
- Leave — only the member themselves, and only once
Joined. - Cancel — the requester, or the manager who submitted on their behalf, and only while the request is still
RequestedorPendingApproval.
Every request carries a lifecycle: an append-only list of what happened, each entry recording the status, who acted and when. It is the audit trail for how someone came to have access.
Requesting on behalf of someone¶
A manager can submit a request for one of their direct reports. The request records the subject as the requester, not the manager who filed it, so it appears in the subject's own lists and follows the same gates as if they had asked themselves.
The manager relationship is checked at submission, through the report's relationship or the org unit's manager, and the request is refused if the caller is not actually their manager.
Members¶
Membership on a joinable collection is per relationship, not just per person:
"memberIds": [
{ "objectId": "d42a1f3f-4a1b-42e5-bb04-63536796ec70", "relationshipId": "8c1e..." }
]
Someone holding two positions can be a member for one of them and not the other, which matters when a collection grants something tied to a particular job rather than to the person.
This differs from criteria collections
A criteria collection returns memberIds as plain identifiers. Only joinable collections pair the object with a relationship.
Administrators can add and remove members directly, bypassing the request flow entirely — useful for seeding a new collection with people who already have the access it represents. In PowerShell that is Import-JoinableCollectionMemberBatch, which takes IAM Core identity ids, not Entra object ids.