English
English
Appearance
English
English
Appearance
Create and manage credentials (assertions) — badges issued to specific recipients.
All endpoints require authentication via the X-Api-Key header. See Authentication.
Issue a badge to a recipient.
Need to issue to hundreds or thousands of recipients at once instead of one API call per person? Use the Bulk Credentials UI feature, which accepts a CSV upload.
POST /awards| Parameter | Type | Required | Description |
|---|---|---|---|
badgeId | string | Yes | The badge ID to issue |
recipient | object | Yes | Recipient details (see below) |
recipient.name | string | Yes | Recipient full name (minimum 5 characters) |
recipient.email | string | Yes | Recipient email address |
issuedOn | string | Yes | Issue date in ISO 8601 format (e.g. 2025-01-15) |
expires | string | No | Expiration date in ISO 8601 format |
curl -X POST https://api.badges.ninja/awards \
-H "X-Api-Key: bws_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"parameters": {
"badgeId": "b1c2d3e4-f5a6-7890-bcde-f12345678901",
"recipient": {
"name": "Jane Smith",
"email": "jane@example.com"
},
"issuedOn": "2025-01-15"
}
}'{
"awardId": "https://api.badges.ninja/certify-badge/award/c1d2e3f4-a5b6-7890-cdef-123456789012"
}Retrieve credentials with optional filtering and pagination.
GET /awards| Parameter | Type | Required | Description |
|---|---|---|---|
filter | JSON string | No | Filter object (see below) |
lastEvaluatedKey | string | No | Pagination token from a previous response |
The filter parameter accepts a JSON string with these fields:
| Field | Type | Description |
|---|---|---|
badgeId | string | Filter by badge ID. |
search | string | Substring to look up in either recipient names or emails (see searchField). |
searchField | string | Either name (default) or email — which column to search. |
Pagination via lastEvaluatedKey works with or without filters. Page size is 50.
curl -X GET https://api.badges.ninja/awards \
-H "X-Api-Key: bws_your_api_key_here"curl -X GET "https://api.badges.ninja/awards?filter=%7B%22badgeId%22%3A%22b1c2d3e4%22%7D" \
-H "X-Api-Key: bws_your_api_key_here"{
"count": 1,
"items": [
{
"id": "https://api.badges.ninja/certify-badge/award/c1d2e3f4-...",
"badge": {
"id": "https://api.badges.ninja/certify-badge/badge/b1c2d3e4-...",
"name": "JavaScript Fundamentals",
"image": "https://badges.ninja/images/{sha256}.png"
},
"recipient": {
"name": "Jane Smith",
"email": "jane@example.com"
},
"issuedOn": "2025-01-15T00:00:00.000Z",
"timestamp": "2025-01-15T10:30:00.000Z"
}
],
"lastEvaluatedKey": "eyJ..."
}If lastEvaluatedKey is present in the response, there are more results. Pass it as a query parameter in the next request to get the next page.
Send an email notification to a recipient about their credential.
POST /awards/{awardId}/send| Parameter | Type | Required | Description |
|---|---|---|---|
awardId | string | Yes | The award ID (path parameter and body) |
email | string | Yes | Recipient email address |
curl -X POST https://api.badges.ninja/awards/c1d2e3f4-a5b6-7890-cdef-123456789012/send \
-H "X-Api-Key: bws_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"parameters": {
"awardId": "c1d2e3f4-a5b6-7890-cdef-123456789012",
"email": "jane@example.com"
}
}'Returns a plain confirmation string:
"email sent"Share a credential with multiple recipients via email.
POST /awards/{awardId}/share| Parameter | Type | Required | Description |
|---|---|---|---|
awardId | string | Yes | The award ID (path parameter and body) |
recipients | string | Yes | Comma-separated list of email addresses |
subject | string | Yes | Email subject line |
message | string | Yes | Email message body |
curl -X POST https://api.badges.ninja/awards/c1d2e3f4-a5b6-7890-cdef-123456789012/share \
-H "X-Api-Key: bws_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"parameters": {
"awardId": "c1d2e3f4-a5b6-7890-cdef-123456789012",
"recipients": "manager@example.com,hr@example.com",
"subject": "Check out my new badge!",
"message": "I just earned the JavaScript Fundamentals badge."
}
}'Returns a plain confirmation string:
"email sent"Revoke a credential you issued. The hosted Open Badges v2.0 assertion is marked revoked: true (with an optional reason) so any verifier sees the badge is no longer valid. The credential record is kept for audit purposes, and no credit is refunded.
Revocation also propagates to the credential's Open Badges 3.0 Verifiable Credential: the award's bit is flipped in the W3C Bitstring Status List referenced by the VC's credentialStatus, so VC wallets detect it too. See Revocation (Bitstring Status List).
POST /awards/{awardId}/revoke| Parameter | Type | Required | Description |
|---|---|---|---|
awardId | string | Yes | The award ID (path parameter) |
reason | string | No | Reason for revocation. Truncated to 500 characters. |
notify | boolean | No | When true, emails the recipient that their credential was revoked. Defaults to false. |
curl -X POST https://api.badges.ninja/awards/c1d2e3f4-a5b6-7890-cdef-123456789012/revoke \
-H "X-Api-Key: bws_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"parameters": {
"awardId": "c1d2e3f4-a5b6-7890-cdef-123456789012",
"reason": "Issued to the wrong recipient",
"notify": true
}
}'{
"revoked": true,
"awardId": "c1d2e3f4-a5b6-7890-cdef-123456789012"
}Revoking an already-revoked credential is idempotent — it returns the same response without re-sending a notification.
To revoke many credentials at once, use the durable bulk endpoint with action: "revoke" instead of calling this endpoint per award:
curl -X POST https://api.badges.ninja/awards/bulk-send \
-H "X-Api-Key: bws_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{ "parameters": { "action": "revoke", "awardIds": ["<id1>", "<id2>"], "reason": "Program cancelled", "notify": false } }'It returns { "jobId", "total" }; the job revokes every id server-side (skipping already-revoked ones) and is resumable. Already-revoked and non-existent ids are reported as skipped.
Hard-delete a credential you issued. Unlike revoke, this removes the record entirely and the public credential page will return 404. Use this for genuine mistakes (e.g. issued to the wrong person); prefer revoke for real credentials so the assertion stays verifiable as revoked. No credit is refunded.
DELETE /awards/{awardId}| Parameter | Type | Required | Description |
|---|---|---|---|
awardId | string | Yes | The award ID (path parameter) |
curl -X DELETE https://api.badges.ninja/awards/c1d2e3f4-a5b6-7890-cdef-123456789012 \
-H "X-Api-Key: bws_your_api_key_here"{
"deleted": true,
"awardId": "c1d2e3f4-a5b6-7890-cdef-123456789012"
}Generate a print-ready A4 PDF certificate for a credential.
GET /certify-badge/award/{awardGuid}/pdfNo authentication required — this endpoint is public so recipients can download their own certificate.
curl -OJ https://api.badges.ninja/certify-badge/award/c1d2e3f4-a5b6-7890-cdef-123456789012/pdfThe response is the binary PDF with a Content-Type: application/pdf header.
Record an engagement event. Used by the public credential page to populate engagement stats. No authentication required.
POST /certify-badge/award/{awardGuid}/eventThis endpoint reads its body directly (no parameters wrapper).
| Parameter | Type | Required | Description |
|---|---|---|---|
event | string | Yes | One of view, share, download, click_linkedin_addtoprofile, click_pdf, click_verify. |
network | string | No | When event=share, the social network: linkedin, twitter, facebook, whatsapp, telegram, email, copy. |
Per-IP duplicate suppression: the same event from the same IP is counted once per 24 hours.
curl -X POST https://api.badges.ninja/certify-badge/award/c1d2e3f4-a5b6-7890-cdef-123456789012/event \
-H "Content-Type: application/json" \
-d '{"event": "share", "network": "linkedin"}'{
"ok": true
}Retrieve cumulative engagement counters for a credential.
GET /certify-badge/award/{awardGuid}/statsNo authentication required.
Counters are returned keyed by the raw event type. totals holds the total count per event; networks breaks down the per-network split for events that carry a network (currently share). Events with no recorded activity are simply absent.
{
"totals": {
"view": 142,
"share": 16,
"download": 3,
"click_linkedin_addtoprofile": 4
},
"networks": {
"share": { "linkedin": 8, "twitter": 2, "email": 1, "copy": 5 }
}
}