# SaaS-платформа: оплата за клиентов

> Как дать клиентам вашей платформы принимать Kaspi на их собственные счета: хранение ключей, выставление счетов от имени клиента, полная автоматизация через Partner API и отдельный вебхук на каждого.

## Коротко

Если вы делаете платформу для бизнеса (система записи, конструктор магазинов, сервис учёта), вы можете дать своим клиентам приём Kaspi. Главный принцип: **деньги каждого клиента приходят на его собственный Kaspi-счёт**, через ваш счёт они не проходят. Есть два пути — хранить API-ключ клиента у себя и выставлять счета от его имени, либо через Partner API автоматизировать весь процесс от создания организации до выдачи ключа.

## Сценарий

На вашей платформе сидят 300 салонов, магазинов или мастерских. Каждый берёт деньги со своих клиентов. Вы к этим деньгам не прикасаетесь — ваш доход это подписка на саму платформу.

Клиенту нужно: зайти в настройки, включить приём Kaspi и увидеть в своих заказах кнопку «Оплатить через Kaspi». Деньги должны прийти на Kaspi-счёт именно этого салона, а не на ваш.

## Два пути

| Путь | Как работает | Кому подходит |
|---|---|---|
| Хранение ключа клиента | Клиент регистрируется сам, вводит ключ в вашей платформе, вы выставляете счета от его имени | Небольшое или среднее число клиентов, ручная настройка приемлема |
| Partner API | Платформа сама создаёт организацию клиента, помогает подключить кассира, выдаёт ключ, читает статистику | Много клиентов, регистрация должна проходить внутри платформы |

В обоих случаях движение денег одинаковое: напрямую на Kaspi-счёт клиента.

## Путь 1: хранение ключа клиента

