> Источник: https://apipay.kz/guides/oshibka-422-cart-items · Обновлено: 2026-10-06 · apipay.kz
> ApiPay — независимый сервис приёма платежей поверх вашего Kaspi Pay.

# Ошибка 422 cart_items — как исправить счёт с корзиной?

**TL;DR.** `422 This organization requires cart items` (`error_code: catalog_requires_cart_items`) — у организации в ApiPay подключён каталог (Каспи ОФД), а запрос ушёл на `POST /invoices/qr` или `POST /static-qr`: на этих путях счёт принимается только с корзиной (`cart_items[]` из `catalog_item_id` + `count`). Счёт по номеру (`POST /invoices`) такая организация выставляет и одной суммой. `422 Catalog item has no price set` — у позиции каталога пуста `selling_price`: проставьте цену в каталоге, везде, кроме `POST /invoices`, передача `price` в строке эту ошибку не снимает. `422 qr_discount_unsupported` — скидку на QR к этой корзине применить нельзя: цена позиции в тиынах или скидка обнуляет позицию.

## Сначала проверьте

1. **Полный текст ошибки под рукой?** Диагностика идёт по точной строке из JSON-ответа — «не работает» без текста не диагностируется.
2. **У организации есть каталог (Каспи ОФД)?** Если в кабинете есть каталог — он и есть Каспи ОФД: QR-счёт и статический QR у такой организации создаются только с корзиной; счёт по номеру проходит и одной суммой.
3. **Песочница или прод?** Проверка «каталог ↔ корзина» работает одинаково в обоих режимах; отличие одно — в песочнице флаг каталога организации можно выключить самому, в рабочем режиме он определяется тем, есть ли у организации Kaspi Касса, — «[Переход на каталог товаров](/guides/perehod-na-katalog-tovarov)».

## Ветки диагностики

| Текст ошибки | Причина | Что сделать | Подробнее |
|---|---|---|---|
| `422 This organization requires cart items` (`catalog_requires_cart_items`) | Подключён каталог (Каспи ОФД), а запрос ушёл на `POST /invoices/qr` или `POST /static-qr` — там счёт принимается только с корзиной | Передавать `cart_items[]`: каждый элемент — `catalog_item_id` + `count` | «Как выглядит правильный запрос с корзиной?» в «[Счетах с корзиной](/guides/scheta-s-korzinoy-cart-items-ofd)» |
| `Catalog item has no price set` | `selling_price` позиции в каталоге пуста | Задать цену позиции в каталоге — это снимает ошибку на любом пути. Поле `price` в строке корзины заменяет пустую каталожную цену только на `POST /invoices`, на остальных путях — нет | «Разбор 422-ошибок по строкам корзины» в «[Счетах с корзиной](/guides/scheta-s-korzinoy-cart-items-ofd)» |
| Итог счёта ≠ переданной сумме | Сумма считается по позициям корзины, а не по вашему `amount` | Передавать нужную цену полем `price` в строке `cart_items` | [Счета с корзиной](/guides/scheta-s-korzinoy-cart-items-ofd) |
| `Total discount cannot exceed subtotal.` / `Amount after discounts must be greater than 0.` | Скидка съедает всю сумму корзины | Уменьшить `discount_percentage` либо поднять цены строк | «Скидка и переопределённая цена» ниже |
| `422 qr_discount_unsupported` | Скидка на QR-счёте или статическом QR: цена позиции в тиынах или скидка обнуляет позицию | Цены в целых тенге; позицию, которую скидка обнуляет, — дороже или без скидки. Либо счёт по номеру телефона, если итог после скидки выходит в целых тенге | «Скидка на QR-счёте» ниже |
| `422`, ключ `discount_percentage` в `errors{}` на QR-счёте | Процент скидки дробный, а на QR он только целый | Передать целый процент от 1 до 99 | «Скидка на QR-счёте» ниже |
| `Organization has no tradepoint RFO code configured` (`400`) | Код торговой точки Kaspi не определён. Приходит не на создании счёта, а на операциях с каталогом | Написать в поддержку. Причину также видно в поле `catalog_block_reason` ответа `POST /api/v1/connections/{id}/auth/verify-otp` — значение `no_tradepoint` | — |

