Salesforce Open Badges: Mag-issue ng Verifiable Credentials mula sa CRM Triggers
I-trigger ang pag-issue ng Open Badge mula sa kahit anong event ng Salesforce object — Lead won, Account upgraded, training milestone — gamit ang Apex callout sa Badges Ninja API.
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.
Karamihan ng training teams ay nire-record na sa Salesforce kung sino ang nakatapos ng ano. Ang course enrollment ay napupunta sa “Completed”, ang partner account ay umaabot sa isang certification tier, ang customer ay tapos na sa onboarding. Nagbabago ang record, tapos makalipas ang isang linggo, may mag-e-export ng listahan at mano-manong magpapadala ng mga certificate sa email.
Ipinapakita ng gabay na ito kung paano isara ang puwang na iyon: kapag umabot ang isang record sa status na mahalaga sa iyo, tatawagin ng Salesforce ang https://badges.ninja API, mag-i-issue ng Open Badge v2.0 credential, at ise-save pabalik sa record ang verification link. Puwede mo nang ilagay ang link na iyon sa email template, report, o Experience Cloud page.
Kakailanganin mo ng Salesforce admin (o developer sandbox), isang badge na na-design na sa https://badges.ninja, at isang API key. Kung hindi mo pa nata-try tawagin ang API, basahin muna ang API quickstart; sampung minuto lang ito.
Kailan tamang gamitin ang CRM trigger
Bago magsulat ng Apex, tingnan muna kung kailangan mo ito. Kung nag-i-issue ka ng credentials nang batch, minsan kada term o minsan kada quarter, mas mabilis ang CSV upload ng dashboard at walang code na kailangan. Sulit ang Salesforce route kapag:
- Dapat mag-issue sa mismong sandali na nagbago ang record, nang walang human step.
- Nasa Salesforce na ang data kung sino ang nakakuha at ayaw mo ng pangalawang source of truth.
- Gusto mong naka-store ang credential link sa Contact, Lead, o custom training record para sa reporting.
Kung Zapier ang workflow tool mo at hindi Apex, gumagana rin doon ang parehong API call; tingnan ang Zapier Open Badges automation.
Ano ang bubuuin mo
May apat na piraso ang flow:
- Isang badge na dinisenyo sa visual designer. Kopyahin ang id nito (ang
idna ibinabalik ngGET /badges). - Isang API key na ginawa sa API Keys page ng dashboard mo. Isang beses lang ipinapakita ang key, kaya i-store agad.
- Isang Named Credential sa Salesforce na may hawak ng key, para hindi ito lumabas sa code.
- Isang Apex trigger at Queueable class na nag-i-issue ng award at nagsusulat ng award link pabalik sa record.

