Коды ошибок и ответов
Discuse API сообщает о проблемах двумя способами: HTTP-статусом ошибки с message или обычным ответом 200, поля которого объясняют, что произошло. На этой странице перечислены все случаи, чтобы вы могли корректно их обрабатывать, а также разобран момент, который часто сбивает с толку: исчерпание биллинговой квоты не является HTTP-ошибкой.
Какие HTTP-статусы возвращает API?
| Status | When | What to do |
|---|---|---|
200 |
Успех — включая случай «квота исчерпана» | Проверьте тело ответа; 200 не всегда означает, что всё в порядке (см. ниже) |
400 |
Запрос не прошёл валидацию — пустое содержимое, text длиннее 10 000 символов или слишком много URL медиафайлов |
Исправьте запрос; не повторяйте его без изменений |
401 |
API-ключ отсутствует или недействителен | Проверьте заголовок X-API-Key; не повторяйте запрос без изменений |
429 |
Превышен лимит запросов для ключа | Сделайте паузу и повторите запрос после минутного окна |
500 |
Внутренняя ошибка или ошибка нижележащего сервиса | Повторите запрос с задержкой |
Читайте message в любом ответе не из диапазона 2xx. Ошибки аутентификации возвращают 401, превышение лимита запросов — 429, а ошибки валидации запроса — 400; 5xx считайте временной ошибкой и повторяйте запрос с задержкой.
Почему «квота исчерпана» — это 200, а не ошибка?
Когда проект исчерпывает месячный лимит API-запросов, POST /api/v2/check всё равно возвращает 200 — при этом содержимое считается не имеющим нарушений, message объясняет, что квота исчерпана, а объект usage показывает, что оставшихся запросов нет:
{
"has_violations": false,
"message": "API quota exceeded. Current: 10000, Limit: 10000",
"usage": {
"api_requests_used": 10000,
"api_requests_limit": 10000,
"api_requests_remaining": 0
}
}
Это сделано намеренно: исчерпание квоты не должно выглядеть как сбой сервера или прерывать ваш пайплайн исключением. Проверяйте usage.api_requests_remaining (и message), а не полагайтесь только на код статуса. Если при 200 вы автоматически пропускаете содержимое дальше, исчерпанная квота незаметно позволит непроверенному контенту пройти — поэтому явно ветвите логику по этим полям.
Как читать успешный ответ?
Ответ 200 от /api/v2/check всегда содержит has_violations и cached; остальные поля необязательны:
| Field | Type | Meaning |
|---|---|---|
has_violations |
boolean | True, если хотя бы одна включённая проверка пометила содержимое |
cached |
boolean | True, если ответ взят из кеша недавнего идентичного запроса |
message |
string | Присутствует при исчерпании квоты (и в похожих уведомлениях, не являющихся ошибками) |
request_id |
string | Возвращается обратно, если вы его отправили |
processing_time_ms |
number | Присутствует, если для проекта включено измерение времени |
usage |
object | api_requests_used, api_requests_limit, api_requests_remaining |
results |
object | Детализация по проверкам (spamfinder, sentiment, images, …) и флаг верхнего уровня hits |
Принимайте общее решение по has_violations, а затем смотрите results.<check>.hit, чтобы понять, какая именно проверка сработала.
Как кеширование влияет на ответы?
Идентичные запросы в рамках одного проекта дедуплицируются: повторный запрос возвращает cached: true с тем же результатом. Кеширование работает отдельно для каждого проекта. Обратите внимание: кешированный запрос всё равно учитывается в вашей квоте API-запросов — он экономит время обработки, а не квоту.
Вы можете добавить к запросу request_id для собственной корреляции; он будет возвращён обратно в ответе.
Минимальный корректный клиент
async function check(content, settings) {
const response = await fetch('https://api.discuse.com/api/v2/check', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.DISCUSE_API_KEY
},
body: JSON.stringify({ content, settings })
});
// 400: bad request — fix it, don't retry. 5xx: transient/auth/rate-limit — retry with backoff.
if (response.status === 400) {
throw new Error('Invalid request: ' + (await response.text()));
}
if (!response.ok) {
throw new Error(`Discuse error ${response.status}`); // retry upstream with backoff
}
const data = await response.json();
// Quota exhausted is a 200 — never treat it as "checked and clean".
if (data.usage && data.usage.api_requests_remaining === 0 && data.message) {
throw new Error('Quota exhausted: ' + data.message);
}
return data; // inspect data.has_violations and data.results
}
См. также
- Аутентификация и API-ключи — ключи, заголовок
X-API-Keyи лимиты запросов - Краткое руководство по началу работы — ваш первый запрос за несколько минут
- Анализ текста — подробное описание объекта
results