Salesforce Open Badges: CRM 트리거로 검증 가능한 자격 증명 발급하기
Lead 성사, Account 업그레이드, 교육 마일스톤 등 모든 Salesforce 오브젝트 이벤트에서 Apex 콜아웃으로 Badges Ninja API를 호출해 Open Badge를 발급해 보세요.
대부분의 교육 팀은 누가 무엇을 마쳤는지 이미 Salesforce에 기록하고 있어요. 수강 등록이 “Completed”로 바뀌고, 파트너 계정이 인증 등급에 도달하고, 고객이 온보딩을 끝내죠. 레코드는 바뀌었지만, 일주일 뒤에 누군가 목록을 내보내서 수료증을 손으로 이메일로 보내고 있지는 않나요?
이 가이드에서는 그 간극을 메우는 방법을 보여 드려요. 레코드가 원하는 상태에 도달하면 Salesforce가 https://badges.ninja API를 호출하고, Open Badge v2.0 자격 증명이 발급되며, 검증 링크가 레코드에 다시 저장돼요. 그러면 그 링크를 이메일 템플릿, 리포트, Experience Cloud 페이지에 바로 넣을 수 있어요.
Salesforce 관리자(또는 개발자 샌드박스), https://badges.ninja 에서 이미 디자인한 배지, 그리고 API 키가 필요해요. API를 한 번도 호출해 본 적이 없다면 먼저 API 퀵스타트를 읽어 보세요. 10분이면 끝나요.
CRM 트리거가 적합한 경우
Apex를 작성하기 전에 정말 필요한지 먼저 확인하세요. 학기별 또는 분기별로 자격 증명을 일괄 발급한다면 대시보드의 CSV 업로드가 더 빠르고 코드도 전혀 필요 없어요. Salesforce 방식이 제값을 하는 경우는 다음과 같아요.
- 레코드가 바뀌는 즉시, 사람의 개입 없이 발급해야 할 때
- “누가 취득했는가”라는 데이터가 이미 Salesforce에 있고, 두 번째 데이터 원본을 만들고 싶지 않을 때
- 자격 증명 링크를 Contact, Lead 또는 커스텀 교육 레코드에 저장해 리포트에 활용하고 싶을 때
워크플로 도구가 Apex가 아니라 Zapier라면 같은 API 호출을 그쪽에서도 쓸 수 있어요. Zapier Open Badges 자동화를 참고하세요.
만들 것
이 흐름은 네 가지 요소로 이루어져요.
- 배지: 비주얼 디자이너에서 디자인해요. 해당 배지의 id(
GET /badges가 반환하는id)를 복사해 두세요. - API 키: 대시보드의 API Keys 페이지에서 만들어요. 키는 한 번만 표시되므로 바로 보관하세요.
- Named Credential: Salesforce에서 키를 보관해서 코드에 키가 드러나지 않게 해요.
- Apex 트리거와 Queueable 클래스: 어워드를 발급하고 어워드 링크를 레코드에 다시 기록해요.