Step 1: I-store ang key sa Named Credential
Ang pag-hard-code ng API key sa Apex ang pagkakamaling dapat iwasan. Sa Setup, gumawa ng External Credential na may custom header, tapos Named Credential na tumuturo sa API host:
- URL:
https://api.badges.ninja - Custom header name:
X-Api-Key - Custom header value: ang key mo, sa anyong
bws_YOUR_KEY_HERE - Named Credential name:
BadgesNinja
Bigyan ng access ang permission set na nagpapatakbo ng automation mo sa principal ng External Credential. Kapag may Named Credential, hindi mo na kailangan ng hiwalay na Remote Site Setting; ina-authorize ng Salesforce ang callout sa pamamagitan ng credential. Kung legacy Named Credentials o plain endpoint pa rin ang gamit ng org mo, idagdag ang https://api.badges.ninja bilang Remote Site Setting at ipadala ang header mula sa code.
Step 2: Magdagdag ng fields sa record
Sa object na kumakatawan sa achievement (gagamit tayo ng custom object na tinatawag na Training_Enrollment__c), idagdag ang:
Badge_Id__c(Text): ang badge na i-i-issue. Kapag naka-store ito kada course, isang trigger lang ang magseserbisyo sa maraming badges.Badge_Award_Id__c(Text, unique): ang award id na ibinalik ng API.Badge_Url__c(URL): ang public verification page.Badge_Error__c(Long Text): ang huling error, para makita ng admins ang mga pagkabigo nang hindi nagbubukas ng debug logs.
Dalawa ang silbi ng Badge_Award_Id__c. Ito ang duplicate guard mo: nag-i-issue lang ang trigger kapag walang laman ito.
Step 3: Ang Apex callout
Hindi makakagawa ng callout nang direkta ang trigger, dahil hindi pinapayagan ang callouts sa parehong transaction ng uncommitted DML. Ipasa ang trabaho sa Queueable na nag-i-implement ng Database.AllowsCallouts.
Maikli lang ang API contract ng POST /awards. Dala ng body ang badgeId, isang nested na recipient object na may name at email, at required na issuedOn. Ang matagumpay na call ay nagbabalik ng HTTP 200 na may { "awardId": "..." }. Dapat hindi bababa sa limang character ang recipient name, kaya ire-reject ang Contact na pangalang “Al Li”; mag-validate bago tumawag.
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;
}
}
Dalawang detalyeng dapat pansinin. Una, ang issuedOn ay epoch milliseconds, na eksaktong ibinabalik ng Datetime.getTime(). Pangalawa, hindi kasama sa response ang verification URL, kaya binubuo ito ng code mula sa award id: https://badges.ninja/awards/<awardId>.
Step 4: Ang trigger
Panatilihing manipis ang trigger. Ang trabaho lang nito ay magpasya kung aling records ang kwalipikado at mag-enqueue ng isang job kada record.
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));
}
}
}
Mahalaga ang wasCompleted check. Kung wala ito, kahit anong susunod na edit sa completed record ay muling magpapagana ng logic. Kasama ng empty-award-id guard sa loob ng job, isang credential lang ang puwedeng mabuo ng isang record.
Isang limitasyong dapat igalang: pinapayagan ng Salesforce ang kaunting Queueable jobs na ma-enqueue mula sa iisang transaction (50 sa synchronous context). Kung bulk ang pag-load mo ng completions, halimbawa data import na 2,000 rows, aabot sa ceiling na iyon ang trigger sa itaas. Para sa bulk loads, i-upload ang listahan gamit ang CSV bulk awards ng dashboard, o lumipat sa Batchable class na may Database.AllowsCallouts na nagpoproseso ng ilang records kada scope.

