Open Badges con Salesforce: emettere credenziali verificabili dai trigger del CRM
Fai partire l'emissione di Open Badge da qualsiasi evento di un oggetto Salesforce — Lead vinto, Account promosso, traguardo formativo — con una callout Apex verso l'API di 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.
La maggior parte dei team di formazione registra già in Salesforce chi ha completato cosa. L’iscrizione a un corso passa a «Completed», un account partner raggiunge un livello di certificazione, un cliente termina l’onboarding. Il record cambia, e poi qualcuno esporta un elenco e invia i certificati a mano una settimana dopo.
Questa guida mostra come colmare quel vuoto: quando un record raggiunge lo stato che ti interessa, Salesforce chiama l’API di https://badges.ninja, viene emessa una credenziale Open Badge v2.0 e il link di verifica viene salvato di nuovo sul record. A quel punto puoi inserire il link in un template email, in un report o in una pagina di Experience Cloud.
Ti serviranno un amministratore Salesforce (o una developer sandbox), un badge già progettato su https://badges.ninja e una chiave API. Se non hai mai chiamato l’API, leggi prima la guida rapida all’API: bastano dieci minuti.
Quando un trigger del CRM è lo strumento giusto
Prima di scrivere Apex, verifica se ti serve davvero. Se emetti le credenziali in blocco una volta a semestre o a trimestre, il caricamento CSV della dashboard è più veloce e non richiede alcun codice. La strada Salesforce si giustifica quando:
- L’emissione deve avvenire nel momento in cui un record cambia, senza alcun passaggio manuale.
- I dati su «chi l’ha ottenuto» risiedono già in Salesforce e non vuoi una seconda fonte di verità.
- Vuoi salvare il link della credenziale su Contact, Lead o su un record di formazione personalizzato, per i report.
Se il tuo strumento di workflow è Zapier e non Apex, la stessa chiamata API funziona anche lì; vedi l’automazione Open Badges con Zapier.
Cosa stai costruendo
Il flusso ha quattro elementi:
- Un badge progettato nel designer visuale. Copia il suo id (l’
idrestituito daGET /badges). - Una chiave API creata nella pagina API Keys della tua dashboard. La chiave viene mostrata una sola volta, quindi salvala subito.
- Una Named Credential in Salesforce che custodisce la chiave, così non compare mai nel codice.
- Un trigger Apex più una classe Queueable che emette il riconoscimento e scrive il link dell’award sul record.

Passo 1: salva la chiave in una Named Credential
Inserire una chiave API direttamente in Apex è l’errore da evitare. In Setup crea una External Credential con un header personalizzato, poi una Named Credential che punti all’host dell’API:
- URL:
https://api.badges.ninja - Nome dell’header personalizzato:
X-Api-Key - Valore dell’header personalizzato: la tua chiave, nella forma
bws_YOUR_KEY_HERE - Nome della Named Credential:
BadgesNinja
Concedi al permission set che esegue la tua automazione l’accesso al principal della External Credential. Con una Named Credential non serve una Remote Site Setting separata; Salesforce autorizza la callout tramite la credenziale. Se la tua org usa ancora le Named Credential legacy o un endpoint semplice, aggiungi https://api.badges.ninja come Remote Site Setting e invia l’header dal codice.
Passo 2: aggiungi i campi al record
Sull’oggetto che rappresenta il traguardo (useremo un oggetto personalizzato chiamato Training_Enrollment__c), aggiungi:
Badge_Id__c(Text): il badge da emettere. Salvarlo per ogni corso permette a un solo trigger di servire molti badge.Badge_Award_Id__c(Text, unique): l’id dell’award restituito dall’API.Badge_Url__c(URL): la pagina pubblica di verifica.Badge_Error__c(Long Text): l’ultimo errore, così gli amministratori vedono i fallimenti senza aprire i debug log.
Il campo Badge_Award_Id__c ha una doppia funzione. È la tua protezione dai duplicati: il trigger emette solo quando è vuoto.
Passo 3: la callout Apex
Un trigger non può eseguire una callout direttamente, perché le callout non sono consentite nella stessa transazione di un DML non ancora confermato. Affida il lavoro a un Queueable che implementa Database.AllowsCallouts.
Il contratto API di POST /awards è breve. Il body contiene badgeId, un oggetto annidato recipient con name ed email, e un issuedOn obbligatorio. Una chiamata riuscita restituisce HTTP 200 con { "awardId": "..." }. Il nome del destinatario deve avere almeno cinque caratteri, quindi un Contact chiamato «Al Li» verrebbe rifiutato; valida i dati prima di chiamare.
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;
}
}
Due dettagli da notare. Primo, issuedOn è in millisecondi epoch, esattamente ciò che restituisce Datetime.getTime(). Secondo, la risposta non include l’URL di verifica, quindi il codice lo costruisce a partire dall’id dell’award: https://badges.ninja/awards/<awardId>.
Passo 4: il trigger
Tieni il trigger snello. Deve solo decidere quali record sono idonei e mettere in coda un job per ciascuno.
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));
}
}
}
Il controllo wasCompleted è importante. Senza di esso, qualsiasi modifica successiva a un record completato farebbe scattare di nuovo la logica. Insieme alla protezione sull’award id vuoto dentro il job, un record può produrre una sola credenziale.
Un limite da rispettare: Salesforce consente di mettere in coda solo un numero ridotto di job Queueable da una singola transazione (50 in contesto sincrono). Se carichi i completamenti in blocco, ad esempio un import di 2.000 righe, il trigger qui sopra raggiungerà quel tetto. Per i caricamenti massivi, o carichi l’elenco con gli award in blocco via CSV dalla dashboard, oppure passi a una classe Batchable con Database.AllowsCallouts che elabora pochi record per scope.

