iblai-api-catalog-invitation
Manage an organization's catalog invitations, licenses, access requests, and
content suggestions from the API. This is the Data Manager (DM)
dl_catalog_invitations app — the entitlement and onboarding layer on top of
the catalog (/iblai-api-catalog):
- Invitations — invite users (or generate redeemable "blank" invites) to a platform, a course, or a program; single, bulk, blank, redeem, and check.
- Licenses — create/update seat pools (platform / user / course / program licenses) and assign them to individual users or to user groups.
- Access requests — let members request course (or program) access and let admins approve/reject them.
- Suggestions — push course, program, or pathway suggestions to a user or a user group (single, bulk, group).
Use when inviting users, issuing or assigning license seats, reviewing access requests, or suggesting content.
Auth & conventions
- Base URL:
https://api.iblai.app/dm— these are Data Manager (DM) endpoints, so the/dmprefix is required; the/api/catalog/...paths below are appended to it (e.g.https://api.iblai.app/dm/api/catalog/invitations/platform/)./dmis the gateway prefix and is not part of the app's own route table. - Header:
Authorization: Api-Token $IBLAI_API_KEYon every request (except the two public check endpoints, which take no auth). - Path vars: none — every resource is selected by query param (GET /
DELETE) or body field (POST).
{org}=$IBLAI_ORGappears on the wire asorg/platform_key/key/platform_org(all mean the org key);course_id(opaque-keys form, URL-encode in query strings) andprogram_key(e.g.org+program-id) identify catalog items. - Permission tiers (enforced per view):
IsDMAdmin= DM admin;Is(DM|Platform)Admin= platform admins or DM admins;IsPlatformAdminReadOnly= read-only for platform admins;IsPlatformMember= any platform member;IsEdxUserReadOnly/IsDepartmentModeAdminInPlatformwiden suggestion access. License create/update is DM-admin only. When RBAC is enabled, invitation calls also require the matchingIbl.Catalog/{Platform|Course|Program}Invitations/permission for the target platform. - DELETE / destructive / outward-facing calls (invite send, bulk invite, redeem, license assign/unassign, access-request approve) say "Confirm with the user first."
- Not connected yet? Run
/iblai-api-loginfirst to populateIBLAI_ORG,IBLAI_USERNAME, andIBLAI_API_KEY.
Reads
Platform invitations
Is(DM|Platform)Admin (the check endpoint is public). Invitation to_json()
returns {id, user_id, username, email, created, started, source, redirect_to, expired, active, metadata, platform_key}.
- GET
/api/catalog/invitations/platform/— paginated list; filter byplatform_key,org,email,source,active,sort(default-id); any other param becomes ametadata__<key>filter. (RBAC:platform_keyrequired when RBAC is on.) - GET
/api/catalog/invitations/platform/check/— public, no auth;email(required, query).200if an active platform invitation exists,404if not.
Course invitations
IsDMAdmin | IsPlatformAdminReadOnly | IsPlatformAdminForCourse on list/create;
IsDMAdmin | IsPlatformAdminForCourse on blank/redeem. Result to_json() carries course_id instead of platform_key.
- GET
/api/catalog/invitations/course/— paginated list; filter bycourse_id,email,source,active,platform_key/key,org/platform_org,sort(default-id); other params →metadata__<key>.
Program invitations
IsDMAdmin | IsPlatformAdminReadOnly | IsPlatformAdminForProgram on list/create;
IsDMAdmin | IsPlatformAdminForProgram on blank/redeem (bulk is Is(DM|Platform)Admin). Result to_json() carries program_key.
- GET
/api/catalog/invitations/program/— paginated list; filter byprogram_key,program_id,email,source,active,platform_key/key,org/platform_org,sort(default-id); other params →metadata__<key>.
Platform licenses
Seat pools at the platform level. GET is IsDMAdmin | IsPlatformAdminReadOnly; create/update are IsDMAdmin only. License to_json() returns {id, created, started, expired, name, count, active, metadata, source, external_id, platform_key}.
- GET
/api/catalog/licenses/platform/— paginated list; filter byplatform_key/key,name,source,active,query(name icontains),sort(default-id); other params →metadata__<key>.
User licenses
Platform-level seat pools assignable to specific users/groups. GET is IsDMAdmin | IsPlatformAdminReadOnly; create/update IsDMAdmin only; assignments Is(DM|Platform)Admin (the assignment check is public).
- GET
/api/catalog/licenses/user/— paginated list; same filters as platform licenses. Each result embeds anassignmentssummary{total, active, pending}. - GET
/api/catalog/licenses/user/assignment/— paginated per-user assignments;license_idrequired, plusplatform_key/platform_org(required when multitenancy is on),sort(defaultid). - GET
/api/catalog/licenses/user/assignment/group/— paginated per-group assignments;license_idrequired, plus platform params,sort. - GET
/api/catalog/licenses/user/assignment/check/— public, no auth;email(required, query).200if an active user-license assignment exists,404if not.
Course licenses
Seat pools tied to a course. GET IsDMAdmin | IsPlatformAdminReadOnly; create/update IsDMAdmin only; assignments Is(DM|Platform)Admin. License to_json() adds course_id.
- GET
/api/catalog/licenses/course/— paginated list; filter byplatform_key/key,course_id,name,source,active,query,sort(default-id); other params →metadata__<key>. - GET
/api/catalog/licenses/course/assignment/— paginated per-user assignments;license_idrequired, platform params,sort(defaultid). - GET
/api/catalog/licenses/course/assignment/group/— paginated per-group assignments;license_idrequired, platform params,sort.
Program licenses
Seat pools tied to a program. Permissions identical to course licenses; result to_json() adds program_id/program_key.
- GET
/api/catalog/licenses/program/— paginated list; filter byplatform_key/key,program_id,name,source,active,query,sort(default-id); other params →metadata__<key>. Each result embeds anassignmentssummary. - GET
/api/catalog/licenses/program/assignment/— paginated per-user assignments;license_idrequired, platform params,sort(defaultid). - GET
/api/catalog/licenses/program/assignment/group/— paginated per-group assignments;license_idrequired, platform params,sort.
Access requests (course)
Members request access to a course; admins review. The user endpoint is
IsPlatformMember; the manage endpoint is Is(DM|Platform)Admin. Request
to_json() returns {id, user_id, username, name, approved, reviewed, created, modified, metadata, platform_key, course_id}.
- GET
/api/catalog/access_requests/course/request/— check the signed-in user's request status for a course;course_idrequired (query), plusplatform_key/platform_org. Returns{active, approved, exists}. - GET
/api/catalog/access_requests/course/manage/— admin: paginated list of access requests;platform_keyorplatform_orgrequired, plusreviewed(filter),sort(default-id).
Note:
urls.pyregisters only the course access-request routes (course/request,course/manage). There are no program/pathway access-request endpoints in this app.
Suggestions (course / program / pathway)
Push catalog suggestions to users or groups. The user (read) endpoint is
IsDMAdmin | IsPlatformAdminReadOnly | IsEdxUserReadOnly; manage / bulk /
group are IsDMAdmin | IsPlatformAdmin | IsDepartmentModeAdminInPlatform. The
three resource families (course, program, pathway) are structurally identical;
only the item identifier differs: course → course_id, program →
program_key, pathway → pathway_id.
Course suggestions
- GET
/api/catalog/suggestions/course/user/— a user's suggestions;userrequired (username or id, query), plusplatform_key/platform_org,sort(default-id),page,page_size. - GET
/api/catalog/suggestions/course/manage/— admin: platform suggestions;platform_keyorplatform_orgrequired, plusquery,sort(default-id),department_mode,page,page_size. - GET
/api/catalog/suggestions/course/manage/group/— admin: group suggestions;platform_keyorplatform_orgrequired, plusquery,sort(defaultid),department_mode,page,page_size.
Program suggestions
Same shapes; the item field is program_key (instead of course_id).
- GET
/api/catalog/suggestions/program/user/— a user's program suggestions (userrequired). - GET
/api/catalog/suggestions/program/manage/— admin list (platform_key/platform_orgrequired). - GET
/api/catalog/suggestions/program/manage/group/— admin group list.
Pathway suggestions
Same shapes; the item field is pathway_id.
- GET
/api/catalog/suggestions/pathway/user/— a user's pathway suggestions (userrequired). - GET
/api/catalog/suggestions/pathway/manage/— admin list (platform_key/platform_orgrequired). - GET
/api/catalog/suggestions/pathway/manage/group/— admin group list.
Writes
Platform invitations
- POST
/api/catalog/invitations/platform/— create/update one invitation. Confirm with the user first (outward-facing).{ "platform_key": "str (required)", "email": "str (required)", "active": "bool", ...metadata }. - POST
/api/catalog/invitations/platform/bulk/— bulk-create. Confirm with the user first.{ "platform_key": "str (required)", "invitation_data": [{ "platform_key": "...", "email": "...", "active": "bool", ...metadata }] }. All items must belong toplatform_key. Returns{successes, error_codes}. - POST
/api/catalog/invitations/platform/blank/— create N redeemable blank invitations (no user yet). Confirm with the user first.{ "platform_key": "str (required)", "source": "str (required)", "count": "int (required)", ...metadata }. Returns{successes, error_codes}. - POST
/api/catalog/invitations/platform/redeem/— redeem a blank invitation onto a user. Confirm with the user first.{ "platform_key": "str (required)", "source": "str (required)", "email": "str", "username": "str", ...metadata }.
Course invitations
- POST
/api/catalog/invitations/course/— create/update one invitation (404if course unknown). Confirm with the user first.{ "course_id": "str (required)", "email": "str (required)", "active": "bool", ...metadata }. - POST
/api/catalog/invitations/course/bulk/— bulk-create. Confirm with the user first.{ "invitation_data": [{ "course_id": "...", "email": "...", "active": "bool", ...metadata }], "platform_key": "str (optional; inferred from first course if omitted)" }. All courses must share one platform. Returns{successes, error_codes}. - POST
/api/catalog/invitations/course/blank/— create N blank course invitations. Confirm with the user first.{ "course_id": "str (required)", "source": "str (required)", "count": "int (required)", ...metadata }. Returns{successes, error_codes}. - POST
/api/catalog/invitations/course/redeem/— redeem a blank course invitation. Confirm with the user first.{ "course_id": "str (required)", "source": "str (required)", "email": "str", "username": "str", ...metadata }.
Program invitations
- POST
/api/catalog/invitations/program/— create/update one invitation (404if program unknown). Confirm with the user first.{ "program_key": "str (required)", "email": "str (required)", "active": "bool", ...metadata }. - POST
/api/catalog/invitations/program/bulk/— bulk-create. Confirm with the user first.{ "invitation_data": [{ "program_key": "...", "email": "...", "active": "bool", ...metadata }], "platform_key": "str (optional; inferred from first program)" }. All programs must share one platform. Returns{successes, error_codes}. - POST
/api/catalog/invitations/program/blank/— create N blank program invitations. Confirm with the user first.{ "program_key": "str (required)", "source": "str (required)", "count": "int (required)", ...metadata }. Returns{successes, error_codes}. - POST
/api/catalog/invitations/program/redeem/— redeem a blank program invitation. Confirm with the user first.{ "program_key": "str (required)", "source": "str (required)", "email": "str", "username": "str", ...metadata }.
Platform licenses
- POST
/api/catalog/licenses/platform/create/— create a license.{ "platform_key": "str (required)", "name": "str", "count": "int (default 0)", "started": "datetime", "expired": "datetime", "active": "bool (default true)", "metadata": {}, "source": "str", "external_id": "str (unique)" }. - POST
/api/catalog/licenses/platform/update/— update a license; identify bylicense_idorexternal_id.{ "license_id": "int", "external_id": "str", "name": "str", "count": "int", "started": "datetime", "expired": "datetime", "active": "bool", "metadata": {}, "source": "str", "change_type": "str (default 'update')" }. The platform cannot be changed; each update writes a history record.
User licenses
- POST
/api/catalog/licenses/user/create/— create. Same body as platform create plus optionalenrollment_config(dict).platform_keyrequired. - POST
/api/catalog/licenses/user/update/— update; identify bylicense_idorexternal_id; same fields as platform update plusenrollment_config. - POST
/api/catalog/licenses/user/assignment/— assign/update a seat for one user. Confirm with the user first.{ "license_id": "int (required)", "user_id": "int", "email": "str", "platform_key": "str", "platform_org": "str", "active": "bool", "fulfilled": "bool", "metadata": {} }(one ofuser_id/emailrequired). - DELETE
/api/catalog/licenses/user/assignment/— unassign one seat;assignment_idrequired (query), optionalplatform_key/platform_org. Confirm with the user first. - POST
/api/catalog/licenses/user/assignment/group/— assign/update a seat for a user group. Confirm with the user first.{ "license_id": "int (required)", "group_id": "int (required)", "platform_key": "str", "platform_org": "str", "active": "bool", "fulfilled": "bool", "metadata": {} }. - DELETE
/api/catalog/licenses/user/assignment/group/— unassign a group seat;assignment_idrequired (query). Confirm with the user first.
Course licenses
- POST
/api/catalog/licenses/course/create/— create.{ "platform_key": "str (required)", "course_id": "str (required)", "name": "str", "count": "int", "started": "datetime", "expired": "datetime", "active": "bool", "metadata": {}, "enrollment_config": {}, "source": "str", "external_id": "str" }. - POST
/api/catalog/licenses/course/update/— update; identify bylicense_idorexternal_id; same updatable fields as user-license update (platform/course immutable). - POST
/api/catalog/licenses/course/assignment/— assign/update a course seat to a user. Confirm with the user first.{ "license_id": "int (required)", "user_id": "int" | "email": "str", "platform_key": "str", "platform_org": "str", "active": "bool", "fulfilled": "bool", "metadata": {} }. - DELETE
/api/catalog/licenses/course/assignment/— unassign one course seat;assignment_idrequired (query). Confirm with the user first. - POST
/api/catalog/licenses/course/assignment/group/— assign/update a course seat to a group. Confirm with the user first.{ "license_id": "int (required)", "group_id": "int (required)", "platform_key": "str", "platform_org": "str", "active": "bool", "fulfilled": "bool", "metadata": {} }. - DELETE
/api/catalog/licenses/course/assignment/group/— unassign a group course seat;assignment_idrequired (query). Confirm with the user first.
Program licenses
- POST
/api/catalog/licenses/program/create/— create.{ "platform_key": "str (required)", "program_id": "str (required)", "name": "str", "count": "int", "started": "datetime", "expired": "datetime", "active": "bool", "metadata": {}, "enrollment_config": {}, "source": "str", "external_id": "str" }. - POST
/api/catalog/licenses/program/update/— update; identify bylicense_idorexternal_id; same updatable fields (platform/program immutable). - POST
/api/catalog/licenses/program/assignment/— assign/update a program seat to a user. Confirm with the user first.{ "license_id": "int (required)", "user_id": "int" | "email": "str", "platform_key": "str", "platform_org": "str", "active": "bool", "fulfilled": "bool", "metadata": {} }. - DELETE
/api/catalog/licenses/program/assignment/— unassign one program seat;assignment_idrequired (query). Confirm with the user first. - POST
/api/catalog/licenses/program/assignment/group/— assign/update a program seat to a group. Confirm with the user first.{ "license_id": "int (required)", "group_id": "int (required)", "platform_key": "str", "platform_org": "str", "active": "bool", "fulfilled": "bool", "metadata": {} }. - DELETE
/api/catalog/licenses/program/assignment/group/— unassign a group program seat;assignment_idrequired (query). Confirm with the user first.
Access requests (course)
- POST
/api/catalog/access_requests/course/request/— create an access request as the signed-in user.{ "course_id": "str (required)", "platform_key": "str", "platform_org": "str", ...metadata }. - POST
/api/catalog/access_requests/course/manage/— admin: approve/reject a request. Confirm with the user first (approving grants access).{ "request_id": "int (required)", "approved": "bool", "active": "bool", "platform_key": "str", "platform_org": "str" }.
Suggestions (course / program / pathway)
Course suggestions
- POST
/api/catalog/suggestions/course/manage/— create/update a per-user suggestion (201created,200updated).{ "platform_key": "str (required)", "course_id": "str (required)", "user_id": "str|int (required)", "accepted": "bool", "visible": "bool", "metadata": {} }. - DELETE
/api/catalog/suggestions/course/manage/— delete a suggestion;suggestion_idrequired (query). Confirm with the user first. - POST
/api/catalog/suggestions/course/manage/bulk/— bulk-create.{ "platform_key": "str (required)", "suggestion_data": [{ "course_id": "...", "user_id": "...", "accepted": "bool", "visible": "bool", "metadata": {} }] }. Returns{successes, error_codes}. - POST
/api/catalog/suggestions/course/manage/group/— create/update a group suggestion.{ "platform_key": "str (required)", "course_id": "str (required)", "group_id": "str|int (required)", "accepted": "bool", "visible": "bool", "metadata": {} }. - DELETE
/api/catalog/suggestions/course/manage/group/— delete a group suggestion;suggestion_idrequired (query). Confirm with the user first.
Program suggestions
Same shapes; the item field is program_key (instead of course_id).
- POST
/api/catalog/suggestions/program/manage/— create/update per-user:{ "platform_key": "...", "program_key": "...", "user_id": "...", "accepted": "bool", "visible": "bool", "metadata": {} }. - DELETE
/api/catalog/suggestions/program/manage/— delete bysuggestion_id(query). Confirm with the user first. - POST
/api/catalog/suggestions/program/manage/bulk/— bulk;{ "platform_key": "...", "suggestion_data": [{ "program_key": "...", "user_id": "...", ... }] }. - POST
/api/catalog/suggestions/program/manage/group/— create/update group:{ "platform_key": "...", "program_key": "...", "group_id": "...", ... }. - DELETE
/api/catalog/suggestions/program/manage/group/— delete group suggestion bysuggestion_id(query). Confirm with the user first.
Pathway suggestions
Same shapes; the item field is pathway_id.
- POST
/api/catalog/suggestions/pathway/manage/— create/update per-user:{ "platform_key": "...", "pathway_id": "...", "user_id": "...", "accepted": "bool", "visible": "bool", "metadata": {} }. - DELETE
/api/catalog/suggestions/pathway/manage/— delete bysuggestion_id(query). Confirm with the user first. - POST
/api/catalog/suggestions/pathway/manage/bulk/— bulk;{ "platform_key": "...", "suggestion_data": [{ "pathway_id": "...", "user_id": "...", ... }] }. - POST
/api/catalog/suggestions/pathway/manage/group/— create/update group:{ "platform_key": "...", "pathway_id": "...", "group_id": "...", ... }. - DELETE
/api/catalog/suggestions/pathway/manage/group/— delete group suggestion bysuggestion_id(query). Confirm with the user first.
Example
Assign one user-license seat to a user by email (outward-facing — confirm first):
curl -X POST \
"https://api.iblai.app/dm/api/catalog/licenses/user/assignment/" \
-H "Authorization: Api-Token $IBLAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"license_id": 789,
"email": "newhire@example.com",
"platform_key": "'"$IBLAI_ORG"'",
"active": true
}'
Notes
- All endpoints are DM endpoints under
https://api.iblai.app/dm(/dm+/api/catalog/...); omitting/dmwill not resolve. - No path parameters. Select every resource by query param (GET/DELETE) or
body field (POST). License/assignment IDs are integers (
license_id,assignment_id,suggestion_id,request_id); identify a license to update bylicense_idorexternal_id. - Bulk and blank/redeem operations are write-heavy and user-facing — bulk invites send to every listed email, blank invites create redeemable codes, redeem associates a code with a real user. Treat all of them, plus every license assign/unassign and every access-request approval, as actions to confirm with the user first.
- Bulk invitations must stay within one platform — the server rejects
(
400) any item whose course/program/platform differs from the request'splatform_key. - Org on the wire appears as
org,platform_key,key, orplatform_org(all the org key). When multitenancy is enabled, license- and assignment-related GETs require aplatform_key/platform_org. - Pagination envelope is the standard
{count, next, previous, results[]}for every list endpoint here (invitations, licenses, assignments, access requests, suggestions);sortdefaults to-idon most lists butidon the assignment and group-suggestion lists. - Public, unauthenticated endpoints:
invitations/platform/check/andlicenses/user/assignment/check/— both take onlyemailand answer200(exists) /404(none). - RBAC gating on invitations. When
rbac_enabled(), invitation calls additionally enforceIbl.Catalog/{Platform|Course|Program}Invitations/permission for the target platform (and platform invitation GET then requiresplatform_key); a missing permission returns403. - DELETE on the invitation collection endpoints is a stub. The
delete()handlers oninvitations/platform/,invitations/course/, andinvitations/program/are unimplemented (return200without deleting) — they are not usable for removing invitations, so they are not listed above.