agentsclimarketplace

Iblai api credential

Skill iblai/api/skills/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

Install
npx -y skills add iblai/api --skill iblai-api-credential

Assembled 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 /dm prefix 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_KEY on every request.
  • Path vars: {org} = $IBLAI_ORG (the credentials API path segment is platform_key; it resolves against Platform.key, with Platform.org as a fallback; on the wire it is also the platform_org query 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_USERNAME works 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 as course-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 the entity_id.
  • Responses are wrapped: {"status": {"success": bool, "description": str}, "result": {…}}. Paged list result objects carry count, next, previous, and either results or data.
  • DELETE / destructive / outward-facing (assign, issue, import/export) calls — confirm with the user first.
  • Not connected yet? Run /iblai-api-login first to populate IBLAI_ORG, IBLAI_USERNAME, and IBLAI_API_KEY.

Pagination, ordering & search (list endpoints)

  • page (default 1), page_size (default 10, max 100; provider/mapping lists default 50, max 1000).
  • 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 (only public=True credentials 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 paged result carries results (not data).
  • GET …/images/ — search uploaded credential images. Requires a query param (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), plus page/page_size. Each issuer has name, org, entityId, signatories, url, iconImage, allowed_template_tags.
  • GET …/issuers/{id} — read one issuer ({id} = issuer entity_id, or its org identifier).

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 with status == "COMPLETED" that have a matching non-revoked assertion are returned. Supports search (credential name / username / email), page, page_size, and optional platform_org.
  • GET …/assignments/groups/ — list group assignments (department-filtered). Optional group_id filter; 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} = assertion entity_id).
  • GET /api/credentials/public/assertions/{id}/public, unauthenticated lookup of a single assertion by entity_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 (returns course_id + a credentials array with entityId, 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). Optional page, page_size (default 50, max 1000). Each entry: name, display_name, description, enabled, metadata.

Provider configuration — …/provider-config/

  • GET …/provider-config/ — list provider configs. Optional provider_name, page, page_size. Each entry has provider_name, provider_name_display, config (provider settings), enabled.

External credential mapping — …/external-mapping/

  • GET …/external-mapping/ — list mappings. Optional credential_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 a meta block 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. name and issuer (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"]
    }
    
    signal defaults to COURSE_PASSED. Body field names are camelCase as shown (these map to the credential output fields). The response result uses entityId, 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 (image file, optional name); returns the created {id, name, image}.

Issuers & signatories — …/issuers/

  • POST …/issuers/ — create an issuer. Confirm with the user first. Body: name (and optionally iconImage, 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; optionally org, entityId (issuer entity id), or credential (credential entity id) to associate it. If none of org/entityId/credential is 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_ids are numeric user ids. Returns result with successful_assignments, failed_assignments, and message.
  • 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_id and group_ids are both required (group_ids are strings). Returns result with successful_assignments / failed_assignments.
  • DELETE …/assignments/{id} — delete one assignment ({id} = the assignment entity_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} (= credential entity_id). This issues a credential — confirm with the user first. Body requires a recipient object and an item the credential is attached to:
    {
      "recipient": { "identity": "username" },
      "course": "course-v1:org+course+run",
      "metadata": {}
    }
    
    Instead of course you may pass catalog_item (item id), program / program_id, or pathway / pathway_id to identify the item.
  • POST …/{id}/assertions/bulk/ — issue the credential to many users at once. Confirm with the user first. Body: users is a list of usernames, plus the same item field (course / catalog_item / program / pathway) and optional metadata. 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:
    {
      "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" } ]
        }
      ]
    }
    
    Existing credentials (matched by name + course + default issuer) are updated; missing ones are created. Response result lists course_id, imported_credentials (each with entityId, name, and status = created|updated) and errors. 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_name is required; config and enabled are each optional. Config keys are normalized to lowercase; values are preserved verbatim. For provider_name: "accredible", config must include accredible_api_key (validation rejects it otherwise). Returns 201 + description Created on create, 200 + Updated on update.
  • DELETE …/provider-config/ — deactivate a provider config (sets enabled=false; external issuance is then skipped; the record is not removed). Confirm with the user first. Body: { "provider_name": "accredible" }. Returns description Deactivated with 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_id and provider_name are required; external_template_id, group_id, and metadata are 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 the platform_key URL segment; it resolves against Platform.key first, then Platform.org as a fallback, and may also be passed as the platform_org query param.
  • Accredible provider specifics: config keys are lowercased on save (values preserved); when issuing, the system uses the mapping's group_id first and falls back to the provider config's accredible_group_id. use_sandbox toggles 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 to 50 (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).

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.