У отказов «каталог ↔ корзина» есть `error_code` (`catalog_requires_cart_items`, `catalog_not_supported`) — ветвитесь по нему. Ошибки отдельных строк корзины приходят текстом в `errors["cart_items.N.catalog_item_id"]`. Поля корзины и коды отказов — в документации API: [QR-счёт](/docs#invoices-qr), [статический QR](/docs#static-qr-create).

## Скидка и переопределённая цена

`discount_percentage` считается на нашей стороне от **фактической** цены строки: если вы передали `price`, скидка берётся именно от него, и в Kaspi уходит уже посчитанная сумма скидки по каждой позиции. Сочетать `price` и `discount_percentage` **можно**.

На счёте по номеру телефона счёт со скидкой отбивают две проверки:

- `Total discount cannot exceed subtotal.` — суммарная скидка больше суммы позиций.
- `Amount after discounts must be greater than 0.` — итог после скидок ≤ 0.

Оба ответа — `422`, ключ `discount` или `amount` в `errors{}`. Можно пересчитать скидку у себя и слать уже уценённые цены без `discount_percentage` — итог по деньгам тот же, но покупатель не увидит скидку отдельной строкой в чеке, а в вебхуке не придут `subtotal` и `discount_sum` для сверки.

## Скидка на QR-счёте

На QR-счёте (`POST /invoices/qr`, в том числе со `static: true`) и статическом QR (`POST /static-qr`) скидку считают по правилу Kaspi: процент только целый, а скидка каждой строки округляется вверх до целого тенге. Правило и примеры расчёта — «Как считается скидка на QR-счёте?» в «[Счетах с корзиной](/guides/scheta-s-korzinoy-cart-items-ofd)».

Дробный процент (`7.5`) на QR отбивается `422` с ключом `discount_percentage` в `errors{}` — передайте целый процент от 1 до 99. Счёт по номеру телефона дробный процент принимает.

`422 qr_discount_unsupported` значит, что скидку на QR к этой корзине применить нельзя. Счёт не создаётся, причина приходит текстом в `errors.discount_percentage`. Ветвитесь по `error_code`, а не по тексту. Причин две:

- **Цена позиции задана в тиынах** — в `cart_items[].price` или в каталоге. Задайте цены в целых тенге.
- **Скидка обнуляет позицию.** У позиции за 1 ₸ скидка 10 % после округления — тоже 1 ₸. Поднимите цену позиции или уберите скидку.

В песочнице эти проверки действуют так же. Если скидка на такую корзину всё же нужна, выставьте счёт по номеру телефона (`POST /invoices`): там итог после скидки должен выйти в целых тенге, иначе `422 amount_must_be_whole_tenge`.

## Пустая цена позиции

`has no price set` возникает, когда `selling_price` позиции **пуста** (типично для товаров, приехавших синхронизацией из Kaspi, — там цену вводят на кассе). Проставьте цену в кабинете или через `PATCH /catalog/{id}` — минимум `0.01`, нулевую цену API не примет.

## Частые вопросы

**Обязательно заводить все товары в каталог?**
Позиции — да, но цены можно переопределять в каждом счёте полем `price`. Минимальный вариант — несколько «служебных» позиций с реальными ценами; в чек ОФД идёт именно название позиции из каталога.

**Можно ли дать на QR-счёте скидку 7,5 %?**
Нет: на QR-счёте и статическом QR процент скидки только целый, дробный отбивается `422` с ключом `discount_percentage`. Дробный процент принимает счёт по номеру телефона.

---

ApiPay — независимый сервис и не аффилирован с АО «Kaspi Bank». Kaspi и Kaspi Pay — товарные знаки их правообладателя.
База знаний: https://apipay.kz/guides
