Open Badges no Salesforce: emitir credenciais verificáveis a partir de gatilhos do CRM
Desencadeia a emissão de Open Badges a partir de qualquer evento de um objeto do Salesforce — Lead ganho, Conta promovida, marco de formação — com um callout Apex para a API do 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.
A maioria das equipas de formação já regista no Salesforce quem concluiu o quê. Uma inscrição num curso passa a “Completed”, uma conta de parceiro atinge um nível de certificação, um cliente termina o onboarding. O registo muda e, uma semana depois, alguém exporta uma lista e envia os certificados por email, à mão.
Este guia mostra como fechar essa lacuna: quando um registo atinge o estado que te interessa, o Salesforce chama a API de https://badges.ninja, é emitida uma credencial Open Badge v2.0 e a ligação de verificação fica guardada no próprio registo. Depois, podes colocar essa ligação num modelo de email, num relatório ou numa página do Experience Cloud.
Vais precisar de um administrador do Salesforce (ou de uma sandbox de desenvolvimento), de um emblema já desenhado em https://badges.ninja e de uma chave de API. Se nunca chamaste a API, lê primeiro o guia rápido da API; demora dez minutos.
Quando um gatilho do CRM é a ferramenta certa
Antes de escreveres Apex, vê se precisas mesmo dele. Se emites credenciais em lote, uma vez por semestre ou por trimestre, o carregamento de CSV no painel é mais rápido e não exige código. A via Salesforce compensa quando:
- A emissão deve acontecer no instante em que o registo muda, sem qualquer passo humano.
- Os dados de “quem conquistou” já vivem no Salesforce e não queres uma segunda fonte de verdade.
- Queres guardar a ligação da credencial no Contacto, no Lead ou no registo de formação personalizado, para efeitos de relatórios.
Se a tua ferramenta de workflow é o Zapier e não o Apex, a mesma chamada à API funciona lá também; vê automatização de Open Badges com o Zapier.
O que vais construir
O fluxo tem quatro peças:
- Um emblema desenhado no designer visual. Copia o respetivo id (o
iddevolvido porGET /badges). - Uma chave de API criada na página de Chaves de API do teu painel. A chave só é mostrada uma vez, por isso guarda-a logo.
- Uma Named Credential no Salesforce que guarda a chave, para que nunca apareça no código.
- Um gatilho Apex mais uma classe Queueable que emite a atribuição e escreve a ligação da atribuição de volta no registo.

Passo 1: Guardar a chave numa Named Credential
Codificar uma chave de API diretamente no Apex é o erro a evitar. Em Setup, cria uma External Credential com um cabeçalho personalizado e, a seguir, uma Named Credential que aponte para o anfitrião da API:
- URL:
https://api.badges.ninja - Nome do cabeçalho personalizado:
X-Api-Key - Valor do cabeçalho personalizado: a tua chave, no formato
bws_YOUR_KEY_HERE - Nome da Named Credential:
BadgesNinja
Dá ao permission set que executa a tua automatização acesso ao principal da External Credential. Com uma Named Credential configurada, não precisas de uma Remote Site Setting separada; o Salesforce autoriza o callout através da credencial. Se a tua organização ainda usa Named Credentials legadas ou um endpoint simples, adiciona https://api.badges.ninja como Remote Site Setting e envia o cabeçalho a partir do código.
Passo 2: Adicionar campos ao registo
No objeto que representa a conquista (vamos usar um objeto personalizado chamado Training_Enrollment__c), adiciona:
Badge_Id__c(Text): o emblema a emitir. Guardá-lo por curso permite que um só gatilho sirva vários emblemas.Badge_Award_Id__c(Text, unique): o id da atribuição devolvido pela API.Badge_Url__c(URL): a página pública de verificação.Badge_Error__c(Long Text): o último erro, para que os administradores vejam as falhas sem abrir os registos de depuração.
O campo Badge_Award_Id__c serve duas funções. É a tua proteção contra duplicados: o gatilho só emite quando este campo está vazio.
Passo 3: O callout Apex
Um gatilho não pode fazer um callout diretamente, porque não são permitidos callouts na mesma transação que um DML ainda não confirmado. Entrega o trabalho a um Queueable que implemente Database.AllowsCallouts.
O contrato da API para POST /awards é curto. O corpo leva badgeId, um objeto recipient aninhado com name e email, e um issuedOn obrigatório. Uma chamada bem-sucedida devolve HTTP 200 com { "awardId": "..." }. O nome do destinatário tem de ter pelo menos cinco caracteres, pelo que um Contacto chamado “Al Li” seria rejeitado; valida antes de chamares.
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;
}
}
Há dois detalhes a notar. Primeiro, issuedOn está em milissegundos desde a época Unix, que é exatamente o que Datetime.getTime() devolve. Segundo, a resposta não inclui o URL de verificação, por isso o código constrói-o a partir do id da atribuição: https://badges.ninja/awards/<awardId>.
Passo 4: O gatilho
Mantém o gatilho enxuto. Ele só decide que registos qualificam e coloca um job em fila por cada registo.
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));
}
}
}
A verificação wasCompleted é importante. Sem ela, qualquer edição posterior a um registo concluído voltaria a disparar a lógica. Combinada com a proteção do id de atribuição vazio dentro do job, um registo só pode gerar uma única credencial.
Um limite a respeitar: o Salesforce permite que um número reduzido de jobs Queueable seja colocado em fila numa única transação (50 em contexto síncrono). Se carregares conclusões em massa, digamos uma importação de 2000 linhas, o gatilho acima vai bater nesse teto. Para cargas em massa, ou carregas a lista através das atribuições em massa por CSV do painel, ou passas a uma classe Batchable com Database.AllowsCallouts que processe alguns registos por âmbito.

