Open Badges no Salesforce: emita credenciais verificáveis a partir de gatilhos do CRM

Dispare a emissão de Open Badges a partir de qualquer evento de objeto do Salesforce (Lead ganho, conta promovida, marco de treinamento) com um callout Apex para a API do Badges Ninja.

Nacho Coll Por Atualizado 10 min de leitura
Dispare a emissão de Open Badges a partir de qualquer evento de objeto do Salesforce (Lead ganho, conta promovida, marco de treinamento) com um callout Apex para a API do Badges Ninja.

A maioria das equipes de treinamento já registra no Salesforce quem concluiu o quê. Uma matrícula em um curso passa para “Concluído”, uma conta de parceiro atinge um nível de certificação, um cliente termina o onboarding. O registro muda e, uma semana depois, alguém exporta uma lista e envia os certificados por e-mail na mão.

Este guia mostra como fechar essa lacuna: quando um registro chega ao status que importa para você, o Salesforce chama a API do https://badges.ninja, uma credencial Open Badge v2.0 é emitida e o link de verificação é gravado de volta no registro. Depois você pode colocar esse link em um modelo de e-mail, em um relatório ou em uma página do Experience Cloud.

Você vai precisar de um administrador do Salesforce (ou de um sandbox de desenvolvimento), de um emblema já desenhado no https://badges.ninja e de uma chave de API. Se você nunca chamou a API, leia antes o guia rápido da API; leva dez minutos.

Quando um gatilho do CRM é a ferramenta certa

Antes de escrever Apex, confira se você realmente precisa dele. Se você emite credenciais em lote uma vez por semestre ou por trimestre, o upload de CSV do painel é mais rápido e não exige nenhum código. O caminho pelo Salesforce vale a pena quando:

  • A emissão deve acontecer no instante em que o registro muda, sem nenhuma etapa manual.
  • Os dados de “quem conquistou” já estão no Salesforce e você não quer uma segunda fonte da verdade.
  • Você quer guardar o link da credencial no Contato, no Lead ou no registro de treinamento personalizado para fins de relatório.

Se a sua ferramenta de fluxo é o Zapier em vez de Apex, a mesma chamada de API funciona lá também; veja automação de Open Badges com Zapier.

O que você vai construir

O fluxo tem quatro peças:

  1. Um emblema desenhado no designer visual. Copie o id dele (o id retornado por GET /badges).
  2. Uma chave de API criada na página de chaves de API do seu painel. A chave é exibida uma única vez, então guarde-a imediatamente.
  3. Uma Named Credential no Salesforce que guarda a chave, para que ela nunca apareça no código.
  4. Um gatilho Apex mais uma classe Queueable que emite o prêmio e grava o link do prêmio de volta no registro.

Newly created API key revealed once

Passo 1: guarde a chave em uma Named Credential

Deixar uma chave de API fixa no código Apex é o erro a evitar. No Setup, crie uma External Credential com um cabeçalho personalizado e, depois, uma Named Credential apontando para o host da API:

  • URL: https://api.badges.ninja
  • Nome do cabeçalho personalizado: X-Api-Key
  • Valor do cabeçalho personalizado: sua chave, no formato bws_YOUR_KEY_HERE
  • Nome da Named Credential: BadgesNinja

Conceda ao permission set que executa sua automação acesso ao principal da External Credential. Com uma Named Credential, você não precisa de um Remote Site Setting separado; o Salesforce autoriza o callout por meio da credencial. Se a sua org ainda usa Named Credentials legadas ou um endpoint simples, adicione https://api.badges.ninja como Remote Site Setting e envie o cabeçalho pelo código.

Passo 2: adicione campos ao registro

No objeto que representa a conquista (vamos usar um objeto personalizado chamado Training_Enrollment__c), adicione:

  • Badge_Id__c (Text): o emblema a emitir. Guardá-lo por curso permite que um único gatilho atenda a vários emblemas.
  • Badge_Award_Id__c (Text, único): o id do prêmio retornado 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 logs de depuração.

O campo Badge_Award_Id__c tem dupla função. Ele é a sua proteção contra duplicidade: o gatilho só emite quando ele está vazio.

Passo 3: o callout Apex

Um gatilho não pode fazer um callout diretamente, porque callouts não são permitidos na mesma transação de um DML não confirmado. Passe o trabalho para um Queueable que implemente Database.AllowsCallouts.

O contrato da API para POST /awards é curto. O corpo traz badgeId, um objeto recipient aninhado com name e email, e um issuedOn obrigatório. Uma chamada bem-sucedida retorna HTTP 200 com { "awardId": "..." }. O nome do destinatário precisa ter pelo menos cinco caracteres, então um Contato chamado “Al Li” seria rejeitado; valide antes de chamar.

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;
    }
}

Dois detalhes que vale notar. Primeiro, issuedOn é em milissegundos desde a época Unix, exatamente o que Datetime.getTime() retorna. Segundo, a resposta não inclui a URL de verificação, então o código a monta a partir do id do prêmio: https://badges.ninja/awards/<awardId>.

Passo 4: o gatilho

Mantenha o gatilho enxuto. Ele só decide quais registros se qualificam e enfileira um job por registro.

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 importa. Sem ela, qualquer edição posterior em um registro concluído dispararia a lógica de novo. Combinada com a proteção de id de prêmio vazio dentro do job, um registro só pode gerar uma credencial.

Um limite a respeitar: o Salesforce permite enfileirar um número pequeno de jobs Queueable a partir de uma única transação (50 em contexto síncrono). Se você carrega conclusões em massa, por exemplo uma importação de 2.000 linhas, o gatilho acima vai bater nesse teto. Para cargas em massa, envie a lista pelos prêmios em massa via CSV do painel ou troque por uma classe Batchable com Database.AllowsCallouts que processe poucos registros por escopo.

API keys list showing the masked prefix

Tratamento de erros e novas tentativas

A API retorna códigos de status padrão, e cada um pede uma resposta diferente do seu código:

StatusSignificadoO que fazer
400Um campo estava ausente ou inválido, incluindo nome de destinatário com menos de cinco caracteresNão tente de novo. Corrija os dados e grave a mensagem em Badge_Error__c.
401Chave de API inválida ou ausenteVerifique a Named Credential. Tentar de novo não adianta até corrigir.
402Sem credenciais ou cota no seu planoPare de emitir e avise um administrador; tente de novo após fazer upgrade ou quando a cota for renovada.
404O badgeId não existeCorrija Badge_Id__c no registro ou no curso.
5xx ou timeoutFalha transitóriaPode tentar de novo mais tarde.

Como o job grava o erro no registro e deixa Badge_Award_Id__c vazio, tentar de novo é tão simples quanto marcar uma caixa de seleção ou salvar o registro outra vez. Uma pequena classe Apex agendada que procure matrículas concluídas sem id de prêmio e com erro transitório, e as enfileire de novo, dá a você uma fila de novas tentativas automática sem nenhuma infraestrutura extra. Limite as tentativas com um campo contador para que um registro permanentemente ruim não fique em loop para sempre.

Confira o seu plano antes de ligar isso à produção. O plano Free cobre 1.200 credenciais por ano; o Starter custa $9 por mês e o Pro, $29 por mês. Um gatilho que dispara em todo Lead consumiria um plano pequeno rapidamente, então restrinja os critérios a conquistas reais.

Tornando a credencial visível no Salesforce

Depois que Badge_Url__c estiver preenchido, você pode usá-lo em qualquer lugar:

  • Alertas e modelos de e-mail: insira o campo em um e-mail de “Parabéns, aqui está a sua credencial”.
  • Relatórios: um relatório sobre Badge_Award_Id__c != null dá a você a contagem de emissões por curso, região ou proprietário da conta.
  • Experience Cloud: exiba o link na página de certificação de um parceiro para que os compradores possam verificar por conta própria.
  • Page layouts: adicione o campo de URL para que a equipe de suporte responda “ela recebeu o emblema?” num piscar de olhos.

A página de verificação é pública e dispensa cadastro, e esse é justamente o ponto. Um destinatário, um gestor de contratação ou o time de compras de um cliente pode abrir o link e confirmar quem emitiu a credencial, o que ela certifica e quando. Para verificações legíveis por máquina, o JSON-LD Open Badge v2.0 de qualquer prêmio está disponível em https://api.badges.ninja/certify-badge/award/<awardId>.

Os destinatários também recebem os extras de sempre: uma URL de verificação única, um QR code, um certificado em PDF A4 e a opção de adicionar ao LinkedIn pelo portal do destinatário, que faz login com um link mágico em vez de senha.

Por que isso supera um plugin de emblemas do AppExchange

Os plugins de emblemas do AppExchange costumam ser cobrados por usuário do Salesforce ou por licença de pacote gerenciado. Esse custo cresce com o tamanho da sua equipe de Salesforce, não com o número de credenciais que você emite, então uma equipe de treinamento de dez pessoas e um programa com dez mil alunos pagam de forma muito diferente pelo mesmo resultado.

Uma integração por API inverte esse modelo. Você paga pelo volume de credenciais em um plano fixo, o código do gatilho é seu para ler e alterar, e a saída é Open Badge v2.0 padrão, então os destinatários não ficam presos a um visualizador proprietário. Você também mantém a liberdade de design: o designer visual oferece mais de 80 modelos, formas, ícones e uploads personalizados, em vez de um layout fixo dentro de um pacote.

A troca, sendo honesto: um plugin se instala com um clique e não precisa de Apex. Se ninguém na sua equipe consegue manter algumas dezenas de linhas de código, um plugin ou um conector no-code pode ser a melhor escolha. Se você está comparando plataformas em geral, e não integrações, o comparativo de alternativa ao Credly cobre preços e diferenças de recursos lado a lado.

Testando antes de entrar em produção

Rode o fluxo inteiro em um sandbox primeiro.

  1. Crie um emblema de teste e um destinatário de teste com um endereço de e-mail que você controle.
  2. Nos testes Apex, implemente HttpCalloutMock retornando status 200 e {"awardId":"test-award-id"}; o Salesforce não permite callouts reais em contexto de teste, e você precisa dessa cobertura para fazer o deploy.
  3. No sandbox, coloque uma matrícula como Completed e confira se Badge_Award_Id__c e Badge_Url__c são preenchidos em até um minuto.
  4. Abra a URL em uma janela anônima do navegador para confirmar que a página pública de verificação carrega sem login.
  5. Force uma falha (deixe o id do emblema em branco ou use um nome de destinatário com menos de cinco caracteres) e confirme que o erro chega em Badge_Error__c.

Gire a chave de API se ela algum dia vazar para um log de depuração ou uma captura de tela. A revogação é imediata pela página de chaves de API, e você só precisa atualizar a External Credential, não o seu código.

Resumindo

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 registro armazenam o resultado. Funciona para marcos de treinamento, níveis de parceiro, presença em eventos ou qualquer mudança de estado que você consiga expressar no Salesforce.

Comece com um objeto e um emblema, acompanhe por uma semana e expanda quando o comportamento das novas tentativas se encaixar nos seus dados.

Pronto para emitir sua primeira credencial verificável? Comece grátis no 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.

Nacho Coll

Sobre o autor

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.

Voltar ao Blog

Artigos Relacionados