iblai-api-catalog
Manage an organization's learning catalog from the API: courses, programs, pathways, and resources; the skills and roles taxonomy (including each user's desired/reported skills and roles); course and program metadata; plus enrollment (course / program / pathway, admin and self), eligibility checks, catalog search, and course reviews. Use when populating the catalog, enrolling users, checking who can take what, or curating the skills/roles graph.
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/courses/). - Header:
Authorization: Api-Token $IBLAI_API_KEYon every request. - Path vars:
{org}=$IBLAI_ORG(a.k.a.org/platform_key/platform_orgon the wire),{username}=$IBLAI_USERNAME. Org/user are passed as query params or body fields, not baked into the path. - DELETE / destructive / outward-facing calls say "Confirm with the user first."
course_idvalues must be URL-encoded in query strings.- Not connected yet? Run
/iblai-api-loginfirst to populateIBLAI_ORG,IBLAI_USERNAME, andIBLAI_API_KEY.
Reads
Courses
- GET
/api/catalog/courses/— retrieve courses; filter bycourse_id,slug(case-insensitive),org(query params). Returns[{course_id, name, slug, org}].
Programs
- GET
/api/catalog/programs/— retrieve programs; filter byprogram_id,course_id,name,slug,enabled,org(query params). Returns[{program_id, org, slug, name, program_type, platform_key, enabled, course_list}].
Pathways
- GET
/api/catalog/pathways/— retrieve pathway(s); filter (query params) bypathway_id,pathway_uuid,user_id/username,platform_key,item_id,name,slug(case-insensitive),visible. Returns a (non-paginated) list of pathways, each with apath[]of items.
Resources
- GET
/api/catalog/resources/— retrieve resources; filter (query params) byid,user_id/username,platform_key/key,org/platform_org,resource_type,name,query(matchesnamevia icontains),item_id. Returns a non-paginated list. - GET
/api/catalog/resources/search/— paginated resource search; same filters,page(default1),page_size(default50). Results newest-first. Prefer this for large result sets.
Metadata
Course
- GET
/api/catalog/metadata/course/— read a course's metadata bycourse_id(query param; the response keys are dynamic, e.g.{subject, tags, level, topics, promotion, slug, ...}).GET /api/catalog/metadata/course/{field}/reads one metadata field. - GET
/api/catalog/metadata/course-public/— read a course's public metadata bycourse_id(no auth/permission required; ignores course visibility).course-public/{field}/reads one field. Read-only.
Program
- GET
/api/catalog/metadata/program/— read a program's metadata;program_idrequired, optionalorg(query params).program/{field}/reads one field. - GET
/api/catalog/metadata/program-public/— read a program's public metadata (program_idrequired, optionalorg; no auth required).program-public/{field}/reads one field. Read-only.
Choices
- GET
/api/catalog/metadata/choices/— query allowed metadata choices; requiresfield_keyorscope(query params), optionalorg. Returns the choice dict (404if none).
Skills
- GET
/api/catalog/skills/— retrieve skills (paginated); filter byid,name,name__iexact,slug,platform_key;sort(defaultid). - GET
/api/catalog/skills/desired/— a user's desired skills byuser_id/username(400if the user has none). - GET
/api/catalog/skills/reported/— a user's reported skills byuser_id/username(200with an empty record{"user_id":null,"username":null,"skills":[],"data":null}when there are none).
Roles
- GET
/api/catalog/roles/— retrieve roles (paginated); filter byid,name,name__iexact,slug,platform_key;sort(defaultid). Each role embeds itsskills[]. - GET
/api/catalog/roles/desired/— a user's desired roles byuser_id/username. - GET
/api/catalog/roles/reported/— a user's reported roles byuser_id/username.
Eligibility
- GET
/api/catalog/eligibility/courses/— list courses a user is eligible for; paramsuser_id/username,org,query. - GET
/api/catalog/eligibility/courses/check/— check eligibility for one course;course_idrequired plususer_idorusername(course_idURL-encoded), plusorg,local_only(skip the remote edX enroll-status call). Always returns{is_eligible}; unlesslocal_onlyis set, the response is merged with the edX enroll-status fields (e.g.is_enrolled, etc.).
Enrollment
Courses
- GET
/api/catalog/enrollment/courses/search/— paginated enrollment search; query params (at least one ofuser_id,username,email,course_id,slug,org,platform_keyrequired) pluscourse_name(substring),sort(default-id),include_default_platform,include_archived_courses(default false),page,page_size. Returns{count, next_page, previous_page, results[]}of active enrollments.
Programs
- GET
/api/catalog/enrollment/programs/— query program enrollments; a user identifier (user_id/username) is required (the call400s on an unresolvable user), and you may also filter byprogram_id/slug,org/platform_key,program_type(standard|platform|custom),include_metadata(defaulttrue),include_default_platform. - GET
/api/catalog/enrollment/programs/search/— paginated program-enrollment search; same params as the GET above plussort,page,page_size. Active enrollments only.
Pathways
- GET
/api/catalog/enrollment/pathways/— query pathway enrollments; a user identifier (user_id/username) is required, plus optionalpathway_id/pathway_uuid/slug,org/platform_key,include_metadata(defaulttrue),include_default_platform. - GET
/api/catalog/enrollment/pathways/search/— paginated pathway-enrollment search; user identifier required, pluspathway_id/slug,org/platform_key,sort,page,page_size,include_default_platform. Active enrollments only.
Recommendation
- GET
/api/catalog/recommendation/courses/— get the recommended "next" course relative to a current course.course_idrequired (query param), plus optionaluser_idandorg. Returns a single serialized course, ornull(with200) when there is no next course.
Reviews
Course reviews
- GET
/api/catalog/reviews/course/— paginated list of (visible) course reviews; filter (query params) bycourse_id,user_id,platform_key,platform_org/org,sort(default-id),page,page_size. Returns{count, next_page, previous_page, results[]}where each result is{user_id, username, content, rating, title, visible, created, modified, course_id, metadata}. - GET
/api/catalog/reviews/course/info/— aggregate review stats for a course;course_idrequired (query param). Returns{course_id, avg_rating, count}.
Program reviews
- GET
/api/catalog/reviews/program/— paginated list of (visible) program reviews; filter byprogram_id,user_id,platform_key,platform_org/org,sort,page,page_size. Each result includesprogram_key. - GET
/api/catalog/reviews/program/info/— aggregate review stats;program_keyrequired (query param). Returns{program_key, avg_rating, count}.
Writes
Courses
- POST
/api/catalog/courses/— create/update a course (200updated,201created):
Newly created courses are assigned to the org's platform (default platform if{ "course_id": "string (required)", "org": "string (required)", "name": "string (optional)" }orgis unknown). On update the org is only changed if you also sendoverwrite_existing_org: true. (The handler ignoresslug/dataon write.) - DELETE
/api/catalog/courses/— delete a course bycourse_id(query param). Confirm with the user first.
Programs
- POST
/api/catalog/programs/— create/update a program (200updated,201created). Identify the platform byprogram_id+ (org/platform_key) or byprogram_key.program_id,name, andcourse_listare required:{ "program_id": "string (required)", "name": "string (required)", "course_list": [{ "course_id": "course-v1:A+B+C" }], "org": "string", "platform_key": "string", "program_key": "string", "slug": "string", "enabled": "boolean (default true)", "program_type": "number (1=standard, 2=platform, 3=custom)", "data": "object" } - DELETE
/api/catalog/programs/— delete a program byprogram_id+org(query params, both required). Returns{count, type}. Confirm with the user first.
Pathways
- POST
/api/catalog/pathways/— create/update a pathway.user_id(required),name(required), andpath(required). Use (user_id/usernameorplatform_key) +pathway_idto create; do not sendpathway_uuidon create (generated). For an existing pathway, identify bypathway_uuid. Eachpath[]item is keyed byitem_type:resource(resource fields below; created on the fly when noid),course(course_id),program(program_key), orpathway(pathway_id).{ "user_id": "number (required)", "name": "string (required)", "username": "string", "platform_key": "string", "pathway_id": "string", "pathway_uuid": "uuid (update only)", "slug": "string", "visible": "boolean (default true)", "path": [ { "item_type": "resource", "id": "number (omit to create)", "resource_type": "string", "url": "string", "name": "string", "description": "string", "data": "object" }, { "item_type": "course", "course_id": "course-v1:A+B+C" }, { "item_type": "program", "program_key": "program-v1:org+id" } ], "data": "object" }
Resources
- POST
/api/catalog/resources/— create/update a resource (omitidto create). Accepts JSON or multipart (forimage):{ "id": "number (update only)", "username": "string", "user_id": "number", "platform_key": "string", "platform_org": "string", "name": "string", "url": "string", "resource_type": "string", "description": "string", "skills": ["string"], "image": "file (multipart)", "data": "object" } - DELETE
/api/catalog/resources/— delete a resource; requiresidplususer_idorplatform_key(query params). Returns{count, type}. Confirm with the user first.
Metadata
Course
- POST
/api/catalog/metadata/course/— create/update course metadata.course_idandmetadatarequired. Withupdate: true(default) the supplied keys are merged;update: falseoverwrites. Special keys insidemetadata:slug,skills(list of existing skill names). Field-path POSTs (course/{field}/) are not supported (404).{ "course_id": "string", "update": "boolean (default true)", "metadata": { "subject": "string", "tags": ["string"], "level": "string", "topics": ["string"], "promotion": "string|null", "slug": "string", "skills": ["string"] } } - POST
/api/catalog/metadata/course-search/— return course info (to_json()) for courses matching metadata filters in the body, e.g.{ "data__contains": {...}, "slug": "string", "course_id": "string" }. Body must be non-empty; invalid filter keys return400.
Program
- POST
/api/catalog/metadata/program/— create/update program metadata;program_idrequired, optionalorg, plusmetadataandupdate(default true) in the body. Field-path POSTs not supported (404).
Skills
- POST
/api/catalog/skills/— create/update a skill (omitidto create;platform_key: nullfor global):{ "id": "number (update only)", "name": "string", "slug": "string", "platform_key": "string|null", "data": "object" } - POST
/api/catalog/skills/public/— create a skill, open to any user (config-gated; names lowercased/trimmed):{ "name": "string", "slug": "string", "data": "object" }. - POST
/api/catalog/skills/desired/— set a user's desired skills (refer to skills byid):{ "user_id": "number", "username": "string", "skills": [{ "id": "number" }], "data": "object" } - POST
/api/catalog/skills/reported/— set a user's reported skills (same shape as desired).
Roles
- POST
/api/catalog/roles/— create/update a role (omitidto create):{ "id": "number (update only)", "name": "string", "slug": "string", "platform_key": "string", "data": "object" } - POST
/api/catalog/roles/public/— create a role, open to any user (config-gated; names lowercased/trimmed):{ "name": "string", "slug": "string", "data": "object" }. - POST
/api/catalog/roles/desired/— set a user's desired roles:{ "user_id": "number", "roles": ["string"|{ "id": "number" }], "data": "object" }. - POST
/api/catalog/roles/reported/— set a user's reported roles (same shape as desired).
Enrollment
Programs
- POST
/api/catalog/enrollment/programs/— create/update an enrollment. Requires a user (user_id/username) and a program (program_keyorprogram_id+org/platform_key):{ "user_id": "number", "username": "string", "program_id": "string", "program_key": "string", "org": "string", "platform_key": "string", "started": "datetime", "expired": "datetime", "active": "boolean (default true)" } - DELETE
/api/catalog/enrollment/programs/— deactivate an enrollment (query params: useruser_id/username+ programprogram_id/program_key+org/platform_key, optionalignore_expirationdefaultfalse). Confirm with the user first. - POST
/api/catalog/enrollment/programs/self/— self-enrollment (the program must be in a platform the target user belongs to;403otherwise). Same body as the admin POST, includinguser_id/username:{ "user_id": "number", "username": "string", "program_id": "string", "program_key": "string", "org": "string", "platform_key": "string", "started": "datetime", "expired": "datetime", "active": "boolean (default true)" } - DELETE
/api/catalog/enrollment/programs/self/— self-unenroll (same identifiers as the admin DELETE; membership-checked, optionalignore_expirationdefaultfalse). Confirm with the user first.
Pathways
- POST
/api/catalog/enrollment/pathways/— create a pathway enrollment; requires a user (user_id/username) and a pathway (pathway_uuid, orpathway_id+org/platform_key):{ "username": "string", "user_id": "number", "pathway_id": "string", "pathway_uuid": "uuid", "org": "string", "platform_key": "string", "active": "boolean (default true)" } - DELETE
/api/catalog/enrollment/pathways/— deactivate a pathway enrollment (same identifiers, query params). Confirm with the user first. - POST
/api/catalog/enrollment/pathways/self/— self-enrollment (membership-checked;403if the user is not in the pathway's platform). Same body as the admin POST, includinguser_id/username. - DELETE
/api/catalog/enrollment/pathways/self/— self-unenroll (same identifiers, membership-checked). Confirm with the user first.
Search
- POST
/api/catalog/search/programs/— full-text program search acrossprogram_id,name,slug, andmetadata; returns catalog program objects withmetadata:{ "query": "string", "org": "string (optional)" }
Reviews
Course reviews
- POST
/api/catalog/reviews/course/update/— create/update a course review (201created,200updated).course_idandusernamerequired (oruser_id):{ "course_id": "string", "username": "string", "user_id": "number", "rating": "number", "title": "string", "content": "string", "visible": "boolean (default true)", "metadata": "object" } - DELETE
/api/catalog/reviews/course/update/— delete a user's course review;course_id+username/user_idrequired (query params). Confirm with the user first.
Program reviews
- POST
/api/catalog/reviews/program/update/— create/update a program review.program_keyandusernamerequired (oruser_id):{ "program_key": "program-v1:org+id", "username": "string", "user_id": "number", "rating": "number", "title": "string", "content": "string", "visible": "boolean (default true)", "metadata": "object" } - DELETE
/api/catalog/reviews/program/update/— delete a user's program review;program_key+username/user_idrequired (query params). Confirm with the user first.
Example
Check whether a user is eligible for a specific course (note the URL-encoded course_id):
curl -G \
"https://api.iblai.app/dm/api/catalog/eligibility/courses/check/" \
-H "Authorization: Api-Token $IBLAI_API_KEY" \
--data-urlencode "user_id=36" \
--data-urlencode "org=$IBLAI_ORG" \
--data-urlencode "course_id=course-v1:IBLTEST+IBL000+RUN"
Notes
- All endpoints are DM endpoints served under
https://api.iblai.app/dm(/dm+/api/catalog/...). Omitting the/dmprefix will not resolve. - Course id format is the opaque-keys form
course-v1:ORG+NUMBER+RUN(e.g.course-v1:IBLTEST+IBL000+RUN). Always URL-encode it in query strings (%3A,%2B). - Program ids are slug-like strings (e.g.
test-program-000);program_typeis a numeric code on write. Resource / skill / role ids are integers; resources also carry a UUIDitem_id; pathways carry a UUIDpathway_uuid(generated on create — never send it on a create call). - Org on the wire appears as
org,platform_key, or (resource search legacy)platform_org/key— all mean the org key. Pass it as a query param (GET) or body field (POST), not in the path. - Skills/roles by id, not name. When setting a user's desired/reported skills or roles, reference them by
{"id": …}(recommended) rather than name. Course-metadataskillsmust reference existing skill names. - Self vs admin enrollment. Both the non-self and the
…/self/enrollment endpoints take an explicituser_id/usernamein the request. The difference is permission scope:…/self/additionally checks that the target user is a member of the program/pathway's platform (returns403if not), so it is the endpoint to use for non-admin (user-token) self-service; the non-self endpoints are for admin tokens enrolling other users. - Pagination envelope is
{count, next_page, previous_page, results[]}for the search/paginated endpoints (course/program/pathway enrollment search, resource search, skills, roles, course/program review query); plainGETs likeresources/andpathways/are not paginated. public/skill and role creation endpoints are config-gated (ALLOW_PUBLIC_SKILL_CREATE/ALLOW_PUBLIC_ROLE_CREATE) and return404when disabled; created names are lowercased and trimmed.- Auto-increment utility.
GET/POST /api/catalog/increment/reads/advances per-platform auto-increment numbers (org/key, andnumber_typeonPOST). It is an internal numbering helper, not a catalog-management operation — included for completeness only. - The source repo also ships Django management commands (
convert_slugs_lower,link_item_objects,verify_course_existence); those are server-side operations, not REST endpoints, and are out of scope for this skill.