Русский
Русский
Appearance
Русский
Русский
Appearance
Веб-хуки уведомляют ваше приложение в реальном времени о событиях, происходящих с вашими учётными данными, — когда они выданы, доставлены, отозваны или просмотрены. Вместо опроса API вы регистрируете HTTPS-эндпоинт, и badges.ninja отправляет на него подписанный POST для каждого события, на которое вы подписаны.
Все управляющие эндпоинты требуют аутентификации через заголовок X-Api-Key. См. Аутентификация. Создание или удаление эндпоинтов требует ключа с областью доступа write; для получения списка нужна read. См. Ключи API.
POST /webhooks| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
url | string | Да | Ваш HTTPS-эндпоинт. Должен начинаться с https://. |
events | string[] | Нет | Типы событий, на которые нужно подписаться. Опустите или передайте ["*"], чтобы получать все события. |
curl -X POST https://api.badges.ninja/webhooks \
-H "X-Api-Key: bws_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/badges",
"events": ["credential.issued", "credential.delivered"]
}'201 Created. Секрет подписи возвращается только один раз — сохраните его сейчас; получить его повторно нельзя.
{
"id": "e4b19ff5-063d-4799-bd75-d03641be624f",
"url": "https://example.com/hooks/badges",
"events": ["credential.issued", "credential.delivered"],
"secret": "2be6d335682c1658242fde3a523fd8a2493bab8c"
}GET /webhooksВозвращает ваши зарегистрированные эндпоинты. Секреты подписи никогда не включаются.
{
"webhooks": [
{
"id": "e4b19ff5-063d-4799-bd75-d03641be624f",
"url": "https://example.com/hooks/badges",
"events": ["credential.issued", "credential.delivered"],
"active": true,
"failureCount": 0,
"createdAt": 1787685415083,
"lastStatus": 200,
"lastDeliveryAt": 1787685480777
}
]
}DELETE /webhooks/{id}curl -X DELETE https://api.badges.ninja/webhooks/e4b19ff5-063d-4799-bd75-d03641be624f \
-H "X-Api-Key: bws_your_api_key_here"Доставка на этот эндпоинт прекращается немедленно.
| Событие | Срабатывает, когда… |
|---|---|
credential.issued | Учётные данные выданы получателю. |
credential.delivered | Письмо с уведомлением об учётных данных отправлено получателю (одиночно или массово). |
credential.revoked | Учётные данные отозваны. |
credential.viewed | Публичная страница учётных данных получателя просмотрена в первый раз. |
Каждая доставка — это POST с телом в формате JSON следующего вида:
{
"id": "b1c2d3e4-...",
"type": "credential.issued",
"createdAt": 1787685415083,
"data": { }
}| Поле | Описание |
|---|---|
id | Уникальный идентификатор доставки (используйте его для дедупликации). |
type | Тип события. |
createdAt | Метка времени события (миллисекунды эпохи). |
data | Полезная нагрузка, зависящая от события (см. ниже). |
data по типам событий credential.issued
{
"awardId": "https://api.badges.ninja/certify-badge/award/<guid>",
"badgeId": "https://api.badges.ninja/certify-badge/badge/<guid>",
"badgeName": "Advanced Certification",
"recipient": { "email": "jane@example.com", "name": "Jane Doe" },
"issuedOn": "2026-08-25",
"expires": null
}credential.delivered
{
"awardId": "https://api.badges.ninja/certify-badge/award/<guid>",
"recipient": { "email": "jane@example.com", "name": "Jane Doe" },
"badgeName": "Advanced Certification"
}credential.revoked
{ "awardId": "https://api.badges.ninja/certify-badge/award/<guid>", "reason": "Issued in error" }credential.viewed
{
"awardId": "https://api.badges.ninja/certify-badge/award/<guid>",
"recipient": { "email": "jane@example.com", "name": "Jane Doe" }
}Каждая доставка несёт эти заголовки:
| Заголовок | Описание |
|---|---|
X-Bws-Event | Тип события (тот же, что type в теле). |
X-Bws-Delivery | Идентификатор доставки (тот же, что id в теле). |
X-Bws-Signature | sha256=, за которым следует HMAC-SHA256 сырого тела запроса, вычисленный с ключом — секретом вашего эндпоинта. |
User-Agent | badges.ninja-webhooks/1 |
Всегда проверяйте подпись, прежде чем доверять доставке. Вычислите HMAC-SHA256 сырого тела запроса, используя секрет подписи вашего эндпоинта, и сравните его (за постоянное время) с заголовком X-Bws-Signature.
import crypto from "node:crypto";
function verify(rawBody, signatureHeader, secret) {
const expected = "sha256=" +
crypto.createHmac("sha256", secret).update(rawBody, "utf8").digest("hex");
const a = Buffer.from(signatureHeader);
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Используйте ровно те байты, которые вы получили, — разбор и повторная сериализация JSON изменят байты и нарушат подпись.
2xx.failureCount; после 20 последовательных сбоев эндпоинт автоматически отключается (active: false) и перестаёт получать доставки, пока вы не устраните проблему и не зарегистрируете новый эндпоинт.X-Bws-Delivery (или id из тела), чтобы сделать ваш обработчик идемпотентным.Вы также можете управлять эндпоинтами без API — откройте Webhooks в боковом меню панели, чтобы добавлять, просматривать и удалять эндпоинты и выбирать, какие события получает каждый из них.