iblai-api-scim
Mirrored from
iblai/vibe·skills/users/iblai-api-scim/SKILL.md. This page is generated — edit it in the repository, not here.
Provision and manage an organization's directory over the SCIM 2.0 REST API: users (modeled on the SCIM User schema plus the Enterprise User extension) and RBAC groups (exposed via the SCIM Group schema), including RBAC group membership that automatically links users to the platforms behind those groups. Use when standing up or syncing directory provisioning for an org — creating or deactivating users, managing RBAC group membership, or wiring an identity provider's SCIM provisioning.
Scope is exactly two resources:
UsersandGroups. The SCIM app in the DM service registers only these two — there are no Departments, DepartmentMembers, or GroupMembers SCIM endpoints. (Departments and non-RBAC groups still appear inside a user's Enterprise-extension response block, but they are read-only there; there are no SCIM routes to manage them.)
Auth & conventions
- Base URL:
https://api.iblai.app/dm— these are Data Manager (DM) endpoints, so the/dmprefix is required; the/api/orgs/…/scim/v2/…paths below are appended to it (e.g.https://api.iblai.app/dm/api/orgs/{platform_key}/scim/v2/Users). - Header: SCIM accepts two auth schemes (both authentication classes are
wired on every view:
PlatformApiKeyAuthentication,OAuth2ClientCredentialAuthentication):Authorization: Api-Token $IBLAI_API_KEY— the Platform API Token used by the otheriblai-*skills; orAuthorization: Bearer <oauth2-token>— an OAuth2 client-credentials token.
- Content type: send
Content-Type: application/scim+jsonon every write (the server also accepts plainapplication/json). - Path / scope: SCIM paths are
/api/orgs/{platform_key}/scim/v2/...where{platform_key}=$IBLAI_ORG(the org key). The token's scope must match theplatform_keyin the URL. - Resource casing — keep verbatim. Both resources are PascalCase:
UsersandGroups. Do not lowercase them. - Trailing slash — keep verbatim. Collection routes have no trailing
slash (
/Users,/Groups); single-resource detail routes require a trailing slash (/Users/{id}/,/Groups/{id}/). The group action routes (/Groups/{id}/add_members,/Groups/{id}/remove_members) have no trailing slash. - DELETE / destructive calls — confirm with the user first.
- Not connected yet? Run
/iblai-api-loginfirst to populateIBLAI_ORG,IBLAI_USERNAME, andIBLAI_API_KEY.
Reads
Users
User resources use the SCIM core User schema
(urn:ietf:params:scim:schemas:core:2.0:User) with the Enterprise User
extension on responses
(urn:ietf:params:scim:schemas:extension:enterprise:2.0:User).
- GET
/api/orgs/{platform_key}/scim/v2/Users— list users (filtering, sorting, and pagination supported — see Notes). - GET
/api/orgs/{platform_key}/scim/v2/Users/{id}/— retrieve one user.
Response — Enterprise extension. The extension block is returned under the
key urn_ietf_params_scim_schemas_extension_enterprise_2_0_User (underscores,
not colons) and carries:
edxData— edX-specific user data.userData— additional user metadata.departments— departments the user belongs to (id,name,$ref,isAdmin).groups— user-groups the user belongs to (id,name,$ref).rbacGroups— RBAC groups (id,uniqueId,name,description,platformKey).platforms— platforms the user can access (id,key,name,org).
(On create/update/PATCH responses these lists are returned empty; the populated lists come back on GET list/retrieve.)
Groups (RBAC groups)
The Group resource maps to the platform's RBAC groups and is exposed via the
SCIM Group schema (urn:ietf:params:scim:schemas:core:2.0:Group). The SCIM id
field is the RBAC group's unique_id (not a numeric id). These endpoints
manage existing RBAC groups only — POST does not create a new group; if the
referenced group's unique_id does not exist you get a 404 SCIM error.
- GET
/api/orgs/{platform_key}/scim/v2/Groups— list RBAC groups (filtering supported; passexcludedAttributes=membersto omit the member list). - GET
/api/orgs/{platform_key}/scim/v2/Groups/{id}/— retrieve one RBAC group byunique_id.
Writes
Users
- POST
/api/orgs/{platform_key}/scim/v2/Users— create (or, with"update": true, modify an existing) user. - PUT
/api/orgs/{platform_key}/scim/v2/Users/{id}/— replace a user's core fields (userName,name.formatted, primaryemailsvalue,active); only the fields present in the body are changed. - PATCH
/api/orgs/{platform_key}/scim/v2/Users/{id}/— patch a user. Accepts either a SCIM PatchOp body (Operationswithop/path/value; supported paths:userName,name.formatted,emails[type eq "work"].value,active,displayName, andexternalId— whereexternalIdis treated as an RBAC groupunique_idto add the user to) or a plain partial body (userName,name,emails,active,displayName). - DELETE
/api/orgs/{platform_key}/scim/v2/Users/{id}/— not supported; returns405 Method Not Allowed. (User deactivation is done by settingactive: false, not by DELETE.)
Request body for POST (key attributes):
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "john.doe@example.com",
"name": { "formatted": "John Doe", "givenName": "John", "familyName": "Doe" },
"emails": [{ "value": "john.doe@example.com", "primary": true }],
"password": "securepassword123",
"provider": "google-oauth2",
"tpaUid": "john.doe@example.com",
"isStaff": false,
"active": true,
"update": false,
"platformOrgs": ["org1", "org2"],
"departmentIds": [1, 2, 3],
"groupIds": [1, 2, 3],
"rbacGroupUniqueIds": ["students", "course_123_enrolled"]
}
Field notes: userName is the unique username/email (required); emails is
required; name is required (may be partly blank); password / provider /
tpaUid / isStaff are optional and forwarded to the LMS on create;
active toggles account activation (set false to deactivate); update: true
modifies an existing user instead of creating (skips the duplicate check);
platformOrgs links the user to those org platforms; departmentIds /
groupIds assign existing departments / user-groups by integer id (validated —
unknown ids return 400); rbacGroupUniqueIds assigns RBAC groups by unique id
and auto-links the required platforms (see Notes). On a create that finds the
user already exists, the API returns the existing user with HTTP 200 and still
applies the link fields, rather than erroring.
Groups (RBAC groups)
POST
/api/orgs/{platform_key}/scim/v2/Groups— manage an existing RBAC group: optionally update itsdisplayName/descriptionand set its full member list. The group is located byid(orexternalId), both of which map to the RBAC group'sunique_id.{ "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"], "id": "students", "displayName": "Students", "description": "All enrolled students", "members": [{ "value": "user-id-1", "display": "john.doe@example.com" }] }members[].valueis resolved as a user id, then username, then email; if no user matches, one is created from the member data. The member list passed here replaces the group's current membership.PUT
/api/orgs/{platform_key}/scim/v2/Groups/{id}/— update an existing RBAC group'sdisplayName/description, and (ifmembersis present) replace its complete member list (same body shape as POST, without needingidin the body — the id comes from the URL).PATCH
/api/orgs/{platform_key}/scim/v2/Groups/{id}/— patch an RBAC group. Accepts a SCIM PatchOp body whoseOperationssupportreplaceondisplayName/description/members(replace whole list),addonmembers, andremovewith amembers[value eq "<user-id>"]path — or a plain partial body (displayName,description,members).POST
/api/orgs/{platform_key}/scim/v2/Groups/{id}/add_members— add members via a SCIM PatchOp (onlyop: add,path: membersoperations are applied).{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], "Operations": [ { "op": "add", "path": "members", "value": [{ "value": "user-id-3", "display": "bob.wilson@example.com" }] } ] }POST
/api/orgs/{platform_key}/scim/v2/Groups/{id}/remove_members— remove members via a SCIM PatchOp. Each operation must beop: removewith a path of the formmembers[value eq "<user-id>"].{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], "Operations": [ { "op": "remove", "path": "members[value eq \"user-id-1\"]" } ] }DELETE
/api/orgs/{platform_key}/scim/v2/Groups/{id}/— hard-delete the RBAC group (returns204). Confirm with the user first.
Example
Create a SCIM user with RBAC groups (which auto-link the user's platforms):
curl -X POST \
"https://api.iblai.app/dm/api/orgs/$IBLAI_ORG/scim/v2/Users" \
-H "Authorization: Api-Token $IBLAI_API_KEY" \
-H "Content-Type: application/scim+json" \
-d '{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "jane.smith@example.com",
"name": { "formatted": "Jane Smith", "givenName": "Jane", "familyName": "Smith" },
"emails": [{ "value": "jane.smith@example.com", "primary": true }],
"active": true,
"rbacGroupUniqueIds": ["students", "course_123_enrolled"]
}'
Notes
- Error schema. Group-not-found returns the SCIM error object:
{"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"], "scimType": "invalidValue", "detail": "..."}with404. Other failures return a plain{"error": "..."}body. Standard HTTP codes apply:400invalid/missing fields (e.g. unknowndepartmentIds/groupIds/rbacGroupUniqueIds),401missing/invalid auth,404not found,405onDELETE Users/{id}/,409the user already exists on create (on a local match the API instead returns the existing user with200— useupdate: trueto modify),500server error. - Editing semantics. Users are edited by re-POSTing with
update: true, or viaPUT Users/{id}//PATCH Users/{id}/. Groups are edited viaPUT Groups/{id}/(replaces the wholememberslist) orPATCH Groups/{id}/; incremental membership changes go through the dedicatedadd_members/remove_membersactions, which take a PatchOp body (urn:ietf:params:scim:api:messages:2.0:PatchOpwith anOperationsarray ofop/path/value). - RBAC group assignment auto-links platforms. Assigning
rbacGroupUniqueIdson a user validates the groups exist, then automatically creates platform links for any platforms behind those RBAC groups the user isn't already linked to — so you can grant RBAC access without listingplatformOrgsexplicitly. RBAC assignment runs after all other linking. Default RBAC groups (server-configured) are applied to every user on platform link;rbacGroupUniqueIdsis additive on top of those. - Group lookup is platform-scoped, with optional fallback. Group lookups try
(unique_id, platform_key)first; if the server has strict platform matching disabled, they fall back to matchingunique_idon any platform. - Filtering, sorting & pagination. Both list endpoints accept SCIM
filterexpressions (e.g.userName eq "john.doe",displayName eq "Students"; user filters supportuserName,name.formatted,emails.value,active,id,externalId; group filters supportdisplayName,id,description).Userslist also honorsstartIndex/countpagination (1-based; defaultsstartIndex=1,count=50),sortBy(userName,name.formatted,active) /sortOrder(ascending/descending), andattributes/excludedAttributes.Groupslist does not paginate (it returns all matching groups) but does honorexcludedAttributes=members. - Enterprise extension key. On responses the extension block's key uses
underscores —
urn_ietf_params_scim_schemas_extension_enterprise_2_0_User— not the colon-delimited URN. - Schema reference. Interactive SCIM API docs (drf-spectacular) are published
at
https://base.manager.iblai.tech/api-docs/#/scim.