API v2

Вопросы можно задавать по адресам на странице контактов.

Для использования API v2 клиентам, зарегистрированным до момента ввода новых API, необходимо провести миграцию в личном кабинете - без этого API не примет запросы. Все новые пользователи после указанной даты автоматически подключаются на новую версию. С 27.02.2027 версии v1 будут отключены, а аккаунты автоматически переведены на новую версию. Официально v2 будет запущено около 27.09.2026 - точнее в новостях. Информация в настоящей инструкции в разработке, но основные параметры вполне надежны.

Концепция

Запросы

Только POST-запросы в формате JSON принимаются скриптом. Тело запроса обязано иметь Content-Type application/json.

Недопускаются пустые значения в обязательных параметрах: пустой текст проверки, пустой список словарей или отсутствующий payload будут отклонены с ошибкой 400.

Частота запросов

Частота запросов не имеет ограничений на данный момент, но функционал запланирован. Ориентируйтесь на 5 запросов в секунду. Если нужно снятие ограничений, то рассмотрите вариант размещения функционала на отдельном сервере по индивидуальной договоренности - для этого напишите нам по контактам.

Ошибочные запросы, например, с несуществующим токеном, могут быть приняты 3 раза, затем заблокированы на 1 час.

Лимиты запроса

  • размер тела запроса - не более 100 КБ, включая сам текст проверки;
  • длина токена авторизации - не более 512 символов;
  • длина значения заголовка версии API - не более 10 символов;
  • длина пути эндпоинта - не более 100 символов.

Виды обрабатываемого контента

Данная версия API работает со сплошным текстом в кодировке UTF-8.

URL запроса и точки ендпоинтов

В версии API v2 существует ровно один URL обращения: https://api.statusnick.com/lf/. На него принимаются все запросы ко всем эндпоинтам. Путь конкретного эндпоинта в URL не входит - он передается в теле запроса в ключе endpoint.

Логика API

Основное действие определяется значением ключа [endpoint] в теле запроса. Например, [endpoint]=>text/check определит, что именно нужно сделать, а параметры, переданные внутри [payload], например, [payload]=>[dicts]=>[rus]=>[heavy, expletive] - как именно нужно сделать.

Тело любого запроса к API v2 имеет фиксированную структуру:

  • [endpoint] - строка с путем эндпоинта, только строчные латинские буквы, цифры и знак "/". Например, text/check, finance/balance/get;
  • [payload] - объект с параметрами конкретного эндпоинта. Если нечего передать, отправьте пустой объект {}.

Версия API

В API v2 версия передается заголовком Api-Version и является обязательной. Если заголовок не передан, запрос будет отклонен ошибкой - автоматической подстановки последней версии, как в API v1, здесь нет. Пример:

Markdown
Api-Version: v2

Токен

Токен используется для идентификации пользователя во всех запросах без исключения. В API v2 он передается заголовком Authorization по схеме Bearer - не в теле запроса:

Markdown
Authorization: Bearer PD1k0qeo123j4rJ

Общий пример обращения

Bash
curl -X POST 'https://lf.statusnick.com/api/' \
	-H 'Content-Type: application/json' \
	-H 'Authorization: Bearer PD1k0qeo123j4rJ' \
	-H 'Api-Version: v2' \
	-d '{
		"endpoint": "text/check",
		"payload": {
			"text": "some_text",
			"dicts": {
	      "rus": [
	      	"childhood", 
	      	"expletive", 
	      	"hate", 
	      	"heavy", 
	      	"terrorism", 
	      	"weapons"
	      ]
	    },
	    "modes": [
	    	"tags", 
	    	"patterns", 
	    	// "translit", не работает одновременно с "subst"
	      "subst",
	      "masks",
	      "deep"
	    ]
		}
	}'
Ответы от API

Ответы от сервиса возвращаются в JSON-формате в следующей структуре:

  • [code] - HTTP-код результата. Успешный ответ - 200, ошибки - 4xx и 5xx. HTTP-статус ответа всегда равен этому значению;
  • [details] - короткое описание результата если code != 200, например Token is invalid;
  • [data] - полезные данные ответа. При ошибках ключ может быть пустым массивом.

Пример успешного ответа:

JSON
{
	"code": 403,
	"details": "API not active temporarily", // Только если code != 200 
	"data": {}
}

