Документация
1pay API
Принимайте платежи через Kaspi Pay по REST API. Все запросы используют JSON, авторизуются Bearer-ключом и возвращают нормализованную модель платежа — единую для счетов на телефон, платёжных ссылок и QR.
Базовый URL
https://pay.1app.kzНет ключа? Зарегистрируйтесь, подключите устройство и создайте API-ключ в дашборде.
Начало
Авторизация
Каждый запрос к /v1/* должен содержать заголовок Authorization с вашим API-ключом вида 1pay_live_…. Ключ привязан к устройству и показывается один раз при создании.
Authorization: Bearer 1pay_live_xxxxxxxxxxxx/v1/paymentsСоздать счёт на телефон
Выставляет счёт в Kaspi на указанный номер. Покупатель подтверждает оплату в приложении Kaspi. Тип платежа — invoice.
| Поле | Тип | Описание |
|---|---|---|
amountобяз. | number | Сумма в тенге (KZT). |
payer_phoneобяз. | string | Телефон плательщика, формат +7XXXXXXXXXX. |
comment | string | Назначение платежа, видно покупателю. |
merchant_order_id | string | Ваш идентификатор заказа. Обеспечивает идемпотентность — повтор вернёт 409 DUPLICATE. |
metadata | object | Произвольные данные, вернутся в вебхуке. |
Запрос
curl -X POST https://pay.1app.kz/v1/payments \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"amount": 1500,
"payer_phone": "+77011234567",
"comment": "Заказ #1042",
"merchant_order_id": "order_1042"
}'Ответ · 201 Created
{
"id": "pay_3kQ7v2",
"status": "PENDING",
"type": "invoice",
"amount": 1500,
"currency": "KZT",
"payer_phone": "+77011234567",
"comment": "Заказ #1042",
"merchant_order_id": "order_1042",
"payment_link": null,
"receipt_url": null,
"created_at": "2026-06-02T09:14:00Z",
"updated_at": "2026-06-02T09:14:00Z"
}/v1/payments/linkСоздать платёжную ссылку (QR)
Создаёт платёжную ссылку / QR-токен Kaspi без привязки к номеру телефона. Тип платежа — link. Ссылка возвращается в поле payment_link.
| Поле | Тип | Описание |
|---|---|---|
amountобяз. | number | Сумма в тенге (KZT). |
comment | string | Назначение платежа. |
merchant_order_id | string | Ваш идентификатор заказа (идемпотентность). |
metadata | object | Произвольные данные. |
Запрос
curl -X POST https://pay.1app.kz/v1/payments/link \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"amount": 4990,
"comment": "Подписка Pro",
"merchant_order_id": "sub_771"
}'Ответ · 201 Created
{
"id": "pay_8Lm2qX",
"status": "PENDING",
"type": "link",
"amount": 4990,
"currency": "KZT",
"payer_phone": null,
"comment": "Подписка Pro",
"merchant_order_id": "sub_771",
"payment_link": "https://pay.kaspi.kz/pay/abc123",
"receipt_url": null,
"created_at": "2026-06-02T09:20:00Z",
"updated_at": "2026-06-02T09:20:00Z"
}/v1/payments/:idПолучить статус платежа
Возвращает текущее состояние платежа из базы 1pay. Статус обновляется поллером каждые 3 секунды.
Запрос
curl -X GET https://pay.1app.kz/v1/payments/pay_3kQ7v2 \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx"Ответ · 200 OK
{
"id": "pay_3kQ7v2",
"status": "COMPLETED",
"type": "invoice",
"amount": 1500,
"currency": "KZT",
"payer_phone": "+77011234567",
"comment": "Заказ #1042",
"merchant_order_id": "order_1042",
"payment_link": null,
"receipt_url": "https://kaspi.kz/receipt/...",
"created_at": "2026-06-02T09:14:00Z",
"updated_at": "2026-06-02T09:15:12Z"
}/v1/payments/:id/cancelОтменить платёж
Отменяет платёж в статусе PENDING. Уже оплаченные платежи отменить нельзя — используйте возврат.
Запрос
curl -X POST https://pay.1app.kz/v1/payments/pay_3kQ7v2/cancel \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx"Ответ · 200 OK
{
"id": "pay_3kQ7v2",
"status": "CANCELLED",
"type": "invoice",
"amount": 1500,
"currency": "KZT",
"payer_phone": "+77011234567",
"merchant_order_id": "order_1042",
"created_at": "2026-06-02T09:14:00Z",
"updated_at": "2026-06-02T09:16:40Z"
}/v1/refundsСделать возврат
Возвращает средства по проведённому платежу. Поддерживается полный и частичный возврат. Платёж переходит в статус REFUNDED.
| Поле | Тип | Описание |
|---|---|---|
payment_idобяз. | string | ID платежа 1pay (pay_...). |
amountобяз. | number | Сумма возврата в тенге, не больше суммы платежа. |
Запрос
curl -X POST https://pay.1app.kz/v1/refunds \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"payment_id": "pay_3kQ7v2",
"amount": 1500
}'Ответ · 200 OK
{
"id": "pay_3kQ7v2",
"status": "REFUNDED",
"type": "invoice",
"amount": 1500,
"currency": "KZT",
"payer_phone": "+77011234567",
"merchant_order_id": "order_1042",
"created_at": "2026-06-02T09:14:00Z",
"updated_at": "2026-06-02T10:02:00Z"
}Справочники
Коды ошибок
Ошибки возвращаются с соответствующим HTTP-статусом и полем code в теле ответа.
| HTTP | Код | Описание |
|---|---|---|
| 400 | VALIDATION_ERROR | Некорректное тело запроса или параметры. |
| 401 | UNAUTHORIZED | Отсутствует или недействителен API-ключ. |
| 402 | SESSION_EXPIRED | Сессия устройства истекла — переавторизуйте устройство. |
| 404 | NOT_FOUND | Платёж или ресурс не найден. |
| 409 | DUPLICATE | merchant_order_id уже использован. |
| 422 | KASPI_ERROR | Kaspi отклонил операцию. |
| 500 | INTERNAL_ERROR | Внутренняя ошибка сервиса. |
Справочники
Вебхуки
1pay отправляет POST-запрос на ваш URL при изменении статуса платежа. Тело — JSON с конвертом события и нормализованным платежом в поле data. Настройте вебхуки в дашборде.
payment.completedПлатёж успешно проведён (статус COMPLETED).
payment.failedПлатёж отклонён или произошла ошибка (FAILED).
payment.cancelledПлатёж отменён мерчантом или плательщиком (CANCELLED).
payment.expiredИстёк срок действия счёта или QR (EXPIRED).
payment.refundedВыполнен возврат средств (REFUNDED).
payment.refund_failedВозврат не удалось выполнить.
Пример payload
{
"id": "wh_9aB3cD",
"event": "payment.completed",
"created_at": "2026-06-02T09:15:12Z",
"data": {
"id": "pay_3kQ7v2",
"status": "COMPLETED",
"type": "invoice",
"amount": 1500,
"currency": "KZT",
"payer_phone": "+77011234567",
"comment": "Заказ #1042",
"merchant_order_id": "order_1042",
"payment_link": null,
"receipt_url": "https://kaspi.kz/receipt/...",
"created_at": "2026-06-02T09:14:00Z",
"updated_at": "2026-06-02T09:15:12Z"
}
}Проверка подписи и доставка
// Заголовок каждого вебхука:
// X-Webhook-Signature: sha256=<hmac>
// Проверка подписи (Node.js):
import crypto from 'crypto';
function verify(rawBody, signatureHeader, secret) {
const expected =
'sha256=' + crypto.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signatureHeader),
Buffer.from(expected),
);
}
// Ретраи доставки: 5с → 30с, до 3 попыток. Таймаут 10с.
// Отвечайте 2xx как можно быстрее, обработку делайте асинхронно.Справочники
Маппинг статусов Kaspi → 1pay
Поллер опрашивает Kaspi каждые 3 секунды и приводит внутренние статусы к нормализованной модели.
| Processed | COMPLETED |
| CancelledByUser, NotConfirmedByUser, Rejected, Error, Insufficient*, Iris* | FAILED |
| QrTokenDiscarded, Expired | EXPIRED |
| QrTokenCreated, Wait | PENDING |
| Processed | COMPLETED |
| RemotePaymentCanceled, RemotePaymentRejected | FAILED |
| Expired | EXPIRED |
| RemotePaymentCreated | PENDING |