# Сумма неверная или теряются тиыны

> Счёт по телефону принимает только целые тенге, QR-счёт — не более двух знаков после запятой. Откуда берётся ошибка amount_must_be_whole_tenge и как правильно округлять на своей стороне.

## Коротко

Всё объясняют два правила. **Счёт по телефону (`kind: "phone"`) принимает только целые тенге** — отправите тиыны, получите ошибку `amount_must_be_whole_tenge`. **QR-счёт принимает не более двух знаков после запятой.** Валюта всегда KZT, другой нет.

Отсюда следует: округлять нужно **на своей стороне**, до создания счёта. Тогда вы сами знаете, какая сумма посчитана, и можете показать её покупателю. Если оставить округление нам, сумма в вашей базе и реально оплаченная сумма могут разойтись.

## Причина по симптому

| Симптом | Причина | Решение |
|---|---|---|
| `amount_must_be_whole_tenge` | В счёт по телефону отправлены тиыны | Округлите до целых тенге |
| `invalid_amount` | Сумма отсутствует, равна нулю, отрицательна или не число | Передайте положительное число |
| `amount_too_small` | Меньше минимума | Увеличьте сумму |
| `amount_too_large` | Больше максимума | Уменьшите или разбейте на несколько счетов |
| Покупатель видит другую сумму | Сумма отправлена строкой, разделитель разобран неверно | Передавайте числом |
| Потерялись тиыны | QR принимает два знака, остальное отсекается | Округляйте у себя |

## Как передаётся сумма

Поле `amount` — **число** в тенге. Не в тиынах: чтобы выставить 1 000 ₸, пишете `1000`, а не `100000`.

```bash
curl -X POST https://api.qut.kz/api/v1/invoices \
  -H "X-API-Key: qp_live_ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{"amount":1000,"kind":"qr","description":"Заказ №1042"}'
```

Счёт по телефону:

```bash
curl -X POST https://api.qut.kz/api/v1/invoices \
  -H "X-API-Key: qp_live_ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{"amount":1000,"kind":"phone","customer":{"phone":"77771234567"},"description":"Заказ №1042"}'
```

Отправите здесь `1000.50` — вернётся `amount_must_be_whole_tenge`.

## Округляйте на своей стороне

Самая частая картина: в корзине `3 333,33 ₸`, а покупатель платит `3 333 ₸`. Разница копеечная, но при сверке в конце месяца она вся вылезет наружу.

Стройте порядок так:

```js
// 1. Округляем сумму у себя
const total = Math.round(cart.total);   // 3333.33 → 3333

// 2. Записываем именно её в свою базу
await orders.update(orderId, { chargedAmount: total });

// 3. Отправляем ровно эту же сумму
await createInvoice({ amount: total, kind: 'phone', ... });
```

Три принципа:

- **Одна точка округления.** Если округлять в разных местах расчёта, погрешность накапливается.
- **Записывайте округлённую сумму в базу.** При сверке будет ясно, какая сумма настоящая.
- **Показывайте покупателю ту же сумму.** Одна сумма в корзине и другая в счёте — это вопросы от покупателей.

`Math.round` округляет вверх на `0.5`. Если вы хотите всегда вниз, используйте `Math.floor` — но выбранное правило должно быть одним для всей системы.

## Работа с сотыми долями

Если в вашей системе цены хранятся в тиынах (например `333333` = 3 333,33 ₸), делайте перевод в одном месте:

```js
const tenge = Math.round(priceInTiyn / 100);
```

Осторожнее с числами с плавающей точкой: `0.1 + 0.2` во многих языках даёт `0.30000000000000004`. Надёжнее хранить цены целыми числами (в тиынах) и переводить в тенге только на последнем шаге.

## Разница между двумя типами счёта

| Что | QR-счёт (`qr`) | Счёт по телефону (`phone`) |
|---|---|---|
| Сумма | Не более 2 знаков после запятой | Только целые тенге |
| Описание | До 100 символов | До 60 символов |
| Номер покупателя | Не нужен | Обязателен, `7XXXXXXXXXX` |
| Как выглядит | QR, ссылка, deep link | Уведомление в Kaspi покупателя |

На практике удобнее отправлять целые тенге в обоих случаях: тогда при смене типа счёта логику переписывать не придётся.

## Ограничения по сумме

Минимум и максимум существуют, и ограничивает их не только наша сторона, но и Kaspi. При выходе за границы придёт `amount_too_small` или `amount_too_large`.

Если вы работаете с крупными суммами (например, опт), учтите две вещи:

- Разбить сумму на несколько счетов — рабочий приём, но каждый счёт придётся отслеживать отдельно
- На стороне покупателя тоже могут быть свои лимиты, это настройка Kaspi

Кроме того, `amount_too_large` нередко приходит из-за ошибки в коде: переменная передана в тиынах, и сумма выросла в сто раз. Такое число обычно видно невооружённым глазом.

## Валюта

Валюта только **KZT**. Отправить другую нельзя, поля `currency` искать не нужно.

Если сайт показывает цены в нескольких валютах, пересчёт делайте у себя, до создания счёта. В Kaspi покупатель всегда платит в тенге.

## Порядок проверки

1. Прочитайте текст ошибки: `amount_must_be_whole_tenge` или `invalid_amount`
2. Проверьте тип отправляемого значения: число или строка
3. Для счёта по телефону — посмотрите, нет ли тиынов
4. Сверьте сумму в своей базе и отправленную сумму
5. Убедитесь, что округление в коде происходит в одном месте

Если сумма верна, а денег не видно, дело в другом: [Счёт оплачен, а денег нет](/kb/ru/money-not-received).

## Вопросы и ответы

**Можно ли отправлять тиыны в QR-счёт?** До двух знаков после запятой — можно. Но на практике целые тенге проще и безопаснее.

**Может ли покупатель сам изменить сумму?** В обычном счёте нет, сумма зафиксирована. В ссылке с открытой суммой покупатель вводит её сам.

**Что будет, если отправить сумму строкой?** В одних случаях она примется, в других вернётся `invalid_amount`. Всегда передавайте числом.

**Кто платит разницу при округлении?** Это ваше решение. Многие округляют вниз и берут несколько тиынов на себя — объясняться с покупателем сложнее.

**Счёт уже создан, можно ли изменить сумму?** Нет. Нужно отменить счёт и создать новый.
