# Приём удалённых платежей через POST /payments

Как работает удалённый платёж: ваш сервер отправляет запрос, xpayment отправляет счёт на телефон покупателя через Kaspi.

## Что такое прямой платёж?

Прямой платёж — это **платёж по счёту** в xpayment. Когда вы вызываете `POST /v1/payments`, xpayment отправляет счёт в приложение Kaspi покупателя. Покупатель получает **push-уведомление** на телефон, открывает его и либо оплачивает, либо отклоняет.

---

## Когда использовать прямые платежи

Прямые платежи идеальны, когда вы **уже знаете номер телефона покупателя**:

- **Оформление заказов в интернет-магазинах** — покупатель вводит телефон при оформлении
- **Telegram/чат-боты** — собирают номер телефона в диалоге
- **Системы выставления счетов** — отправляют запросы на оплату существующим клиентам
- **SaaS-платформы** — списывают абонентскую плату с зарегистрированных пользователей
- **Бронирование услуг** — запрашивают оплату после подтверждения записи

---

## Что нужно

Перед созданием первого платежа убедитесь, что у вас есть:

1. **Зарегистрированное устройство** — см. [руководство по настройке устройства](https://xpayment.kz/blog/device-setup)
2. **API-ключ** (`xdev_...`) для этого устройства
3. **Номер телефона покупателя**, зарегистрированный в Kaspi (должен совпадать с его аккаунтом Kaspi)

---

## Как работает процесс

Вот что происходит от начала до конца:

1. **Ваш сервер** отправляет запрос `POST /v1/payments` с телефоном покупателя и суммой
2. **xpayment** проверяет ваш ключ устройства и создаёт платёж со статусом `PENDING`
3. **Kaspi отправляет** push-уведомление на телефон покупателя: "Магазин ShopMebel выставил вам счёт"
4. **Покупатель** открывает приложение Kaspi и видит счёт (название мерчанта, сумму, сообщение)
5. **Покупатель подтверждает** → Kaspi обрабатывает платёж
6. **Фоновый поллер xpayment** обнаруживает изменение статуса (работает каждые 15 секунд)
7. **Срабатывает webhook** → ваш сервер получает уведомление `payment.completed`
8. **Вы выполняете** заказ (отправляете товар, открываете доступ и т.д.)

На диаграмме ниже показан технический поток между серверами:

## Что видит покупатель

Когда вы создаёте платёж через `POST /v1/payments`, вот что происходит на стороне покупателя:

### 1. Появляется push-уведомление

Покупатель получает **push-уведомление** на телефон:

> **Kaspi.kz**  
> Магазин ShopMebel выставил вам счёт на 50 000 ₸

Уведомление появляется мгновенно — даже если телефон заблокирован. Покупатель может нажать на него, чтобы сразу открыть приложение Kaspi.

### 2. Открывается экран счёта

Когда покупатель открывает уведомление, Kaspi показывает полный экран счёта с:

- **Название мерчанта** (например, "ShopMebel")
- **Сумма** крупным шрифтом (например, "50 000 ₸")
- **Сообщение от продавца** (поле `comment` из вашего API-запроса)
- **Две кнопки действия:**
  - 🟢 **"Оплатить"** — зелёная, заметная
  - 🔴 **"Отклонить счёт"** — вторичная, менее заметная

### 3. Покупатель принимает решение

**Если нажимает "Оплатить":**
- Kaspi обрабатывает платёж с привязанной карты или счёта Kaspi Gold
- Деньги переводятся мгновенно
- Покупатель видит экран подтверждения
- Поллер xpayment обнаруживает изменение статуса в течение 15 секунд
- Ваш webhook получает событие `payment.completed`

**Если нажимает "Отклонить счёт":**
- Счёт отменяется
- Поллер xpayment обнаруживает отмену
- Ваш webhook получает событие `payment.cancelled`

**Если игнорирует:**
- Счёт истекает после тайм-аута Kaspi (обычно 24 часа)
- Ваш webhook получает событие `payment.expired`

---

## Важные примечания для покупателей

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

Макет ниже показывает, что видит покупатель на своём телефоне:

## Детали интеграции

### Создание платежа

Отправьте запрос `POST /v1/payments` с API-ключом вашего устройства:

```http
POST /v1/payments
Authorization: Bearer xdev_live_abc123...
Content-Type: application/json
X-Idempotency-Key: order-12345

{
  "payer_phone": "+77001234567",
  "amount": 1500.00,
  "comment": "Заказ #12345 — Премиум подписка",
  "merchant_order_id": "order-12345"
}
```

**Поля запроса:**

| Поле | Обязательно | Тип | Описание |
|------|-------------|-----|----------|
| `payer_phone` | Да | string | Номер телефона покупателя, зарегистрированный в Kaspi (формат E.164) |
| `amount` | Да | number | Сумма платежа в KZT (должна быть > 0) |
| `comment` | Нет | string | Сообщение, показываемое покупателю в приложении Kaspi (макс. 255 символов) |
| `merchant_order_id` | Нет | string | Ваш внутренний ID заказа/транзакции |
| `metadata` | Нет | object | Любой JSON-объект, который вы хотите сохранить (макс. 1КБ) |

**Ответ (201 Created):**

```json
{
  "id": "pay_a1b2c3d4e5f6...",
  "status": "PENDING",
  "amount": 1500.00,
  "currency": "KZT",
  "payer_phone": "+77001234567",
  "comment": "Заказ #12345 — Премиум подписка",
  "merchant_order_id": "order-12345",
  "created_at": "2026-04-10T12:00:00Z",
  "updated_at": "2026-04-10T12:00:00Z"
}
```

---

## Жизненный цикл платежа

| Статус | Описание | Можно отменить? |
|--------|----------|------------------|
| `PENDING` | Создан, ожидает подтверждения покупателя в приложении Kaspi | ✅ Да |
| `COMPLETED` | Покупатель подтвердил, деньги получены на ваш счёт | ❌ Нет (используйте возврат) |
| `CANCELLED` | Отменён вами или отклонён покупателем | ❌ Нет |
| `FAILED` | Kaspi отклонил (неверный телефон, недостаточно средств и т.д.) | ❌ Нет |
| `EXPIRED` | Покупатель не ответил в течение тайм-аута (обычно 24ч) | ❌ Нет |

### Переходы между статусами

```
PENDING → COMPLETED    (покупатель подтверждает)
PENDING → CANCELLED    (вы отменяете ИЛИ покупатель отклоняет)
PENDING → FAILED       (Kaspi отклоняет)
PENDING → EXPIRED      (истекает время)
```

После того как платёж покидает статус `PENDING`, он **неизменяем**. Чтобы вернуть завершённый платёж, используйте API возврата.

---

## Отмена платежа

Пока платёж находится в статусе `PENDING`, вы можете его отменить:

```http
POST /v1/payments/{paymentId}/cancel
Authorization: Bearer xdev_live_abc123...
```

**Ответ (200 OK):**

```json
{
  "id": "pay_a1b2c3...",
  "status": "CANCELLED",
  "amount": 1500.00,
  "cancelled_at": "2026-04-10T12:05:00Z"
}
```

**Когда отменять:**
- Покупатель запросил отмену заказа до оплаты
- Товар закончился после создания платежа
- Заказ истёк в ожидании оплаты

---

## События webhook

| HTTP-статус | Код ошибки | Причина |
|-------------|-----------|---------|
| 400 | `VALIDATION_ERROR` | Отсутствуют или невалидны поля |
| 422 | `KASPI_ERROR` | Устройство не зарегистрировано или сессия истекла |
| 409 | `DUPLICATE` | Дублирующий `merchant_order_id` |
| 500 | `INTERNAL_ERROR` | Неожиданная ошибка сервера |

Если получаете `KASPI_ERROR`, возможно истекла сессия устройства. Перерегистрируйте устройство или проверьте статус сессии в личном кабинете.

---

## Смотрите также

- [Подключение устройства](https://xpayment.kz/blog/device-setup) — первоначальная настройка
- [QR-платежи](https://xpayment.kz/blog/payment-link) — когда номер телефона клиента неизвестен
- [Вебхуки](https://xpayment.kz/blog/webhooks) — как узнать, что покупатель заплатил (шаг 7 в потоке)

## Читайте также
- [Подключение устройства](https://xpayment.kz/blog/device-setup)
- [Платёжные ссылки](https://xpayment.kz/blog/payment-link)
- [Webhooks xpayment](https://xpayment.kz/blog/webhooks)

---

Источник: https://xpayment.kz/blog/direct-payment
