hochu-sdelat-mini-servis-po/docs/API.md

694 lines
21 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 📖 API Documentation
Kaspi POS Automation предоставляет REST API для работы с платежами Kaspi Pay: авторизация по SMS, выставление счетов, QR-оплата, история операций и возвраты.
**Base URL:** `http://localhost:3000`
---
## Содержание
- [Аутентификация](#аутентификация)
- [Заголовки сессии](#заголовки-сессии)
- [Health Check](#health-check)
- [Auth — Авторизация](#auth--авторизация)
- [POST /api/auth/init](#post-apiauthinit)
- [POST /api/auth/send-phone](#post-apiauthsend-phone)
- [POST /api/auth/verify-otp](#post-apiauthverify-otp)
- [POST /api/auth/session](#post-apiauthsession)
- [POST /api/auth/logout](#post-apiauthlogout)
- [Invoice — Счета](#invoice--счета)
- [GET /api/invoice/client-info](#get-apiinvoiceclient-info)
- [POST /api/invoice/create](#post-apiinvoicecreate)
- [GET /api/invoice/details](#get-apiinvoicedetails)
- [POST /api/invoice/cancel](#post-apiinvoicecancel)
- [POST /api/invoice/history](#post-apiinvoicehistory)
- [QR — QR-оплата](#qr--qr-оплата)
- [POST /api/qr/create](#post-apiqrcreate)
- [GET /api/qr/status](#get-apiqrstatus)
- [History — История операций](#history--история-операций)
- [POST /api/history/operations](#post-apihistoryoperations)
- [POST /api/history/details](#post-apihistorydetails)
- [Refund — Возвраты](#refund--возвраты)
- [POST /api/refund/create](#post-apirefundcreate)
- [Session — Проверка сессии](#session--проверка-сессии)
- [GET /api/session/check](#get-apisessioncheck)
- [Webhooks — Уведомления](#webhooks--уведомления)
- [Настройка](#настройка)
- [События](#события)
- [Формат payload](#формат-payload)
- [Подпись (HMAC)](#подпись-hmac)
- [Повторные попытки (Retry)](#повторные-попытки-retry)
---
## Аутентификация
API использует 3-шаговую SMS-авторизацию. После успешной авторизации клиент получает `tokenSN` и `vtokenSecret`, которые передаются в заголовках для всех защищённых эндпоинтов.
### Заголовки сессии
Все эндпоинты кроме `/api/auth/*` и `/health` требуют следующие заголовки:
| Заголовок | Тип | Обязательный | Описание |
|---|---|---|---|
| `X-Token-SN` | `string` | ✅ | Токен сессии, полученный при авторизации |
| `X-Vtoken-Secret` | `string` | ✅ | Зашифрованный секрет сессии |
| `X-Profile-Id` | `string` | ❌ | ID профиля организации |
---
## Health Check
### `GET /health`
Проверка работоспособности сервера.
**Ответ:**
```json
{ "status": "ok" }
```
---
## Auth — Авторизация
Трёхшаговый процесс авторизации через SMS-код Kaspi.
> ⚠️ **Важно:** Для входа используйте номер телефона аккаунта **кассира** Kaspi Pay.
### `POST /api/auth/init`
Инициализация процесса авторизации. Возвращает `processId` для последующих шагов.
**Тело запроса:** не требуется
**Пример запроса:**
```bash
curl -X POST http://localhost:3000/api/auth/init
```
**Успешный ответ:**
```json
{
"success": true,
"processId": "abc123-...",
"view": "EnterPhoneNumber",
"body": { ... }
}
```
---
### `POST /api/auth/send-phone`
Отправка номера телефона — инициирует отправку SMS-кода.
**Тело запроса:**
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
| `phoneNumber` | `string` | ✅ | Номер телефона (формат: `7XXXXXXXXXX`) |
| `processId` | `string` | ✅ | ID процесса из `/api/auth/init` |
**Пример запроса:**
```bash
curl -X POST http://localhost:3000/api/auth/send-phone \
-H "Content-Type: application/json" \
-d '{"phoneNumber": "77001234567", "processId": "abc123-..."}'
```
**Успешный ответ:**
```json
{
"success": true,
"processId": "abc123-...",
"desc": "Код отправлен на номер +7 700 *** ** 67",
"view": "EnterOtp",
"body": { ... }
}
```
---
### `POST /api/auth/verify-otp`
Подтверждение SMS-кода. При успехе автоматически завершает авторизацию и возвращает данные сессии.
**Тело запроса:**
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
| `otp` | `string` | ✅ | SMS-код |
| `processId` | `string` | ✅ | ID процесса из `/api/auth/init` |
**Пример запроса:**
```bash
curl -X POST http://localhost:3000/api/auth/verify-otp \
-H "Content-Type: application/json" \
-d '{"otp": "1234", "processId": "abc123-..."}'
```
**Успешный ответ:**
```json
{
"success": true,
"processId": "abc123-...",
"step": "finished",
"message": "OTP verified and finish completed",
"tokenSN": "TOKEN_SN_VALUE",
"vtokenSecret": "ENCRYPTED_SECRET",
"profileId": 12345,
"organizationId": 67890,
"orgName": "ИП Иванов",
"phone": "77001234567",
"organizations": [ ... ]
}
```
> ⚠️ Сохраните `tokenSN` и `vtokenSecret` — они нужны для всех последующих запросов.
---
### `POST /api/auth/session`
Проверка наличия токена (клиентская проверка).
**Тело запроса:**
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
| `tokenSN` | `string` | ❌ | Токен сессии |
**Ответ:**
```json
{
"authenticated": true,
"tokenSN": "TOKEN_SN_VALUE"
}
```
---
### `POST /api/auth/logout`
Завершение сессии.
**Тело запроса:** не требуется
**Ответ:**
```json
{ "success": true }
```
---
## Invoice — Счета
Выставление счетов на оплату по номеру телефона клиента.
> 🔒 Все эндпоинты требуют [заголовки сессии](#заголовки-сессии).
### `GET /api/invoice/client-info`
Получение информации о клиенте по номеру телефона.
**Query-параметры:**
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
| `phoneNumber` | `string` | ✅ | Номер телефона клиента |
**Пример запроса:**
```bash
curl "http://localhost:3000/api/invoice/client-info?phoneNumber=77001234567" \
-H "X-Token-SN: ..." \
-H "X-Vtoken-Secret: ..." \
-H "X-Profile-Id: ..."
```
---
### `POST /api/invoice/create`
Создание счёта на оплату.
**Тело запроса:**
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
| `phoneNumber` | `string` | ✅ | Номер телефона клиента |
| `amount` | `number` | ✅ | Сумма в тенге |
| `comment` | `string` | ❌ | Комментарий к платежу |
**Пример запроса:**
```bash
curl -X POST http://localhost:3000/api/invoice/create \
-H "Content-Type: application/json" \
-H "X-Token-SN: ..." \
-H "X-Vtoken-Secret: ..." \
-H "X-Profile-Id: ..." \
-d '{"phoneNumber": "77001234567", "amount": 1000, "comment": "Оплата заказа #42"}'
```
**Успешный ответ:**
```json
{
"StatusCode": 0,
"Data": {
"Id": 123456,
"Status": "RemotePaymentCreated",
"Amount": 1000,
"ClientMobile": "77001234567",
"ReceiptUrl": "https://...",
"OrderNumber": "..."
}
}
```
---
### `GET /api/invoice/details`
Получение деталей счёта.
**Query-параметры:**
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
| `operationId` | `string` | ✅ | ID операции |
**Пример запроса:**
```bash
curl "http://localhost:3000/api/invoice/details?operationId=123456" \
-H "X-Token-SN: ..." \
-H "X-Vtoken-Secret: ..."
```
---
### `POST /api/invoice/cancel`
Отмена выставленного счёта.
**Тело запроса:**
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
| `operationId` | `string` | ✅ | ID операции для отмены |
**Пример запроса:**
```bash
curl -X POST http://localhost:3000/api/invoice/cancel \
-H "Content-Type: application/json" \
-H "X-Token-SN: ..." \
-H "X-Vtoken-Secret: ..." \
-d '{"operationId": "123456"}'
```
---
### `POST /api/invoice/history`
Получение истории выставленных счетов (последние 20).
**Тело запроса:** не требуется (пустой JSON `{}`)
**Пример запроса:**
```bash
curl -X POST http://localhost:3000/api/invoice/history \
-H "Content-Type: application/json" \
-H "X-Token-SN: ..." \
-H "X-Vtoken-Secret: ..." \
-d '{}'
```
---
## QR — QR-оплата
Генерация QR-кодов для оплаты через Kaspi Pay.
> 🔒 Все эндпоинты требуют [заголовки сессии](#заголовки-сессии).
### `POST /api/qr/create`
Создание QR-токена для оплаты.
**Тело запроса:**
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
| `amount` | `number` | ✅ | Сумма в тенге |
| `latitude` | `number` | ❌ | Широта (по умолчанию: Алматы) |
| `longitude` | `number` | ❌ | Долгота (по умолчанию: Алматы) |
**Пример запроса:**
```bash
curl -X POST http://localhost:3000/api/qr/create \
-H "Content-Type: application/json" \
-H "X-Token-SN: ..." \
-H "X-Vtoken-Secret: ..." \
-H "X-Profile-Id: ..." \
-d '{"amount": 500}'
```
**Успешный ответ:**
```json
{
"StatusCode": 0,
"Data": {
"QrOperationId": 789012,
"QrToken": "https://pay.kaspi.kz/pay/...",
"ExpireDate": "2025-01-01T12:05:00",
"Amount": 500,
"ReceiptUrl": "https://..."
}
}
```
> 💡 `QrToken` содержит ссылку для оплаты — можно преобразовать в QR-код.
---
### `GET /api/qr/status`
Проверка статуса QR-платежа.
**Query-параметры:**
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
| `qrOperationId` | `string` | ✅ | ID QR-операции из `/api/qr/create` |
**Пример запроса:**
```bash
curl "http://localhost:3000/api/qr/status?qrOperationId=789012" \
-H "X-Token-SN: ..." \
-H "X-Vtoken-Secret: ..."
```
---
## History — История операций
Просмотр истории всех операций (QR + счета).
> 🔒 Все эндпоинты требуют [заголовки сессии](#заголовки-сессии).
### `POST /api/history/operations`
Получение списка операций за период.
**Тело запроса:**
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
| `endDate` | `string` | ✅ | Конечная дата (формат: `YYYY-MM-DD`) |
| `lastTransactionDate` | `string` | ❌ | Дата последней транзакции (для пагинации) |
| `statementPeriodCode` | `number` | ❌ | Код периода (по умолчанию: `0`) |
**Пример запроса:**
```bash
curl -X POST http://localhost:3000/api/history/operations \
-H "Content-Type: application/json" \
-H "X-Token-SN: ..." \
-H "X-Vtoken-Secret: ..." \
-d '{"endDate": "2025-01-15"}'
```
---
### `POST /api/history/details`
Получение деталей конкретной операции.
**Тело запроса:**
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
| `id` | `number` | ✅ | ID операции |
| `operationMethod` | `number` | ❌ | Метод операции (по умолчанию: `0`) |
**Пример запроса:**
```bash
curl -X POST http://localhost:3000/api/history/details \
-H "Content-Type: application/json" \
-H "X-Token-SN: ..." \
-H "X-Vtoken-Secret: ..." \
-d '{"id": 123456}'
```
---
## Refund — Возвраты
Возврат средств по ранее проведённой операции.
> 🔒 Все эндпоинты требуют [заголовки сессии](#заголовки-сессии).
### `POST /api/refund/create`
Создание возврата.
**Тело запроса:**
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
| `qrOperationId` | `number` | ✅ | ID операции для возврата |
| `returnAmount` | `number` | ✅ | Сумма возврата в тенге |
**Пример запроса:**
```bash
curl -X POST http://localhost:3000/api/refund/create \
-H "Content-Type: application/json" \
-H "X-Token-SN: ..." \
-H "X-Vtoken-Secret: ..." \
-d '{"qrOperationId": 789012, "returnAmount": 500}'
```
---
## Session — Проверка сессии
### `GET /api/session/check`
Проверка валидности текущей сессии через запрос к Kaspi API.
> 🔒 Требует [заголовки сессии](#заголовки-сессии).
**Пример запроса:**
```bash
curl "http://localhost:3000/api/session/check" \
-H "X-Token-SN: ..." \
-H "X-Vtoken-Secret: ..."
```
**Активная сессия:**
```json
{ "active": true }
```
**Неактивная сессия:**
```json
{
"active": false,
"error": "Session rejected by Kaspi API.",
"code": 401,
"details": { ... }
}
```
---
## Коды ошибок
Все эндпоинты возвращают ошибки в формате:
```json
{ "error": "Описание ошибки" }
```
| HTTP-код | Описание |
|---|---|
| `400` | Отсутствуют обязательные параметры |
| `401` | Отсутствуют или невалидные заголовки сессии |
| `500` | Внутренняя ошибка сервера или ошибка Kaspi API |
---
## Webhooks — Уведомления
Система автоматически отслеживает статусы созданных QR- и invoice-платежей (polling каждые 3 секунды) и отправляет HTTP POST-уведомления (webhooks) на указанные URL при изменении статуса платежа.
### Настройка
Вебхуки настраиваются в файле `webhooks.json` в корне проекта. Файл содержит массив объектов:
```json
[
{
"url": "https://example.com/webhook",
"events": ["payment.success", "payment.failed", "payment.expired"],
"secret": "your-webhook-secret"
}
]
```
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
| `url` | `string` | ✅ | URL, на который будут отправляться уведомления |
| `events` | `string[]` | ✅ | Список событий для подписки |
| `secret` | `string` | ❌ | Секрет для HMAC-подписи (рекомендуется) |
> 💡 Для начала скопируйте `webhooks.example.json` → `webhooks.json` и отредактируйте.
Можно указать несколько вебхуков с разными URL и событиями:
```json
[
{
"url": "https://my-crm.com/kaspi-hook",
"events": ["payment.success"],
"secret": "crm-secret-key"
},
{
"url": "https://my-accounting.com/hook",
"events": ["payment.success", "payment.failed", "payment.expired"],
"secret": "accounting-secret"
}
]
```
### События
| Событие | Описание | Когда срабатывает |
|---|---|---|
| `payment.success` | Платёж успешно проведён | QR: статус `Processed`; Invoice: статус `Processed` |
| `payment.failed` | Платёж отклонён / отменён | QR: `CancelledByUser`, `Rejected`, `Error` и др.; Invoice: `RemotePaymentCanceled`, `RemotePaymentRejected` |
| `payment.expired` | Время оплаты истекло | QR: `QrTokenDiscarded`, `Expired`; Invoice: `Expired` |
### Формат payload
При срабатывании события на каждый подписанный URL отправляется POST-запрос с JSON-телом:
```json
{
"event": "payment.success",
"paymentId": "123456",
"type": "qr",
"status": "Processed",
"statusDesc": "Операция проведена успешно",
"amount": 5000,
"qrToken": "QR-TOKEN-...",
"receiptUrl": "https://...",
"orderNumber": "ORDER-001",
"data": { ... },
"timestamp": "2026-05-10T00:00:00.000Z"
}
```
| Поле | Тип | Описание |
|---|---|---|
| `event` | `string` | Название события (`payment.success`, `payment.failed`, `payment.expired`) |
| `paymentId` | `string` | ID платежа (QR operationId или invoice operationId) |
| `type` | `string` | Тип платежа: `qr` или `invoice` |
| `status` | `string` | Финальный статус от Kaspi API |
| `statusDesc` | `string` | Описание статуса |
| `amount` | `number\|null` | Сумма платежа в тенге |
| `qrToken` | `string\|null` | QR-токен (только для QR-платежей) |
| `receiptUrl` | `string\|null` | Ссылка на чек |
| `orderNumber` | `string\|null` | Номер заказа |
| `data` | `object` | Полные данные ответа от Kaspi API |
| `timestamp` | `string` | Время отправки уведомления (ISO 8601) |
### Подпись (HMAC)
Каждый запрос подписывается HMAC SHA-256 с использованием `secret` из конфигурации вебхука. Подпись передаётся в заголовке:
```
X-Webhook-Signature: sha256=<hex-digest>
```
**Проверка подписи на стороне получателя (Node.js):**
```javascript
import crypto from 'crypto';
const verifySignature = (body, signature, secret) => {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
};
// В обработчике запроса:
const rawBody = JSON.stringify(req.body); // или используйте raw body
const sig = req.headers['x-webhook-signature'];
if (!verifySignature(rawBody, sig, 'your-webhook-secret')) {
return res.status(401).send('Invalid signature');
}
```
### Повторные попытки (Retry)
Если доставка вебхука не удалась (ошибка сети, таймаут, HTTP-ошибка), система выполняет до **3 попыток** с нарастающей задержкой:
| Попытка | Задержка |
|---|---|
| 1-я (первая) | Немедленно |
| 2-я | 5 секунд |
| 3-я | 30 секунд |
- Таймаут запроса: **10 секунд**.
- Очередь повторных попыток сохраняется в `webhook-retries.json` и переживает перезапуск сервера.
- После 3 неудачных попыток уведомление отбрасывается (логируется ошибка).
---
## Типичный сценарий использования
```
1. POST /api/auth/init → получить processId
2. POST /api/auth/send-phone → отправить SMS
3. POST /api/auth/verify-otp → подтвердить код → получить tokenSN + vtokenSecret
4. POST /api/qr/create → создать QR для оплаты
5. GET /api/qr/status → проверить статус оплаты
— или —
4. POST /api/invoice/create → выставить счёт по номеру телефона
5. GET /api/invoice/details → проверить статус счёта
6. POST /api/refund/create → возврат средств (при необходимости)
```