Быстрый старт
Создайте ключ в приложении в разделе Wire → API-ключи и вызывайте API откуда угодно. Ответы в JSON, время в ISO-8601 UTC.
curl -H "Authorization: Bearer rr_live_…" \
https://realityradar-7h6.pages.dev/api/v1/public/alerts?limit=5const res = await fetch('https://realityradar-7h6.pages.dev/api/v1/public/entities', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.RADAR_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ entityType: 'software_version', displayName: 'Node.js', modelOrVersion: '18.20.0',
identifiers: { eolProduct: 'nodejs' }, relationship: 'used' }),
});
console.log(res.status, await res.json());import os, requests
r = requests.get("https://realityradar-7h6.pages.dev/api/v1/public/events", params={"type": "product_recall", "limit": 20},
headers={"Authorization": f"Bearer {os.environ['RADAR_KEY']}"}, timeout=10)
r.raise_for_status()
for e in r.json()["items"]:
print(e["firstSeenAt"], e["title"], e["sourceUrl"])Аутентификация
Передавайте ключ как Bearer-токен. Ключ показывается один раз, хранится только в виде хэша, может истекать через 30, 90 или 365 дней и заменяться с 24-часовым перекрытием.
Authorization: Bearer rr_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXПрава
У ключа есть только выбранные вами права. Запрос вне них возвращает 403 insufficient_scope, поэтому ключ только для чтения не может добавлять объекты или управлять вебхуками.
| Право | Эндпоинты |
|---|---|
read:signals | GET /public/eventsGET /public/events/{id} |
read:entities | GET /public/entities |
write:entities | POST /public/entities |
read:alerts | GET /public/alerts |
manage:webhooks | GET /public/webhooksPOST /public/webhooksDELETE /public/webhooks/{id}GET /public/webhooks/{id}/deliveriesPOST /public/webhooks/{id}/deliveries/{deliveryId}/replay |
Лимиты запросов
Стандартные ключи — 60 запросов в минуту, с повышенным лимитом — 300. Ответ 429 означает: подождите и повторите; использование по ключам и эндпоинтам видно в Wire.
Пагинация
Списки возвращают items и nextCursor. Передавайте курсор обратно, пока он не станет null; курсоры непрозрачны и стабильны при листании.
cursor = None
while True:
page = requests.get(f"https://realityradar-7h6.pages.dev/api/v1/public/events", headers=H, params={"limit": 100, "cursor": cursor}).json()
handle(page["items"])
cursor = page["nextCursor"]
if not cursor:
breakОшибки
Ошибки имеют единый формат со стабильным кодом. 5xx и 429 повторяйте с нарастающей паузой, 4xx означает проблему в запросе.
{ "error": { "code": "insufficient_scope", "message": "This key lacks the \"write:entities\" scope" } }invalid_api_key | 401 | Ключ отсутствует, неверен или отозван |
api_key_expired | 401 | Истёк срок действия или период замены ключа |
insufficient_scope | 403 | У ключа нет права, нужного этому эндпоинту |
not_found | 404 | Не найдено или недоступно этому пространству |
plan_limit | 409 | Достигнут лимит объектов бесплатного тарифа |
ssrf_blocked | 422 | URL указывает на частный или внутренний адрес |
rate_limited | 429 | Слишком много запросов — повторите после окна |
Вебхуки
Вебхуки отправляют POST с JSON-событием, когда создаётся оповещение вашего уровня или выше. Журнал доставок хранит 30 дней со статусом, задержкой и повтором в один клик.
POST /your/endpoint
Content-Type: application/json
User-Agent: RealityRadar-Webhook/1.0
X-Radar-Signature: t=1761112800,v1=5f2b…a91c,v1=03de…77b0
{"type":"alert.created","alert":{"impactLevel":"critical","matchType":"exact",…},"event":{…}}Проверка подписи
Вычислите HMAC-SHA256 от t, точки и сырого тела с вашим секретом, сравните за постоянное время с любым v1 и отклоняйте метки старше пяти минут. После смены секрета 24 часа приходят два v1.
import { createHmac, timingSafeEqual } from 'node:crypto';
// rawBody: the exact bytes you received (do not re-serialize JSON)
export function verifyRadar(header, rawBody, secret) {
const parts = header.split(',').map((p) => p.split('='));
const t = Number(parts.find(([k]) => k === 't')?.[1]);
const sigs = parts.filter(([k]) => k === 'v1').map(([, v]) => v);
if (!Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > 300) return false;
const mac = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return sigs.some((v) => v.length === mac.length && timingSafeEqual(Buffer.from(v), Buffer.from(mac)));
}import hmac, hashlib, time
def verify_radar(header: str, raw_body: bytes, secret: str) -> bool:
parts = [p.split("=", 1) for p in header.split(",")]
t = next((int(v) for k, v in parts if k == "t"), None)
sigs = [v for k, v in parts if k == "v1"]
if t is None or abs(time.time() - t) > 300:
return False
mac = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return any(hmac.compare_digest(mac, s) for s in sigs)func VerifyRadar(header string, rawBody []byte, secret string) bool {
var t int64 = -1
var sigs []string
for _, p := range strings.Split(header, ",") {
k, v, ok := strings.Cut(p, "=")
if !ok { continue }
if k == "t" { t, _ = strconv.ParseInt(v, 10, 64) }
if k == "v1" { sigs = append(sigs, v) }
}
if t < 0 || math.Abs(float64(time.Now().Unix()-t)) > 300 { return false }
m := hmac.New(sha256.New, []byte(secret))
fmt.Fprintf(m, "%d.", t)
m.Write(rawBody)
want := hex.EncodeToString(m.Sum(nil))
for _, s := range sigs {
if hmac.Equal([]byte(want), []byte(s)) { return true }
}
return false
}# Replay a delivery (fresh timestamp + signature)
curl -X POST -H "Authorization: Bearer rr_live_…" \
https://realityradar-7h6.pages.dev/api/v1/public/webhooks/WEBHOOK_ID/deliveries/DELIVERY_ID/replayЗависимости и OSV
Отслеживайте пакеты по purl вида pkg:npm/lodash и точной версии. Reality Radar проверяет OSV.dev и отмечает точное совпадение, если ваша версия указана как затронутая. Lock-файлы и SBOM загружайте в приложении в разделе «Импорт».
curl -X POST -H "Authorization: Bearer rr_live_…" -H "Content-Type: application/json" \
-d '{"entityType":"software_version","displayName":"lodash","modelOrVersion":"4.17.20","identifiers":{"purl":"pkg:npm/lodash"},"relationship":"used"}' \
https://realityradar-7h6.pages.dev/api/v1/public/entitiesГлоссарий
Термины, которые встречаются в ответах.
- Signal (сигнал)
- Обнаруженное изменение из официального источника с доказательствами и метками времени.
- Beacon (маяк)
- Источник данных. Уровень A — официальный регулятор или производитель, уровень B — проверенная база данных.
- Тип совпадения
- exact, strong, probable или weak — насколько мы уверены, что событие касается вашего объекта. Как точные подаются только exact и strong.
- Релевантность, достоверность, серьёзность
- Три отдельно рассчитанные оценки 0–100: касается ли это вас, насколько надёжны доказательства, насколько серьёзно изменение.
- purl
- Package URL, например pkg:npm/lodash, — стандартный идентификатор для сопоставления с OSV.
- Реестр доказательств
- Защищённая от подделки цепочка хэшей всех сохранённых доказательств, которую может проверить любой.