Gestione degli errori e nuovi tentativi
L’API restituisce i codici di stato standard, e ciascuno richiede una reazione diversa da parte del tuo codice:
| Stato | Significato | Cosa fare |
|---|---|---|
| 400 | Un campo mancava o non era valido, incluso un nome del destinatario sotto i cinque caratteri | Non riprovare. Correggi i dati e scrivi il messaggio in Badge_Error__c. |
| 401 | Chiave API errata o mancante | Controlla la Named Credential. Riprovare non servirà finché non è corretta. |
| 402 | Credenziali o quota esaurite per il tuo piano | Smetti di emettere e avvisa un amministratore; riprova dopo l’upgrade o dopo il reset della quota. |
| 404 | Il badgeId non esiste | Correggi Badge_Id__c sul record o sul corso. |
| 5xx o timeout | Errore transitorio | Puoi riprovare più tardi in sicurezza. |
Poiché il job scrive l’errore sul record e lascia vuoto Badge_Award_Id__c, un nuovo tentativo è semplice come spuntare una checkbox o risalvare il record. Una piccola classe Apex schedulata che cerca le iscrizioni completate senza award id e con un errore transitorio, e le rimette in coda, ti dà una coda di retry automatica senza alcuna infrastruttura aggiuntiva. Limita i tentativi con un campo contatore, in modo che un record irrimediabilmente errato non giri all’infinito.
Controlla il tuo piano prima di collegare tutto alla produzione. Il piano Free copre 1.200 credenziali all’anno; Starter costa $9 al mese e Pro $29 al mese. Un trigger che scatta su ogni Lead consumerebbe in fretta un piano piccolo, quindi limita i criteri ai traguardi reali.
Rendere visibile la credenziale in Salesforce
Una volta compilato Badge_Url__c, puoi usarlo ovunque:
- Avvisi email e template: inserisci il campo in una email «Congratulazioni, ecco la tua credenziale».
- Report: un report su
Badge_Award_Id__c != nullti dà il numero di emissioni per corso, regione o proprietario dell’account. - Experience Cloud: mostra il link nella pagina di certificazione di un partner, così i clienti possono verificarlo da soli.
- Page layout: aggiungi il campo URL così il supporto può rispondere a «ha ricevuto il suo badge?» con un’occhiata.
La pagina di verifica è pubblica e non richiede registrazione, ed è proprio questo il punto. Un destinatario, un selezionatore o l’ufficio acquisti di un cliente possono aprire il link e confermare chi ha emesso la credenziale, cosa certifica e quando. Per le verifiche automatiche, il JSON-LD Open Badge v2.0 di qualsiasi award è disponibile su https://api.badges.ninja/certify-badge/award/<awardId>.
I destinatari ricevono anche i soliti extra: un URL di verifica univoco, un codice QR, un certificato PDF in formato A4 e un’opzione Add to LinkedIn dal portale destinatari, che consente l’accesso con un magic link anziché con una password.
Perché è meglio di un plugin badge su AppExchange
I plugin per badge su AppExchange tendono ad avere un prezzo per posto Salesforce o per licenza di managed package. Quel costo cresce con le dimensioni del tuo team Salesforce, non con il numero di credenziali che emetti, quindi un team di formazione di dieci persone e un programma da diecimila studenti pagano in modo molto diverso per lo stesso risultato.
Un’integrazione via API ribalta questo modello. Paghi in base al volume di credenziali con un piano fisso, il codice del trigger è tuo da leggere e modificare, e l’output è Open Badge v2.0 standard, quindi i destinatari non restano vincolati a un viewer proprietario. Mantieni anche la libertà di design: il designer visuale offre oltre 80 template, forme, icone e caricamenti personalizzati, invece di un layout fisso dentro un package.
Il compromesso, onestamente: un plugin si installa con un clic e non richiede Apex. Se nessuno nel tuo team può mantenere qualche decina di righe di codice, un plugin o un connettore no-code potrebbe essere più adatto. Se stai confrontando le piattaforme in generale e non le integrazioni, l’analisi sull’alternativa a Credly copre prezzi e funzionalità fianco a fianco.
Testare prima di andare in produzione
Esegui prima l’intero flusso in una sandbox.
- Crea un badge di prova e un destinatario di prova con un indirizzo email che controlli.
- Nei test Apex, implementa
HttpCalloutMockrestituendo stato 200 e{"awardId":"test-award-id"}; Salesforce non consente callout reali nel contesto di test, e ti serve quella copertura per il deploy. - Nella sandbox, imposta un’iscrizione su Completed e verifica che
Badge_Award_Id__ceBadge_Url__csi compilino entro un minuto. - Apri l’URL in una finestra di navigazione privata per confermare che la pagina pubblica di verifica venga mostrata senza effettuare l’accesso.
- Forza un errore (svuota l’id del badge, oppure usa un nome di destinatario sotto i cinque caratteri) e conferma che l’errore finisca in
Badge_Error__c.
Ruota la chiave API se mai finisce in un debug log o in uno screenshot. La revoca è immediata dalla pagina API Keys, e dovrai aggiornare solo la External Credential, non il tuo codice.
Per concludere
Lo schema è piccolo: un trigger snello decide quando, un Queueable esegue la callout, una Named Credential custodisce la chiave e tre campi sul record memorizzano l’esito. Funziona per traguardi formativi, livelli dei partner, partecipazione a eventi o qualsiasi cambio di stato tu possa esprimere in Salesforce.
Parti da un solo oggetto e un solo badge, osservalo per una settimana ed estendi quando il comportamento dei retry si adatta ai tuoi dati.
Pronto a emettere la tua prima credenziale verificabile? Inizia gratis su badges.ninja — designer visuale, pagina pubblica di verifica, certificato PDF, output Open Badge v2.0. Nessuna carta di credito richiesta.
Come è stato realizzato questo articolo
Alcuni articoli di questo blog vengono redatti con l'aiuto di un assistente IA e poi revisionati, verificati e modificati dal team di Badges Ninja prima della pubblicazione. Ogni esempio di codice e ogni prezzo viene verificato rispetto al prodotto live. Scopri di più sul nostro processo editoriale e sull'uso dell'IA nella nostra pagina sul processo editoriale .

Informazioni sull'autore
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.
Altri articoli di Nacho Coll
- Emettere Open Badges tramite l'API REST di Badges Ninja: guida rapida28 set 2026 · 10min di lettura
- Incorpora la verifica dei badge nel tuo sito (senza iframe, senza SDK)24 set 2026 · 11min di lettura
- Certifier vs Accredible: confronto tra piattaforme di certificati (2026)21 set 2026 · 10min di lettura

