Open Badges 3.0 API Documentation

Open Badges 3.0 compliant REST API for managing digital credentials

v1.0 Base URL: 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

POST /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

GET /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

GET /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

POST /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

PUT /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

DELETE /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

GET /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

GET /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

POST /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

POST /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

DELETE /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

GET /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

POST /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

GET /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

GET /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 allowed
  • X-RateLimit-Remaining - Remaining requests in window
  • X-RateLimit-Reset - Unix timestamp when limit resets

Support

Need help with the API? Contact our support team or check out our resources: