Вградете верификация на значки в сайта си (без iframe, без SDK)
Добавете към сайта си малък JavaScript фрагмент (или заявка от страна на сървъра), който верифицира всяка Open Badge чрез публичен JSON-LD endpoint. Без iframe, без външен тракер.
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.
Ако издавате удостоверения, рано или късно някой ще попита: „как да разбера, че тази значка е истинска?“ Честният отговор никога не бива да е „доверете се на PNG файла“. Open Badge v2.0 решава този проблем с публичен, машинночетим endpoint за верификация, а добавянето на джаджа „Верифицирано“ към вашия сайт отнема около десет реда код — без iframe, без външен скрипт за вграждане и без SDK.
Тази публикация показва точно как да извикате endpoint-а и как да изобразите резултата — с чист JavaScript и от страна на сървъра в Node и Python. Тя обяснява и какво всъщност проверява „верификацията“, как endpoint-ът се вписва до страниците за хора, които badges.ninja вече предлага на получателите, и кои грешки правят джаджата да изглежда завършена, докато тихомълком не доказва нищо.
Какво всъщност означава „верифицирано“
Assertion на Open Badge v2.0 е JSON-LD документ с фиксирана структура: самият assertion (кой го е получил и кога), препратка към BadgeClass (какво представлява и кой определя критериите) и препратка към профила на издателя (кой гарантира за него). Когато „верифицирате“ значка, всъщност проверявате три отделни неща:
- Съществува ли assertion-ът и разрешава ли се. Идентификаторът на наградата е реален, не е налучкан или подправен.
- Отменен ли е. Издателят може да отмени значка впоследствие — удостоверение, издадено по грешка, нарушение на правила, изтекла сертификация — и коректният верификатор трябва да го покаже, а не само да потвърди, че записът съществува.
- Издържа ли веригата. Препратките на assertion-а към значката и издателя наистина водят до реални, съвпадащи записи, а не до осиротели или несъответстващи идентификатори.
Джаджа, която само пингва URL адрес и проверява за статус 200, изцяло пропуска точка 2. Отменен assertion продължава да се разрешава нормално — просто носи флаг за отмяна в данните. Ако джаджата ви проверява само „успешна ли беше заявката“, отменено удостоверение ще се покаже като верифицирано, което е по-лошо, отколкото изобщо да нямате джаджа.
Публичната страница за хора срещу API endpoint-а
Всяка награда, издадена в https://badges.ninja, получава публичен URL адрес, който получателите могат да споделят директно, без регистрация за разглеждане:

Именно към тази страница повечето получатели ще препращат от LinkedIn, от автобиографията или от имейл подписа си — тя е изградена за хора, показва изображението на значката, издателя и датата на издаване и не изисква нищо от вас, за да работи. Endpoint-ът по-долу връща същия assertion като структуриран JSON-LD, което е точно онова, което ви трябва, когато изграждате собствен интерфейс, вместо просто да препращате към нашия.
Endpoint-ът
GET https://api.badges.ninja/certify-badge/award/{guid}
Не се изисква auth header — това е умишлено публично, защото целият смисъл на Open Badges е всеки (работодател, рекрутър, лицензиращ орган) да може да верифицира удостоверение без акаунт. Пълните подробности за договора, включително точните имена на полетата във върнатия assertion, са в документацията за верификация.
Подайте GUID на наградата, който ще имате или от собствените си записи за издаване, или извлечен от линк badges.ninja/awards/<guid>, споделен ви от получател.
Чист JS: заявка и изобразяване
Това е цялата джаджа. Без стъпка за изграждане, без npm пакет — просто я поставете на всяка страница:
<div id="badge-verify"></div>
<script>
async function renderBadgeVerification(awardId, mountId) {
const el = document.getElementById(mountId);
el.textContent = "Checking badge status";
try {
const res = await fetch(
`https://api.badges.ninja/certify-badge/award/${awardId}`
);
if (!res.ok) {
el.textContent = "Credential not found.";
return;
}
const assertion = await res.json();
// —— revocation check first, a resolvable assertion isn't enough on its own
if (assertion.revoked) {
el.textContent = `Revoked: ${assertion.revocationReason || "no reason given"}`;
return;
}
el.textContent = `Verified, issued ${new Date(assertion.issuedOn).toLocaleDateString()}`;
} catch (err) {
el.textContent = "Verification check failed.";
}
}
renderBadgeVerification("REPLACE_WITH_AWARD_ID", "badge-verify");
</script>
Заменете REPLACE_WITH_AWARD_ID с реален GUID на награда. Това е цялата интеграция от страна на клиента: няма граница на iframe, с която да се борите с CSS, и няма външен скрипт, който да носи собствена аналитика или проследяващи пиксели покрай проверката.
От страна на сървъра: Node
Ако предпочитате да верифицирате в бекенда си — например преди да покажете значка „Верифициран партньор“ на профилна страница, която контролирате, или преди да приемете удостоверение като доказателство в процес на въвеждане — заявката е идентична, само без частта с DOM:
async function verifyAward(awardId) {
const res = await fetch(
`https://api.badges.ninja/certify-badge/award/${awardId}`
);
if (!res.ok) return { verified: false, reason: "not_found" };
const assertion = await res.json();
if (assertion.revoked) {
return { verified: false, reason: assertion.revocationReason || "revoked" };
}
return { verified: true, issuedOn: assertion.issuedOn, badge: assertion.badge };
}
От страна на сървъра: Python
import requests
# —— resolve the assertion, then check revocation before trusting it
def verify_award(award_id):
res = requests.get(f"https://api.badges.ninja/certify-badge/award/{award_id}")
if res.status_code != 200:
return {"verified": False, "reason": "not_found"}
assertion = res.json()
if assertion.get("revoked"):
return {"verified": False, "reason": assertion.get("revocationReason", "revoked")}
return {"verified": True, "issued_on": assertion.get("issuedOn"), "badge": assertion.get("badge")}
И двата примера третират отговор, различен от 200, като „не е намерено“, вместо да хвърлят грешка. Повреден или налучкан идентификатор на награда е очакван вход за публичен endpoint за верификация, а не изключение, затова обработвайте го като нормален клон, а не като уловена грешка.
Стилизиране на резултата вместо вграждане на чужд интерфейс
Тъй като джаджата по-горе е просто fetch заявка към вашия собствен DOM, вие контролирате всеки пиксел. Често срещан модел са три визуални състояния, извлечени директно от отговора:
- Верифицирано — зелена отметка плюс „Верифицирано“ и датата на издаване, стилизирани в съответствие с компонентите за значки/тагове на сайта ви.
- Отменено — приглушено или червено състояние, което показва причината за отмяната, вместо да я крие. Както получателите, така и третите страни печелят от честното „защо“, а не от тиха грешка.
- Не е намерено — третирайте го визуално като „отменено“ (не показвайте фалшиво състояние на успех), но с различен текст, тъй като грешен идентификатор и умишлена отмяна са различни ситуации за този, който чете страницата.
Нищо от това не изисква библиотека с компоненти. Един switch върху verified / revoked / not_found и три CSS класа са достатъчни.
Кеширане, за да не затрупвате endpoint-а
Endpoint-ът за верификация е публичен и без автентикация, което означава и че няма разход на кредити за заявка, за който да се безпокоите — но при извикване от клиента без кеширане това си остава мрежова заявка при всяко зареждане на страница. За страница, която показва една и съща значка на всеки посетител (например значка „Верифициран партньор“ във footer-а), кеширайте резултата от страна на сървъра с кратък TTL — пет до петнадесет минути са напълно достатъчни, тъй като отмените не са бързо променящ се сигнал — вместо да извличате наново при всяка заявка:
const cache = new Map();
async function verifyAwardCached(awardId, ttlMs = 10 * 60 * 1000) {
const hit = cache.get(awardId);
if (hit && Date.now() - hit.at < ttlMs) return hit.result;
const result = await verifyAward(awardId);
cache.set(awardId, { result, at: Date.now() });
return result;
}
За джаджа за всеки посетител поотделно (получател, който вгражда собственото си удостоверение в личен сайт), пропуснете кеша и просто я извиквайте наново при зареждане на страницата — допълнителната заявка е пренебрежима в такъв мащаб.
Какво badges.ninja вече предлага на получателите
Преди да изградите напълно персонализирано вграждане, струва си да знаете какво вече е налично наготово. Публичната страница на всяка награда включва готови фрагменти за споделяне и вграждане, които получателите могат да копират директно, без нужда от код от тяхна страна:

