# Приём Kaspi для интернет-магазина

> Полная схема от корзины до статуса «оплачен»: счёт, страница оплаты, вебхук. Способы без кода для Tilda, WooCommerce и OpenCart, и путь через API для самописного сайта.

## Коротко

Для интернет-магазина порядок всегда один: покупатель оформляет корзину → ваш сайт создаёт счёт в Qut Pay → покупатель сканирует QR или открывает ссылку на оплату → подтверждает в Kaspi → к вам приходит вебхук → заказ становится «оплачен». Для WooCommerce и OpenCart 4 есть готовые модули, Tilda и любая другая форма подключается через форма-хук, а самописному сайту хватает одного метода API.

## Как это работает

| Шаг | Кто делает | Что происходит |
|---|---|---|
| 1 | Покупатель | Оформляет корзину, выбирает оплату через Kaspi |
| 2 | Ваш сервер | `POST /api/v1/invoices` — создаёт счёт, в `externalOrderId` кладёт номер заказа |
| 3 | Ваш сервер | Берёт из ответа `payUrl` или `qrImageUrl` и показывает покупателю |
| 4 | Покупатель | Подтверждает оплату в приложении Kaspi |
| 5 | Qut Pay | Отправляет на ваш адрес событие `invoice.paid` |
| 6 | Ваш сервер | Переводит заказ в «оплачен», отправляет письмо покупателю |

Деньги приходят напрямую на ваш счёт в Kaspi, у нас они не задерживаются. Подробнее: [Когда и куда приходят деньги](/kb/ru/money-arrival).

## Какой метод API используется

Основной всего один — создание счёта:

```
POST https://api.qut.kz/api/v1/invoices
X-API-Key: qp_live_…
Idempotency-Key: order-10482
Content-Type: application/json

{
  "amount": 24900,
  "kind": "qr",
  "description": "Заказ №10482",
  "externalOrderId": "10482",
  "successUrl": "https://moymagazin.kz/thanks?order=10482",
  "failUrl": "https://moymagazin.kz/cart",
  "metadata": { "source": "site", "city": "almaty" }
}
```

В ответе 201: `id`, `status`, `payUrl`, `qrUrl`, `deepLink`, `qrImageUrl`, `expiresAt`.

Что понадобится дополнительно:

- `GET /api/v1/invoices/{id}` — узнать статус счёта (если вебхук задерживается или вы делаете кнопку «Я оплатил»)
- `POST /api/v1/invoices/{id}/cancel` — покупатель отказался от заказа
- `POST /api/v1/invoices/{id}/refund` — возврат товара, `{ amount?, reason? }`

## Способы без кода

**WooCommerce.** Есть готовый плагин. Ставите, вводите API-ключ, адрес вебхука подставляется сам. Статус заказа меняется по факту оплаты. Инструкция: [интеграция с WordPress](https://api.qut.kz/docs/guide/wordpress), файл — в [разделе загрузок](https://api.qut.kz/downloads/).

**OpenCart 4.** Есть расширение, порядок тот же: ключ, режим, вебхук.

**Tilda и любые формы.** Через форма-хук. В качестве адреса отправки формы указываете наш хук, сопоставляете поля (сумма, описание, телефон) — при отправке формы создаётся счёт, и покупателя перебрасывает на страницу оплаты. Этот путь удобен магазинам, у которых есть сайт, но нет своего сервера.

**Ссылки на оплату.** Если ассортимент небольшой, на каждый товар можно сделать постоянную ссылку вида `qut.kz/p/<slug>` и поставить её на сайт кнопкой — писать код не нужно вовсе. Есть и ссылка с открытой суммой: покупатель вводит сумму сам.

**Ручной счёт из кабинета.** Если заказов пока несколько в день, начните с этого: [Как создать первый счёт](/kb/ru/first-invoice).

## Путь через API: самописный сайт

Достаточно сделать правильно три вещи.

**1. Ключ только на сервере.** `X-API-Key` не должен попадать в код, который выполняется в браузере. JavaScript на странице корзины обращается к вашему серверу, а счёт создаёт сервер.

**2. Идемпотентность.** Если покупатель нажмёт «Оплатить» дважды, второго счёта быть не должно. Передавайте номер заказа в заголовке `Idempotency-Key` — при повторе с тем же ключом новый счёт не создаётся, возвращается прежний.

**3. Обработка вебхука.** Кабинет → Интеграции → добавляете адрес. В бою принимается только `https` и настоящий домен. Проверяйте подпись: `HMAC-SHA256(secret, timestamp + "." + rawBody)`, причём по **сырому телу до разбора JSON**. Если не ответить 2xx, доставка повторится 11 раз.

Есть SDK для Node.js, PHP и Python. Общий порядок: [руководство по интеграции](https://api.qut.kz/docs/guide/integration).

## На что обратить внимание

- **Окно сканирования QR — около трёх минут.** Его задаёт Kaspi. Показывайте таймер на странице оплаты и давайте кнопку «Обновить QR»: старый счёт останется `expired`, вы создаёте новый. Не пишите фиксированное время в коде — берите `expiresAt` из ответа.
- **Бывает поздняя оплата.** Если деньги придут на `expired` или `cancelled` счёт, событие `invoice.paid` придёт с признаком `late: true`. Такой заказ нельзя молча закрывать: либо выдайте товар, либо верните деньги.
- **Обработчик вебхука должен быть идемпотентным.** Одно событие может прийти несколько раз. Обрабатывайте по паре `(invoice.id, status)` ровно один раз.
- **Не полагайтесь только на вебхук.** На странице «Спасибо» один раз запросите `GET /invoices/{id}` — тогда покупатель увидит верный результат даже при задержке доставки.
- **Сначала песочница.** Прогоните всю цепочку ключом `qp_test_…`, оплату имитируйте через `simulate`. Разница режимов: [Чем песочница отличается от боевого режима](/kb/ru/sandbox-vs-live).
- **Не забудьте выключить тестовый режим.** Это самая частая причина обращений: [Оплата не приходит покупателю](/kb/ru/payment-not-arriving).

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

**У меня нет сервера, только Tilda. Подойдёт?** Да. Форма-хук или ссылки на оплату работают без кода, статусы смотрите в кабинете.

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

**Покупатель оплатил, а заказ не обновился. Что делать?** Сначала посмотрите журнал доставок: [Вебхук не приходит](/kb/ru/webhook-not-arriving) — там видны попытки и код ошибки.

**А если у покупателя нет приложения Kaspi?** Тогда только QR или ссылка, счёт по телефону не подойдёт: [У покупателя нет приложения Kaspi](/kb/ru/customer-no-kaspi).

**Сколько заказов в месяц я смогу провести?** Зависит от тарифа: Старт — 800, Бизнес — 4 000, Про — 15 000 счетов. Как выбрать: [Какой тариф выбрать](/kb/ru/tariff-choose).
