Stitex/Документация

Обзор

Stitex предоставляет два бесплатных сервиса защиты от ботов:

Stitex Captcha

Активная проверка — пользователь решает задание (математика, слова, последовательности). Включает Proof-of-Work и поведенческий анализ. Адаптивная сложность на основе ML-модели антифрода.

Stitex Antifraud

Невидимый анализ — JS-виджет собирает 30+ сигналов (fingerprint, поведение, окружение) и вычисляет fraud score 0–100 в реальном времени.

Оба сервиса можно использовать отдельно или вместе. При совместном использовании antifraud score автоматически влияет на сложность captcha.

Базовый URL: https://pulse.stitex.com

Captcha виджет: https://pulse.stitex.com/captcha/stitex-captcha.js

Antifraud виджет: https://pulse.stitex.com/captcha/stitex-antifraud.js

Ключи: sc_... (siteKey), scs_... (secretKey)

Получить ключи: pulse.stitex.com/register

Адаптивная сложность captcha

Сложность автоматически выбирается на основе antifraud ML-скора сессии:

Invisible
score < 0.3
Easy
score < 0.6
Medium
score < 0.8
Hard
score ≥ 0.8

Быстрый старт

Интеграция капчи за 3 шага — без SDK, без зависимостей.

1

Добавьте виджет в HTML

<form method="POST" action="/submit">
  <!-- Ваши поля формы -->
  <input type="email" name="email" required />

  <!-- Captcha виджет -->
  <div id="stitex-captcha" data-sitekey="sc_YOUR_SITE_KEY"></div>

  <button type="submit">Отправить</button>
</form>

<script src="https://pulse.stitex.com/captcha/stitex-captcha.js"></script>
2

Проверьте токен на сервере

curlbash
# Верифицировать solveToken на сервере
curl -X POST https://pulse.stitex.com/api/captcha/verify \
  -H "Content-Type: application/json" \
  -d '{
    "secretKey": "scs_YOUR_SECRET_KEY",
    "solveToken": "eyJhbGciOiJIUzI1NiJ9..."
  }'

# Ответ:
# {"success":true,"domain":"example.com","timestamp":"2026-03-30T12:00:00Z"}
3

Готово!

При success: true — пользователь прошёл проверку. Обработайте форму.

Stitex Captcha: Клиентский виджет

Добавьте виджет на страницу с формой:

HTML — вставьте в формуhtml
<!-- Контейнер капчи (внутри <form>) -->
<div id="stitex-captcha" data-sitekey="sc_YOUR_SITE_KEY"></div>

<!-- Скрипт виджета (перед </body>) -->
<script src="https://pulse.stitex.com/captcha/stitex-captcha.js"></script>

Атрибуты контейнера

data-sitekeyобяз.
string
Site Key вашего сайта из Dashboard (начинается с sc_)
data-theme
string
Тема виджета: light или dark. По умолчанию light
data-callback
string
Имя глобальной JS-функции, вызываемой при успешном решении. Получает solveToken

JavaScript API

Программная работа с виджетомjavascript
// Получить текущий solveToken
const token = document.querySelector('#stitex-captcha')
  ?.getAttribute('data-solve-token');

// Сбросить капчу
window.stitexCaptchaReset && window.stitexCaptchaReset();

// Callback при решении
window.onStitexCaptchaSolved = function(token) {
  console.log('Captcha solved:', token);
};

Stitex Captcha: API эндпоинты

Все эндпоинты вызывает виджет автоматически. Документация полезна для кастомных интеграций.

GET/api/captcha?siteKey=YOUR_KEY30 req/min

Получить challenge для отображения пользователю.

Ответ (обычный пользователь)

{
  "display": "3 + 7",
  "token": "eyJ...",
  "segments": ["3", "+", "7"],
  "type": "math",
  "difficulty": "easy"
}

Ответ (доверенный пользователь — invisible)

{
  "invisible": true,
  "solveToken": "eyJ...",
  "score": 0.98
}
POST/api/captcha20 req/min

Отправить ответ пользователя на challenge.

Тело запроса