Tratamento de erros e novas tentativas
A API devolve códigos de estado standard, e cada um pede uma resposta diferente do teu código:
| Status | Significado | O que fazer |
|---|---|---|
| 400 | Um campo em falta ou inválido, incluindo um nome de destinatário com menos de cinco caracteres | Não voltes a tentar. Corrige os dados e escreve a mensagem em Badge_Error__c. |
| 401 | Chave de API errada ou em falta | Verifica a Named Credential. Tentar de novo não ajuda enquanto não estiver corrigida. |
| 402 | Sem credenciais ou quota esgotada no teu plano | Pára de emitir e alerta um administrador; tenta de novo após a atualização do plano ou após a reposição da quota. |
| 404 | O badgeId não existe | Corrige Badge_Id__c no registo ou no curso. |
| 5xx ou timeout | Falha transitória | Podes tentar de novo mais tarde. |
Como o job escreve o erro no registo e deixa Badge_Award_Id__c vazio, repetir é tão simples como alternar uma caixa de seleção ou voltar a guardar o registo. Uma pequena classe Apex agendada que procure inscrições concluídas sem id de atribuição e com um erro transitório, e as volte a colocar em fila, dá-te uma fila de novas tentativas automática sem infraestrutura adicional. Limita as tentativas com um campo contador, para que um registo permanentemente errado não fique em ciclo para sempre.
Verifica o teu plano antes de ligares isto à produção. O plano Free cobre 1200 credenciais por ano; o Starter custa $9 por mês e o Pro $29 por mês. Um gatilho que dispare em cada Lead esgotaria depressa um plano pequeno, por isso restringe os critérios a conquistas reais.
Tornar a credencial visível no Salesforce
Assim que Badge_Url__c estiver preenchido, podes usá-lo em qualquer lado:
- Alertas e modelos de email: junta o campo a um email do tipo “Parabéns, aqui está a tua credencial”.
- Relatórios: um relatório sobre
Badge_Award_Id__c != nulldá-te contagens de emissão por curso, região ou responsável da conta. - Experience Cloud: mostra a ligação na página de certificação de um parceiro, para que os compradores a possam verificar por si.
- Page layouts: adiciona o campo de URL para que o suporte responda a “ela recebeu o emblema?” num relance.
A página de verificação é pública e não exige registo, e é esse o objetivo. Um destinatário, um responsável de contratação ou a equipa de compras de um cliente pode abrir a ligação e confirmar quem emitiu a credencial, o que ela certifica e quando. Para verificações automáticas, o JSON-LD Open Badge v2.0 de qualquer atribuição está disponível em https://api.badges.ninja/certify-badge/award/<awardId>.
Os destinatários recebem ainda os extras habituais: um URL de verificação único, um código QR, um certificado PDF em A4 e uma opção de Adicionar ao LinkedIn a partir do portal do destinatário, que inicia sessão com uma ligação mágica em vez de uma palavra-passe.
Porque é que isto vence um plugin de emblemas da AppExchange
Os plugins de emblemas da AppExchange tendem a ser cobrados por utilizador do Salesforce ou por licença de pacote gerido. Esse custo cresce com o tamanho da tua equipa Salesforce, não com o número de credenciais que emites, pelo que uma equipa de formação de dez pessoas e um programa com dez mil formandos pagam de forma muito diferente pelo mesmo resultado.
Uma integração por API inverte esse modelo. Pagas por volume de credenciais num plano fixo, o código do gatilho é teu para ler e alterar, e o resultado é Open Badge v2.0 standard, pelo que os destinatários não ficam presos a um visualizador proprietário. Manténs também a liberdade de design: o designer visual oferece mais de 80 modelos, formas, ícones e carregamentos personalizados, em vez de um layout fixo dentro de um pacote.
A troca, com honestidade: um plugin instala-se com um clique e não precisa de Apex. Se ninguém na tua equipa conseguir manter algumas dezenas de linhas de código, um plugin ou um conector sem código pode ser a melhor opção. Se estás a comparar plataformas em geral e não integrações, a análise alternativa ao Credly cobre preços e diferenças de funcionalidades lado a lado.
Testar antes de entrar em produção
Executa primeiro todo o fluxo numa sandbox.
- Cria um emblema de teste e um destinatário de teste com um endereço de email que controles.
- Nos testes Apex, implementa
HttpCalloutMocka devolver o estado 200 e{"awardId":"test-award-id"}; o Salesforce não permite callouts reais em contexto de teste, e precisas dessa cobertura para fazer deploy. - Na sandbox, define uma inscrição como Completed e verifica que
Badge_Award_Id__ceBadge_Url__cficam preenchidos num minuto. - Abre o URL numa janela privada do navegador para confirmar que a página pública de verificação é apresentada sem iniciar sessão.
- Força uma falha (deixa o id do emblema em branco ou usa um nome de destinatário com menos de cinco caracteres) e confirma que o erro aparece em
Badge_Error__c.
Roda a chave de API se alguma vez ela vazar para um registo de depuração ou para uma captura de ecrã. A revogação é imediata a partir da página de Chaves de API, e só precisas de atualizar a External Credential, não o teu código.
Para concluir
O padrão é pequeno: um gatilho enxuto decide quando, um Queueable faz o callout, uma Named Credential guarda a chave e três campos no registo guardam o resultado. Funciona para marcos de formação, níveis de parceiros, presença em eventos ou qualquer mudança de estado que consigas exprimir no Salesforce.
Começa com um objeto e um emblema, observa durante uma semana e expande quando o comportamento das novas tentativas se adequar aos teus dados.
Pronto para emitir a tua primeira credencial verificável? Começa grátis em badges.ninja — designer visual, página pública de verificação, certificado em PDF, saída Open Badge v2.0. Sem cartão de crédito.
Como este artigo foi feito
Alguns artigos deste blog são redigidos com a ajuda de um assistente de IA e depois revistos, verificados e editados pela equipa da Badges Ninja antes da publicação. Todos os exemplos de código e preços são verificados no produto em produção. Saiba mais sobre o nosso processo editorial e de IA na nossa página do processo editorial .

Sobre o autor
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.
Mais de Nacho Coll
- Emitir Open Badges através da API REST do Badges Ninja: guia de início rápido28/09/2026 · 10min de leitura
- Incorpora a verificação de emblemas no teu site (sem iframe, sem SDK)24/09/2026 · 11min de leitura
- Certifier vs Accredible: comparação de plataformas de certificados (2026)21/09/2026 · 10min de leitura

