Коды ошибок и ограничения
Что вернёт API, когда баллов не хватает, карта не найдена или ключ отозван. Разбирайте код, а не текст сообщения.
Ошибка API — это всегда JSON одного вида: машинный код, человеческий текст и, где есть что добавить, details. Разбирайте code: текст сообщения может измениться, код — нет.
Любая ошибка
{
"error": {
"code": "REDEEM_LIMIT_EXCEEDED",
"message": "Превышен лимит списания баллов",
"details": { "maxAllowed": 425, "requested": 500 }
}
}Общие
| Код | HTTP | Что случилось |
|---|---|---|
VALIDATION_ERROR | 400 | Запрос не прошёл проверку. Если виновато поле — в details.fields имя поля и что с ним не так. Сюда же: нет заголовка Idempotency-Key, не похоже на номер телефона, неверный код подтверждения, несколько программ без programId |
UNAUTHORIZED | 401 | Ключ не передан, недействителен или отозван |
FORBIDDEN | 403 | Ключу не хватает области доступа — недостающие названы в тексте. Или компания приостановлена платформой: ключ работает снова, только когда приостановку снимут |
NOT_FOUND | 404 | Объекта нет — или он принадлежит другой компании: чек для возврата, карта в истории, программа, сотрудник в staffId. Сюда же попадает чек с чужой или выдуманной точкой продаж: на ней держатся и правила, и выручка в отчётах |
CONFLICT | 409 | Запись с такими данными уже существует — в details.fields названы поля |
RATE_LIMITED | 429 | Слишком много запросов. В details.retryAfterSec — через сколько секунд повторить |
Лояльность
| Код | HTTP | Что случилось |
|---|---|---|
CARD_NOT_FOUND | 404 | Карты с таким штрихкодом нет, у гостя с таким телефоном нет действующей карты, или вместо номера пришла строка, на номер не похожая |
CARD_BLOCKED | 409 | Карта не действует — заблокирована или удалена по просьбе гостя. Операции по ней запрещены |
REDEEM_LIMIT_EXCEEDED | 409 | Списание больше потолка: доли чека по правилам (в том числе правилам этой точки) или баланса карты. В details.maxAllowed — сколько было можно, в details.requested — сколько просили |
INSUFFICIENT_POINTS | 409 | На карте меньше баллов, чем просят списать; details.available и details.requested. В POST /transactions вместо него приходит REDEEM_LIMIT_EXCEEDED: потолок не бывает выше баланса |
COUPON_NOT_FOUND | 404 | Кода купона нет или купон выдан другому гостю; код — в details.code |
COUPON_UNUSABLE | 409 | Купон есть, но погасить его нельзя: погашен, отозван, ещё не начал действовать, срок вышел, гость уже пользовался промокодом. Причина — в details.reason, её можно повторить гостю |
PROGRAM_INACTIVE | 409 | Программа выключена — чеки по ней не проводятся, карты не выдаются |
OPERATOR_NOT_NAMED | 409 | Заведение не указало в кабинете юридическое название и ИНН — карты не выдаются, пока оно не назовёт себя оператором персональных данных |
CARDS_LIMIT_REACHED | 409 | Исчерпан лимит карт по тарифу — новые карты не выдаются и коды новым гостям не отправляются. Уже выданные карты работают |
CODE_QUOTA_EXCEEDED | 429 | Квота подтверждений заведения перебрана втрое — коды не отправляются |
TRANSACTION_ALREADY_REFUNDED | 409 | Этот чек уже возвращён целиком; details.transactionId |
IDEMPOTENCY_KEY_REUSED | 422 | Тот же Idempotency-Key прислан с другим телом запроса |
Инфраструктура
| Код | HTTP | Что случилось |
|---|---|---|
INTERNAL_ERROR | 500 | Ошибка на нашей стороне. Повторить можно, но не сразу |
SERVICE_UNAVAILABLE | 503 | Сервис перегружен или недоступен. В details.retryAfterSec — через сколько секунд повторить |
Остальные коды — CAPTCHA_REQUIRED, EMAIL_NOT_VERIFIED, TENANT_ACCESS_REVOKED, PROMO_INVALID, PASS_NOT_FOUND — отдают страница выдачи карты, кабинет и страница гостя; запросам по ключу API они не приходят. CAPTCHA_REQUIRED увидит и тот, кто берёт песочницу.
Ограничения
| Что | Предел | Что будет сверх |
|---|---|---|
| Все запросы к API с одного IP-адреса | 300 в минуту | Отказ до конца минуты. Предел общий для всех ключей и методов, включая чтение карт и возвраты: касса за общим адресом делит его с соседями. Остаток — в заголовках x-ratelimit-remaining и x-ratelimit-reset, после отказа — Retry-After |
| Коды подтверждения на один номер | Не чаще раза в минуту | Не ошибка: POST /customers/phone-code отвечает sent: false и retryAfterSec |
| Коды на один номер за сутки | Пять платных (Telegram, звонок, SMS) и пять писем | Исчерпаны платные — остаётся только письмо; исчерпано и оно — RATE_LIMITED |
| Попытки ввести код | Пять, код живёт пять минут | VALIDATION_ERROR — запросите новый код |
| Квота подтверждений заведения | По тарифу, в месяц и в сутки | Сверх квоты платные каналы закрываются, письмо остаётся; сверх тройной — CODE_QUOTA_EXCEEDED |
| Idempotency-Key | Уникален в компании; тело сверяется сутки | Другое тело в первые сутки — IDEMPOTENCY_KEY_REUSED; повтор всегда отдаёт уже проведённый чек |
| Чек | Сумма до 10 000 000 ₽, до 500 позиций | VALIDATION_ERROR |
Пределы на номер и квоту подтверждений держат не ради нас, а ради заведения: платные каналы оплачиваются из его квоты и пакета, и перебор чужих номеров через вашу интеграцию тратил бы его деньги. Предела по адресу и проверки «я не робот» у запросов по ключу нет — адрес принадлежит вашему серверу, а не гостю.
RATE_LIMITED— сбавьте темп и повторите не раньшеdetails.retryAfterSec; у общего предела по адресу то же число приходит и в заголовкеRetry-After. Разумная стратегия — удвоение задержки.- Песочница ограничена отдельно: три выдачи в сутки с адреса, 30 в час и 500 живых на всю платформу — см. её страницу.
Что смотреть при разборе
- Журнал действий в кабинете — что менялось и кто это сделал.
- «Выпущенные ключи» на вкладке «Интеграции» — когда ключом пользовались последний раз и чей адрес пришёл в
User-Agent. - «Доставки» у адреса на вкладке «Вебхуки» — код ответа вашего сервера или ошибка, число попыток и время следующей.
- История карты —
GET /cards/:id/history: движение баллов, включая сгорание и ручные правки. - status.snovacard.ru — состояние сервисов, если ошибки пошли разом и у всех.
Частые вопросы
Чем отличается 404 «карты нет» от 404 «чужая компания»?
Ничем, и это намеренно: ответ «объект есть, но не ваш» сообщал бы посторонним факт существования карты. Изоляция компаний проверяется на уровне базы, а не кода, поэтому чужая строка просто не видна.
Стоит ли разбирать текст сообщения?
Нет. Текст пишется для человека и может измениться в любой момент — например, стать понятнее. Машинный контракт — это поле code и поля details.
Как отличить временную ошибку от постоянной?
По HTTP-статусу: 5xx — наша сторона, повтор оправдан; 4xx — запрос нужно исправить, повтор ничего не изменит. Исключение — 429: он временный, но требует паузы, а не немедленного повтора.
Первые 20 карт — бесплатно. Программа настраивается за вечер.
Создать программу
Снова