tokenобяз.
string
Токен из GET-ответа
answerобяз.
string
Ответ пользователя
siteKey
string
Site Key (опционально, для валидации)
behavioral
object
Поведенческие данные (мышь, клавиши, время)

Ответ

{
  "valid": true,
  "solveToken": "eyJ...",
  "score": 0.95
}

Stitex Captcha: Серверная верификация

После отправки формы проверьте solveToken на вашем сервере. Это единственный обязательный серверный вызов.

POST/api/captcha/verify

Тело запроса (JSON)

secretKeyобяз.
string
Secret Key вашего сайта (начинается с scs_)
solveTokenобяз.
string
Токен из формы (скрытое поле stitex-captcha-token)
sessionId
string
ID сессии antifraud (для связки данных)

Ответ

Успешная верификацияjson
{
  "success": true,
  "domain": "example.com",
  "timestamp": "2026-03-30T12:00:00Z",
  "antifraud": {
    "score": 12,
    "isBot": false,
    "recommendation": "allow"
  }
}
Ошибка верификацииjson
{
  "success": false,
  "error": "Token expired or invalid"
}

Важно: Токены одноразовые (HMAC-SHA256 с nonce). Повторная верификация того же токена вернёт ошибку. Redis обеспечивает защиту от replay-атак.

Stitex Captcha: Примеры интеграции

curl — получить challengebash
# Получить challenge
curl "https://pulse.stitex.com/api/captcha?siteKey=sc_YOUR_SITE_KEY"

# Ответ:
# {"display":"3 + 7","token":"eyJ...","segments":["3","+","7"],
#  "type":"math","difficulty":"easy"}
curl — отправить ответbash
# Отправить ответ на challenge
curl -X POST https://pulse.stitex.com/api/captcha \
  -H "Content-Type: application/json" \
  -d '{
    "token": "eyJ...",
    "answer": "10",
    "siteKey": "sc_YOUR_SITE_KEY"
  }'

# Ответ:
# {"valid":true,"solveToken":"eyJ...","score":0.95}
curl — серверная верификацияbash
# Верифицировать solveToken на сервере
curl -X POST https://pulse.stitex.com/api/captcha/verify \
  -H "Content-Type: application/json" \
  -d '{
    "secretKey": "scs_YOUR_SECRET_KEY",
    "solveToken": "eyJhbGciOiJIUzI1NiJ9..."
  }'

# Ответ:
# {"success":true,"domain":"example.com","timestamp":"2026-03-30T12:00:00Z"}
PHPphp
<?php
$token = $_POST['stitex-captcha-token'] ?? '';

$response = file_get_contents(
  'https://pulse.stitex.com/api/captcha/verify',
  false,
  stream_context_create([
    'http' => [
      'method'  => 'POST',
      'header'  => 'Content-Type: application/json',
      'content' => json_encode([
        'secretKey'  => 'scs_YOUR_SECRET_KEY',
        'solveToken' => $token,
      ]),
    ],
  ])
);

$data = json_decode($response, true);

if (!$data || !$data['success']) {
  die('Капча не пройдена');
}

// Капча пройдена
echo 'Score: ' . $data['score'];
Python (requests)python
import requests

token = request.form.get('stitex-captcha-token', '')

resp = requests.post(
    'https://pulse.stitex.com/api/captcha/verify',
    json={
        'secretKey': 'scs_YOUR_SECRET_KEY',
        'solveToken': token,
    }
)
data = resp.json()

if not data.get('success'):
    return 'Капча не пройдена', 403

print(f"Score: {data['score']}")
Node.js (fetch)javascript
const resp = await fetch(
  'https://pulse.stitex.com/api/captcha/verify',
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      secretKey: process.env.STITEX_SECRET_KEY,
      solveToken: req.body['stitex-captcha-token'],
    }),
  }
);
const data = await resp.json();

if (!data.success) {
  return res.status(403).json({ error: 'Captcha failed' });
}

console.log('Score:', data.score);

Stitex Antifraud: Виджет

Невидимый JS-виджет. Собирает поведенческие сигналы и отправляет их на сервер для ML-анализа.

HTML — вставьте перед </body>html
<script src="https://pulse.stitex.com/captcha/stitex-antifraud.js"
        data-key="YOUR_API_KEY" async></script>

