Коротко
Если пришёл 403, ваш ключ распознан — это хорошая новость. Дело уже не в ключе, а в правах. Читайте поле error в ответе: оно принимает одно из пяти значений, и решение у каждого своё. insufficient_scope — добавить право ключу. tariff_inactive — оплатить тариф. forbidden — ресурс не принадлежит вашей организации. not_sandbox — действие доступно только в песочнице. account_blocked — написать в поддержку.
Никогда не пишите код, ориентируясь только на HTTP-статус. 403 слишком общий, решение — в поле error.
Пять ошибок, пять решений
error | Что произошло | Что делать |
|---|---|---|
insufficient_scope | Ключу не выдано право на это действие | Добавьте нужный scope в кабинете |
tariff_inactive | Тариф неактивен или пробный период закончился | Кабинет → Тариф |
forbidden | Ресурс не виден вашей организации или вашему ключу | Проверьте, к одной ли организации относятся ключ и счёт |
not_sandbox | Действие работает только в песочнице | Например, simulate в боевом режиме недоступен |
account_blocked | Аккаунт заблокирован | Напишите в поддержку |
Если не хватает scope
Scope — метка права, ограничивающая то, что ключ может делать. Их шесть:
| Scope | Что открывает |
|---|---|
invoices:read | Чтение списка счетов и статуса одного счёта |
invoices:write | Создание и отмена счетов |
refunds:write | Возвраты |
subscriptions:manage | Управление подписками |
webhooks:manage | Добавление и изменение адресов вебхуков |
partner:manage | Партнёрские методы |
Самый частый случай: ключ выдан только на чтение, а код пытается создать счёт. Или при возврате не хватает refunds:write — это право намеренно вынесено отдельно, возврат самое опасное действие.
Как добавить: кабинет → Интеграции → открыть ключ и отметить нужное право. Создавать новый ключ не нужно, старый продолжает работать.
Не выдавайте прав больше, чем нужно. Сайту магазина хватает invoices:read и invoices:write. Если ключ утечёт, ущерб ограничится этими правами.
Если тариф неактивен
tariff_inactive приходит в двух случаях: пробный период закончился и тариф не выбран, либо тариф не оплачен. Пробный период начинается с первого боевого счёта, а не со дня регистрации, — поэтому довод «я же только вчера зарегистрировался» здесь не работает, отсчёт идёт от первого live-счёта.
В песочнице этой ошибки не бывает: с ключом qp_test_ работа продолжается, даже если тариф неактивен. Поэтому если в песочнице всё работало, а в боевом режиме пришёл 403, проверять надо в первую очередь именно это.
forbidden: ресурс вам не виден
forbidden означает, что запрошенный счёт существует, но он не ваш. Так бывает в трёх случаях.
1. Ключ от другой организации. Если в аккаунте несколько организаций, у каждой свои ключи. Запрос счёта одной организации ключом другой даёт ровно эту ошибку. К какой организации относится ключ, видно в кабинете.
2. Ключ привязан к конкретному кассиру. Боевые счета привязанного ключа идут только через этого кассира. Счёт, созданный другим кассиром, такому ключу не виден. Чаще в этом случае приходит invoice_not_found (404), иногда forbidden. О работе с несколькими кассирами: Можно ли подключить несколько кассиров.
3. Идентификатор взят из другой среды. Запросить id счёта из песочницы боевым ключом — частая путаница, особенно сразу после перехода с тестов.
Разделить просто: вызовите тем же ключом GET /api/v1/invoices. Пришёл список — ключ рабочий, дело в конкретном счёте. Посмотрите, есть ли в этом списке счёт, который вы ищете.
not_sandbox
Некоторые методы существуют только в песочнице. Самый частый — симуляция оплаты:
# Работает только в песочнице
curl -X POST https://api.qut.kz/api/v1/invoices/INV_ID/simulate \
-H "X-API-Key: qp_test_ВАШ_КЛЮЧ" \
-H "Content-Type: application/json" \
-d '{"status":"paid"}'
Отправьте это боевым ключом — получите not_sandbox. Это защита: счёт, по которому реальные деньги не двигались, нельзя пометить оплаченным.
Если ваши автотесты случайно пошли с боевым ключом, они упрутся именно в эту ошибку. Убедитесь, что в тестовом окружении стоит ключ qp_test_.
Несовпадение организации
Самый запутанный случай — кассир принадлежит вообще другой организации Kaspi. Организация фиксируется при первой привязке: после этого попытка подключить кассира другой организации Kaspi приводит к тому, что счета либо не создаются, либо вам не видны.
Проверяется так: в разделе Kaspi в кабинете посмотрите, какая организация указана на карточке подключения, и совпадает ли она с той, которую вы видите в приложении Kaspi Pay. Если организации разные, подключать нужно кассира правильной организации.
Порядок проверки
- Прочитайте поле
errorв ответе — ориентируйтесь на него, а не на HTTP-код insufficient_scope— добавьте право ключу в кабинетеtariff_inactive— откройте раздел «Тариф»forbidden— запроситеGET /api/v1/invoicesи посмотрите, какие счета видит ключ- Список пуст — ключ от другой организации или привязан к другому кассиру
- Всё выглядит верно: Проблема у вас или у Kaspi
Если не распознаётся сам ключ, придёт не 403, а 401: API отвечает 401.
Вопросы и ответы
Нужно ли менять ключ после добавления scope? Нет. Право вступает в силу сразу, старый ключ продолжает работать.
Имеет ли смысл повторять запрос при 403? Нет. Пока права не изменились, ответ не изменится.
Можно ли отвязать ключ от кассира? Да, привязку можно снять в кабинете. Но пока к кассиру привязан ключ, удалить самого кассира нельзя — сначала снимите привязку.
Заработает ли сразу после оплаты тарифа? Да, как только тариф становится активным, tariff_inactive исчезает.
Почему приходит account_blocked? Это редкий случай, и самостоятельно его не решить. Напишите в поддержку: WhatsApp +7 778 881 3333 или Telegram @qutpaybot.