Коротко
Возврат делается через POST /api/v1/invoices/{id}/refund с телом { amount?, reason? }. Если пришла ошибка, смотрите в первую очередь на код error — от него зависит, что делать дальше. Главное правило: при refund_unknown и refund_pending_unknown запрос повторять нельзя. Эти два кода означают «результат пока неизвестен», и повтор может вернуть деньги дважды. Вместо повтора прочитайте статус счёта и узнайте из него, что произошло на самом деле.
По кодам ошибок
| Код | HTTP | Что случилось | Что делать |
|---|---|---|---|
invoice_not_refundable | 409 | По этому счёту возврат невозможен | Прочитайте статус: оплачен ли счёт, не вышел ли срок |
invalid_refund_amount | 422 | Неверная сумма | Положительное число, не больше оплаченной суммы |
refund_failed | 502 | Kaspi не выполнил возврат | Проверьте, хватает ли денег на счёте Kaspi |
refund_unknown | 502 | Kaspi не ответил, результат неизвестен | Не повторять. Прочитайте статус счёта |
refund_pending_unknown | 409 | Результат предыдущего возврата ещё не ясен | Не повторять. Подождите |
refund_state_conflict | 409 | Состояние возврата не то, которого ждали | Перечитайте статус счёта и решайте по нему |
invoice_not_found | 404 | Счёта нет или он вам не виден | Проверьте идентификатор и кассира, к которому привязан ключ |
Три самые частые причины
1. Счёт не подлежит возврату. Возврат делается только по оплаченному счёту. По pending, expired и cancelled возвращать нечего — на них приходит invoice_not_refundable. Полностью возвращённый счёт второй раз тоже не вернуть.
Сначала прочитайте статус через GET /api/v1/invoices/{id}: возврат возможен, только если это paid или partially_refunded.
2. На счёте Kaspi не хватает денег. Это самая частая причина ошибки refund_failed. Деньги на возврат уходят с вашего счёта Kaspi, а не от нас — мы деньги никогда не держим. Если остатка не хватает, Kaspi операцию не выполняет.
Решение простое: проверьте остаток на счёте Kaspi, пополните при необходимости и повторите возврат. refund_failed — одна из немногих ошибок, которую повторять можно, потому что она прямо говорит «не выполнено».
3. Привязка кассира неактивна. Возврат тоже идёт через роль «Кассир» в Kaspi. Если привязка оборвалась, не пройдёт ни возврат, ни создание счёта. Восстановите её в разделе Kaspi.
К тому же кассир может возвращать только по своим счетам. Если API-ключ привязан к конкретному кассиру, счёт другого кассира он вообще не видит — вам придёт invoice_not_found.
Если результат неизвестен
refund_unknown — Kaspi не ответил на запрос. Прошёл возврат или нет, не знаем и мы. refund_pending_unknown — результат предыдущего возврата ещё не определён, и новый запрос не принимается.
В обоих случаях порядок одинаковый:
- Не повторяйте запрос. Гарантии идемпотентности здесь нет: второй запрос может стать вторым возвратом.
- Подождите несколько секунд, при необходимости минуту.
- Прочитайте статус счёта:
GET /api/v1/invoices/{id}. В ответе видны возвраты по этому счёту. - Если статус стал
refundedилиpartially_refunded— возврат прошёл, повторять не нужно. - Если статус всё ещё
paid, а список возвратов пуст — только тогда повторяйте.
И не сообщайте покупателю «деньги вернули», пока не увидели это в статусе счёта.
Частичный возврат
Если указать поле amount, вернётся только указанная сумма, а счёт перейдёт в статус partially_refunded. Без amount возврат будет полным.
- Сумма не может превышать оплаченную, иначе
invalid_refund_amount - При нескольких частичных возвратах их сумма тоже не должна превышать оплаченную
- Поле
reasonстоит заполнять: потом в отчёте будет видно, за что возвращали
После успешного возврата приходит событие invoice.refunded или invoice.partially_refunded. Если ведёте автоматический учёт, удобнее опираться на эти события, чем опрашивать статус.
Срок
Возврат возможен не бессрочно: спустя определённое время Kaspi перестаёт разрешать возврат по старой операции. Срок задаёт Kaspi, продлить его мы не можем. По просроченному счёту приходит invoice_not_refundable.
Поэтому не затягивайте решение о возврате, особенно если покупатель спорит.
Частые ошибки
- Обрабатывать ошибку по тексту
message. Текст может измениться, кодerror— нет. - Включать автоматический повтор при любой ошибке. В возвратах это опасно.
- Отвечать покупателю, не проверив статус счёта.
- Писать боевой возврат, не проверив его в песочнице. В песочнице весь цикл прогоняется безопасно.
Вопросы и ответы
Когда деньги дойдут до покупателя? Это определяет Kaspi, на сроки мы повлиять не можем.
Можно ли отменить возврат? Нет. Прошедший возврат обратно не откатывается — придётся просить покупателя оплатить заново.
Возвращается ли комиссия? Свою комиссию Kaspi определяет сам, уточняйте в поддержке Kaspi. Мы процент с транзакции не берём, поэтому с нашей стороны возвращать нечего.
Какое право нужно ключу? refunds:write. Если права нет, придёт insufficient_scope.
Что будет, если вернуть дважды? Деньги уйдут дважды, и откатить это нельзя. Поэтому при ошибках с неизвестным результатом никогда не повторяйте запрос: принципы защиты из статьи Счета дублируются относятся и к возвратам.