Open Badges 3.0 API Documentation
Open Badges 3.0 compliant REST API for managing digital credentials
https://earnedcredentials.com/api/v1
Authentication
The API uses Bearer token authentication. Include your API key in the Authorization header for all authenticated requests.
Authorization: Bearer badge_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Note: API keys can be generated from your organization's Settings > API Keys page. Keep your API keys secure and never expose them in client-side code.
Deprecation Notice: Passing API keys via URL query parameter (?api_key=...) is deprecated and will be removed on June 1, 2026. Please use the Authorization header or X-API-Key header instead.
Get Access Token
/auth/token
Exchange credentials for an access token.
{
"grant_type": "client_credentials",
"client_id": "your_api_key",
"client_secret": "your_api_secret"
}
Error Handling
The API uses standard HTTP status codes to indicate success or failure. Error responses include a JSON body with details.
| Code | Description |
|---|---|
| 200 | Success |
| 201 | Resource created |
| 400 | Bad request - Invalid input |
| 401 | Unauthorized - Invalid or missing API key |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not found |
| 429 | Too many requests - Rate limit exceeded |
| 500 | Internal server error |
{
"error": "Badge not found",
"code": 404
}
Pagination
List endpoints return paginated results. Use the page and per_page query parameters to navigate.
GET /credentials?page=2&per_page=20
{
"data": [...],
"meta": {
"total": 150,
"per_page": 20,
"current_page": 2,
"last_page": 8
}
}
Badges (Achievements)
Badges represent achievements that can be awarded to earners. In Open Badges 3.0 terminology, these are "Achievements".
List Badges
/badges
Public
Retrieve a list of active badges for an issuer.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| issuer | string | Required. The issuer organization ID |
curl -X GET "https://earnedcredentials.com/api/v1/badges?issuer=org_123"
Get Badge
/badges/{id}
Public
Retrieve a single badge as an OB3 Achievement.
curl -X GET "https://earnedcredentials.com/api/v1/badges/badge_abc123"
# Response (OB3 Achievement format)
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json"
],
"id": "https://earnedcredentials.com/api/v1/badges/badge_abc123",
"type": ["Achievement"],
"name": "Web Development Fundamentals",
"description": "Demonstrates proficiency in HTML, CSS, and JavaScript",
"criteria": {
"narrative": "Complete all course modules and pass the final assessment"
},
"image": {
"id": "https://example.com/badges/webdev.png",
"type": "Image"
}
}
Create Badge
/badges
Authenticated
Create a new badge for your organization.
Request Body
| Field | Type | Description |
|---|---|---|
| name | string | Required. Badge name |
| description | string | Required. Badge description |
| criteria | string|object | Required. Criteria narrative or object with narrative/id |
| image | string|object | Badge image URL or object with id property |
| tag | array | Skills/tags associated with the badge |
| expires_in_days | integer | Days until credentials expire (optional) |
curl -X POST "https://earnedcredentials.com/api/v1/badges" \
-H "Authorization: Bearer badge_xxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Project Management Professional",
"description": "Demonstrates mastery of project management principles",
"criteria": {
"narrative": "Complete 35 hours of training and pass the certification exam"
},
"tag": ["project-management", "leadership", "agile"]
}'
Update Badge
/badges/{id}
Authenticated
Update an existing badge. Only provided fields will be updated.
curl -X PUT "https://earnedcredentials.com/api/v1/badges/badge_abc123" \
-H "Authorization: Bearer badge_xxxx" \
-H "Content-Type: application/json" \
-d '{
"description": "Updated description for the badge"
}'
Delete Badge
/badges/{id}
Authenticated
Archive a badge. Existing credentials remain valid but no new ones can be issued.
curl -X DELETE "https://earnedcredentials.com/api/v1/badges/badge_abc123" \
-H "Authorization: Bearer badge_xxxx"
Credentials
Credentials are issued badges - the actual awards given to earners. They follow the Open Badges 3.0 Verifiable Credential format.
List Credentials
/credentials
Authenticated
List credentials issued by your organization.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| page | integer | Page number (default: 1) |
| per_page | integer | Items per page (default: 20, max: 100) |
| status | string | Filter by status: pending, claimed, accepted, revoked, expired |
| badge_id | string | Filter by badge ID |
curl -X GET "https://earnedcredentials.com/api/v1/credentials?status=claimed&page=1" \
-H "Authorization: Bearer badge_xxxx"
Get Credential
/credentials/{id}
Public
Retrieve a credential in OB3 Verifiable Credential format.
curl -X GET "https://earnedcredentials.com/api/v1/credentials/cred_xyz789"
# Response (OB3 Verifiable Credential format)
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json"
],
"id": "https://earnedcredentials.com/api/v1/credentials/cred_xyz789",
"type": ["VerifiableCredential", "OpenBadgeCredential"],
"issuer": {
"id": "https://earnedcredentials.com/api/v1/issuers/org_123",
"type": ["Profile"],
"name": "Example Organization"
},
"validFrom": "2024-01-15T00:00:00Z",
"credentialSubject": {
"id": "did:email:sha256:...",
"type": ["AchievementSubject"],
"achievement": {
"id": "https://earnedcredentials.com/api/v1/badges/badge_abc123",
"type": ["Achievement"],
"name": "Web Development Fundamentals"
}
},
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-rdfc-2022",
"created": "2024-01-15T12:00:00Z",
"proofPurpose": "assertionMethod",
"proofValue": "z..."
}
}
Issue Credential
/credentials
Authenticated
Issue a credential to an earner.
Request Body
| Field | Type | Description |
|---|---|---|
| badge_id | string | Required. ID of the badge to issue |
| recipient | string|object | Required. Email address or object with email and name |
| evidence | array | Optional. Evidence supporting the achievement |
| metadata | object | Optional. Additional metadata |
curl -X POST "https://earnedcredentials.com/api/v1/credentials" \
-H "Authorization: Bearer badge_xxxx" \
-H "Content-Type: application/json" \
-d '{
"badge_id": "badge_abc123",
"recipient": {
"email": "earner@example.com",
"name": "Jane Smith"
},
"evidence": [
{
"id": "https://example.com/portfolio/project1",
"name": "Capstone Project",
"description": "Final project demonstrating all skills"
}
]
}'
Bulk Issue Credentials
/credentials/bulk
Authenticated
Issue credentials to multiple recipients at once.
curl -X POST "https://earnedcredentials.com/api/v1/credentials/bulk" \
-H "Authorization: Bearer badge_xxxx" \
-H "Content-Type: application/json" \
-d '{
"badge_id": "badge_abc123",
"recipients": [
{"email": "alice@example.com", "name": "Alice Johnson"},
{"email": "bob@example.com", "name": "Bob Williams"},
{"email": "carol@example.com", "name": "Carol Davis"}
]
}'
# Response
{
"success_count": 3,
"failed_count": 0,
"success": ["cred_1", "cred_2", "cred_3"],
"failed": []
}
Revoke Credential
/credentials/{id}
Authenticated
Revoke a credential. The credential will no longer be valid.
curl -X DELETE "https://earnedcredentials.com/api/v1/credentials/cred_xyz789" \
-H "Authorization: Bearer badge_xxxx" \
-H "Content-Type: application/json" \
-d '{
"reason": "Certificate requirements not met"
}'
Verification
Verify the authenticity and validity of credentials.
Verify Credential by ID
/verify/{id}
Public
Verify a credential issued by this platform.
curl -X GET "https://earnedcredentials.com/api/v1/verify/cred_xyz789"
# Response
{
"valid": true,
"checks": {
"not_revoked": true,
"not_expired": true,
"signature_valid": true
},
"credential": { ... }
}
Verify External Credential
/verify
Public
Verify any OB3 Verifiable Credential by submitting the credential JSON.
curl -X POST "https://earnedcredentials.com/api/v1/verify" \
-H "Content-Type: application/json" \
-d '{
"@context": [...],
"type": ["VerifiableCredential", "OpenBadgeCredential"],
...
}'
Issuers
Retrieve issuer profiles and public keys for verification.
Get Issuer Profile
/issuers/{id}
Public
Retrieve an issuer's profile in OB3 format.
curl -X GET "https://earnedcredentials.com/api/v1/issuers/org_123"
# Response
{
"@context": [...],
"id": "https://earnedcredentials.com/api/v1/issuers/org_123",
"type": ["Profile"],
"name": "Example Organization",
"url": "https://example.com",
"email": "badges@example.com",
"image": {
"id": "https://example.com/logo.png",
"type": "Image"
}
}
Get Issuer Public Key
/issuers/{id}/public-key
Public
Retrieve an issuer's public key for credential verification.
curl -X GET "https://earnedcredentials.com/api/v1/issuers/org_123/public-key"
# Response (JWK format for RS256)
{
"keys": [
{
"kty": "RSA",
"use": "sig",
"alg": "RS256",
"kid": "org_123#key-1",
"n": "...",
"e": "AQAB"
}
]
}
Code Examples
PHP
$ch = curl_init('https://earnedcredentials.com/api/v1/credentials');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'badge_id' => 'badge_abc123',
'recipient' => 'user@example.com',
]),
]);
$response = curl_exec($ch);
JavaScript
const response = await fetch(
'https://earnedcredentials.com/api/v1/credentials',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
badge_id: 'badge_abc123',
recipient: 'user@example.com',
}),
}
);
const data = await response.json();
Python
import requests
response = requests.post(
'https://earnedcredentials.com/api/v1/credentials',
headers={
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json',
},
json={
'badge_id': 'badge_abc123',
'recipient': 'user@example.com',
}
)
data = response.json()
cURL
curl -X POST \
"https://earnedcredentials.com/api/v1/credentials" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"badge_id": "badge_abc123",
"recipient": "user@example.com"
}'
Rate Limits
API requests are rate limited to ensure fair usage. Rate limit information is included in response headers.
| Endpoint Type | Limit |
|---|---|
| Public endpoints | 100 requests per minute |
| Authenticated endpoints | 1000 requests per minute |
| Bulk operations | 10 requests per minute |
Response Headers:
X-RateLimit-Limit- Maximum requests allowedX-RateLimit-Remaining- Remaining requests in windowX-RateLimit-Reset- Unix timestamp when limit resets
Support
Need help with the API? Contact our support team or check out our resources:
- Open Badges 3.0 Specification
- Email: support@earnedcredentials.com