Атрибуты

data-keyобяз.
string
API Key вашего сайта из Dashboard (раздел Antifraud)

Что собирается

User-Agent
Screen / Window size
Timezone
Canvas fingerprint
WebGL vendor/renderer
AudioContext FP
Installed plugins
WebDriver API
Chrome headless
Mouse trajectory
Keystroke dynamics
Scroll behavior
Focus/blur events
Touch events
Connection type

Collect API (внутренний)

POST/api/antifraud/collect

Вызывается JS-виджетом автоматически. Документация для справки.

keyобяз.
string
API Key сайта
sidобяз.
string
Session ID
url
string
Текущий URL страницы
ref
string
Referrer
ua
string
User-Agent
dur
number
Время на странице (мс)
clicks
number
Количество кликов
moves
number
Количество движений мыши
scrollPct
number
Процент прокрутки
scrollEvents
number
Количество scroll-событий
avgMoveMs
number
Среднее время между движениями мыши
signals
object
Fingerprint-данные (canvas, webgl, audio и т.д.)
mouseTrajectory
array
Траектория мыши (массив координат)
keystrokeDynamics
array
Динамика нажатий клавиш
Ответjson
{"ok": true, "score": 15}

Stitex Antifraud: Серверная проверка

Проверьте fraud score конкретной сессии на вашем сервере.

POST/api/antifraud/check

Тело запроса (JSON)

apiKeyобяз.
string
API Key вашего сайта
sessionIdобяз.
string
ID сессии (cookie stitex_af_sid)

Полная схема ответа

Ответjson
{
  "found": true,
  "score": 78,
  "isBot": true,
  "reasons": ["webdriver", "headless_chrome", "sw_renderer"],
  "recommendation": "block",
  "requireCaptcha": false,
  "sessionId": "sess_abc123..."
}

Значения recommendation

RecommendationScoreОписание
allow< 25Нормальный пользователь — пропускать
monitor25 – 50Подозрительная активность — логировать
captcha50 – 70Показать Stitex Captcha для проверки
block≥ 70Вероятный бот — заблокировать доступ

Stitex Antifraud: Примеры интеграции

curlbash
# Проверить fraud-скор сессии
curl -X POST https://pulse.stitex.com/api/antifraud/check \
  -H "Content-Type: application/json" \
  -d '{
    "apiKey": "YOUR_API_KEY",
    "sessionId": "sess_abc123..."
  }'

# Ответ:
# {"found":true,"score":78,"isBot":true,
#  "recommendation":"block",
#  "reasons":["webdriver","headless_chrome"],
#  "requireCaptcha":false,"sessionId":"sess_abc123..."}
PHPphp
<?php
$sessionId = $_COOKIE['stitex_af_sid'] ?? '';
if (!$sessionId) {
  die('No antifraud session');
}

$response = file_get_contents(
  'https://pulse.stitex.com/api/antifraud/check',
  false,
  stream_context_create([
    'http' => [
      'method'  => 'POST',
      'header'  => 'Content-Type: application/json',
      'content' => json_encode([
        'apiKey'    => 'YOUR_API_KEY',
        'sessionId' => $sessionId,
      ]),
    ],
  ])
);

$data = json_decode($response, true);

if ($data && $data['recommendation'] === 'block') {
  http_response_code(403);
  die('Доступ запрещён');
}

if ($data && $data['recommendation'] === 'captcha') {
  // Показать Stitex Captcha
}
Python (requests)python
import requests

session_id = request.cookies.get('stitex_af_sid', '')

resp = requests.post(
    'https://pulse.stitex.com/api/antifraud/check',
    json={
        'apiKey': 'YOUR_API_KEY',
        'sessionId': session_id,
    }
)
data = resp.json()

if data.get('recommendation') == 'block':
    abort(403)
elif data.get('recommendation') == 'captcha':
    # Показать Stitex Captcha
    pass

