Документация
Сайт работает на одном публичном API с восемнадцатью мгновенными эндпоинтами. Ниже — документация по каждому: что делает, лимиты и пример запроса/ответа. Без аккаунта; мгновенные результаты не сохраняются. Управляющие API в конце страницы (мониторинг, страницы статуса, короткие ссылки) — stateful-исключение: они хранятся под собственными ключами доступа.
Коды ответов
- 301 — Постоянное перенаправление
Постоянное перенаправление. Поисковые системы переносят сигналы ранжирования на новый адрес.
- 302 — Временное перенаправление
Временное перенаправление. Исходный URL остаётся каноническим.
- 307 — Временное перенаправление
Временное перенаправление с сохранением метода и тела запроса.
- 308 — Постоянное перенаправление
Постоянное перенаправление с сохранением метода и тела запроса.
- 200 — Успешно
Достигнут конечный адрес. Здесь цепочка заканчивается.
- 404 — Ошибка клиента
Адрес не существует — сломанная цель перенаправления.
- 500 — Ошибка сервера
Адрес найден, но сервер не смог корректно ответить.
Классифицированные результаты, а не ошибки
На четырёх мгновенных эндпоинтах заблокированные цели, неразрешимые домены и некорректные URL — не ошибки: каждый корректный запрос возвращает HTTP 200 со статусом, классифицирующим исход. Ошибки — только у некорректных запросов, слишком больших тел и при превышении лимитов.
Общие лимиты
- Протоколы
- http, https
- Метод
- GET
- Лимиты запросов
- 30 запросов/минуту и 500/сутки на IP — общие для всех эндпоинтов
- Тело запроса
- до 10 КиБ, строгий JSON
Каталог сервисов и репорты сообщества (Phase 14)
Кураторский публичный каталог популярных онлайн-сервисов с анонимными репортами сообщества. Чтение публичное и кэшируется; POST репорта — stateful исключение: он сохраняет данные и несёт рейт-лимиты, дедупликацию и модерацию. Сигнал сообщества и автопроверка — всегда отдельные индикаторы; ничто в этом API не утверждает «подтверждённо лежит».
GET /api/v1/catalog/services?sort=reports_24h&page=1&page_size=20
→ 200
{ "items": [ { "slug": "chatgpt", "name": "ChatGPT",
"category": { "slug": "ai-assistants", "name": "AI Assistants" },
"community": { "signal": "reports_increasing", "reports_15m": 3,
"reports_1h": 11, "reports_24h": 42,
"last_report_at": "2026-10-20T09:58:12Z" },
"automated_check": { "state": "operational",
"checked_at": "2026-10-20T09:55:00Z" } } ],
"page": 1, "page_size": 20, "total": 1 }
POST /api/v1/catalog/services/chatgpt/reports
{ "problem_type": "site_unreachable", "comment": "Login loop on mobile" }
→ 201
{ "service_slug": "chatgpt", "problem_type": "site_unreachable",
"comment": "Login loop on mobile", "created_at": "2026-10-20T10:01:33Z" }
Reads are public and cached (ETag + max-age=30); unknown/draft/hidden
slugs all answer 404 (no existence oracle); merged slugs 301 to the
target. Reports are anonymous: no account, no network fetch on
submission, rate limited per IP, comments plain text (≤500 chars).
Community signal and the automated check are always separate blocks —
no value on this API means "confirmed down".- Пагинация
- page ≥1, page_size по умолчанию 20, максимум 100; детерминированный порядок (тай-брейк по slug)
- Лимиты репортов
- дедуп 1 на сервис за 10 мин на IP, затем 10/час и 30/сутки на IP; 429 + Retry-After; fail-closed
- Модерация и приватность
- политика auto-publish или hold-all; kill-переключатели; хранится только ежедневноротируемый псевдонимный хеш — сырой IP и user-agent никогда
Redirect Checker — POST /api/v1/check
Проходит всю цепочку редиректов и сохраняет результат.
POST /api/v1/check
Content-Type: application/json
{ "url": "https://bit.ly/example" }
{
"id": "9pr2kxq4",
"status": "completed",
"input_url": "https://bit.ly/example",
"final_url": "https://example.com/product",
"final_domain": "example.com",
"final_status": 200,
"redirect_count": 3,
"duration_ms": 482,
"redirects": [
{ "sequence": 0, "requested_url": "https://bit.ly/example",
"status_code": 301, "next_url": "https://tracker.example/click",
"duration_ms": 83 },
{ "sequence": 3, "requested_url": "https://example.com/product",
"status_code": 200, "duration_ms": 184 }
],
"errors": null
}
GET /api/v1/check/{id} — получить сохранённый результат по публичному ID.- Максимум редиректов
- 20 переходов
- Таймаут запроса
- 15 секунд
GET /api/v1/check/{id} — получить сохранённый результат по публичному ID.
Uptime Checker — POST /api/v1/uptime-check
Проверяет, отвечает ли сайт. Результат классифицируется: UP при успешном ответе, HTTP_ERROR если сайт отвечает 4xx/5xx, плюс TIMEOUT, DNS_ERROR, TLS_ERROR, CONNECTION_ERROR и BLOCKED_TARGET.
POST /api/v1/uptime-check
Content-Type: application/json
{ "url": "https://example.com" }
{
"url": "https://example.com",
"status": "UP",
"reachable": true,
"httpStatus": 200,
"httpStatusText": "OK",
"responseTimeMs": 184,
"finalUrl": "https://example.com/",
"redirectCount": 1,
"tls": { "enabled": true, "valid": true }
}- Максимум редиректов
- 10 переходов
- Таймаут запроса
- 10 секунд
HTTP Status Checker — POST /api/v1/http-status-check
Возвращает итоговый код состояния URL, заголовки финального ответа, краткую сводку цепочки редиректов и состояние TLS.
POST /api/v1/http-status-check
Content-Type: application/json
{ "url": "https://example.com" }
{
"url": "https://example.com",
"status": "UP",
"reachable": true,
"httpStatus": 200,
"httpStatusText": "OK",
"finalUrl": "https://example.com/",
"redirectCount": 1,
"headers": {
"Content-Type": ["text/html; charset=utf-8"],
"Server": ["nginx"]
},
"headers_analysis": {
"security_missing": ["Strict-Transport-Security", "Content-Security-Policy"],
"caching": { "Cache-Control": "max-age=604800" }
},
"tls": { "enabled": true, "valid": true }
}- Максимум редиректов
- 10 переходов
- Таймаут запроса
- 10 секунд
Response Time Checker — POST /api/v1/response-time-check
Делает 1–5 замеров и классифицирует скорость по медиане времени до первого байта. Возвращает время каждого замера, min/медиана/max/среднее и разбивку таймингов финального хопа.
POST /api/v1/response-time-check
Content-Type: application/json
{ "url": "https://example.com", "samples": 3 }
{
"url": "https://example.com",
"samples": 3,
"status": "UP",
"verdict": "FAST",
"completed": 3,
"timesMs": [184, 201, 176],
"stats": { "minMs": 176, "medianMs": 184, "maxMs": 201, "meanMs": 187 },
"breakdown": { "dnsMs": 12, "connectMs": 23, "tlsMs": 45, "ttfbMs": 184, "totalMs": 190 },
"httpStatus": 200,
"httpStatusText": "OK",
"finalUrl": "https://example.com/",
"redirectCount": 1,
"tls": { "enabled": true, "valid": true }
}- Замеры
- 1–5 (по умолчанию 3)
- Таймаут замера
- 10 секунд
- Дедлайн серии
- 30 секунд
SSL Checker — POST /api/v1/ssl-check
Проверяет TLS-сертификат хоста: срок действия, издатель, SAN, согласованные протокол и шифр, цепочку. Только TLS-зонд — страница никогда не загружается; сломанный сертификат сопровождается конкретной причиной.
POST /api/v1/ssl-check
Content-Type: application/json
{ "url": "https://example.com" }
{
"url": "https://example.com",
"host": "example.com",
"status": "UP",
"reachable": true,
"handshakeMs": 45,
"tls": {
"version": "TLS 1.3",
"cipher": "TLS_AES_256_GCM_SHA384",
"verified": true,
"status": "valid",
"daysRemaining": 89,
"notBefore": "2026-08-01T00:00:00Z",
"notAfter": "2026-10-30T00:00:00Z",
"subject": "CN=example.com",
"issuer": "CN=R3,O=Let's Encrypt,C=US",
"sans": ["example.com", "www.example.com"],
"chain": ["CN=example.com", "CN=R3,O=Let's Encrypt,C=US"]
}
}- Порт
- из URL (по умолчанию 443)
- Тайм-аут зонда
- 10 секунд
DNS Checker — POST /api/v1/dns-check
Получает A-, AAAA-, CNAME-, MX-, TXT- и NS-записи хоста. Только запрос и отчёт: никаких соединений не устанавливается, каждый найденный адрес помечается как публичный или непубличный.
POST /api/v1/dns-check
Content-Type: application/json
{ "url": "example.com" }
{
"url": "example.com",
"host": "example.com",
"status": "UP",
"durationMs": 38,
"records": {
"a": ["93.184.216.34"],
"aaaa": ["2606:2800:220:1:248:1893:25c8:1946"],
"cname": [],
"mx": [{ "host": "mail.example.com", "pref": 10 }],
"txt": ["v=spf1 include:_spf.example.com ~all"],
"ns": ["ns1.example.com", "ns2.example.com"]
},
"addressLabels": [
{ "address": "93.184.216.34", "classification": "public", "reason": "public" }
]
}- Семейства записей
- A, AAAA, CNAME, MX, TXT, NS
- Тайм-аут запроса
- 10 секунд на всё, 3 секунды на семейство
Проверка истечения домена — POST /api/v1/domain-expiry-check
Отвечает, когда истекает срок домена, через фиксированный RDAP-поток rdap.org: вердикт, остаток дней, даты регистрации/истечения и статусы реестра. Первый в репозитории инструмент с обращением к фиксированному стороннему сервису: только HTTPS на каждом переходе, без прокси, ограниченные перенаправления и размер; сам домен не опрашивается. 404 превращается в вердикт not_found (не зарегистрирован / в реестре нет RDAP / запись не публикуется), 429 и 5xx — в честный UNKNOWN_ERROR.
POST /api/v1/domain-expiry-check
Content-Type: application/json
{ "url": "example.com" }
{
"url": "example.com",
"host": "example.com",
"status": "UP",
"verdict": "ok",
"daysRemaining": 214,
"registration": "2019-01-15T05:00:00Z",
"expiration": "2027-04-15T04:00:00Z",
"lastChanged": "2026-08-01T11:20:00Z",
"registryStatuses": ["ok"],
"source": "rdap",
"durationMs": 420
}- Вердикты
- ok, expiring (≤30 дней), expired, not_found, unknown
- Таймаут проверки
- 10 секунд общий (DOMAIN_EXPIRY_TIMEOUT)
- Исходящий доступ
- только rdap.org; HTTPS на каждом переходе; прокси отключён; лимит перенаправлений 10; лимит размера 1 МиБ; домен не опрашивается
WHOIS-запрос — POST /api/v1/whois-check
Отвечает, что реестр знает о домене: регистратор, неймсерверы, даты и статусные флаги. Сначала RDAP через rdap.org, при отсутствии — классический WHOIS (сырой TCP 43): первый в репозитории инструмент с сырым TCP — каждая переадресация обязана быть целью вида host[:43], проверяется через общий SSRF-конвейер и дозванивается по закреплённому публичному адресу; лимит 2 переадресации, лимит ответа 64 КиБ; сам домен не опрашивается. 404 от RDAP включает откат; однозначный ответ «домена нет» возвращается как notFound.
POST /api/v1/whois-check
Content-Type: application/json
{ "url": "mail.ru" }
{
"url": "mail.ru",
"host": "mail.ru",
"status": "UP",
"source": "whois",
"registrar": "VK-TECH",
"nameservers": ["ns1.mail.ru", "ns2.mail.ru"],
"registration": "1997-10-01T00:00:00Z",
"expiration": "2026-10-01T00:00:00Z",
"statuses": ["REGISTERED, DELEGATED, VERIFIED"],
"durationMs": 640
}- Источники
- RDAP через rdap.org; классический WHOIS (TCP 43) по цепочке переадресаций whois.iana.org
- Таймаут проверки
- 15 секунд общий (WHOIS_TIMEOUT)
- Исходящий доступ
- переадресации только host[:43]; SSRF-проверка и закрепление перед соединением; лимит 2 переадресации; лимит 64 КиБ; домен не опрашивается
Доступность домена — POST /api/v1/domain-availability
Отвечает по каждому TLD, свободно ли имя, с честной машиной состояний: AVAILABLE — только если RDAP-запрос вернул 404 и встроенные метаданные TLD подтверждают работу RDAP у реестра; «не найден» только по WHOIS остаётся UNKNOWN (вероятно свободен); RESTRICTED определяется метаданными. Полная поддержка IDN (Unicode на входе, punycode канонически, displayDomain на выходе) и опциональный мульти-TLD-обход (1–10 на запрос). Premium в MVP всегда unknown — цены вынесены в отдельную будущую подсистему.
POST /api/v1/domain-availability
Content-Type: application/json
{ "domain": "пример.рф", "tlds": ["com", "io"] }
{
"url": "пример.рф",
"displayDomain": "пример.рф",
"host": "xn--e1afmkfd.xn--p1ai",
"status": "UP",
"results": [
{
"tld": "com",
"availability": "AVAILABLE",
"reason": "rdap_not_found",
"confidence": "high",
"source": "rdap",
"premium": "unknown",
"checkedAt": "2026-09-03T12:00:02Z"
},
{
"tld": "io",
"availability": "UNKNOWN",
"reason": "tld_rdap_unknown",
"confidence": "low",
"source": "tld-metadata",
"premium": "unknown",
"checkedAt": "2026-09-03T12:00:02Z"
}
],
"tldMetaVersion": "2026-09-02",
"durationMs": 1240
}- TLD на запрос
- 1–10 уникальных (Unicode или punycode); не более 4 одновременных запросов в рамках общего 15-секундного бюджета (DOMAIN_AVAILABILITY_TIMEOUT)
- Вердикты
- AVAILABLE | REGISTERED | RESTRICTED | INVALID | UNKNOWN | ERROR — UNKNOWN никогда не выдаётся за AVAILABLE; PREMIUM в MVP недостижим
- Кэширование
- di:avail 60s, di:reg 6h, fail-open; негативные результаты никогда не кэшируются
Возраст домена — POST /api/v1/domain-age
Сообщает возраст домена: точную дату создания из реестра и детерминированную разбивку по годам/месяцам/дням. Тонкая проекция поверх WHOIS-данных — один запрос провайдера обслуживает доступность, возраст и регистратора в пределах окна кэша.
POST /api/v1/domain-age
Content-Type: application/json
{ "domain": "example.com" }
{
"url": "example.com",
"host": "example.com",
"status": "UP",
"age": {
"known": true,
"createdAt": "2019-01-15T05:00:00Z",
"ageInDays": 2809,
"years": 7,
"months": 7,
"days": 20
},
"source": "rdap",
"durationMs": 390
}- Математика возраста
- только календарные даты UTC; полные годы/месяцы через якорь с клампингом; общие дни с округлением вниз
- Неизвестный возраст
- age.known=false + ограниченная причина (no_data, inconsistent_data) — никогда не догадка
- Кэширование
- di:reg 6h, общее с доступностью/регистратором (fail-open)
Проверка регистратора — POST /api/v1/domain-registrar
Сообщает, у какого регистратора зарегистрирован домен, с нормализацией по курируемой таблице псевдонимов (GoDaddy, Namecheap, Cloudflare и другие) — неизвестные имена показываются ровно как опубликовано. Организация реестра и происхождение RDAP/WHOIS в комплекте; делит кэш регистрации с возрастом/доступностью.
POST /api/v1/domain-registrar
Content-Type: application/json
{ "domain": "example.com" }
{
"url": "example.com",
"host": "example.com",
"status": "UP",
"registrar": "GoDaddy.com, LLC",
"registrarCanonical": "GoDaddy",
"registrarIanaId": 625,
"registry": "Verisign, Inc.",
"source": "rdap",
"checkedAt": "2026-09-04T12:00:00Z",
"durationMs": 410
}- Регистратор
- отображаемое имя + канонический бейдж псевдонима при совпадении; IANA ID показывает «—» (данных реестра пока нет)
- Не опубликовано
- регистрации за privacy-прокси или с редактированием отвечают UP с причиной no_data — никогда не пустая оболочка
Генератор доменов — POST /api/v1/domain-generate
Генерирует домены-кандидаты из 1–3 ключевых слов: прямые формы, префиксы, суффиксы, составные и короткие — с дедупликацией, в порядке и с лимитом. Чисто и мгновенно: во время генерации нет обращений к реестрам; проверки по кандидату — отдельные явные действия.
POST /api/v1/domain-generate
Content-Type: application/json
{ "keywords": ["coffee", "map"], "tlds": ["com", "io"], "limit": 24 }
{
"status": "UP",
"candidates": [
{ "domain": "coffee.com", "strategy": "direct" },
{ "domain": "coffee.io", "strategy": "direct" },
{ "domain": "getcoffee.com", "strategy": "prefix" },
{ "domain": "coffeemap.com", "strategy": "compound" }
],
"total": 24
}- Кандидаты
- жёсткий лимит 50, по умолчанию 24; ≤10 TLD, отфильтрованных через снимок метаданных TLD
- Нет трафика к реестрам
- генерация не делает ни одного вызова реестра — проверки по кандидату идут в эндпоинт доступности со своими лимитами
Обзор домена — POST /api/v1/domain-overview
Составной профиль: доступность на собственном TLD домена, дата создания с детерминированной разбивкой возраста, регистратор (нормализованный, с номером IANA), проекция истечения и находки конфигурации реестра. Секции независимы — один неудавшийся запрос никогда не обнуляет остальные.
POST /api/v1/domain-overview
Content-Type: application/json
{ "domain": "example.com" }
{
"url": "example.com",
"host": "example.com",
"status": "UP",
"availability": {
"tld": "com", "availability": "REGISTERED", "reason": "registered",
"confidence": "high", "source": "rdap", "premium": "unknown",
"checkedAt": "2026-09-05T12:00:00Z"
},
"registration": {
"known": true, "createdAt": "2019-01-15T05:00:00Z",
"ageYears": 7, "ageMonths": 7, "ageDays": 21,
"registrar": "GoDaddy.com, LLC", "registrarCanonical": "GoDaddy",
"registrarIanaId": 625, "registry": "Verisign, Inc.", "source": "rdap",
"checkedAt": "2026-09-05T12:00:01Z"
},
"expiry": {
"host": "example.com", "source": "rdap", "verdict": "ok",
"daysRemaining": 222, "expiration": "2027-04-15T04:00:00Z",
"checkedAt": "2026-09-05T12:00:02Z"
},
"holds": [],
"dnssec": [{ "id": "dnssec-absent", "state": "info", "severity": "info", "detail": "unsigned" }],
"tldMetaVersion": "2026-09-02",
"durationMs": 1620
}- Секции
- доступность (с метаданными-шлюзом) + регистрация (di:reg, 6h, общая) + истечение (rdap.org) + находки holds/dnssec
- Находки — факты
- holds/DNSSEC — сигналы конфигурации реестра, а не вердикты безопасности; DNS/SSL остаются в отдельных инструментах
Проверка безопасности — POST /api/v1/security-check
Пассивный консультационный обзор конфигурации одного полученного ответа: заголовки безопасности (глубина HSTS, акценты CSP, COOP/COEP/CORP, X-XSS-Protection), флаги cookie, факты TLS, понижения в цепочке и раскрытие информации. Никакого зондирования, утверждений об уязвимостях и оценок; значения cookie не покидают бэкенд. HTTP-статус не влияет на проверку (доступный 404/500 анализируется).
POST /api/v1/security-check
Content-Type: application/json
{ "url": "https://example.com" }
{
"url": "https://example.com",
"finalUrl": "https://example.com/",
"status": "UP",
"durationMs": 610,
"summary": { "total": 14, "passed": 9, "warn": 3, "failed": 2 },
"findings": [
{ "id": "hsts-present", "state": "fail", "severity": "high" },
{ "id": "tls-cert", "state": "pass", "severity": "info", "detail": "valid" }
],
"cookies": [
{ "name": "session", "secure": false, "httpOnly": true, "sameSite": "Lax" }
],
"tls": { "enabled": true, "version": "TLS 1.3", "certStatus": "valid", "daysRemaining": 89 }
}- Объём
- ~23 идентификатора проверок по разделам заголовки/cookie/TLS/цепочка/раскрытие; только пассивный запрос
- Cookie
- Только имена и флаги (Secure/HttpOnly/SameSite) — значения не покидают бэкенд
- Таймаут проверки
- 10 секунд общий (SECURITY_CHECK_TIMEOUT)
URL Analyzer — POST /api/v1/url-analyze
Чистый синтаксический разбор URL: каноническая идентичность с редактированием (схема, хост, формы IDN, «регистрируемый домен» по наивному правилу, порт, путь, запрос, фрагмент), упорядоченные параметры с дубликатами и версионируемой классификацией трекинга, счётчики по категориям, информационные сигналы и заметки о нормализации. Ни запросов, ни DNS, ни сохранения — анализ локальный и выполняется за миллисекунды.
POST /api/v1/url-analyze
Content-Type: application/json
{ "url": "https://xn--e1afmkfd.xn--p1ai/search?q=thing&utm_source=news&id=7&id=8" }
{
"status": "UP",
"identity": {
"hasCredentials": false,
"scheme": "https",
"host": "xn--e1afmkfd.xn--p1ai",
"displayHost": "пример.рф",
"registrableDomain": "пример.рф",
"isIdn": true,
"path": "/search",
"query": "q=thing&utm_source=news&id=7&id=8",
"normalized": "https://xn--e1afmkfd.xn--p1ai/search?q=thing&utm_source=news&id=7&id=8"
},
"parameters": [
{ "name": "q", "value": "thing", "classification": { "category": "unknown", "confidence": "none" } },
{ "name": "utm_source", "value": "news", "classification": { "category": "utm", "label": "utm_source", "confidence": "exact" } },
{ "name": "id", "value": "7", "occurrence": 1 },
{ "name": "id", "value": "8", "occurrence": 2 }
],
"tracking": { "utm": 1, "analytics": 0, "adsClickId": 0, "sessionSensitive": 0, "unknown": 3 },
"signals": ["idn_host"],
"normalization": { "schemeAssumed": false, "punycodeApplied": true, "defaultPortOmitted": false, "hostLowercased": false },
"registryVersion": "2026-09-1"
}- Состав
- Компоненты + упорядоченные параметры + классификация по реестру + информационные сигналы; ноль сетевой активности
- Редактирование
- Пароли никогда не возвращаются; значения чувствительных параметров скрыты (***) везде, имена видны
URL Expander — POST /api/v1/url-expand
Мгновенное раскрытие цепочки редиректов поверх общего движка, без сохранения: каждый хоп проходит ту же централизованную SSRF-проверку, циклы и лимит в 10 редиректов различаются по reason, финальный URL получает полный трекинг-анализ. Возвращаемые URL редактируются — пароли не покидают бэкенд. Без кэша: цепочки чувствительны ко времени, свежесть — правильный ответ.
POST /api/v1/url-expand
Content-Type: application/json
{ "url": "https://bit.ly/3xyz" }
{
"url": "https://bit.ly/3xyz",
"status": "UP",
"finalUrl": "https://example.com/landing?utm_source=n",
"hopCount": 2,
"chain": [
{ "url": "https://bit.ly/3xyz", "status": 301, "location": "https://bit.ly/abc" },
{ "url": "https://bit.ly/abc", "status": 302, "location": "https://example.com/landing?utm_source=n" }
],
"analysis": { "status": "UP", "tracking": { "utm": 1, "analytics": 0, "adsClickId": 0, "sessionSensitive": 0, "unknown": 0 } },
"source": "engine",
"durationMs": 820
}- Состав
- Редактированная цепочка хопов + классифицированный статус (цикл vs лимит) + анализ финального URL; без DNS/TLS/таймингов по хопам (зона Redirect Checker)
- Бюджет раскрытия
- 10 секунд на запрос (URL_EXPAND_TIMEOUT); лимит хопов 10
UTM Builder — POST /api/v1/utm-build
Детерминированная сборка кампанных URL без состояния: нерелевантные параметры сохраняются в порядке, канонические UTM перезаписываются или сохраняются по полям, дубликаты схлопываются к последнему, фрагмент сохраняется, адреса с учётными данными отвергаются in-band. Одинаковый ввод всегда даёт байт-в-байт одинаковый вывод.
POST /api/v1/utm-build
Content-Type: application/json
{ "url": "https://example.com/landing?foo=1&utm_source=old#pricing", "utmSource": "newsletter", "utmMedium": "email", "utmCampaign": "spring_sale", "utmContent": "header_cta" }
{
"status": "UP",
"generatedUrl": "https://example.com/landing?foo=1&utm_source=newsletter&utm_medium=email&utm_campaign=spring_sale&utm_content=header_cta#pricing",
"warnings": ["existing_utm_overwritten:utm_source", "empty_field_skipped:utm_term"],
"parameters": { "utm_source": "newsletter", "utm_medium": "email", "utm_campaign": "spring_sale", "utm_content": "header_cta" }
}- Состав
- Добавление UTM в фиксированном порядке + политика preserve/overwrite/collapse + предупреждения; чисто, без сети
- Детерминизм
- Байт-в-байт одинаковый вывод для одинакового ввода; поля ≤256 символов; неизвестные поля запроса отвергаются
Website Health — POST /api/v1/website-health
Композитная диагностика: один запрос нормализует цель и запускает ограниченные параллельные lanes над существующими движками — один HTTP-чек кормит пять секций (доступность, статус, время ответа, заголовки, конфигурация безопасности), а DNS, TLS-проба и профиль домена идут отдельными lanes. Итог — агрегатное состояние с деталями по каждой проверке и ссылками на отдельные инструменты. Находки описывают только выполненные проверки — никакой гарантии безопасности.
POST /api/v1/website-health
Content-Type: application/json
{ "url": "https://example.com" }
{
"target": {
"canonical": "https://example.com/",
"displayHost": "example.com",
"scheme": "https",
"hasCredentials": false,
"isDomain": true,
"isHttp": true,
"valid": true
},
"overall": "WARNING",
"summaryKey": "health.summary.warning",
"checks": [
{ "type": "http_availability", "state": "pass",
"summaryKey": "health.check.httpAvailability.pass",
"value": "200", "durationMs": 612, "applicable": true,
"detailUrl": "/uptime-checker" },
{ "type": "http_status", "state": "pass",
"summaryKey": "health.check.httpStatus.pass",
"value": "200 OK", "applicable": true,
"detailUrl": "/http-status-checker" },
{ "type": "response_time", "state": "pass",
"summaryKey": "health.check.responseTime.pass",
"value": "612 ms", "applicable": true,
"detailUrl": "/response-time-checker" },
{ "type": "headers", "state": "warn",
"summaryKey": "health.check.headers.warn",
"value": "2 missing", "reason": "findings", "applicable": true,
"detailUrl": "/security-checker" },
{ "type": "security", "state": "warn",
"summaryKey": "health.check.security.warn",
"value": "14 of 21 passed", "reason": "findings", "applicable": true,
"detailUrl": "/security-checker" },
{ "type": "tls", "state": "pass",
"summaryKey": "health.check.tls.pass",
"value": "TLS 1.3 · valid, 89 days", "durationMs": 140,
"applicable": true, "detailUrl": "/ssl-checker" },
{ "type": "dns", "state": "pass",
"summaryKey": "health.check.dns.pass",
"value": "A, AAAA, MX, NS", "durationMs": 95,
"applicable": true, "detailUrl": "/dns-checker" },
{ "type": "domain", "state": "pass",
"summaryKey": "health.check.domain.pass",
"value": "expires in 214 days", "durationMs": 730,
"applicable": true, "detailUrl": "/domain-overview" }
],
"meta": { "checksTotal": 8, "checksPassed": 6, "checksWarn": 2,
"checksFailed": 0, "checksUnknown": 0,
"tldMetaVersion": "2026-09-03", "durationMs": 1480 }
}- Охват
- Одно HTTP-исполнение кормит пять секций; lanes DNS/TLS/домен; агрегат HEALTHY/WARNING/ERROR/PARTIAL/UNKNOWN
- Ограничения
- Общий бюджет 25 с + бюджеты lanes, ≤3 lanes одновременно; невалидные цели — in-band; без кэша — свежесть прежде всего
Uptime Monitoring — управляющий API /api/v1/monitors
Stateful-исключение среди мгновенных инструментов: создайте монитор для одного URL, и воркер проверяет его по фиксированному расписанию — с историей проверок, статистикой доступности, инцидентами и webhook-уведомлениями. Владение — ключ управления, показываемый ровно один раз при создании; каждый запрос читает/пишет с ним, а неверный ключ неотличим от отсутствующего монитора (единый 404).
POST /api/v1/monitors
Content-Type: application/json
{ "url": "https://example.com", "name": "Prod site", "interval": 300 }
201 Created
{
"monitor": { "id": "b1…", "name": "Prod site",
"normalizedTarget": "https://example.com/",
"state": "unknown", "interval": 300 },
"manageUrl": "/monitors/b1…?key=…",
"key": "…shown exactly once…"
}
GET /api/v1/monitors/{id}?key=… detail + stats window + incidents
GET /api/v1/monitors/{id}/history cursor-paginated executions
GET /api/v1/monitors/{id}/history/daily per-day buckets (30-day cap)
GET /api/v1/monitors/{id}/incidents incident episodes
POST /api/v1/monitors/{id}/check enqueue a priority manual check
PATCH /api/v1/monitors/{id} name / interval / webhook / pause
DELETE /api/v1/monitors/{id} cascade delete
Credentials in the target are rejected (credentials_not_allowed); the
target is SSRF-pre-validated at creation and re-validated on every run.- Объём
- Создание / список / детали / пауза / удаление / ручная проверка / история / инциденты; фиксированные интервалы 60–3600с; in-band INVALID_URL и BLOCKED_TARGET при создании
- Управление ключом
- 256-битный ключ показывается один раз (хранится sha256); credentials в целях отклоняются; SSRF-проверка при создании и перед каждым запуском
Публичные статус-страницы — management API /api/v1/status-pages
Соберите свои мониторы в публичную статус-страницу: выберите компоненты, задайте порядок и отображаемые имена, опубликуйте под постоянным слагом. Страницы живут под тем же ключом управления, что и мониторы; черновики приватны, публикация идемпотентна и обратима, а каждая мутация удаляет запись публичного кэша — доступ меняется в пределах запроса.
POST /api/v1/status-pages
Content-Type: application/json
X-Monitor-Key: <your key>
{ "name": "Prod API" }
201 Created
{
"page": { "publicId": "p1…", "name": "Prod API",
"slug": "prod-api", "published": false },
"manageUrl": "/status-pages/p1…?key=…"
}
GET /api/v1/status-pages/{id}?key=… editor payload (members + monitors)
PATCH /api/v1/status-pages/{id} name/description/slug + membership
POST /api/v1/status-pages/{id}/publish → live at /status/{slug}
POST /api/v1/status-pages/{id}/unpublish → removed within the request
DELETE /api/v1/status-pages/{id} cascade delete
GET /api/v1/public/status-pages/{slug} the public DTO (no key; cached 60s)
Membership is same-key only (≤25 monitors, replace-list semantics);
publish requires ≥1 visible member; the public DTO is an explicit
projection — target URLs, keys and internal ids never cross.- Возможности
- Создание / список / правка / список участников (≤25, только свой ключ) / публикация / снятие / удаление; слаги 3-63 символа со списком зарезервированных слов; до 5 страниц на ключ
- Публичная часть
- GET /api/v1/public/status-pages/{slug} + /status/{slug}; только явная публичная DTO — целевые URL, ключи, хосты уведомлений и внутренние id не пересекают границу; кэш Redis 60с, fail-open
Сократитель URL — управляющий API /api/v1/short-links
Превратите длинный URL в короткую ссылку /go/{code}, которой можно управлять: проверенный адрес, криптографически случайный код, статистика кликов за сегодня/7 дней/30 дней. Ссылки живут под тем же ключом управления, что ваши мониторы и страницы статуса, — создание привязывается к существующему ключу и никогда не создаёт новый. Адреса проверяются при создании и редактировании (синтаксис, учётные данные отклоняются, SSRF-классификация); публичный редирект сам ничего не загружает и отвечает 302 без кэширования.
POST /api/v1/short-links
Content-Type: application/json
X-Monitor-Key: <your key>
{ "destinationUrl": "https://example.com/launch?utm_source=newsletter" }
201 Created
{
"link": { "id": "sl1…", "code": "a3f9k2mz",
"shortUrl": "/go/a3f9k2mz",
"destination": "https://example.com/launch?utm_source=newsletter" }
}
GET /api/v1/short-links?key=… your links (newest first)
GET /api/v1/short-links/{id}?key=… full link + stats
PATCH /api/v1/short-links/{id}?key=… destination/title/expiry (re-validated)
POST /api/v1/short-links/{id}/disable public 404, stats kept (enable restores)
DELETE /api/v1/short-links/{id}?key=… soft delete (idempotent)
GET /api/v1/short-links/{id}/stats?key=… total + today/7d/30d clicks
GET /go/a3f9k2mz → 302 Found + Location (Cache-Control: no-store);
unknown/disabled/expired/deleted all answer 404.
Destinations are validated at create/update (http/https, credentials
rejected, SSRF classification); the redirect itself never fetches.- Возможности
- Создание / список / редактирование / выключение / включение / мягкое удаление / статистика; ≤100 активных ссылок на ключ, 30 созданий на ключ в час; адрес ревалидируется при каждом изменении
- Публичный редирект
- GET /go/{code} → 302 + no-store; неизвестный/выключенный/истёкший/удалённый отвечают одинаковым нейтральным 404; редирект — чистый lookup: он не принимает параметр адреса и никогда не резолвит и не загружает цель; без IP и user-agent
Жалоба на короткую ссылку — анонимный API репортов
Если ссылка /go/{code} выглядит как фишинг, малварь, спам или скам — отправьте жалобу: аккаунт не нужен, ответ вам не придёт. Жалобы попадают в очередь оператора; погасить ссылку может только оператор. На каждую корректную жалобу эндпоинт отвечает одинаково, поэтому репортёр не узнаёт, существует ли код.
POST /api/v1/short-link-reports
Content-Type: application/json
{ "code": "a3f9k2mz", "reason": "phishing",
"detail": "Imitates a login page" }
202 Accepted
{ "status": "received" }
Reasons: phishing | malware | spam | scam | other (detail ≤500 chars,
optional plain text). The SAME 202 comes back for unknown, disabled
and deleted codes — no existence oracle. Limits per IP: one report
per code per 10 min, 10/hour, 30/day (429 + Retry-After; Redis
failure = 503, fail-closed). Reports go to the operator queue; only
the operator can take a link down (the owner key cannot override).- Лимиты и приватность
- 1 жалоба на код в 10 мин с IP, далее 10/час и 30/день (429 + Retry-After; при сбое Redis — 503, fail-closed); причины phishing | malware | spam | scam | other; без аккаунта, без email, сырой IP не хранится — только ежедневный ротируемый отпечаток
- Единый ответ
- любая корректная жалоба получает одинаковый 202 received — для живых, отключённых, удалённых и несуществующих кодов (no existence oracle); битый код или неизвестная причина — 400 до каких-либо lookup'ов
Аккаунты и API-ключи — /api/v1/auth/register и /api/v1/api-keys
Браузерные аккаунты (email + пароль, открытая регистрация; email в этой версии не подтверждается) с серверными сессиями в защищённой cookie. API-ключи авторизуют серверные вызовы по явному белому списку ресурсных семейств. Ошибки входа неразличимы — неизвестный email и неверный пароль отвечают одинаково, вплоть до таймингов.
POST /api/v1/auth/register
Content-Type: application/json
{ "email": "you@example.com", "password": "…", "displayName": "…" }
201 Created + Set-Cookie: wg_session (HttpOnly; Secure; SameSite=Lax)
{ "account": { "id": "acc…", "email": "you@example.com", … } }
POST /api/v1/auth/login 200 + Set-Cookie (401 generic on failure)
POST /api/v1/auth/logout deletes the server-side session
GET /api/v1/account the session's own profile
PATCH /api/v1/account update display name (displayName)
GET /api/v1/account/summary account-owned resource counts
POST /api/v1/account/claim management key → re-own key-held resources
POST /api/v1/api-keys (SESSION) create; secret shown ONCE
{ "name": "CI", "scopes": ["monitors:read"] }
GET /api/v1/api-keys (SESSION) list — no secrets
POST /api/v1/api-keys/{id}/revoke (SESSION) immediate 401 on next use
Bearer access (Authorization: Bearer wg_live_…) is an EXPLICIT
allowlist only: account GET/PATCH, monitors CRUD + reads, status-pages
GET, short-links CRUD + stats; everything else refuses API keys.
Missing/unknown/revoked → generic 401; wrong scope → 403; per-key and
per-account rate limits → 429 + Retry-After.- Bearer-список
- account GET/PATCH (account:read), мониторы (чтение/запись), статус-страницы GET (чтение), короткие ссылки (чтение/запись); всё остальное ключи не принимает. Непривязанные key-ресурсы невидимы, пока не привязаны через claim-by-key.
- Обращение с секретом
- Полный ключ wg_live_ показывается ровно один раз при создании; хранится только однонаправленный хэш. Отсутствующий/неизвестный/отозванный ключ отвечает одним общим 401; нехватка скоупа — 403; лимиты — 429 + Retry-After.
Подтверждение email и восстановление доступа
Email-фундамент Phase J: подтвердите адрес, восстановите пароль и подтвердите недавнее знание пароля для чувствительных действий.
POST /api/v1/auth/verification/request (SESSION) 202 {accepted:true}
POST /api/v1/auth/verification/confirm { "token": "…" } → 200 {verified:true}
POST /api/v1/auth/password-reset/request { "email": "you@example.com" } → 202 (always the same answer)
POST /api/v1/auth/password-reset/confirm { "token": "…", "password": "…" } → 200 {reset:true}
POST /api/v1/auth/reauthenticate (SESSION) { "password": "…" } → 200 {confirmed:true}
Reset revokes ALL sessions in the same transaction; API keys stay
active. Tokens ride mail links as URL fragments — never query strings —
and every mismatch (wrong account, replay, expiry, unknown) answers the
same generic 404.- Токены
- одноразовые, 24 ч (верификация) / 30 мин (сброс), только во фрагменте, одинаковый 404 при любой ошибке
- Сброс
- атомарно завершает все сессии; API-ключи остаются активными
- Повторная аутентификация
- 5 минут, серверная, привязана к сессии
- Рабочие пространства
- GET /api/v1/workspaces — личное + организации, no-store, только сессия
- Организации
- создание/список/чтение/переименование/удаление + передача владения; верифицированные сессии, оптимистичные версии, reauth для разрушительных действий
- Приглашения
- email-приглашения с одноразовыми ссылками на 7 дней, четырьмя фиксированными ролями, капами с резервированием мест и обязательными окнами частоты
- Ресурсы организаций
- общие мониторы/страницы/ссылки под /organizations/{orgId}; сессионный RBAC, версионные мутации, legacy-ключи исключены на уровне SQL
- Перенос ресурсов
- атомарный перенос личных мониторов/страниц/ссылок в организацию (замыкание ≤100, версии, идемпотентность)
- Ключи организаций
- сервисные ключи организации (wg_live_…), показываются один раз, со скоупами, переживают уход создателя, отзыв мгновенный
- Аудит организации
- дополняемая история изменений организации (365 дней), чтение Owner/Admin, минимальная раскрытость акторов