Ако случаят ви е „нека получателят покаже, че значката му е истинска“, препратката към страницата му badges.ninja/awards/<guid> често е по-проста от изграждането на персонализирана джаджа — това е показаната по-рано страница за хора и тя вече се грижи за разликата между верифицирано и отменено. Изградете персонализираната джаджа от тази публикация, когато ви трябва статусът на верификацията да се изобразява вътре в интерфейса на вашия продукт — партньорски указател, вътрешно табло за одит, инструмент за наемане, който проверява заявените сертификации на кандидат — където препращането към друг сайт не е правилното потребителско изживяване.
Защо не iframe или джаджа от доставчик?
Някои платформи ви дават фрагмент като <iframe src="https://vendor.example.com/verify-widget"> за вграждане на статус на верификация. Работи, но има реални недостатъци: не можете да преоформите съдържанието, за да пасне на сайта ви (зависите от CSS, който доставчикът е предоставил), въвежда се междудомейнов документ, който вашата Content-Security-Policy трябва изрично да позволи, и при всяко зареждане на страница се прави заявка към хоста на iframe-а на трета страна, независимо дали посетителят се интересува от статуса на верификацията. Джаджа с две заявки чрез fetch избягва и трите — това е вашият DOM, вашият стил и тя се изпълнява само когато вие решите да я извикате.
Обхождане на цялата верига за верификация
Ако изграждате нещо по-обстойно от джаджа за статус — например инструмент за одит, който проверява партида удостоверения, или справка за съответствие — обходете цялата верига, вместо да спирате при assertion-а. Assertion-ът препраща към URL адрес на badge (BadgeClass: име, описание, критерии), а BadgeClass на свой ред препраща към URL адрес на issuer (профила на организацията). Строгият верификатор разрешава и трите и потвърждава, че са вътрешно съгласувани — значката наистина принадлежи на издателя, който заявява, assertion-ът наистина препраща към значката, която заявява — а не само че assertion-ът от най-високо ниво връща 200. Това е повече дълбочина, отколкото ви трябва за джаджа за статус на единично удостоверение, но е добре да знаете, че тази структура съществува, ако партньор или одитор някога попита: „колко дълбока е всъщност вашата верификация?“
Често срещани грешки, които да избягвате
- Проверка само на HTTP статуса. Както е описано по-горе, отменен assertion продължава да се разрешава. Винаги четете
assertion.revoked, не извеждайте верификацията само от статус кода. - Твърдо кодиран идентификатор на награда в споделен компонент. Ако джаджата е предназначена за многократна употреба в страниците на много получатели, приемайте идентификатора на наградата като параметър (data атрибут, query string, prop), а не като литерал, вграден в скрипта.
- Тихо поглъщане на мрежови грешки. Един
try/catch, който нищо не логва и показва същия текст „не е намерено“ като при наистина липсваща значка, прави отстраняването на грешки болезнено по-късно. Разграничавайте „мрежовата заявка се провали“ от „API-то каза не“ във вашите клонове за грешки, поне в логовете. - Повторна верификация при всяко изобразяване в клиентско приложение. Ако джаджата живее в React или Vue компонент, който се изобразява често, верифицирайте веднъж при монтиране (или веднъж за прозорец на кеширан TTL, според раздела за кеширане по-горе), а не при всяко повторно изобразяване.
Струва ли кредити и работи ли с безплатния план?
Не. Endpoint-ът за верификация е умишлено извън системата от кредити, която управлява издаването — проверката дали една значка е валидна не струва нищо на издателя и не изисква посетителят, който я извиква, да има акаунт, API ключ или какъвто и да е план. Това важи независимо дали значката е издадена на план Free, Starter или Pro: верификацията е свойство на самото удостоверение, а не функция, ограничена от абонамента на издателя. Затова спокойно можете да поставите тази джаджа на публична страница с непредвидим трафик (страница за кариери, партньорски указател), без да се тревожите за лимити на заявките, свързани с вашия акаунт — извиквате публичен endpoint само за четене, а не автентикиран API маршрут.
Едно нещо заслужава изричното уточнение: JSON assertion-ът, върнат от endpoint-а, не включва суровия имейл адрес на получателя. Имейлът на получателя се съхранява хеширан в бекенда именно за да не може публичният отговор за верификация да бъде обходен за лични контактни данни — получавате достатъчно, за да потвърдите удостоверението (значка, издател, дати, статус на отмяна), без endpoint-ът да се превръща в инструмент за събиране на лийдове за всеки, който обхожда идентификатори на награди.
Готови ли сте да издадете първото си верифицируемо удостоверение?
Започнете безплатно в badges.ninja — визуален дизайнер, публична страница за верификация, PDF сертификат, изход в Open Badge v2.0. Не се изисква кредитна карта.
За пълната анотирана структура на всяко поле в assertion вижте справочника за полетата на JSON-LD. А ако издавате удостоверения програмно, а не само ги верифицирате, бързият старт с API обхваща автентикацията и извикването за създаване на награда, от което идва изходът на този endpoint.
Как беше създадена тази статия
Някои публикации в този блог се изготвят с помощта на 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.