Коды, которые возвращает v2:

HTTP-кодdetailsОписание
200-Успешно.
400Query data invalidДанные запроса ошибочны.
400API version header is missingНе указан заголовок Api-Version.
400Required parameter missingНе хватает обязательного параметра.
400Text is not specifiedНе передан текст для проверки.
400Text encoding must be UTF-8Текст должен быть в кодировке UTF-8.
400Dictionaries are not specifiedНе указаны словари для проверки.
400Dictionary invalid or unavailableСловарь не существует или недоступен.
400Mode invalid or unavailableРежим (modes) не существует или недоступен.
400Modes list format invalidНеверный формат списка режимов.
400Requested modes are mutually exclusiveЗапрошены взаимоисключающие режимы.
401Token is invalidТокен авторизации ошибочен.
402Balance insufficientНедостаточный баланс пользователя.
403API not active temporarilyAPI временно отключен для обслуживания.
404API version not foundЗапрошенная версия API не существует.
404Endpoint not foundУзел API не найден.
405Method not allowedРазрешён только POST-запрос.
413Content-Length exceed of maxРазмер тела запроса превышает допустимый.
413Text exceeds maximum lengthТекст превышает допустимую длину.
415Content-Type not allowedРазрешён только Content-Type: application/json.
500Internal connection errorВнутренняя ошибка подключения.
500Internal server errorНепредвиденная ошибка сервера.
Таблица кодов ответов

Некоторые проверки работают до запуска эндпоинта и обрывают запрос: отсутствующий или неверный токен, неположительный баланс, пропущенный заголовок версии.

Об отличиях от v1

Источники (source)

