通过 Badges Ninja REST API 颁发 Open Badges:快速入门
认证身份、创建颁发者、设计或上传徽章,再把它颁发给接收者——全部通过 REST 完成。附 JavaScript 和 Python 示例。
大多数证书项目其实用不上 API。如果你开设的课程每年只有几百名毕业生,控制台就能搞定一切:在可视化设计器里设计数字徽章,上传一个 CSV,每位接收者都会得到一个验证页面和一份 PDF 证书。如果你的情况正是如此,请先看如何通过 CSV 颁发 Open Badges,以后再回来。
当证书需要由其他系统来颁发时,API 就派上用场了:你的学习平台把某门课程标记为完成,你的报名工具结束了一场活动,你的 HR 系统记录下一个已完成的合规模块。在这些场景里,没人愿意每周末都导出一次电子表格。在完成的那一刻发起一次 HTTP 调用要简单得多,接收者也能在成就还新鲜的时候拿到数字徽章。
本快速入门用四次调用走完整个流程:获取密钥、创建颁发者、创建徽章、颁发徽章。之后我们再看如何把验证链接交给接收者,以及如何检查结果。下面所有请求格式都来自已部署的 handler,所以你可以直接复制并运行。
开始之前你需要准备什么
- 一个 badges.ninja 的免费账号。Free 套餐足够完成本教程:它包含 2 个颁发者、5 个徽章、2 个席位和 1 个 API 密钥。
- 一个在控制台中创建的 API 密钥。
- 一张用作徽章图像的 PNG 或 JPG,或者一个你在可视化设计器中设计好的徽章。
所有请求的基础 URL 都是 https://api.badges.ninja。
第 1 步:创建 API 密钥
登录后,在侧边栏打开 API Keys,点击 Create API Key。给它起一个能说明用途的名字,比如 “LMS integration”,这样以后轮换密钥时你就能分清它们。