1단계: Named Credential에 키 저장하기
API 키를 Apex에 하드코딩하는 것은 피해야 할 실수예요. Setup에서 커스텀 헤더가 있는 External Credential을 만든 다음, API 호스트를 가리키는 Named Credential을 만드세요.
- URL:
https://api.badges.ninja - 커스텀 헤더 이름:
X-Api-Key - 커스텀 헤더 값:
bws_YOUR_KEY_HERE형식의 키 - Named Credential 이름:
BadgesNinja
자동화를 실행하는 권한 집합에 External Credential 프린시펄에 대한 접근 권한을 부여하세요. Named Credential이 있으면 별도의 Remote Site Setting은 필요 없어요. Salesforce가 해당 자격 증명을 통해 콜아웃을 승인해요. 조직에서 아직 레거시 Named Credential이나 일반 엔드포인트를 쓴다면 https://api.badges.ninja를 Remote Site Setting으로 추가하고, 헤더는 코드에서 보내세요.
2단계: 레코드에 필드 추가하기
성취를 나타내는 오브젝트(여기서는 Training_Enrollment__c라는 커스텀 오브젝트를 사용할게요)에 다음 필드를 추가하세요.
Badge_Id__c(텍스트): 발급할 배지예요. 코스별로 저장해 두면 트리거 하나로 여러 배지를 처리할 수 있어요.Badge_Award_Id__c(텍스트, 고유): API가 반환한 어워드 id예요.Badge_Url__c(URL): 공개 검증 페이지예요.Badge_Error__c(긴 텍스트): 마지막 오류예요. 관리자가 디버그 로그를 열지 않고도 실패를 확인할 수 있어요.
Badge_Award_Id__c 필드는 두 가지 역할을 해요. 중복 방지 장치이기도 해서, 트리거는 이 필드가 비어 있을 때만 발급해요.
3단계: Apex 콜아웃
트리거는 직접 콜아웃을 할 수 없어요. 커밋되지 않은 DML과 같은 트랜잭션에서는 콜아웃이 허용되지 않기 때문이에요. 작업은 Database.AllowsCallouts를 구현한 Queueable에 넘기세요.
POST /awards의 API 규약은 간단해요. 본문에는 badgeId, name과 email을 가진 중첩된 recipient 오브젝트, 그리고 필수 항목인 issuedOn이 들어가요. 호출에 성공하면 HTTP 200과 { "awardId": "..." }가 반환돼요. 수령인 이름은 최소 5자여야 하므로 “Al Li”라는 Contact는 거부돼요. 호출하기 전에 검증하세요.
public class BadgeIssueJob implements Queueable, Database.AllowsCallouts {
private Id enrollmentId;
public BadgeIssueJob(Id enrollmentId) { this.enrollmentId = enrollmentId; }
public void execute(QueueableContext ctx) {
Training_Enrollment__c e = [
SELECT Id, Badge_Id__c, Badge_Award_Id__c, Contact__r.Name, Contact__r.Email
FROM Training_Enrollment__c WHERE Id = :enrollmentId LIMIT 1
];
if (e.Badge_Award_Id__c != null) { return; } // already issued
Map<String, Object> recipient = new Map<String, Object>{
'name' => e.Contact__r.Name,
'email' => e.Contact__r.Email
};
Map<String, Object> body = new Map<String, Object>{
'badgeId' => e.Badge_Id__c,
'recipient' => recipient,
'issuedOn' => Datetime.now().getTime()
};
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:BadgesNinja/awards');
req.setMethod('POST');
req.setHeader('Content-Type', 'application/json');
req.setBody(JSON.serialize(body));
HttpResponse res = new Http().send(req);
if (res.getStatusCode() == 200) {
Map<String, Object> out = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
String awardId = (String) out.get('awardId');
e.Badge_Award_Id__c = awardId;
e.Badge_Url__c = 'https://badges.ninja/awards/' + awardId;
e.Badge_Error__c = null;
} else {
e.Badge_Error__c = res.getStatusCode() + ': ' + res.getBody();
}
update e;
}
}
눈여겨볼 점이 두 가지 있어요. 첫째, issuedOn은 에포크 밀리초이며, 바로 Datetime.getTime()이 반환하는 값이에요. 둘째, 응답에는 검증 URL이 포함되지 않으므로 코드가 어워드 id로 https://badges.ninja/awards/<awardId>를 만들어요.
4단계: 트리거
트리거는 얇게 유지하세요. 어떤 레코드가 대상인지 판단하고, 레코드마다 작업 하나를 큐에 넣는 일만 해요.
trigger TrainingEnrollmentBadge on Training_Enrollment__c (after insert, after update) {
for (Training_Enrollment__c e : Trigger.new) {
Boolean completed = e.Status__c == 'Completed';
Boolean wasCompleted = Trigger.isUpdate && Trigger.oldMap.get(e.Id).Status__c == 'Completed';
if (completed && !wasCompleted && e.Badge_Award_Id__c == null && e.Badge_Id__c != null) {
System.enqueueJob(new BadgeIssueJob(e.Id));
}
}
}
wasCompleted 확인은 중요해요. 이게 없으면 완료된 레코드를 나중에 수정할 때마다 로직이 다시 실행돼요. 작업 안의 어워드 id 비어 있음 확인과 함께 쓰면, 레코드 하나가 만들 수 있는 자격 증명은 딱 하나뿐이에요.
지켜야 할 제한이 하나 있어요. Salesforce는 단일 트랜잭션에서 큐에 넣을 수 있는 Queueable 작업 수를 적게 제한해요(동기 컨텍스트에서는 50개). 2,000행짜리 데이터 가져오기처럼 완료 데이터를 대량으로 적재하면 위의 트리거는 이 한도에 걸려요. 대량 적재라면 대신 대시보드의 CSV 일괄 어워드로 목록을 업로드하거나, 스코프당 몇 개의 레코드만 처리하는 Database.AllowsCallouts 기반 Batchable 클래스로 바꾸세요.