**Шаги на стороне клиента.** Клиент регистрируется на [qut.kz](https://qut.kz), подключает своего кассира Kaspi (заводит сотрудника в приложении Kaspi Pay и привязывает его в кабинете), создаёт в кабинете API-ключ и вводит его в настройках вашей платформы.

**Шаги на стороне платформы.**

1. Храните ключ клиента на сервере в зашифрованном виде.
2. Когда заказ нужно оплатить, вызываете `POST /api/v1/invoices` ключом именно этого клиента.
3. Показываете `payUrl` из ответа покупателю вашего клиента.
4. При оплате приходит вебхук, вы закрываете заказ.
5. В кабинете клиента эти счета видны под его собственным именем.

При настройке сразу проверяйте валидность ключа: вызовите `GET /api/v1/invoices` или создайте пробный счёт на ключе песочницы. Если сохранить неверный ключ молча, проблема всплывёт только в момент первой оплаты.

## Путь 2: Partner API

Через Partner API платформа работает за клиента: создаёт организацию, помогает подключить кассира, выдаёт API-ключ, читает статистику. Клиент не выходит из вашего интерфейса.

Для этого нужен ключ со scope `partner:manage`. Подробнее: [Partner API](/kb/ru/partner-api).

Когда выбирать: если клиентов много, если они технически неподготовлены или если вы хотите, чтобы «Включить Kaspi» работало одной кнопкой.

## Какие методы API нужны

| Что делает | Метод |
|---|---|
| Счёт от имени клиента | `POST /api/v1/invoices` (ключом этого клиента) |
| Массовое выставление | `POST /api/v1/invoices/bulk`, 1-100 |
| Запрос статуса | `GET /api/v1/invoices/{id}` |
| Список, отчётность | `GET /api/v1/invoices` |
| Возврат | `POST /api/v1/invoices/{id}/refund` |
| Управление организациями клиентов | Partner API, `partner:manage` |
| Состояние сервиса | `GET /api/v1/status` |

## Безопасное хранение ключей

Ключ клиента косвенно связан с его деньгами. Правила хранения:

- **Шифруйте.** В базе ключ не должен лежать открытым текстом. Ключ шифрования держите в отдельном секрет-хранилище.
- **Только на сервере.** Ключ не должен попадать в браузер, в мобильное приложение (APK/IPA) и во фронтенд-код.
- **Не пишите в логи.** В журналах ошибок и трассировках запросов ключа быть не должно. В интерфейсе показывайте только последние четыре символа.
- **Минимум прав.** Не просите у клиента ключ с полным набором прав. Для выставления счетов хватает `invoices:write` и `invoices:read`, `refunds:write` добавляйте только если нужны возвраты.
- **Дайте возможность заменить.** Если клиент хочет сменить ключ, в интерфейсе должна быть кнопка. После удаления старого ключа API начнёт отвечать 401.
- **Ограничьте круг доступа.** Решите, кто из сотрудников вашей платформы вообще может видеть ключи клиентов.

Полный список: [Безопасность интеграции: чек-лист](/kb/ru/security-checklist).

## Отдельный вебхук на каждого клиента

В адресе вебхука должен быть признак, по которому вы отличите клиента. Два подхода:

- **Признак в пути:** `https://вашаплатформа.kz/hooks/qutpay/<client_id>`. Каждый клиент указывает этот адрес в своём кабинете (или это делаете вы через Partner API).
- **Признак в payload:** при создании счёта пишете идентификатор клиента в `metadata` и читаете его при получении вебхука.

Надёжнее использовать оба сразу. Важные моменты:

- В боевом режиме адрес должен быть только на `https` и на реальном домене; IP и адрес туннеля не принимаются.
- Адрес вебхука должен открываться без авторизации. Редиректы на другой адрес не отрабатываются.
- Проверяйте подпись: `HMAC-SHA256(secret, timestamp + "." + rawBody)`, hex, с префиксом `sha256=`. Проверяйте **тело в неизменённом байтовом виде**, до разбора в JSON.
- `timestamp` старше 5 минут принимать не надо.
- При ответе не 2xx доставка повторится 11 раз, поэтому обработка должна быть идемпотентной по паре `(invoice.id, status)`.

Подробнее: [Настройка вебхуков](/kb/ru/webhook-setup).

## Есть ли вариант без кода

Со стороны платформы — нет, это работа уровня интеграции. Но **для ваших клиентов** он должен быть без кода: им достаточно создать ключ в кабинете и вставить его в ваши настройки. В варианте с Partner API ещё проще — клиент только привязывает своего кассира.

Когда будете писать инструкцию для клиентов, распишите шаги буквально: завести сотрудника в приложении Kaspi Pay, привязать его в кабинете, создать ключ. Чаще всего люди спотыкаются на требованиях к номеру кассира.

## Особые замечания

- **Не собирайте деньги на себя.** Принимать деньги клиентов на свой счёт и потом распределять — это другой вид деятельности, для него нужна отдельная правовая основа. Наша модель: деньги каждого клиента идут ему самому.
- **Тариф и лимиты у каждой организации свои.** Тарифы клиентов не складываются, каждый выбирает под свой объём. Предусмотрите уведомление клиенту, упёршемуся в лимит.
- **Привязка кассира может оборваться.** Если с номера кассира клиента кто-то войдёт в Kaspi Pay, привязка оборвётся и счета перестанут создаваться. В платформе должно быть место, где эта ошибка перехватывается и показывается клиенту понятным текстом.
- **Сделайте симуляцию клиента в песочнице.** На ключе `qp_test_…` прогоните весь цикл: ввод ключа, создание счёта, приём вебхука, ошибочные ситуации.
- **Данные покупателей.** Вы обрабатываете номера телефонов покупателей — опишите в своей политике, как вы их храните.

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

**Деньги придут на счёт моей платформы?** Нет. Деньги каждого клиента приходят на его собственный Kaspi-счёт. Ни у нас, ни у вас они не задерживаются.

**Как мне брать комиссию?** Брать процент с транзакции в этой модели не получится. Берите собственную абонентскую плату платформы отдельно — её тоже можно собирать через Qut Pay.

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

**Кому доступен Partner API?** Нужен ключ со scope `partner:manage`. Условия обсуждаются через поддержку.

**Что будет, если клиент удалит свой ключ?** Запросы от его имени начнут возвращать 401. Предусмотрите в платформе экран, который перехватывает эту ошибку и просит новый ключ: [API отвечает 401](/kb/ru/api-401).