print(f"Score: {data['score']}, Bot: {data['isBot']}")
Node.js (Express middleware)javascript
async function antifraudMiddleware(req, res, next) {
  const sessionId = req.cookies['stitex_af_sid'];
  if (!sessionId) return next();

  const resp = await fetch(
    'https://pulse.stitex.com/api/antifraud/check',
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        apiKey: process.env.STITEX_AF_KEY,
        sessionId,
      }),
    }
  );
  const data = await resp.json();

  if (data.recommendation === 'block') {
    return res.status(403).json({ error: 'Blocked' });
  }
  if (data.recommendation === 'captcha') {
    return res.status(418).json({ requireCaptcha: true });
  }

  req.fraudScore = data.score;
  req.isBot = data.isBot;
  next();
}

Совместное использование Captcha + Antifraud

При совместном использовании Antifraud автоматически влияет на сложность Captcha. Ботам показывается сложная капча, обычным пользователям — невидимая (invisible mode).

HTML — полная интеграцияhtml
<!-- Antifraud (невидимый, в <head> или перед </body>) -->
<script src="https://pulse.stitex.com/captcha/stitex-antifraud.js"
        data-key="YOUR_API_KEY" async></script>

<!-- Captcha виджет (внутри формы) -->
<form method="POST" action="/submit">
  <input type="text" name="email" placeholder="Email" required />
  <textarea name="message" placeholder="Сообщение" required></textarea>

  <div id="stitex-captcha" data-sitekey="sc_YOUR_SITE_KEY"></div>

  <button type="submit">Отправить</button>
</form>

<script src="https://pulse.stitex.com/captcha/stitex-captcha.js"></script>
Серверная проверка (PHP)php
<?php
// 1. Проверяем Captcha
$token = $_POST['stitex-captcha-token'] ?? '';
$captcha = json_decode(file_get_contents(
  'https://pulse.stitex.com/api/captcha/verify',
  false,
  stream_context_create(['http' => [
    'method'  => 'POST',
    'header'  => 'Content-Type: application/json',
    'content' => json_encode([
      'secretKey'  => 'scs_CAPTCHA_SECRET',
      'solveToken' => $token,
    ]),
  ]])
), true);

if (!$captcha || !$captcha['success']) {
  die('Капча не пройдена');
}

// 2. Проверяем Antifraud (опционально)
$sid = $_COOKIE['stitex_af_sid'] ?? '';
if ($sid) {
  $af = json_decode(file_get_contents(
    'https://pulse.stitex.com/api/antifraud/check',
    false,
    stream_context_create(['http' => [
      'method'  => 'POST',
      'header'  => 'Content-Type: application/json',
      'content' => json_encode([
        'apiKey'    => 'ANTIFRAUD_API_KEY',
        'sessionId' => $sid,
      ]),
    ]])
  ), true);

  if ($af && $af['recommendation'] === 'block') {
    die('Заблокировано антифродом');
  }
}

// Всё ОК — обрабатываем форму

Proof-of-Work (PoW)

PoW используется как дополнительная защита при повторных неудачных попытках решения капчи. Клиент должен найти nonce, при котором SHA-256(challenge + nonce) начинается с заданного количества нулей.

GET/api/captcha/pow

Получить PoW challenge.

Ответ

{
  "challenge": "a1b2c3d4e5f6...",
  "difficulty": 4,
  "prefix": "0000",
  "token": "eyJ...",
  "hint": "Find nonce where SHA-256(challenge+nonce) starts with 0000"
}
POST/api/captcha/pow

Отправить решение PoW.

Тело запроса

challengeобяз.
string
Challenge из GET-ответа
nonceобяз.
string
Найденный nonce
tokenобяз.
string
Токен из GET-ответа

Ответ

{
  "valid": true,
  "powToken": "eyJ..."
}

curl-примеры

curl — получить PoW challengebash
# Получить PoW challenge
curl "https://pulse.stitex.com/api/captcha/pow"

# Ответ:
# {"challenge":"a1b2c3...","difficulty":4,"prefix":"0000",
#  "token":"eyJ...","hint":"Find nonce where SHA-256(challenge+nonce) starts with 0000"}
curl — отправить решениеbash
# Отправить решение PoW
curl -X POST https://pulse.stitex.com/api/captcha/pow \
  -H "Content-Type: application/json" \
  -d '{
    "challenge": "a1b2c3...",
    "nonce": "84721",
    "token": "eyJ..."
  }'