오류 처리와 재시도
API는 표준 상태 코드를 반환하며, 코드마다 대응 방법이 달라요.
| 상태 | 의미 | 대응 |
|---|---|---|
| 400 | 필드 누락 또는 잘못된 값(5자 미만의 수령인 이름 포함) | 재시도하지 마세요. 데이터를 고치고 메시지를 Badge_Error__c에 기록하세요. |
| 401 | 잘못되었거나 없는 API 키 | Named Credential을 확인하세요. 고치기 전에는 재시도해도 소용없어요. |
| 402 | 플랜의 자격 증명 수 또는 할당량 초과 | 발급을 멈추고 관리자에게 알리세요. 플랜을 업그레이드하거나 할당량이 초기화된 뒤에 재시도하세요. |
| 404 | badgeId가 존재하지 않음 | 레코드 또는 코스의 Badge_Id__c를 바로잡으세요. |
| 5xx 또는 타임아웃 | 일시적인 장애 | 나중에 재시도해도 안전해요. |
작업이 오류를 레코드에 기록하고 Badge_Award_Id__c를 비워 두기 때문에, 재시도는 체크박스를 토글하거나 레코드를 다시 저장하는 것만으로 충분해요. 어워드 id가 없고 일시적 오류가 기록된 완료 등록을 찾아 다시 큐에 넣는 작은 스케줄 Apex 클래스를 두면, 추가 인프라 없이 자동 재시도 큐를 갖출 수 있어요. 영구적으로 잘못된 레코드가 무한 반복되지 않도록 카운터 필드로 시도 횟수에 상한을 두세요.
프로덕션에 연결하기 전에 플랜을 확인하세요. Free 플랜은 연 1,200개의 자격 증명을 포함하고, Starter는 월 $9, Pro는 월 $29예요. 모든 Lead에서 실행되는 트리거는 작은 플랜을 금방 소진하므로, 조건은 실제 성취로 한정하세요.
Salesforce에서 자격 증명 보이게 하기
Badge_Url__c가 채워지면 어디서든 쓸 수 있어요.
- 이메일 알림과 템플릿: “축하합니다, 자격 증명이 도착했어요” 이메일에 이 필드를 병합하세요.
- 리포트:
Badge_Award_Id__c != null리포트로 코스, 지역, 계정 소유자별 발급 수를 볼 수 있어요. - Experience Cloud: 파트너의 인증 페이지에 링크를 표시하면 구매자가 직접 검증할 수 있어요.
- 페이지 레이아웃: URL 필드를 추가하면 지원 담당자가 “그분이 배지를 받았나요?”라는 질문에 한눈에 답할 수 있어요.
검증 페이지는 공개되어 있고 가입이 필요 없어요. 이것이 핵심이에요. 수령인, 채용 담당자, 고객의 구매 팀 누구든 링크를 열어 누가 발급했는지, 무엇을 인증하는지, 언제 발급됐는지 확인할 수 있어요. 기계가 읽을 수 있는 확인에는 모든 어워드의 Open Badge v2.0 JSON-LD를 https://api.badges.ninja/certify-badge/award/<awardId>에서 받을 수 있어요.
수령인에게는 고유한 검증 URL, QR 코드, A4 PDF 인증서, 수령인 포털의 Add to LinkedIn 옵션 같은 부가 기능도 제공돼요. 포털에는 비밀번호 대신 매직 링크로 로그인해요.
AppExchange 배지 플러그인보다 나은 이유
AppExchange의 배지 플러그인은 Salesforce 좌석당 또는 관리형 패키지 라이선스당으로 가격이 매겨지는 경우가 많아요. 그 비용은 발급하는 자격 증명 수가 아니라 Salesforce 팀의 규모에 따라 늘어나요. 그래서 10명짜리 교육 팀과 학습자 1만 명 규모의 프로그램은 같은 결과물에 대해 내는 비용이 크게 달라요.
API 연동은 이 모델을 뒤집어요. 자격 증명 발급량에 따라 정액 플랜으로 비용을 내고, 트리거 코드는 직접 읽고 수정할 수 있으며, 출력은 표준 Open Badge v2.0이라 수령인이 독점 뷰어에 묶이지 않아요. 디자인의 자유도도 유지돼요. 비주얼 디자이너는 80개 이상의 템플릿, 도형, 아이콘, 커스텀 업로드를 제공하며, 패키지 안의 고정 레이아웃에 갇히지 않아요.
솔직한 트레이드오프도 있어요. 플러그인은 클릭 한 번으로 설치되고 Apex가 필요 없어요. 팀에 수십 줄의 코드를 유지할 사람이 없다면 플러그인이나 노코드 커넥터가 더 맞을 수 있어요. 연동이 아니라 플랫폼 전반을 비교하고 있다면 Credly 대안 비교 글에서 가격과 기능 차이를 나란히 볼 수 있어요.
라이브 전 테스트
먼저 샌드박스에서 전체 흐름을 실행해 보세요.
- 테스트 배지와, 직접 받을 수 있는 이메일 주소를 가진 테스트 수령인을 만드세요.
- Apex 테스트에서 상태 200과
{"awardId":"test-award-id"}를 반환하는HttpCalloutMock을 구현하세요. Salesforce는 테스트 컨텍스트에서 실제 콜아웃을 허용하지 않으며, 배포하려면 이 커버리지가 필요해요. - 샌드박스에서 등록 하나를 Completed로 설정하고 1분 안에
Badge_Award_Id__c와Badge_Url__c가 채워지는지 확인하세요. - 시크릿 브라우저 창에서 URL을 열어 로그인 없이 공개 검증 페이지가 표시되는지 확인하세요.
- 일부러 실패를 일으키고(배지 id를 비우거나 5자 미만의 수령인 이름 사용) 오류가
Badge_Error__c에 기록되는지 확인하세요.
API 키가 디버그 로그나 스크린샷에 노출되었다면 키를 교체하세요. API Keys 페이지에서 즉시 폐기할 수 있고, 코드가 아니라 External Credential만 업데이트하면 돼요.
마무리
패턴은 작아요. 얇은 트리거가 언제 할지 결정하고, Queueable이 콜아웃을 수행하고, Named Credential이 키를 보관하고, 레코드의 필드 세 개가 결과를 저장해요. 교육 마일스톤, 파트너 등급, 행사 참석 등 Salesforce에서 표현할 수 있는 모든 상태 변화에 쓸 수 있어요.
오브젝트 하나와 배지 하나로 시작해서 일주일쯤 지켜보고, 재시도 동작이 데이터에 맞으면 확장하세요.
첫 번째 검증 가능한 자격 증명을 발급할 준비가 되셨나요? 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.

