Iblai api credential
Agent skills + a chat MCP server to operate the ibl.ai platform via its REST API. Install: npx skills add iblai/api
npx -y skills add iblai/api --skill iblai-api-credentialAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 15 stars15 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Manage an ibl.ai organization's digital credentials via the platform API — credential CRUD, user/group assignments, assertions, course-scoped credential import/export, external provider config + mapping (Accredible), and issuance analytics. Use when issuing, assigning, importing, or reporting on digital credentials and certificates.
SKILL.md
18.4 KB, as published. Nobody here has run it
iblai-api-credential
Manage an organization's digital credentials from the API: create and edit credentials, assign them to users and groups, read the resulting assertions (issued credentials), import/export course-scoped credentials between platforms, wire up external issuing providers (e.g. Accredible) via provider config and per-credential external mappings, and pull issuance analytics over time. Use when issuing, assigning, importing, or reporting on digital credentials and certificates.
Auth & conventions
- Base URL:
https://api.iblai.app/dm— these are Data Manager (DM) endpoints, so the/dmprefix is required; the/api/credentials/…paths below are appended to it (e.g.https://api.iblai.app/dm/api/credentials/…). - Header:
Authorization: Api-Token $IBLAI_API_KEYon every request. - Path vars:
{org}=$IBLAI_ORG(the credentials API path segment isplatform_key; it resolves againstPlatform.key, withPlatform.orgas a fallback; on the wire it is also theplatform_orgquery param). The user segment accepts either a numeric{user_id}or a{username}— both route shapes exist (…/users/<int:user_id>/…and…/users/<str:username>/…), so$IBLAI_USERNAMEworks directly in the path. For provider-config/mapping paths that user segment is the admin making the request (use$IBLAI_USERNAME).{course_id}= an Open edX course id such ascourse-v1:org+course+run. - Most paths are user-scoped under
/api/credentials/orgs/{org}/users/{user}/…(where{user}is a numeric id or username). Below, that prefix is written as…/for brevity. The course import/export (exim) endpoints, the public assertion lookup, and the public provider list are platform-agnostic and live directly under/api/credentials/…with no org/user segment. - Ids: id-taking detail endpoints (credentials, assertions, assignments)
look up by
entity_id(the UUID string) only — numeric database ids are not accepted.{id}below means theentity_id. - Responses are wrapped:
{"status": {"success": bool, "description": str}, "result": {…}}. Paged listresultobjects carrycount,next,previous, and eitherresultsordata. - DELETE / destructive / outward-facing (assign, issue, import/export) calls — confirm with the user first.
- Not connected yet? Run
/iblai-api-loginfirst to populateIBLAI_ORG,IBLAI_USERNAME, andIBLAI_API_KEY.
Pagination, ordering & search (list endpoints)
page(default1),page_size(default10, max100; provider/mapping lists default50, max1000).search— case-insensitive match across the relevant fields (username, email, full name, credential name/description, group name, platform name, course/program name, assigned-by username, depending on the endpoint).- Results are ordered newest-first (by creation / assignment date). For department admins, results are automatically filtered to their department scope.
Reads
Credentials — …/
- GET
…/— list credentials for the org (onlypublic=Truecredentials are returned). Query params:search(name / name_override / description),course(course id),program(program id),page,page_size. - GET
…/{id}— read one credential ({id}=entity_id). - GET
…/course-credentials/— list credentials grouped by course. Query params:search(course name / course id),page,page_size. The pagedresultcarriesresults(notdata). - GET
…/images/— search uploaded credential images. Requires aqueryparam (case-insensitive name match); returns an array of{id, name, image}.
Issuers & signatories — …/issuers/
An issuer is required to create a credential (its entityId is the issuer
field above). Issuers are keyed to the platform.
- GET
…/issuers/— list issuers for the org. Query params:q(search by name), pluspage/page_size. Each issuer hasname,org,entityId,signatories,url,iconImage,allowed_template_tags. - GET
…/issuers/{id}— read one issuer ({id}= issuerentity_id, or itsorgidentifier).
Assignments (users & groups) — …/assignments/
Assignments link a credential to users or groups; issuing an assignment produces assertions. Group assignments are processed asynchronously (Celery). Department admins only see/act on assignments within their department scope.
- GET
…/assignments/users/— list/search user assignments (also serves as the role-filtered assertions for users view — see Notes). Only assignments withstatus == "COMPLETED"that have a matching non-revoked assertion are returned. Supportssearch(credential name / username / email),page,page_size, and optionalplatform_org. - GET
…/assignments/groups/— list group assignments (department-filtered). Optionalgroup_idfilter;page,page_size.
Assertions — …/assertions/
An assertion is an issued credential (a credential granted to a user).
- GET
…/assertions/— list all assertions for this user/org. Query params:course(filter by course id),include_revoked(default false),include_expired(default false),exclude_main_tenant_assertions(default false),page,page_size. Response fields are camelCase:entityId,issuedOn,credentialDetails,recipient,course,program,revoked,revocationReason,acceptance,expires,metadata,narrative. - GET
…/assertions/{id}— read one assertion ({id}= assertionentity_id). - GET
/api/credentials/public/assertions/{id}/— public, unauthenticated lookup of a single assertion byentity_id(no org/user segment, no auth header needed). Returns 404 if not found or revoked (revoked responses include the revocation reason).
Course import/export (exim) — /api/credentials/exim/…
Platform-agnostic; no org/user segment. DM admin only. Export converts item ids to course ids in the response; import converts course ids to item ids and replaces the issuer with the platform's default issuer.
- GET
/api/credentials/exim/credentials/course/{course_id}/export/— export all credential definitions for a course (returnscourse_id+ acredentialsarray withentityId,name, templates,expires,issuerDetails,signatories,courses,programs,pathways, etc.).
Provider config / external mapping — …/provider-config/, …/external-mapping/
Platform admin only (Requires platform admin access). Path uses
…/users/{username}/… where {username} is the admin making the request. These
configure external issuers (e.g. Accredible) and map internal credentials to
external templates.
Available providers (public list) — /api/credentials/providers/
- GET
/api/credentials/providers/— list enabled credential providers (no org/user segment; only requires authentication, not admin). Optionalpage,page_size(default 50, max 1000). Each entry:name,display_name,description,enabled,metadata.
Provider configuration — …/provider-config/
- GET
…/provider-config/— list provider configs. Optionalprovider_name,page,page_size. Each entry hasprovider_name,provider_name_display,config(provider settings),enabled.
External credential mapping — …/external-mapping/
- GET
…/external-mapping/— list mappings. Optionalcredential_id(filter by credential entity_id),provider_name,page,page_size.
Analytics — …/
All take optional start_date / end_date (YYYY-MM-DD) query params and return
{ "data": { "<date>": count, … } } (back-filled with zero-value days when a
range is given).
- GET
…/assertions-over-time/— assertion (issuance) counts over time. Platform admin only. Also returns ametablock with totals and percent changes. - GET
…/course-assertions-over-time/— per-course assertion counts over time. Platform admin only. - GET
…/credentials-over-time/— credential-creation counts over time.
Writes
Credentials — …/
- POST
…/— create a credential. Confirm with the user first.nameandissuer(the issuer entity_id) are required; everything else is optional:{ "name": "string", "issuer": "issuer-entity-id", "description": "string", "criteriaUrl": "string", "criteriaNarrative": "string", "credentialType": "string", "signal": "COURSE_PASSED", "html_template": "string", "css_template": "string", "tags": [], "metadata": {}, "expires": { "amount": 365, "duration": "days" }, "iconImage": "url", "backgroundImage": "url", "thumbnailImage": "url", "courses": ["course-v1:org+course+run"], "programs": ["program-id"], "pathways": ["pathway-id"] }signaldefaults toCOURSE_PASSED. Body field names are camelCase as shown (these map to the credential output fields). The responseresultusesentityId,criteriaUrl,criteriaNarrative,credentialType,signal,issuerDetails,signatories,courses,programs,pathways,expires, etc. - PUT
…/{id}— update one credential (partial; only present fields change). Updatable fields:name,description,html_template,css_template,credentialType,criteriaUrl,criteriaNarrative,signal,iconImage,backgroundImage,thumbnailImage,metadata(merged into existing). - DELETE
…/{id}— delete one credential. Confirm with the user first. Returns 409 Conflict if the credential still has active (non-revoked, unexpired) assertions — revoke/delete those first. - POST
…/images/— upload an image as multipart form data (imagefile, optionalname); returns the created{id, name, image}.
Issuers & signatories — …/issuers/
- POST
…/issuers/— create an issuer. Confirm with the user first. Body:name(and optionallyiconImage,email,url,allowed_template_tags). - PUT
…/issuers/{id}— update an issuer. Confirm with the user first. - DELETE
…/issuers/{id}— delete an issuer. Confirm with the user first. - POST
…/issuers/authority/— create a signatory (issuer authority). Confirm with the user first. Body:name,title,signature(image url) required; optionallyorg,entityId(issuer entity id), orcredential(credential entity id) to associate it. If none oforg/entityId/credentialis given, it falls back to the platform from the URL.
Assignments (users & groups) — …/assignments/
- POST
…/assignments/users/— assign a credential to users. Confirm with the user first:{ "credential_id": "credential-entity-id", "user_ids": [123, 456] }user_idsare numeric user ids. Returnsresultwithsuccessful_assignments,failed_assignments, andmessage. - POST
…/assignments/groups/— assign a credential to groups (async). Confirm with the user first:{ "credential_id": "credential-entity-id", "group_ids": ["group-id-1", "group-id-2"] }credential_idandgroup_idsare both required (group_idsare strings). Returnsresultwithsuccessful_assignments/failed_assignments. - DELETE
…/assignments/{id}— delete one assignment ({id}= the assignmententity_id; resolves to either a group or individual assignment). Confirm with the user first. (This endpoint is DELETE-only — there is no GET on a single assignment.) For a group assignment this cascades to all related user assignments and assertions; for an individual assignment it deletes the assignment and its assertion. The response is a simple{ "status": { "success": true, "description": "…" } }.
Assertions — …/assertions/
- PUT
…/assertions/{id}— revoke an assertion. This is outward-facing — confirm with the user first. Body:{ "revoked": true, "revocationReason": "string" }. - POST
…/{id}/assertions/— issue (create) an assertion for credential{id}(= credentialentity_id). This issues a credential — confirm with the user first. Body requires arecipientobject and an item the credential is attached to:
Instead of{ "recipient": { "identity": "username" }, "course": "course-v1:org+course+run", "metadata": {} }courseyou may passcatalog_item(item id),program/program_id, orpathway/pathway_idto identify the item. - POST
…/{id}/assertions/bulk/— issue the credential to many users at once. Confirm with the user first. Body:usersis a list of usernames, plus the same item field (course/catalog_item/program/pathway) and optionalmetadata. Returns{ "skipped": [...], "issued": [...] }.
Course import/export (exim) — /api/credentials/exim/…
- POST
/api/credentials/exim/credentials/course/{course_id}/import/— import credential definitions into a course. Confirm with the user first:
Existing credentials (matched by name + course + default issuer) are updated; missing ones are created. Response{ "course_id": "course-v1:org+course+run", "credentials": [ { "entityId": "credential-entity-id", "name": "Credential Name", "description": "string", "criteriaUrl": "string", "criteriaNarrative": "string", "credentialType": "COURSE_CERTIFICATE", "expires": { "amount": 365, "duration": "days" }, "signatories": [ { "entityId": "authority-entity-id", "name": "string", "title": "string", "signature": "url" } ], "html_template": "string", "css_template": "string", "signal": "COURSE_PASSED", "courses": [ { "name": "string", "course_id": "course-v1:org+course+run" } ] } ] }resultlistscourse_id,imported_credentials(each withentityId,name, andstatus=created|updated) anderrors. Status is 201 if all succeed, 207 Multi-Status if some succeed with errors, 400 if none succeed.
Provider config / external mapping — …/provider-config/, …/external-mapping/
Provider configuration — …/provider-config/
- POST
…/provider-config/— create or update a provider config (201 on create, 200 on update). Confirm with the user first:{ "provider_name": "accredible", "config": { "accredible_api_key": "your-api-key", "accredible_base_url": "https://dashboard.accredible.com/", "accredible_api_base_url": "https://api.accredible.com/v1/", "accredible_group_id": "123456", "accredible_template_id": "789012", "use_sandbox": false }, "enabled": true }provider_nameis required;configandenabledare each optional. Config keys are normalized to lowercase; values are preserved verbatim. Forprovider_name: "accredible",configmust includeaccredible_api_key(validation rejects it otherwise). Returns 201 + descriptionCreatedon create, 200 +Updatedon update. - DELETE
…/provider-config/— deactivate a provider config (setsenabled=false; external issuance is then skipped; the record is not removed). Confirm with the user first. Body:{ "provider_name": "accredible" }. Returns descriptionDeactivatedwith the updated config object.
External credential mapping — …/external-mapping/
- POST
…/external-mapping/— create or update a mapping (201 on create, 200 on update; unique per credential + platform + provider). Confirm with the user first:{ "credential_id": "credential-entity-id", "provider_name": "accredible", "external_template_id": "123456789", "group_id": "679866", "metadata": {} }credential_idandprovider_nameare required;external_template_id,group_id, andmetadataare optional. - DELETE
…/external-mapping/— delete a mapping. Confirm with the user first. Body:{ "credential_id": "credential-entity-id", "provider_name": "accredible" }.
Example
List a user's issued credentials (assertions), searching for "python":
curl -G \
"https://api.iblai.app/dm/api/credentials/orgs/$IBLAI_ORG/users/$IBLAI_USERNAME/assignments/users/" \
-H "Authorization: Api-Token $IBLAI_API_KEY" \
--data-urlencode "search=python" \
--data-urlencode "page_size=20"
Notes
- Role-based assertion filtering (
…/assignments/users/): the{user}in the path is the user whose role determines visibility — platform admins see assignments for all users in the org; department admins see only users in their department groups; everyone else sees only their own. If the resolved set is empty the call returns 403 ("You don't have permission to view these assignments"). - Ids: detail lookups for credentials, assertions, and assignments are by
entity_id(UUID) only — numeric database ids are not accepted. Course ids are Open edX ids (course-v1:org+course+run). {org}is theplatform_keyURL segment; it resolves againstPlatform.keyfirst, thenPlatform.orgas a fallback, and may also be passed as theplatform_orgquery param.- Accredible provider specifics:
configkeys are lowercased on save (values preserved); when issuing, the system uses the mapping'sgroup_idfirst and falls back to the provider config'saccredible_group_id.use_sandboxtoggles the Accredible sandbox. Disabling a provider config (enabled=false) skips external issuance for that org. - Pagination defaults differ: assignment/assertion lists default to
page_size=10(max 100); provider-config and external-mapping lists default to50(max 1000). - Group assignments are asynchronous (Celery); the immediate response confirms acceptance, not completion.
- Errors use the standard codes: 400 (bad input), 401 (unauthenticated), 403 (insufficient permissions, e.g. "Requires platform admin access"), 404 (not found), 500 (server error).