# Ответ:
# {"valid":true,"powToken":"eyJ..."}

JavaScript — решатель PoW

Пример решения PoW в браузереjavascript
async function solveProofOfWork() {
  // 1. Получаем challenge
  const res = await fetch('https://pulse.stitex.com/api/captcha/pow');
  const { challenge, difficulty, token } = await res.json();

  // 2. Brute-force nonce (SHA-256)
  const prefix = '0'.repeat(difficulty);
  let nonce = 0;

  while (true) {
    const input = challenge + nonce;
    const hash = await crypto.subtle.digest(
      'SHA-256',
      new TextEncoder().encode(input)
    );
    const hex = Array.from(new Uint8Array(hash))
      .map(b => b.toString(16).padStart(2, '0'))
      .join('');

    if (hex.startsWith(prefix)) break;
    nonce++;
  }

  // 3. Отправляем решение
  const verify = await fetch('https://pulse.stitex.com/api/captcha/pow', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ challenge, nonce: String(nonce), token }),
  });
  const result = await verify.json();
  return result.powToken; // Используйте вместо solveToken
}

Примечание: Difficulty 4 (4 нуля) означает ~65 000 итераций в среднем. На современном устройстве это занимает 1–3 секунды. Виджет решает PoW автоматически, когда это необходимо.

Rate Limits

Все лимиты применяются per IP через Redis. При превышении возвращается 429 Too Many Requests.

ЭндпоинтМетодЛимитОкно
/api/captchaGET30 запросов1 минута
/api/captchaPOST20 запросов1 минута
/api/captcha/verifyPOSTбез лимита
/api/captcha/powGET30 запросов1 минута
/api/captcha/powPOST20 запросов1 минута
/api/antifraud/collectPOSTбез лимита
/api/antifraud/checkPOSTбез лимита

Заголовки ответа при rate limit

HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1711800090

Коды ошибок

HTTPОписаниеЧто делать
200УспехОбработайте ответ
400Неверные параметрыПроверьте тело запроса и обязательные поля
401Неверный ключПроверьте secretKey (scs_) или apiKey
403Домен не разрешёнДобавьте домен в Dashboard
404Сессия / токен не найденыПроверьте sessionId / solveToken
409Токен уже использованКаждый solveToken одноразовый (replay protection)
429Rate limit превышенПодождите Retry-After секунд
500Внутренняя ошибкаПовторите позже или напишите sti@stitex.com

Формат ошибки

{
  "error": "Token expired or invalid",
  "code": "INVALID_TOKEN"
}

FAQ

Сервис бесплатный?+
Да, полностью бесплатный. Нет ограничений по количеству запросов (кроме rate limits для защиты от злоупотреблений).
Какие типы captcha поддерживаются?+
Математические задачи, текстовые последовательности, визуальные паттерны. Тип и сложность выбираются автоматически на основе fraud score.
Что такое invisible captcha?+
Если antifraud ML-модель оценивает пользователя как доверенного (score < 0.3), капча не показывается — solveToken выдаётся автоматически.
Зачем нужен Proof-of-Work?+
PoW активируется при повторных неудачных попытках решения. Это замедляет brute-force атаки, заставляя клиент тратить вычислительные ресурсы.
Можно ли использовать только Antifraud без Captcha?+
Да, оба сервиса полностью независимы. Подключите только antifraud-виджет и проверяйте score на сервере.
Как токены защищены от replay-атак?+
Каждый токен подписан HMAC-SHA256 с уникальным nonce. После использования nonce сохраняется в Redis и повторное использование блокируется.
Какие данные antifraud отправляет на сервер?+
Только анонимные сигналы: fingerprint (canvas, WebGL, audio), поведение (мышь, клавиатура, скролл), метаданные (UA, экран, timezone). Персональные данные не собираются.
Где хранятся данные?+
Все данные обрабатываются в реальном времени и хранятся во временном Redis-хранилище. Сессии удаляются автоматически.

Нужна помощь с интеграцией?

Напишите нам — поможем настроить за 10 минут.