프로그램
배지를 발급할 활동입니다. 교육, 행사, 공모전 등이 해당합니다.
각 가이드는 구현 순서와 API 요청 예시를 함께 안내합니다.
키를 연동 서버의 환경 변수에 저장합니다.
GET /organization으로 인증과 조직 범위를 확인합니다.
첫 배지 발급, 플랫폼 사용자 배지 표시, 수료·수상 시 배지 발급 중 필요한 가이드로 이동합니다.
프로그램에 배지를 연결해 발급하면 수신자별로 발급된 배지(Assertion)가 만들어집니다.
배지를 발급할 활동을 만듭니다.
이름, 기준과 이미지를 연결합니다.
한 명 이상에게 발급을 요청합니다.
수신자별 발급 결과를 조회합니다.
배지를 발급할 활동입니다. 교육, 행사, 공모전 등이 해당합니다.
여러 수신자에게 발급할 이름, 설명, 기준과 이미지입니다.
배지를 한 명 이상에게 발급하는 비동기 요청입니다.
특정 수신자에게 실제로 발급된 디지털 배지입니다. 배지 이미지와 검증 URL을 포함하며, 필요하면 PDF로 다운로드할 수 있습니다.
프로그램과 배지에 연결하는 업로드 파일입니다.
GET /badges발급에 사용할 배지 목록GET /assertions사용자에게 발급된 배지 목록API 키를 연동 서버의 환경 변수에 저장한 뒤 GET /organization으로 연결을 확인합니다.
https://api.certi.world/public/v2써티 콘솔의 조직 API 키 관리 안내 에서 Manager 이상 권한으로 키를 발급합니다. 키 원문은 처음 한 번만 표시되므로 비밀 저장소에 보관합니다.
.env에 키 저장프로젝트 루트의 서버 환경 변수 파일이나 배포 서비스의 비밀 저장소에 넣습니다. 이 파일은 Git에 올리지 않습니다.
프로젝트 루트/.envCERTI_API_KEY=your-key-from-certi-console아래는 Node.js 예시입니다. 사용하는 언어와 관계없이 API 키를 서버에만 보관하고 인증·오류 처리를 한 곳에서 공통으로 적용하세요.
lib/certi.js// lib/certi.js — 서버에서만 사용합니다.
const BASE_URL = "https://api.certi.world/public/v2";
export async function certi(path, options = {}) {
const response = await fetch(`https://api.certi.world/public/v2${path}`, {
...options,
headers: {
"X-API-KEY": process.env.CERTI_API_KEY,
"Content-Type": "application/json",
...options.headers,
},
});
const result = await response.json();
if (!response.ok) {
throw new Error(`${result.error?.code ?? response.status}: ${result.error?.message ?? "Certi API request failed"}`);
}
return result.data;
}GET /organization은 읽기 권한만으로 호출할 수 있어 첫 연결 확인에 적합합니다. 응답의 조직 이름이 예상과 같은지 확인하세요.
curl -X GET "https://api.certi.world/public/v2/organization" \
-H "X-API-KEY: $CERTI_API_KEY"200 · application/json{
"success": true,
"message": null,
"data": {
"id": "01946e3c-72dc-7a42-a40f-f36df9b73d7a",
"name": "Certi Labs",
"roleCode": "ORG_MANAGER"
}
}브라우저 번들, 모바일 앱, 공개 저장소에 키를 포함하지 마세요.
브라우저는 연동 서버를 호출하고, 연동 서버만 써티 API 키를 사용합니다. 아래 파일명은 Node.js·Next.js 예시이며 같은 원칙을 다른 서버 언어에도 적용할 수 있습니다.
연동 서버의 API만 호출합니다. 써티 API 키는 알지 못합니다.
권한을 확인하고 환경 변수의 키로 써티 API를 호출합니다.
프로그램·배지·발급 작업·발급된 배지 데이터를 반환합니다.
필요하면 플랫폼 사용자·프로그램 ID와 써티 리소스 ID의 연결 정보를 저장합니다.
발급 요청, 상태 재확인, 대량 처리는 큐나 스케줄러에서 처리합니다.
CERTI_API_KEY는 서버 환경 변수나 클라우드 Secret Manager에 보관합니다.
.envAPI 키 저장서버 런타임만lib/certi.js인증·오류 처리 공통 함수서버 API와 작업 큐app/api/…/route.js화면에 필요한 데이터만 가공브라우저·LMSjobs/…발급 요청·상태 확인·대량 처리큐·스케줄러// lib/certi.js — 서버에서만 사용합니다.
const BASE_URL = "https://api.certi.world/public/v2";
export async function certi(path, options = {}) {
const response = await fetch(`https://api.certi.world/public/v2${path}`, {
...options,
headers: {
"X-API-KEY": process.env.CERTI_API_KEY,
"Content-Type": "application/json",
...options.headers,
},
});
const result = await response.json();
if (!response.ok) {
throw new Error(`${result.error?.code ?? response.status}: ${result.error?.message ?? "Certi API request failed"}`);
}
return result.data;
}모든 요청에 X-API-KEY를 보내며 키의 조직과 역할에 따라 접근 범위가 정해집니다.
X-API-KEY: $CERTI_API_KEYORG_VIEWER조직·프로그램·배지·발급 작업·발급된 배지 조회ORG_MANAGERVIEWER 권한 + 생성·수정·삭제·발급·취소·이미지 업로드ORG_OWNER써티 API에서는 MANAGER와 동일한 전체 권한브라우저 번들, 모바일 앱, 공개 저장소에 키를 포함하지 마세요. 노출이 의심되면 키를 교체하고 기존 키를 폐기하세요.
날짜는 ISO-8601, ID는 UUID를 사용하며 정상 응답은 HTTP 200입니다.
page는 1부터, size는 기본 20·최대 100입니다. sort는 반복 가능하며 기본값은 createdAt,desc와 id,desc입니다.
JSON 단건 응답은 success · message · data, 목록은 items · pagination을 포함합니다. PDF 다운로드는 파일 바이너리를 바로 반환합니다.
프로그램·배지 생성과 수정은 PUBLISHED 상태로 처리되며, PATCH는 생략한 필드를 유지합니다.
써티 API의 프로그램·배지 생성과 수정 요청에는 publishStatusCode를 보내지 않습니다. 응답은 PUBLISHED 상태입니다.
요청에서 생략한 필드는 유지합니다. null과 빈 배열의 의미는 각 엔드포인트의 Request body 설명을 확인하세요.
직접 발급에는 1~300자의 Idempotency-Key가 필요합니다. 같은 키와 같은 본문은 동일 요청으로 처리되며, 수신자 순서를 포함한 본문이 달라지면 409 · ISS057로 응답합니다.
JSON API 표에는 아래 공통 구조를 제외하고 data 또는 data.items[]의 실제 필드만 표시합니다. PDF 다운로드 응답은 이 구조를 사용하지 않습니다.
successmessagedatasuccessdata.itemsdata.paginationpagesizetotalElementtotalPagesfirstlastemptyAPI 오류는 HTTP 상태, 오류 코드, 메시지와 요청 경로를 포함한 JSON 구조로 반환됩니다. 분기 처리는 메시지가 아닌 고정된 오류 코드를 기준으로 구현하세요.
COM002파라미터 형식 오류타입·UUID·날짜 형식을 확인하세요.COM006요청 값 검증 실패필수값과 필드 제약을 확인하세요.COM020지원하지 않는 정렬이 API에서 허용하는 sort 필드만 사용하세요.AST008잘못된 생성 일시 범위startAt이 endAt보다 늦지 않도록 입력하세요.AST023수신자 필터 충돌email과 phoneNumber 중 하나만 사용하세요.ISS056멱등성 키 오류1~300자의 Idempotency-Key를 추가하세요.SEC065API 키 인증 실패X-API-KEY 헤더와 키 상태를 확인하세요. 노출된 키는 교체하세요.ORG004권한 부족필요한 역할이 VIEWER+인지 MANAGER+인지 확인하세요.PRG001프로그램을 찾을 수 없음ID와 API 키의 조직 범위를 확인하세요.BDG001배지를 찾을 수 없음ID와 API 키의 조직 범위를 확인하세요.ISS001발급 작업을 찾을 수 없음ID와 API 키의 조직 범위를 확인하세요.AST001발급된 배지를 찾을 수 없음ID와 API 키의 조직 범위를 확인하세요.BDG064FIXED 만료 정책 배지만료 정책이 없거나 상대 만료 개월 수를 사용하는 배지로 발급하세요.ISS057멱등성 키 충돌같은 요청은 같은 본문으로 재시도하세요. 다른 요청에는 새 키를 사용하세요.AST022취소할 수 없는 상태취소 가능한 상태인지 확인하세요.PAY054발급 크레딧 부족발급 가능 여부를 확인하세요.{
"success": false,
"error": {
"timestamp": "2026-07-23T10:24:31",
"code": "SEC065",
"message": "유효한 조직 API Key가 필요합니다.",
"status": 401,
"path": "/external/v2/organization",
"errors": []
}
}연동 서비스의 플랫폼 사용자 이메일과 recipient.email이 일치하는 발급된 배지를 조회해 openbadgeImageUrl과 credentialUrl을 표시합니다. 아래는 Next.js·React 구현 예시입니다.
빠른 시작의 Node.js 예시를 사용하거나, 같은 인증·오류 처리 원칙을 사용하는 서버 언어로 구현하세요.
lib/certi.js// lib/certi.js — 서버에서만 사용합니다.
const BASE_URL = "https://api.certi.world/public/v2";
export async function certi(path, options = {}) {
const response = await fetch(`https://api.certi.world/public/v2${path}`, {
...options,
headers: {
"X-API-KEY": process.env.CERTI_API_KEY,
"Content-Type": "application/json",
...options.headers,
},
});
const result = await response.json();
if (!response.ok) {
throw new Error(`${result.error?.code ?? response.status}: ${result.error?.message ?? "Certi API request failed"}`);
}
return result.data;
}email은 앞뒤 공백과 대소문자를 정규화한 뒤 완전 일치로 조회합니다. External API v2는 운영 발급만 반환하며, 상태 필터는 서비스의 화면 표시 정책에 맞게 조정하세요. 목록 응답의 badge.image를 표시용 이미지로 사용할 수 있고, 검증 URL과 OpenBadge 이미지는 상세 응답에서 가져옵니다.
app/api/my-badges/route.js// app/api/my-badges/route.js — 홈페이지 서버 API
import { certi } from "@/lib/certi";
import { getCurrentUser } from "@/lib/auth"; // 사용 중인 인증 함수로 바꾸세요.
export async function GET() {
const user = await getCurrentUser();
const email = user?.email?.trim().toLowerCase();
if (!email) return Response.json({ message: "sign in required" }, { status: 401 });
const page = await certi(
`/assertions?${new URLSearchParams({ email, page: "1", size: "100" })}`,
);
// email은 정규화 후 완전 일치하며 External API v2는 운영 발급만 반환합니다.
// 아래 상태 필터는 화면 표시 정책 예시입니다.
const issued = page.items.filter((item) =>
item.recipient.email?.toLowerCase() === email &&
["ISSUED", "RECEIVED", "REISSUED"].includes(item.stateCode),
);
const items = await Promise.all(issued.map(async (item) => {
const detail = await certi(`/assertions/${item.id}`);
return {
id: detail.id,
name: detail.badge.name,
imageUrl: detail.openbadgeImageUrl ?? item.badge.image?.urls.medium ?? item.badge.image?.urls.original,
credentialUrl: detail.credentialUrl,
};
}));
return Response.json({ items });
}프론트엔드는 여러분의 /api/my-badges만 호출합니다. 서버가 선택한 이미지와 검증 링크를 그대로 표시합니다.
components/BadgeList.jsx// components/BadgeList.jsx — 홈페이지 화면
export function BadgeList({ badges }) {
return (
<ul className="badge-list">
{badges.map((badge) => (
<li key={badge.id}>
<img src={badge.imageUrl} alt={`${badge.name} 디지털 배지`} />
<strong>{badge.name}</strong>
<a href={badge.credentialUrl} target="_blank" rel="noreferrer">
배지 검증
</a>
</li>
))}
</ul>
);
}recipient.email을 서버에서 다시 비교합니다.수료·수상·승인 결과가 확정되면 발급 작업을 만들고, 발급 작업의 처리 상태가 COMPLETED가 될 때까지 확인합니다. 아래는 Node.js 작업 큐 구현 예시입니다.
badgeId 발급할 배지programId 연결할 프로그램화면 요청을 처리하는 동안 발급 작업이 끝날 때까지 기다리지 마세요. 수료 확정, 수상자 등록, 승인 완료 시점에 작업 큐로 내부 결과 ID와 수신자 정보를 전달합니다.
같은 결과를 다시 처리해도 중복 발급되지 않도록 내부 결과 ID에서 같은 Idempotency-Key를 만듭니다.
jobs/issue-completion-badge.js// jobs/issue-completion-badge.js — 수료 처리 후 실행되는 서버 작업
import { createHash } from "node:crypto";
import { certi } from "@/lib/certi";
export async function issueCompletion({ completionId, badgeId, programId, learner }) {
// 같은 수료 건에는 같은 키를 사용해 중복 발급을 막습니다.
const key = "completion:" + createHash("sha256").update(completionId).digest("hex");
return certi(`/badges/${badgeId}/issuances`, {
method: "POST",
headers: { "Idempotency-Key": key },
body: JSON.stringify({
programId,
recipients: [{
name: learner.name,
email: learner.email,
receiveType: "EMAIL",
}],
}),
});
}직접 발급 응답의 data.id를 내부 결과 건에 저장합니다. PROCESSING이면 플랫폼의 재확인 정책에 따라 같은 ID를 다시 조회하고, COMPLETED 후 발급된 배지 목록을 가져옵니다.
jobs/check-issuance.js// jobs/check-issuance.js — 백그라운드 작업에서 주기적으로 확인
import { certi } from "@/lib/certi";
export async function checkIssuance(issuanceId) {
const issuance = await certi(`/issuances/${issuanceId}`);
if (issuance.processingStatus === "PROCESSING") {
return { done: false };
}
if (issuance.processingStatus === "FAILED") {
throw new Error("발급 작업이 실패했습니다. issuanceId로 발급된 배지 목록과 errorCode를 확인하세요.");
}
const page = await certi(
`/assertions?${new URLSearchParams({ issuanceId, page: "1", size: "100" })}`,
);
return { done: true, assertions: page.items };
}PROCESSING정책에 따라 재확인COMPLETED발급된 배지 조회ISSUED내부 상태 완료이미지 업로드부터 발급된 배지 확인까지, 배지 한 개를 실제로 발급하는 전 과정을 순서대로 따라 합니다.
POST /media-files/images로 배지 이미지를 업로드합니다.
curl -X POST "https://api.certi.world/public/v2/media-files/images" \
-H "X-API-KEY: $CERTI_API_KEY" \
-F "image=@badge.png"{
"success": true,
"message": null,
"data": {
"id": "01947a1b-66d1-7a51-8d7c-67b80b4162db",
"urls": {
"original": "https://cdn.certi.world/media/badge.png",
"medium": "https://cdn.certi.world/media/badge-medium.png",
"small": "https://cdn.certi.world/media/badge-small.png"
}
}
}이 단계가 끝나면: 응답의 data.id를 imageId로 사용합니다.
1단계의 imageId를 사용해 교육, 행사, 공모전처럼 배지를 받을 활동을 만듭니다.
curl -X POST "https://api.certi.world/public/v2/programs" \
-H "X-API-KEY: $CERTI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "AI Literacy Program",
"description": "데이터 리터러시를 배우는 교육 과정입니다.",
"url": "https://example.com/programs/ai-literacy",
"categoryCode": "EDUCATION",
"startsAt": "2026-08-01T09:00:00",
"endsAt": "2026-08-31T18:00:00",
"isVisibleAtOrganizationPage": true,
"imageId": "01947a1b-66d1-7a51-8d7c-67b80b4162db",
"badgeIds": []
}'{
"success": true,
"message": null,
"data": {
"id": "0194775c-6402-7b98-baa4-1c8f8af208b8",
"name": "AI Literacy Program",
"description": "데이터 리터러시를 배우는 교육 과정입니다.",
"url": "https://example.com/programs/ai-literacy",
"categoryCode": "EDUCATION",
"startsAt": "2026-08-01T09:00:00",
"endsAt": "2026-08-31T18:00:00",
"publishStatusCode": "PUBLISHED",
"isVisibleAtOrganizationPage": true,
"image": {
"id": "01947a1b-66d1-7a51-8d7c-67b80b4162db",
"urls": {
"original": "https://cdn.certi.world/media/badge.png",
"medium": "https://cdn.certi.world/media/badge-medium.png",
"small": "https://cdn.certi.world/media/badge-small.png"
}
},
"badgeIds": [
"01947a42-1b58-7cb1-91d7-b386d629db96"
],
"createdAt": "2026-07-23T10:24:31",
"updatedAt": "2026-07-23T10:24:31"
}
}이 단계가 끝나면: 응답의 data.id를 programId로 사용합니다.
imageId와 2단계의 programId를 포함해 이름, 발급 기준, 카테고리와 스킬을 정의합니다.
curl -X POST "https://api.certi.world/public/v2/badges" \
-H "X-API-KEY: $CERTI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "AI Literacy Certificate",
"description": "데이터 리터러시 교육 이수를 인증합니다.",
"criteria": [
{
"category": "COMPLETION",
"value": "필수 과정 이수"
}
],
"categoryCode": "CERTIFICATION",
"expirationPolicy": {
"relativeExpirationMonths": 12
},
"imageId": "01947a1b-66d1-7a51-8d7c-67b80b4162db",
"skills": [
{
"sourceType": "CUSTOM",
"skillName": "AI literacy"
}
],
"programIds": [
"0194775c-6402-7b98-baa4-1c8f8af208b8"
]
}'{
"success": true,
"message": null,
"data": {
"id": "01947a42-1b58-7cb1-91d7-b386d629db96",
"name": "AI Literacy Certificate",
"description": "데이터 리터러시 교육 이수를 인증합니다.",
"criteria": [
{
"category": "COMPLETION",
"value": "필수 과정 이수"
}
],
"categoryCode": "CERTIFICATION",
"publishStatusCode": "PUBLISHED",
"expirationPolicy": {
"relativeExpirationMonths": 12
},
"image": {
"id": "01947a1b-66d1-7a51-8d7c-67b80b4162db",
"urls": {
"original": "https://cdn.certi.world/media/badge.png",
"medium": "https://cdn.certi.world/media/badge-medium.png",
"small": "https://cdn.certi.world/media/badge-small.png"
}
},
"signatureImage": null,
"skills": [
{
"sourceType": "CUSTOM",
"skillName": "AI literacy"
}
],
"programIds": [
"0194775c-6402-7b98-baa4-1c8f8af208b8"
],
"createdAt": "2026-07-23T10:24:31",
"updatedAt": "2026-07-23T10:24:31"
}
}이 단계가 끝나면: 응답의 data.id를 badgeId로 사용합니다.
uuidgen 등으로 요청마다 멱등성 키를 만들고 수신자 목록을 보냅니다.
curl -X POST "https://api.certi.world/public/v2/badges/01947a42-1b58-7cb1-91d7-b386d629db96/issuances" \
-H "X-API-KEY: $CERTI_API_KEY" \
-H "Idempotency-Key: $CERTI_IDEMPOTENCY_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipients": [
{
"name": "Kim Certi",
"email": "recipient@example.com",
"receiveType": "EMAIL"
}
],
"programId": "0194775c-6402-7b98-baa4-1c8f8af208b8"
}'{
"success": true,
"message": null,
"data": {
"id": "01947b37-9c9d-7e8c-981a-a6f8cdf95a6e",
"badgeId": "01947a42-1b58-7cb1-91d7-b386d629db96",
"programId": "0194775c-6402-7b98-baa4-1c8f8af208b8",
"processingStatus": "PROCESSING",
"assertionCount": 1,
"createdAt": "2026-07-23T10:24:31",
"updatedAt": "2026-07-23T10:24:31"
}
}이 단계가 끝나면: 응답의 data.id를 issuanceId로 사용합니다.
GET /issuances/{issuanceId}로 처리 상태를 조회합니다. PROCESSING이면 같은 ID로 다시 확인하고, COMPLETED가 되면 다음 단계로 이동합니다.
curl -X GET "https://api.certi.world/public/v2/issuances/01947b37-9c9d-7e8c-981a-a6f8cdf95a6e" \
-H "X-API-KEY: $CERTI_API_KEY"{
"success": true,
"message": null,
"data": {
"id": "01947b37-9c9d-7e8c-981a-a6f8cdf95a6e",
"badgeId": "01947a42-1b58-7cb1-91d7-b386d629db96",
"programId": "0194775c-6402-7b98-baa4-1c8f8af208b8",
"processingStatus": "PROCESSING",
"assertionCount": 1,
"createdAt": "2026-07-23T10:24:31",
"updatedAt": "2026-07-23T10:24:31"
}
}이 단계가 끝나면: processingStatus가 COMPLETED인지 확인했습니다.
발급 작업 ID로 발급된 배지 목록을 좁혀 조회하고, 수신자별 id와 stateCode를 확인합니다.
curl -X GET "https://api.certi.world/public/v2/assertions?page=1&size=20&sort=createdAt,desc" \
-H "X-API-KEY: $CERTI_API_KEY"{
"success": true,
"data": {
"items": [
{
"id": "01947b8e-54d7-79a7-835d-7ea2376bc4d2",
"serialNumber": "CERTI-2026-000042",
"badge": {
"id": "01947a42-1b58-7cb1-91d7-b386d629db96",
"name": "AI Literacy Certificate",
"image": {
"id": "01947a1b-66d1-7a51-8d7c-67b80b4162db",
"urls": {
"original": "https://cdn.certi.world/media/badge.png",
"medium": "https://cdn.certi.world/media/badge-medium.png",
"small": "https://cdn.certi.world/media/badge-small.png"
}
}
},
"program": {
"id": "0194775c-6402-7b98-baa4-1c8f8af208b8",
"name": "AI Literacy Program",
"image": {
"id": "01947a1b-66d1-7a51-8d7c-67b80b4162db",
"urls": {
"original": "https://cdn.certi.world/media/badge.png",
"medium": "https://cdn.certi.world/media/badge-medium.png",
"small": "https://cdn.certi.world/media/badge-small.png"
}
}
},
"issuanceId": "01947b37-9c9d-7e8c-981a-a6f8cdf95a6e",
"recipient": {
"name": "Kim Certi",
"email": "recipient@example.com",
"phoneNumber": null,
"receiveType": "EMAIL"
},
"stateCode": "ISSUED",
"errorCode": null,
"expiredAt": "2027-07-23T10:24:31",
"createdAt": "2026-07-23T10:24:31"
}
],
"pagination": {
"page": 1,
"size": 20,
"totalElement": 1,
"totalPages": 1,
"first": true,
"last": true,
"empty": false
}
}
}이 단계가 끝나면: data.items[0].id를 assertionId로 사용합니다.
발급된 배지 상세 응답에서 OpenBadge 이미지 URL인 openbadgeImageUrl과 배지 검증 URL인 credentialUrl을 가져옵니다.
curl -X GET "https://api.certi.world/public/v2/assertions/01947b8e-54d7-79a7-835d-7ea2376bc4d2" \
-H "X-API-KEY: $CERTI_API_KEY"{
"success": true,
"message": null,
"data": {
"id": "01947b8e-54d7-79a7-835d-7ea2376bc4d2",
"serialNumber": "CERTI-2026-000042",
"badge": {
"id": "01947a42-1b58-7cb1-91d7-b386d629db96",
"name": "AI Literacy Certificate",
"image": {
"id": "01947a1b-66d1-7a51-8d7c-67b80b4162db",
"urls": {
"original": "https://cdn.certi.world/media/badge.png",
"medium": "https://cdn.certi.world/media/badge-medium.png",
"small": "https://cdn.certi.world/media/badge-small.png"
}
}
},
"program": {
"id": "0194775c-6402-7b98-baa4-1c8f8af208b8",
"name": "AI Literacy Program",
"image": {
"id": "01947a1b-66d1-7a51-8d7c-67b80b4162db",
"urls": {
"original": "https://cdn.certi.world/media/badge.png",
"medium": "https://cdn.certi.world/media/badge-medium.png",
"small": "https://cdn.certi.world/media/badge-small.png"
}
}
},
"issuanceId": "01947b37-9c9d-7e8c-981a-a6f8cdf95a6e",
"recipient": {
"name": "Kim Certi",
"email": "recipient@example.com",
"phoneNumber": null,
"receiveType": "EMAIL"
},
"stateCode": "ISSUED",
"errorCode": null,
"expiredAt": "2027-07-23T10:24:31",
"createdAt": "2026-07-23T10:24:31",
"credentialUrl": "https://certs.certi.world/assertions/01947b8e-54d7-79a7-835d-7ea2376bc4d2",
"openbadgeImageUrl": "https://certs.certi.world/assertions/01947b8e-54d7-79a7-835d-7ea2376bc4d2/image"
}
}이 단계가 끝나면: OpenBadge 이미지 URL(openbadgeImageUrl)과 배지 검증 URL(credentialUrl)을 사용할 수 있습니다.
한 명 이상의 수신자에게 배지를 비동기로 발급합니다. 안전한 재시도를 위해 Idempotency-Key가 필요합니다.
/badges/{badgeId}/issuances409 · ISS057로 응답합니다.badgeId필수Idempotency-Key필수recipients는 필수이며 수신 방식에 맞는 이메일 또는 전화번호가 필요합니다. 지원하지 않는 필드를 보내면 COM002 오류가 발생합니다.
recipients필수recipients[].name필수recipients[].email조건부recipients[].phoneNumber조건부recipients[].receiveType필수EMAILKAKAOTALKprogramId공통 단건 응답의 data에 포함되는 필드입니다.
idbadgeIdprogramIdprocessingStatusPROCESSINGCOMPLETEDFAILEDassertionCountcreatedAtupdatedAt인증·권한·리소스 조회 오류는 공통 오류 처리 가이드를 함께 확인하세요.
BDG064FIXED 만료 정책 배지만료 정책이 없거나 상대 만료 개월 수를 사용하는 배지로 발급하세요.