Error handling at retries
Nagbabalik ang API ng standard status codes, at bawat isa ay nangangailangan ng ibang tugon mula sa code mo:
| Status | Kahulugan | Ano ang gagawin |
|---|---|---|
| 400 | May field na kulang o invalid, kasama ang recipient name na wala pang limang character | Huwag mag-retry. Ayusin ang data at isulat ang mensahe sa Badge_Error__c. |
| 401 | Mali o walang API key | Suriin ang Named Credential. Hindi makakatulong ang retry hangga’t hindi naaayos. |
| 402 | Ubos na ang credentials o quota ng plan mo | Huminto sa pag-issue at i-alert ang admin; mag-retry pagkatapos mag-upgrade o mag-reset ang quota. |
| 404 | Walang badgeId na ganoon | Itama ang Badge_Id__c sa record o course. |
| 5xx o timeout | Pansamantalang pagkabigo | Ligtas mag-retry mamaya. |
Dahil isinusulat ng job ang error sa record at iniiwang walang laman ang Badge_Award_Id__c, kasing-simple lang ng pag-flip ng checkbox o pag-re-save ng record ang retry. Ang maliit na scheduled Apex class na naghahanap ng completed enrollments na walang award id at may transient error, tapos nire-enqueue ulit ang mga ito, ay nagbibigay sa iyo ng automatic retry queue nang walang dagdag na infrastructure. Limitahan ang attempts gamit ang counter field para hindi mag-loop nang walang katapusan ang record na permanenteng may problema.
Suriin ang plan mo bago i-wire sa production. Sakop ng Free plan ang 1,200 credentials kada taon; ang Starter ay $9 kada buwan at ang Pro ay $29 kada buwan. Mabilis uubusin ng trigger na pumuputok sa bawat Lead ang maliit na plan, kaya limitahan ang criteria sa totoong achievements.
Gawing visible ang credential sa Salesforce
Kapag napunan na ang Badge_Url__c, magagamit mo ito kahit saan:
- Email alerts at templates: i-merge ang field sa “Congratulations, here is your credential” na email.
- Reports: ang report sa
Badge_Award_Id__c != nullay nagbibigay ng issuance counts kada course, region, o account owner. - Experience Cloud: ipakita ang link sa certification page ng partner para ma-verify mismo ng mga buyer.
- Page layouts: idagdag ang URL field para masagot ng support staff ang “nakuha na ba niya ang badge niya?” sa isang tingin.
Public ang verification page at hindi nangangailangan ng signup, na siyang buong punto. Ang recipient, hiring manager, o procurement team ng customer ay puwedeng magbukas ng link at kumpirmahin kung sino ang nag-issue ng credential, ano ang pinatutunayan nito, at kailan. Para sa machine-readable na checks, ang Open Badge v2.0 JSON-LD ng kahit anong award ay available sa https://api.badges.ninja/certify-badge/award/<awardId>.
Nakukuha rin ng recipients ang karaniwang extras: unique verification URL, QR code, A4 PDF certificate, at Add to LinkedIn option mula sa recipient portal, na nagsa-sign in gamit ang magic link sa halip na password.
Bakit mas maganda ito kaysa sa AppExchange badge plugin
Ang badge plugins sa AppExchange ay karaniwang may presyong kada Salesforce seat o kada managed-package license. Lumalaki ang gastos na iyon kasabay ng laki ng Salesforce team mo, hindi ng dami ng credentials na ini-issue mo, kaya magkaiba ang binabayaran ng sampung-taong training team at ng sampung-libong-learner na program para sa parehong output.
Binabaligtad ito ng API integration. Nagbabayad ka ayon sa credential volume sa flat plan, sa iyo ang trigger code na puwede mong basahin at baguhin, at standard Open Badge v2.0 ang output, kaya hindi nakakulong ang recipients sa proprietary viewer. Napapanatili mo rin ang design freedom: nag-aalok ang visual designer ng 80+ templates, shapes, icons, at custom uploads, sa halip na fixed layout sa loob ng package.
Ang tapat na trade-off: click-to-install ang plugin at hindi nangangailangan ng Apex. Kung walang makapag-maintain sa team mo ng ilang dosenang linya ng code, baka mas bagay ang plugin o no-code connector. Kung platforms ang kinukumpara mo sa pangkalahatan at hindi integrations, saklaw ng Credly alternative breakdown ang presyo at pagkakaiba ng features nang magkatabi.
Mag-test bago mag-go live
Patakbuhin muna ang buong flow sa sandbox.
- Gumawa ng test badge at test recipient na may email address na hawak mo.
- Sa Apex tests, mag-implement ng
HttpCalloutMockna nagbabalik ng status 200 at{"awardId":"test-award-id"}; hindi pinapayagan ng Salesforce ang totoong callouts sa test context, at kailangan mo ang coverage na iyon para mag-deploy. - Sa sandbox, itakda sa Completed ang isang enrollment at tingnan kung napupunan ang
Badge_Award_Id__catBadge_Url__csa loob ng isang minuto. - Buksan ang URL sa private browser window para kumpirmahing lumalabas ang public verification page nang hindi nagsa-sign in.
- Pilitin ang failure (iwanang blangko ang badge id, o gumamit ng recipient name na wala pang limang character) at kumpirmahing napupunta ang error sa
Badge_Error__c.
I-rotate ang API key kung sakaling tumagas ito sa debug log o screenshot. Agad ang revocation mula sa API Keys page, at External Credential lang ang kailangan mong i-update, hindi ang code mo.
Pagtatapos
Maliit ang pattern: manipis na trigger ang nagpapasya kung kailan, Queueable ang gumagawa ng callout, Named Credential ang may hawak ng key, at tatlong fields sa record ang nag-iimbak ng resulta. Gumagana ito para sa training milestones, partner tiers, event attendance, o kahit anong state change na maipapahayag mo sa Salesforce.
Magsimula sa isang object at isang badge, bantayan ito sa loob ng isang linggo, at palawakin kapag swak na sa data mo ang retry behavior.
Handa ka na bang mag-issue ng una mong verifiable credential? Magsimula nang libre sa badges.ninja — visual designer, public verification page, PDF certificate, Open Badge v2.0 output. Walang credit card na kailangan.
Paano ginawa ang artikulong ito
Ang ilang artikulo sa blog na ito ay ginagawa gamit ang tulong ng AI assistant, pagkatapos ay sinusuri, tinitiyak ang katumpakan, at ine-edit ng Badges Ninja team bago ilathala. Bawat code sample at presyo ay beripikado laban sa live na produkto. Alamin pa ang tungkol sa aming editorial at AI na proseso sa aming pahina ng editorial process .

Tungkol sa may-akda
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.

