| 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. |
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/
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).