密钥只会显示一次。请立即把它复制到你的密钥管理器或环境变量中。密钥以 bws_ 开头,后面跟 32 个十六进制字符,每次请求都要把它放在 X-Api-Key 请求头里发送。在同一个界面中吊销密钥会立即生效。
几个能省去日后麻烦的习惯:
- 永远不要把密钥放进前端代码或公开仓库。请从服务器、无服务器函数或自动化工具中调用 API。
- 每个集成使用一个密钥。一旦某个密钥泄露,你只需要吊销这一个集成,而不是全部。
- 控制台也接受你已登录的会话(以
Authorization: Bearer发送的 Cognito JWT),但对于脚本和集成来说,API 密钥才是合适的工具。
下面所有示例都从名为 BADGES_API_KEY 的环境变量中读取密钥。
第 2 步:创建颁发者
颁发者是为徽章背书的组织。它会出现在每个验证页面以及 Open Badge v2.0 数据中,所以请使用大家真正熟悉的名称。
curl -X POST https://api.badges.ninja/issuers \
-H "X-Api-Key: $BADGES_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Acme Academy","url":"https://acme.example.com","email":"badges@acme.example.com"}'
必填字段是 name(至少 3 个字符)、url(有效的 http 或 https 地址)和 email。可选字段是 logo(base64 编码的图像)和 linkedinOrganizationId,后者会在你的公开证书页面上启用 Add to LinkedIn Profile 按钮。
响应中包含颁发者标识符:
{
"issuerId": "https://api.badges.ninja/certify-badge/issuer/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
请原样保留这个值。它是下一步的输入。
颁发者验证
只有已验证的颁发者才能创建徽章。验证方式如下:
- 如果颁发者邮箱与你账号上的邮箱一致,颁发者会被自动验证。这是首次测试最快的途径。
- 如果邮箱不同,一封带验证码的验证邮件会发送到该地址。在创建徽章之前,你需要在控制台(或通过颁发者 API)确认这个验证码。
因此,在本教程中请使用你注册时用的同一个邮箱。
第 3 步:创建徽章
徽章是可重复使用的模板:名称、描述、颁发标准和图像。你之后颁发的每一次授予都会指向它。
请求是普通的 JSON。图像以 base64 字符串的形式传入,所以不用和 multipart 上传较劲。形如 data:image/png;base64, 的 data URL 前缀会被接受并自动去除。
JavaScript(Node 18 或更高版本):
import { readFileSync } from "node:fs";
const API_KEY = process.env.BADGES_API_KEY;
const image = readFileSync("./badge.png").toString("base64");
const res = await fetch("https://api.badges.ninja/badges", {
method: "POST",
headers: { "X-Api-Key": API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({
name: "JavaScript Fundamentals",
description: "Demonstrates proficiency in core JavaScript concepts",
criteria: "Completed the JavaScript Fundamentals course with a score of 80% or higher",
image,
issuerId: "https://api.badges.ninja/certify-badge/issuer/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
}),
});
const { badgeId } = await res.json();
console.log(badgeId);
Python:
import base64, os, requests
API_KEY = os.environ["BADGES_API_KEY"]
with open("badge.png", "rb") as f:
image = base64.b64encode(f.read()).decode()
res = requests.post(
"https://api.badges.ninja/badges",
headers={"X-Api-Key": API_KEY},
json={
"name": "JavaScript Fundamentals",
"description": "Demonstrates proficiency in core JavaScript concepts",
"criteria": "Completed the JavaScript Fundamentals course with a score of 80% or higher",
"image": image,
"issuerId": "https://api.badges.ninja/certify-badge/issuer/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
},
)
badge_id = res.json()["badgeId"]
print(badge_id)
这五个字段(name、description、criteria、image、issuerId)都是必填的。另有两个值得了解的可选字段:shareText,即接收者在社交网络上分享时看到的默认文案(支持 {{badge_name}}、{{issuer_name}} 和 {{award_url}} 占位符);以及 designJson,它保存可视化设计器的文档,以便之后可以逐图层编辑徽章。
成功时会返回 HTTP 200 和 { "badgeId": "<id>" }。图像会被永久保存,这个徽章现在就是一个任何人都可以获取的 Open Badge v2.0 BadgeClass。
到底该不该用代码创建徽章?
通常不该。徽章设计是创意工作,可视化设计器(80 多个模板、形状、图标、11 种字体以及自定义上传)比脚本合适得多。常见的做法是:在控制台里把每个徽章设计一次,然后让你的集成只针对它颁发授予。你可以用 GET /badges 列出你的徽章,并复制所需徽章的 id。
当你需要以编程方式生成徽章时,例如为拥有数百门课程的目录每门课程生成一个,或者在搭建测试环境时,再通过 API 创建徽章。
第 4 步:颁发徽章
这就是你的集成要调用成千上万次的那个请求。发送徽章、接收者和日期即可。
curl:
curl -X POST https://api.badges.ninja/awards \
-H "X-Api-Key: $BADGES_API_KEY" \
-H "Content-Type: application/json" \
-d '{"badgeId":"<badge-id>","recipient":{"name":"Jane Smith","email":"jane@example.com"},"issuedOn":"2026-09-28"}'
JavaScript:
const res = await fetch("https://api.badges.ninja/awards", {
method: "POST",
headers: { "X-Api-Key": API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({
badgeId,
recipient: { name: "Jane Smith", email: "jane@example.com" },
issuedOn: Date.now(),
}),
});
const { awardId } = await res.json();
Python:
import time, requests
res = requests.post(
"https://api.badges.ninja/awards",
headers={"X-Api-Key": API_KEY},
json={
"badgeId": badge_id,
"recipient": {"name": "Jane Smith", "email": "jane@example.com"},
"issuedOn": int(time.time() * 1000),
},
)
award_id = res.json()["awardId"]
最容易踩坑的几条规则:
recipient是一个嵌套对象,包含name和email。像recipientEmail这样的扁平字段会被拒绝。recipient.name至少要有 5 个字符。issuedOn是必填的。可以发送纪元毫秒数,或2026-09-28这样的 ISO 日期字符串。expires是可选的,接受同样的格式。
成功时返回 HTTP 200,响应体中包含 awardId。接收者的邮箱在 Open Badge 数据中以 SHA-256 哈希的形式保存,因此公开的 JSON 绝不会暴露它。
第 5 步:找到验证页面和 Open Badge JSON
颁发响应给你的是一个标识符,而不是现成的链接。该标识符以一个 GUID 结尾,公开页面就是用这个 GUID 构建的:
- 供人阅读的验证页面:
https://badges.ninja/awards/<awardId> - Open Badge v2.0 JSON-LD:
https://api.badges.ninja/certify-badge/award/<awardId>
如果你拿到的 awardId 是一个完整的 URL,请把路径的最后一段当作 GUID。
两者都是公开的。任何拿到链接的人都无需创建账号就能验证这份证书,这正是关键所在:雇主或招生官应该能在十秒内查验一枚徽章。
获取这份 JSON,看看外界看到的是什么:
curl https://api.badges.ninja/certify-badge/award/<awardId>
你会得到一个 Open Badge v2.0 Assertion:它所引用的徽章、经过哈希的接收者身份、颁发日期,以及一个指回托管 assertion 的验证块。由于这是标准的 Open Badges 数据,任何理解该格式的工具都能读取。这种可移植性正是选择 Open Badges 而不是专有 PDF 的原因;Open Badges vs PDF certificates 对这一取舍有更深入的讨论。
接收者如何收到证书
创建授予和通知接收者是两件事。接收者可以通过接收者门户 badges.ninja/me 打开自己的证书,该门户使用免密码的魔法链接登录,他们还可以在 badges.ninja/u/<handle> 发布公开主页。在验证页面上,他们可以把徽章添加到 LinkedIn、下载 PDF 证书,或分享链接。
最初几次测试时,用你自己的邮箱给自己颁发一个徽章,亲自走一遍接收者的体验。这是发现徽章描述读起来别扭之类问题的最快办法。
不会让你头疼的错误处理
API 使用常规的 HTTP 状态码。你会遇到的有:
| Status | 含义 | 该怎么做 |
|---|---|---|
| 200 | 成功 | 读取 JSON 响应体 |
| 400 | 字段缺失或无效,包括接收者姓名少于 5 个字符 | 修正请求内容;重试同样的请求还会失败 |
| 401 | API 密钥缺失或错误 | 检查 X-Api-Key 请求头,以及密钥是否已被吊销 |
| 402 | 额度或套餐配额用完 | 升级套餐,或等待下一个配额周期 |
| 404 | 未找到该徽章 | 检查你传入的 badgeId |
两条实用建议。第一,把 400 当作数据问题,并记录响应体,因为它会指明出错的字段。第二,在你这一侧实现幂等:把 awardId 和完成记录一起存进你自己的数据库,并在再次调用 API 之前先检查它。这样,重试的 webhook 或重新运行的任务就不会给同一个人颁发两份证书。
在真实集成中把它们串起来
典型的接线方式如下:
- 在控制台中设计徽章,每门课程或每个里程碑一个,并记下每个徽章的 ID。
- 在你的系统里保存一份从课程到徽章 ID 的映射。
- 学员完成课程时,你的服务器用其姓名、邮箱和完成日期调用
POST /awards。 - 把返回的
awardId保存到对应的完成记录上。 - 在你自己的产品里展示验证链接,让学员无需离开就能看到。
如果你不想写代码,任何能发送带 JSON 请求体和自定义请求头的 HTTP 请求的自动化工具,都可以发起同样的调用。把它指向 https://api.badges.ninja/awards,并把表单或电子表格的字段映射到 badgeId、recipient.name、recipient.email 和 issuedOn。
值得了解的套餐与限制
所有套餐都提供 API;解锁它无需额外付费。Free 套餐($0)包含 2 个颁发者、5 个徽章、2 个席位、1 个 API 密钥,以及每年 1,200 份证书。Starter 为每月 $9,Pro 为每月 $29,限额更高。在规划部署规模之前,请查看定价页面了解当前数字。如果你在比较其他平台对 API 访问的收费,Credly alternative 把各家的费用并排列了出来。
接下来去哪里
- 完整的端点参考位于 API 文档,提供 40 种语言版本。
- 关于认证和密钥处理的细节,请参阅认证指南。
- 关于错误码的详细说明,请参阅错误参考。
- 当一次一个调用不够用时,请使用控制台中的批量颁发:上传一个 CSV,需要时可以暂停或恢复这次运行。
第一次成功颁发才是最难的部分。此后,剩下的就是把同一个调用接入你记录成就的各个地方。
准备好颁发你的第一份可验证证书了吗? 在 badges.ninja 免费开始 —— 可视化设计器、公开验证页面、PDF 证书、Open Badge v2.0 输出。无需信用卡。
本文是如何撰写的
本博客的部分文章由 AI 助手协助起草,随后由 Badges Ninja 团队审核、核实并编辑后发布。所有代码示例和价格均已对照产品实际情况核实。欲了解更多关于我们编辑与 AI 流程的信息,请查看我们的 编辑流程页面 .

关于作者
Nacho Coll
Founder & Engineer at Badges Ninja
Nacho founded Badges Ninja to make issuing verifiable digital credentials as simple as a single API call — Open Badge v2.0 badges and certificates, minted, hosted, and verifiable without standing up your own issuer infrastructure. Writes about the Open Badges spec, credential verification, and running a credentialing platform serverless on AWS, from the operator side of the wire.