В API v1 важной сущностью сервиса LF был источник (source) - хранилище настроек, статистики и отдельного баланса. В API v2 сущность "источник" удалена: баланс теперь единый на аккаунт и состоит из промо-баланса и оплаченного баланса. Соответственно, все узлы source/*, sources/* и операции перемещения средств на источник (balance/move, balance/edit_solo) в этой версии отсутствуют.

Работа с тегами и подготовка текста

В отличие от API v1, HTML-теги здесь не вырезаются автоматически: если передаете разметку, подключите режим tags - он вырежет теги по нашим белым спискам, неизвестные конструкции при этом оставит в тексте и может воспринять за обнаружение. Особенности начертания, стилизованные шрифты вроде 𝕷𝖆𝖓𝖌𝖚𝖆𝖌𝖊 система разбирает всегда (в v1 это был отдельный параметр запроса).

Предпроверка длины текста

В этой версии API предпроверки (precheck) нет.

О стоимости

О стоимости

С версии v2 введена абонентская плата, которая списывается 1 раз в час. Вместе с тем, пересмотрев полностью логику поиска, мы смогли значительно уменьшить время проверки (до х10), потребляемые ресурсы (до х3), а значит и стоимость (до х2-5).

Также изменен порядок ценообразования с фиксированной стоимости на процентную надбавку к стоимости за знак. Вместе с тем, ушла стоимость за каждый язык, тарификация за каждый запрос к API приравнена к нулю, как и некоторые разовые запросы, не связанные с проверкой контента.

При списании сначала расходуется промо-баланс, недостающее берется с оплаченного.

Уход в минус по одной операции допускается, но запрос с неположительным суммарным балансом будет отклонен ошибкой. Держите баланс положительным.

Разработан функционал глобальной и персональной скидок со сроком действия. Пока не подключен. Скидки суммируются, но не могут превышать 100%. Скидки не распространяются на некоторые расходы, например, на абонентскую плату.

Таблица цен: абонентская плата

СтоимостьОписание
0.5 руб.Абонентская плата. Списывается 1 раз в час.

Таблица цен: база расчетная и словари

СтоимостьОписание
0.00001 руб.Стоимость за 1 знак входящего на проверку текста. База расчетная = 1, к ней добавляются коэффициенты.
+0.1Коэффициент процентного типа за каждый словарь.

Таблица цен: режимы (modes) проверки

Стоимость (коэф., тип %)Описание
+0.5deep
+0.1masks
+0.08patterns
+0.05translit
+0.05subst
+0.02tags

Таблица цен: разовые операции

СтоимостьОписание
0.0 руб.обращение к finance/balance/get
0.0 руб.обращение к finance/history/get
0.0 руб.каждый запрос к API

Расчеты приведены в российских рублях. Денежные вычисления ведутся с точностью 5 знаков после запятой.

Оплата за разовые операции может взиматься, поскольку такие запросы или опциональны, или клиент может сам вести учет запросов и расходов, также предоставляется бесплатный доступ к текущему балансу на сайте, одновременно это является блокировкой злоупотреблений.

Пример расчета

Вариант 1: проверим роман "Война и мир".

Этот роман удобно брать для расчета, потому что все его читали и представляют объем произведения.

Входные данные: текст около 3 млн. знаков, один словарь rus heavy, движок по умолчанию. Коэффициент = 1 + 0.1 = 1.1.

  1. Текст: "Война и мир" - 3 млн. знаков * 0.00001 * 1.1 = 33 руб.
  2. Если включили deep, то коэффициент = 1 + 0.1 + 0.5 = 1.6: 3 млн. знаков * 0.00001 * 1.6 = 48 руб.

Другими словами, проверка романа "Война и мир" одним словарем обойдется примерно в 33 рубля, а с глубокой проверкой deep - примерно в 48 рублей. В версии v1 аналогичный расчет давал стоимость 69 руб.

Вариант 2: сообщения из чата

Этот расчет чуть сложнее предыдущего, но даст больше понимания владельцам чатов, сайтов, смс-служб и т.д..

Возьмем по максимуму обороты в условном чате. Будем считать, что длинные сообщения (более 200 знаков) пишут редко, в основном все короткие, вроде "Как дела" или какой-то анекдот в 4-5 строчек. Например, этот абзац длиной примерно 270 знаков. Много ли у вас таких сообщений?

При таком подходе все равно будем считать по искусственно завышенным показателям. Проверка одним словарем rus heavy, коэффициент 1.1. Сразу вычисляем оба варианта - обычный и с глубокой проверкой (коэффициент 1.6).

Входные данные:

  1. Каждую секунду в чате появляется сообщение - в сутки выйдет 86400 сообщений.
    1. 70% сообщений - 200 знаков = 86400 * 0.7 * 200 * 0.00001 * 1.1 = 133 руб.
    2. 30% сообщений - 1000 знаков = 86400 * 0.3 * 1000 * 0.00001 * 1.1 = 285,12 руб.
  2. Итого за сутки при обычной проверке: 418,176 рубля.
  3. Если включить deep (коэффициент 1.6): 86400 * 0.7 * 200 * 0.00001 * 1.6 + 86400 * 0.3 * 1000 * 0.00001 * 1.6 = 193,536 + 414,72 = 608,256 рубля. В версии v1 аналогичный расчет давал стоимость 1067 руб.

По наблюдениям, только 2-5% пользователей чата пишут сообщения, остальные пребывают в пассивном состоянии. Это значит, что для достижения подобных трат в день необходимо, чтобы в вашем чате было - возьмем 10% активных - минимум 864 000 пользователей.

Советы

Ускорение

Используйте keep_alive, если отправляете подряд несколько запросов. Это значительно сокращает время на проверку.

PHP
curl_setopt_array($handle, [
		CURLOPT_URL            => self::URL,
		CURLOPT_POST           => true,
		CURLOPT_RETURNTRANSFER => true,
		CURLOPT_TIMEOUT        => 30,
		CURLOPT_TCP_KEEPALIVE  => 1, // Пример KEEP_ALIVE
		CURLOPT_POSTFIELDS     => json_encode(
				$body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
		),
		CURLOPT_HTTPHEADER     => [
				'Content-Type: application/json',
				'Authorization: Bearer ' . $token,
				'Api-Version: ' . $api_version,
		],
]);

Подключение языков и словарей

Безусловно, можно подключать одновременно несколько языков, словарей и - это полностью зависит от ваших потребностей, однако наблюдения показывают, что бывают пересечения, дающие ложные срабатывания. Например, город Bombey с проверкой через английский язык проходит нормально, но если у вас включен русский, то режимы транслитерации/подмен перевернут слово в Бомбэй (или Бомбий, или Бомбай), чем дадут ложное обнаружение по вхождению "бомб". Однако если слово Бомбей пришло на русском языке, то оно не будет обнаружено. Да, можно было бы прописать для русского языка жесткий список исключений, но так потерялась бы гибкость. К тому же на очереди другие языки и прописывать варианты исключений для каждого ради только русского языка не целесообразно.

Подключение словарей рекомендуем делать во взаимосвязи с проверяемым контентом. Так, например, при подключении словаря childhood, проверка контента для бара/ресторана или из книги ужасов, безусловно, покажет ложные срабатывания. Аналогично с другими словарями, например, на некоторых форумах может быть запрещено выражаться матом, но допустимы бытовые ругательства, тогда обосновано подключить heavy, но не подключать expletive.

Подключение режимов

Режимы в версии v2 глубоко продуманы, но все еще не превзошли человеческую изобретательность. Если взять пример выше про Bombey, то можно снизить вероятность ложного срабатывания при нескольких подключенных языках - достаточно убрать поиск транслита (translit) и подмен (subst). С другой стороны, если вы проверяете сообщения из чатов, где пользователи чаще вуалируют, то отключение данных режимов может пропустить проблемный контент. Тут выбор сводится к тому, что для вашей аудитории вероятнее: Бомбей или завуалированный мат.

Касательно транслитерации и подмен - это два похожих режима, но действуют в разных направлениях. Один отвечает за визуальную схожесть (ы:bI), другой за фонетическую (к:k). Они не могут одновременно работать, потому что разгадывают одно и то же слово, и если один изменил слово, то для второго работы не остается. Эти режимы взаимоисключающие, но вы можете два раза прогнать один текст, переключая их.

Режим mask пользовался популярностью в версии v1. Его назначение в том, чтобы без разбора выявлять попытки малейшего вуалирования без сравнения со словарями. Принцип: если была даже безобидная попытка вуалировать, значит тут что-то не чисто. Принцип сохранили, немного снизили параноидальность и перенесли в v2, но вероятность ложного срабатывания с ним слегка повышается.

Описание API

Название данной версии API: v2 - так нужно прописывать в заголовке Api-Version при обращении к скрипту.

text

Узел, через который происходит проверка вашего текста. Стоимость и результат проверки возвращаются в ответе самого узла text/check, а сам расчет стоимости - прозрачный, он описан в разделе "О cтоимости".

check

Конечный узел, через который принимается текст на проверку, проверяется и выдается результат. Ради него мы все здесь собрались.

JSON
// REQUEST

{
	"endpoint": "text/check",
	"payload": {
		"text": "some_text",
		"dicts": {
			"rus": [
				"heavy",
				"expletive"
			],
			"eng": [
				"heavy"
			]
		},
		"modes": [
			"deep"
		]
	}
}
JSON
// RESPONSE

{
		"code": 200,
    "data": {
        "f": [ // f = found
            {
                "w": "word_1", // w = word
                "p": 0, // p = position
                "l": 6 // l = lenght
            },
            {
                "w": "word_2",
                "p": 6,
                "l": 6
            }
        ],
        "l": 4, // l = total lenght
        "t": 0.0145, // t = work time
        "c": "0.00009" // c = cost
    }
}
ПараметрТипRequirementsОписание
[text]stringОбязательно. UTF-8. Непустая строка.Ваши текстовые данные для проверки. Составные символы Unicode нормализуются перед подсчетом длины, поэтому длина текста на нашей стороне может чуть отличаться от подсчета на вашей стороне. Если текст не в кодировке UTF-8, запрос будет отклонен.
[dicts]objectОбязательно. Непустой объект вида {"<язык>": ["<тип>", ...]}. Только словари из списка доступных.Карта словарей для проверки. Словарь, которого нет в списке доступных, делает запрос ошибочным.
[dicts][rus]arrayОпционально (нужен хотя бы один язык). Доступные типы для русского языка: childhood, expletive, hate, heavy, terrorism, weapons.Типы словарей русского языка.
[dicts][eng]arrayПока отсутствует.Типы словарей английского языка.
[modes]arrayОпционально. Список строк из доступных режимов: deep, tags, patterns, masks, translit, subst. Режимы translit и subst взаимоисключающие.Режимы обработки текста. Описания режимов - ниже.
Таблица запроса
ПараметрТипОписание
[f]arrayМассив найденных вхождений, отсортированный по позиции в тексте.
[f][n][w]stringНайденное слово - фрагмент вашего исходного текста, как оно выглядело в запросе, со стилизованными начертаниями и без изменения регистра.
[f][n][p]integerПозиция начала слова в исходном тексте, в символах, отсчет с нуля. Позиция всегда указывает на реальное место в вашем тексте, даже если слово было найдено после преобразований режимов.
[f][n][l]integerДлина найденного слова в символах исходного текста.
[l]integerДлина проверенного текста в символах, по мнению нашего API. Именно от этой длины считается стоимость.
[t]floatВремя собственно проверки текста в секундах, без учета подготовки ответа, списания и логов.
[c]stringСтоимость данной проверки, в рублях. Формула расчета - ниже и в разделе "Стоимость".
Таблица ответа

Режимы проверки (modes)

Режим - это отдельный проход по тексту, поэтому каждый добавляет свою долю к стоимости. Режим canonical (приведение к канонической форме: разбор стилизованных начертаний и диакритики, снятие регистра, склейка "ё" с "е") применяется всегда и первым: без него словарь и текст не совпадут. Отдельно заказывать его не нужно, в списке режимов его нет и к тарифу он не добавляет ничего.

РежимОписание
tagsОчистка текста от HTML-разметки.
patternsНейтрализация структурных разделителей в легальных шаблонах (email, url, телефоны, габариты, цены).
masksДетектирование вуалирования слов спецсимволами. Повышает вероятность ложного срабатывания, по нашим замерам, на 2%.
translitФонетическая транслитерация текста. Взаимоисключающий с режимом subst.
substНормализация визуальных подмен символов. Взаимоисключающий с режимом translit.
deepПодключает ряд дополнительных внутренних режимов, повышающих качество обнаружения при дополнительных видах вуалирования, например, при задвоении символов, их чередовании со знаками и пробелами.
Таблица режимов

finance

Узел для работы с финансами, например, получение баланса, истории операций.

balance/get

Конечный узел для получения полного состояния баланса аккаунта, включая персональную скидку.

JSON
// REQUEST

{
	"endpoint": "finance/balance/get",
	"payload": {}
}
JSON
// RESPONSE

{
    "code": 200,
    "data": {
        "promo": "100.00000",
        "payed": "200.00000",
        "total": "300.00000",
        "discount": 0,
        "discount_until": "27-02-2027 14:54:25"
    }
}
ПараметрТипRequirementsОписание
---Не имеет специальных параметров. Payload нужно передавать пустым объектом.
Таблица запроса
ПараметрТипОписание
[promo]stringТекущий промо-баланс.
[payed]stringТекущий оплаченный баланс.
[total]stringСуммарный баланс: promo + payed.
[discount]integerПерсональная скидка в процентах.
[discount_until]string/nullДата и время окончания персональной скидки в формате YYYY-MM-DD HH:MM:SS. Просроченная скидка не применяется.
Таблица ответа
history/get

Конечный узел для получения отчета по истории затрат и пополнений за выбранный период. Данные агрегируются по дням. Отчет кэшируется на 10 минут: повторный запрос за тот же период в этот интервал вернет готовые данные без пересчета. Максимум 1 месяц (31 день).

JSON
// REQUEST

{
	"endpoint": "finance/history/get",
	"payload": {
		"from": "2027-01-01",
		"to": "2027-01-31"
	}
}
JSON
// RESPONSE

{
    "code": 200,
    "data": {
        "2026-09-15": {
            "decrease": {
                "text/check": "0.66183",
                "balance/get": "0.30000",
                "finance/balance/get": "0.20000",
                "subs": "0.50000"
            },
            "increase": {
                "yoomoney": "100.00000"
            }
        }
    }
}
ПараметрТипRequirementsОписание
[from]stringОбязательно. Дата в формате YYYY-MM-DD.Начало периода отчета.
[to]stringОбязательно. Дата в формате YYYY-MM-DD.Конец периода отчета.
Таблица запроса
ПараметрТипОписание
[YYYY-MM-DD]objectКлюч - дня операций. Дни без операций в ответ не включаются.
[YYYY-MM-DD][decrease]objectСуммы списаний за день, сгруппированные по типу расхода, например text/check, значение - сумма строкой.
[YYYY-MM-DD][increase]objectСуммы пополнений за день, сгруппированные по основанию операции.
Таблица ответа