Skip to content
Back to skills

Iblai Api Credential

ASecurity

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.

  • 15 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 20, 2026
ai-agentspythonbashgitapidatabase

Works with

  • api

Security analysis

A100/100

Scanned September 20, 2026

npx -y skills add iblai/vibe --skill iblai-api-credential --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Iblai Api Credential?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Iblai Api Credential
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/iblai-iblai-api-credential/badge)](https://www.skillsdirectory.com/skills/iblai-iblai-api-credential)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: iblai-api-credential
description: 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.
metadata:
  kind: api
---

# 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:
  ```json
  {
    "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:
  ```json
  { "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:
  ```json
  { "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:
  ```json
  {
    "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:
  ```json
  {
    "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:
  ```json
  {
    "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:
  ```json
  {
    "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":

```bash
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).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.