Документация

1pay API

Принимайте платежи через Kaspi Pay по REST API. Все запросы — JSON, авторизация Bearer-ключом, единая модель платежа для счетов, QR-ссылок и кнопок.

Базовый URL

https://pay.1app.kz

Нет ключа? Зарегистрируйтесь, подключите устройство, создайте API-ключ — и делайте первый запрос.

Начало

Авторизация

Каждый запрос к /v1/* содержит заголовок с API-ключом. Ключ — секрет, держите только на сервере.

Заголовок
Authorization: Bearer 1pay_live_xxxxxxxxxxxx
Никогда не используйте ключ в браузере или мобильном клиенте.

Как принять платёж

Быстрый старт

  1. Подключите устройство (телефон кассира) и создайте API-ключ в дашборде.
  2. Создайте платёж: POST /v1/payments (счёт на телефон) или /v1/payments/link (QR/ссылка).
  3. Настройте вебхук в дашборде — на него придёт payment.completed.
curl — создать счёт
curl -X POST https://pay.1app.kz/v1/payments \
-H "Authorization: Bearer 1pay_live_xxx" \
-H "Content-Type: application/json" \
-d '{"amount":1500,"payer_phone":"+77011234567","merchant_order_id":"order_1042"}'

Счёт на номер телефона

Знаете номер клиента — выставляете счёт. Клиенту приходит push в Kaspi, он подтверждает. Тип платежа: invoice.

Node.js — создать счёт
const res = await fetch("https://pay.1app.kz/v1/payments", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.ONEPAY_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": orderId,
},
body: JSON.stringify({
amount: 1500,
payer_phone: "+77011234567",
merchant_order_id: orderId,
comment: "Заказ №1042",
}),
});
const payment = await res.json();
// payment.id = "pay_..." payment.status = "PENDING"
// Сохраните payment.id — ждите вебхук payment.completed
Ответ · 201
{
"id": "pay_3kQ7v2",
"status": "PENDING",
"type": "invoice",
"amount": 1500,
"currency": "KZT",
"payer_phone": "+77011234567",
"merchant_order_id": "order_1042",
"created_at": "..."
}

Кнопка «Оплатить»

Паттерн для веб-чекаута: бэкенд создаёт ссылку (Сценарий 2), отдаёт payment_link на фронт. На телефоне — открывает Kaspi, на десктопе — рядом QR.

HTML — кнопка + QR
<!-- payment_link пришёл с вашего бэкенда -->
<a href="{{payment_link}}" class="kaspi-btn">Оплатить через Kaspi</a>
<img src="https://api.qrserver.com/v1/create-qr-code/?size=200x200&data={{payment_link}}"
alt="Сканируйте в Kaspi" />
Фронт спрашивает статус у вашего бэкенда — не опрашивайте 1pay из браузера. Ваш бэкенд узнаёт об оплате из вебхука.

Вебхуки

Настройте вебхук в дашборде (URL + события). При создании выдаётся секрет(один раз). Каждый POST подписан: X-Webhook-Signature: sha256=<hmac> — HMAC-SHA256 от сырого тела вашим секретом.

Express — приём и проверка подписи
import crypto from "crypto";
app.post("/webhooks/1pay",
express.raw({ type: "application/json" }), // ВАЖНО: сырой body
(req, res) => {
const sig = req.get("X-Webhook-Signature") || "";
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.ONEPAY_WEBHOOK_SECRET)
.update(req.body)
.digest("hex");
const ok = sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
if (!ok) return res.status(401).end();
const evt = JSON.parse(req.body.toString("utf8"));
if (evt.event === "payment.completed") {
// пометьте заказ оплаченным — ИДЕМПОТЕНТНО (ретраи возможны)
markOrderPaid(evt.data.merchant_order_id);
}
res.json({ ok: true }); // отвечайте 2xx, иначе будут ретраи
}
);
Тело вебхука (POST на ваш URL)
{
"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"
}
}
Отвечайте быстро (≤ 10с) и 2xx. Тяжёлую работу — в фон. Не-2xx или таймаут → до 3 попыток доставки (2 ретрая: через 5с, затем через 30с). Обрабатывайте события идемпотентно по data.id: один платёж может прислать несколько вебхуков, а статус иногда уточняется позже — например, при сверке с Kaspi ранее истёкший/неуспешный платёж может подтвердиться как payment.completed.

Все типы событий — в справочнике событий.

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

Можно отменить платёж в статусе PENDING (до оплаты клиентом).

curl — отмена
curl -X POST https://pay.1app.kz/v1/payments/pay_3kQ7v2/cancel \
-H "Authorization: Bearer 1pay_live_xxx"

Возврат (полный и частичный)

Только по оплаченному платежу (COMPLETED). Укажите сумму — частями или всю. После полного возврата статус станет REFUNDED.

curl — возврат
curl -X POST https://pay.1app.kz/v1/refunds \
-H "Authorization: Bearer 1pay_live_xxx" \
-H "Content-Type: application/json" \
-d '{"payment_id":"pay_3kQ7v2","amount":500,"reason":"частичный возврат"}'

Проверка номера в Kaspi

Перед выставлением счёта можно проверить, зарегистрирован ли номер — меньше неуспешных оплат.

curl — проверка
curl -X POST https://pay.1app.kz/v1/clients/check \
-H "Authorization: Bearer 1pay_live_xxx" \
-H "Content-Type: application/json" \
-d '{"phone":"+77011234567"}'
# → {"phone":"+77011234567","registered":true,"name":"И. Иванов"}

Идемпотентность

  • merchant_order_id — уникален в рамках мерчанта. Повтор с тем же id вернёт 409 DUPLICATE.
  • Заголовок Idempotency-Key — повтор с тем же ключом вернёт тот же платёж (200), не новый. Ставьте при ретраях запроса.

Полный пример — чекаут + вебхук (Node/Express)

server.js
import express from "express";
import crypto from "crypto";
const ONEPAY = "https://pay.1app.kz";
const API_KEY = process.env.ONEPAY_API_KEY;
const SECRET = process.env.ONEPAY_WEBHOOK_SECRET;
const app = express();
// 1) Создать платёж для заказа
app.post("/checkout", express.json(), async (req, res) => {
const { orderId, phone, amount } = req.body;
const r = await fetch(`${ONEPAY}/v1/payments`, {
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": orderId,
},
body: JSON.stringify({ amount, payer_phone: phone, merchant_order_id: orderId }),
});
const payment = await r.json();
if (!r.ok) return res.status(r.status).json(payment);
res.json({ payment_id: payment.id });
});
// 2) Вебхук — узнаём об оплате
app.post("/webhooks/1pay", express.raw({ type: "application/json" }), (req, res) => {
const sig = req.get("X-Webhook-Signature") || "";
const exp = "sha256=" + crypto.createHmac("sha256", SECRET).update(req.body).digest("hex");
if (sig.length !== exp.length || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(exp)))
return res.status(401).end();
const evt = JSON.parse(req.body.toString("utf8"));
switch (evt.event) {
case "payment.completed": markOrderPaid(evt.data.merchant_order_id); break;
case "payment.refunded": recordRefund(evt.data.merchant_order_id); break;
case "payment.cancelled":
case "payment.expired": markOrderUnpaid(evt.data.merchant_order_id); break;
}
res.json({ ok: true });
});
app.listen(3000);

Платформа

Модель платформы

Для SaaS/маркетплейсов, которые подключают приём Kaspi своим клиентам так, что клиент не знает про 1pay. Платформа управляет суб-мерчантами, их кассирами и балансами через один серверный ключ.

  • Платформа — ваш сервис с одним platform-ключом.
  • Школа (суб-мерчант) — ваш клиент. Заводится по API, про 1pay не знает.
  • Баланс комиссии — предоплата школы. Деньги учеников идут ей в Kaspi напрямую; вашу комиссию 1pay списывает с этого баланса. При нуле приём выключается.
Заголовок
Authorization: Bearer 1pay_platform_xxxxxxxxxxxx

Управление школами

Заводите школу с комиссией и опциональным начальным балансом. external_id — ваш id школы.

Создать школу
const res = await fetch("https://pay.1app.kz/platform/merchants", {
method: "POST",
headers: { "Authorization": `Bearer ${PLATFORM_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
name: "Школа Алмаз",
external_id: "school_42",
commission_rate: 3,
initial_balance: 0,
}),
});
const school = await res.json(); // school.id = "mer_..." — сохраните у себя

Ещё: GET /platform/merchants (список, ?external_id=), GET/PATCH /platform/merchants/:id (имя, ставка, active).

Онбординг кассира

Школа подключает Kaspi-кассир прямо в вашем UI — два шага:

Шаг 1 — отправить SMS
const r = await fetch(`https://pay.1app.kz/platform/merchants/${schoolId}/devices`, {
method: "POST",
headers: { "Authorization": `Bearer ${PLATFORM_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ name: "Касса", phone: "+7 7XX XXX XX XX" }),
});
const { device } = await r.json(); // device.id → кассиру пришёл SMS
Шаг 2 — подтвердить код
await fetch(`https://pay.1app.kz/platform/merchants/${schoolId}/devices/${device.id}/otp`, {
method: "POST",
headers: { "Authorization": `Bearer ${PLATFORM_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ otp: "1234" }),
});
// device.status = "ACTIVE" → школа готова принимать платежи
Нужен номер кассира Kaspi Pay (вход по SMS-коду), не обычного Kaspi-аккаунта.

Баланс комиссии

Вы пополняете/корректируете баланс школы; 1pay автоматически списывает комиссию с каждого платежа.

Пополнить / просмотреть
// Пополнить
await fetch(`https://pay.1app.kz/platform/merchants/${schoolId}/balance/topup`, {
method: "POST",
headers: { "Authorization": `Bearer ${PLATFORM_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ amount: 5000, note: "апрель" }),
});
// Остаток
const b = await (await fetch(`https://pay.1app.kz/platform/merchants/${schoolId}/balance`,
{ headers: { "Authorization": `Bearer ${PLATFORM_KEY}` } })).json();
// { commission_rate: 3, commission_balance: 5000, accepting: true }

POST …/balance/adjust — ручная коррекция (+/−). GET …/balance/ledger — журнал (TOPUP / COMMISSION / ADJUST). При нуле баланса — 402 BALANCE_DEPLETED. Подпишитесь на merchant.depleted, чтобы авто-пополнять.

Платежи от имени школы

Деньги идут на Kaspi школы; комиссия списывается с её баланса.

Создать счёт / QR-ссылку
// Счёт на телефон
const p = await (await fetch(`https://pay.1app.kz/platform/merchants/${schoolId}/payments`, {
method: "POST",
headers: { "Authorization": `Bearer ${PLATFORM_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ amount: 4990, payer_phone: "+77011234567", merchant_order_id: "order_1" }),
})).json();
// p.id = "pay_..." p.status = "PENDING"
// QR-ссылка (без номера телефона)
const l = await (await fetch(`https://pay.1app.kz/platform/merchants/${schoolId}/payments/link`, {
method: "POST",
headers: { "Authorization": `Bearer ${PLATFORM_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ amount: 4990, merchant_order_id: "order_2" }),
})).json();
// l.payment_link = "https://pay.kaspi.kz/pay/..."

Ещё: GET …/payments, GET …/payments/:id, POST …/payments/:id/cancel, POST …/refunds, POST …/clients/check.

Статистика

Эндпоинты
GET https://pay.1app.kz/platform/merchants/:id/stats # оборот, баланс, ставка, объём за сегодня
GET https://pay.1app.kz/platform/stats # агрегат по всем школам платформы

Вебхук платформы

Один URL на всю платформу — события всех школ приходят сюда с merchant_id и merchant_external_id.

Настроить вебхук
const { secret } = await (await fetch("https://pay.1app.kz/platform/webhook", {
method: "PUT",
headers: { "Authorization": `Bearer ${PLATFORM_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
url: "https://api.example.com/webhooks/1pay",
events: ["payment.completed", "payment.refunded", "merchant.depleted"],
}),
})).json(); // secret — сохраните для проверки подписи
Тело события платформы
{
"id": "wh_...",
"event": "payment.completed",
"merchant_id": "mer_...",
"merchant_external_id": "school_42",
"data": { "id": "pay_...", "status": "COMPLETED", "amount": 4990, "merchant_order_id": "order_1" }
}

Подпись — та же схема: X-Webhook-Signature: sha256=<hmac>. Код проверки — в разделе Вебхуки.

Полный пример Platform API (Node)

platform.js
const API = "https://pay.1app.kz";
const KEY = process.env.ONEPAY_PLATFORM_KEY;
const h = { "Authorization": `Bearer ${KEY}`, "Content-Type": "application/json" };
// 1) Завести школу
const school = await (await fetch(`${API}/platform/merchants`,
{ method: "POST", headers: h, body: JSON.stringify({ name: "Школа Алмаз", external_id: "school_42", commission_rate: 3 }) }
)).json();
// 2) В UI школы: /devices → SMS → /devices/:id/otp → ACTIVE
// 3) Пополнить баланс
await fetch(`${API}/platform/merchants/${school.id}/balance/topup`,
{ method: "POST", headers: h, body: JSON.stringify({ amount: 5000 }) });
// 4) Платёж от имени школы
const pay = await (await fetch(`${API}/platform/merchants/${school.id}/payments`,
{ method: "POST", headers: h, body: JSON.stringify({ amount: 4990, payer_phone: "+77011234567", merchant_order_id: "ord_1" }) }
)).json();
// 5) На ваш платформенный вебхук прилетит payment.completed (merchant_external_id = "school_42")

Справочник

POST/v1/payments

Создать счёт на телефон

Выставляет счёт в Kaspi на указанный номер. Покупатель подтверждает оплату в приложении Kaspi. Тип платежа — invoice.

ПолеТипОписание
amountnumberСумма в тенге (KZT). Укажите amount ИЛИ cart_items.
cart_itemsarrayПозиции: [{ catalog_item_id|name, count, price?, nds_percentage? }]. Сумма считается из позиций.
discount_percentagenumberСкидка на корзину, 1–99% (только с cart_items).
payer_phoneобяз.stringТелефон плательщика, формат +7XXXXXXXXXX.
commentstringНазначение платежа, видно покупателю.
merchant_order_idstringВаш идентификатор заказа. Идемпотентность — повтор вернёт 409 DUPLICATE.
metadataobjectПроизвольные данные, вернутся в вебхуке.

Запрос

POST /v1/payments
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

JSON
{
"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"
}

GET/v1/payments/:id

Получить статус платежа

Возвращает текущее состояние платежа из базы 1pay. Статус обновляется поллером каждые 3 секунды.

Запрос

GET /v1/payments/:id
curl -X GET https://pay.1app.kz/v1/payments/pay_3kQ7v2 \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx"

Ответ · 200 OK

JSON
{
"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"
}

POST/v1/payments/:id/cancel

Отменить платёж

Отменяет платёж в статусе PENDING. Уже оплаченные платежи отменить нельзя — используйте возврат.

Запрос

POST /v1/payments/:id/cancel
curl -X POST https://pay.1app.kz/v1/payments/pay_3kQ7v2/cancel \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx"

Ответ · 200 OK

JSON
{
"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"
}

POST/v1/refunds

Сделать возврат

Возвращает средства по проведённому платежу. Поддерживается полный и частичный возврат: при полном возврате платёж переходит в REFUNDED, при частичном — в PARTIALLY_REFUNDED (возврат можно добрать позже, пока сумма возвратов меньше суммы платежа). Поле refunded_amount хранит суммарно возвращённое.

ПолеТипОписание
payment_idобяз.stringID платежа 1pay (pay_...).
amountобяз.numberСумма возврата в тенге (целое), не больше остатка к возврату.

Запрос

POST /v1/refunds
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

JSON
{
"id": "pay_3kQ7v2",
"status": "REFUNDED",
"type": "invoice",
"amount": 1500,
"currency": "KZT",
"payer_phone": "+77011234567",
"merchant_order_id": "order_1042",
"refunded_amount": 1500,
"created_at": "2026-06-02T09:14:00Z",
"updated_at": "2026-06-02T10:02:00Z"
}

GET/v1/payments

Список платежей

Возвращает платежи мерчанта с фильтром по статусу и пагинацией. Параметры query: status, merchant_order_id, page, limit (≤100).

Запрос

GET /v1/payments
curl -X GET https://pay.1app.kz/v1/payments?status=COMPLETED&page=1&limit=20 \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx"

Ответ · 200 OK

JSON
{
"data": [ /* объекты платежей */ ],
"page": 1,
"page_size": 20,
"total": 134,
"total_pages": 7
}

GET/v1/payments/:id/refunds

Возвраты по платежу

Журнал возвратов (успешных и неуспешных) по конкретному платежу.

Запрос

GET /v1/payments/:id/refunds
curl -X GET https://pay.1app.kz/v1/payments/pay_3kQ7v2/refunds \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx"

Ответ · 200 OK

JSON
{
"data": [
{
"id": "ref_9aZ1",
"payment_id": "pay_3kQ7v2",
"amount": 500,
"status": "COMPLETED",
"reason": "частичный возврат",
"error": null,
"created_at": "2026-06-02T10:02:00Z"
}
]
}

GET/v1/refunds

Журнал возвратов

Все возвраты мерчанта с пагинацией (query: page, limit ≤100).

Запрос

GET /v1/refunds
curl -X GET https://pay.1app.kz/v1/refunds?page=1&limit=20 \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx"

Ответ · 200 OK

JSON
{
"data": [ /* объекты возвратов */ ],
"page": 1,
"page_size": 20,
"total": 12,
"total_pages": 1
}

POST/v1/clients/check

Проверить номер в Kaspi

Проверяет, зарегистрирован ли номер в Kaspi, до выставления счёта — снижает долю неуспешных платежей.

ПолеТипОписание
phoneобяз.stringТелефон, формат +7XXXXXXXXXX.

Запрос

POST /v1/clients/check
curl -X POST https://pay.1app.kz/v1/clients/check \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"phone": "+77011234567"
}'

Ответ · 200 OK

JSON
{
"phone": "+77011234567",
"registered": true,
"name": "И. Иванов"
}

POST/v1/subscriptions

Создать подписку

Регулярное списание с номера клиента. Списания выполняются автоматически по расписанию; при неудаче — ретраи и льготный период (grace). События приходят в вебхуках subscription.*.

ПолеТипОписание
phone_numberобяз.stringНомер клиента, +7XXXXXXXXXX.
amountобяз.numberСумма каждого списания, ₸ (целое).
billing_periodобяз.stringDAILY | WEEKLY | BIWEEKLY | MONTHLY | QUARTERLY | YEARLY.
billing_daynumberДень списания 1–28 (для месячных периодов).
bill_immediatelybooleanСписать первый платёж сразу.
max_retry_attemptsnumberПопыток до grace (1–10, по умолч. 3).
retry_interval_hoursnumberИнтервал ретрая, ч (1–168, по умолч. 24).
grace_period_daysnumberЛьготный период, дней (1–30, по умолч. 3).

Запрос

POST /v1/subscriptions
curl -X POST https://pay.1app.kz/v1/subscriptions \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+77011234567",
"amount": 4990,
"billing_period": "MONTHLY",
"billing_day": 5,
"bill_immediately": true
}'

Ответ · 201 Created

JSON
{
"id": "sub_7Kp2",
"status": "ACTIVE",
"phone_number": "+77011234567",
"amount": 4990,
"billing_period": "MONTHLY",
"billing_day": 5,
"next_billing_at": "2026-06-02T10:30:00Z",
"failed_attempts": 0,
"in_grace_period": false,
"created_at": "2026-06-02T10:30:00Z"
}

POST/v1/catalog

Каталог товаров

Товары мерчанта для счетов с позициями (cart_items) и чеков. POST — создать товар (или пачку через {products:[...]}); также GET /v1/catalog (список, ?q= поиск), GET/PATCH/DELETE /v1/catalog/:id, GET /v1/catalog/units.

ПолеТипОписание
nameобяз.stringНазвание товара.
priceобяз.numberЦена за единицу, ₸ (целое).
unitstringЕдиница измерения (шт, кг, услуга…).
barcodestringШтрихкод.
ntinstringКод маркировки.
nds_percentagenumberНДС, %.

Запрос

POST /v1/catalog
curl -X POST https://pay.1app.kz/v1/catalog \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Кофе латте",
"price": 990,
"unit": "шт",
"nds_percentage": 12
}'

Ответ · 201 Created

JSON
{
"id": "prod_4Xy",
"name": "Кофе латте",
"price": 990,
"unit": "шт",
"nds_percentage": 12,
"is_active": true,
"created_at": "2026-06-02T12:00:00Z"
}

GET/v1/payments/:id/receipt

Фискальный чек

Фискальный чек по оплаченному платежу (включите фискализацию в настройках). GET — получить чек; POST /v1/payments/:id/receipt — сформировать/дослать. Передача в Kaspi OFD — в процессе подключения; до этого чек в статусе PENDING.

Запрос

GET /v1/payments/:id/receipt
curl -X GET https://pay.1app.kz/v1/payments/pay_3kQ7v2/receipt \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx"

Ответ · 200 OK

JSON
{
"id": "rcpt_1a",
"payment_id": "pay_3kQ7v2",
"status": "PENDING",
"fiscal_id": null,
"receipt_url": null,
"payload": { "total": 1500, "items": [ /* позиции */ ] },
"created_at": "2026-06-02T10:00:00Z",
"sent_at": null
}

POST/v1/subscriptions/:id/pause | /resume | /cancel

Управление подпиской

pause — приостановить, resume — возобновить (следующее списание планируется от момента возобновления), cancel — отменить навсегда. Также: GET /v1/subscriptions, GET /v1/subscriptions/:id, PUT /v1/subscriptions/:id, GET /v1/subscriptions/:id/invoices.

Запрос

POST /v1/subscriptions/:id/pause | /resume | /cancel
curl -X POST https://pay.1app.kz/v1/subscriptions/sub_7Kp2/pause \
-H "Authorization: Bearer 1pay_live_xxxxxxxxxxxx"

Ответ · 200 OK

JSON
{
"id": "sub_7Kp2",
"status": "PAUSED",
"paused_at": "2026-06-02T11:00:00Z"
}

Справочник

Коды ошибок

Ошибки возвращаются с HTTP-статусом и телом { "error": { "code", "message" } }.

HTTPКодОписание
400VALIDATION_ERRORНекорректное тело запроса или параметры.
401UNAUTHORIZEDОтсутствует или недействителен API-ключ.
402SESSION_EXPIREDСессия устройства истекла — переавторизуйте устройство.
403FORBIDDENДействие недоступно (например, не подтверждён email).
404NOT_FOUNDПлатёж или ресурс не найден.
409DUPLICATEmerchant_order_id уже использован.
422KASPI_ERRORKaspi отклонил операцию.
429RATE_LIMITEDСлишком много запросов — повторите позже (см. заголовок Retry-After).
500INTERNAL_ERRORВнутренняя ошибка сервиса.

Статусы платежей

PENDINGСоздан, ждёт оплаты клиентом.
COMPLETEDОплачен.
FAILEDОтклонён / ошибка оплаты.
CANCELLEDОтменён мерчантом.
EXPIREDИстёк срок действия.
PARTIALLY_REFUNDEDВозвращена часть суммы.
REFUNDEDВозвращена вся сумма.

События вебхуков

payment.completedОплачен (терминальный).
payment.failedНе прошёл.
payment.cancelledОтменён.
payment.expiredИстёк срок.
payment.refundedВозврат выполнен.
payment.refund_failedВозврат не удался.
subscription.payment_succeededПодписка: списание прошло.
subscription.payment_failedПодписка: списание не прошло (будет ретрай).
subscription.grace_period_startedПодписка: исчерпаны попытки — начался grace.
subscription.expiredПодписка: grace закончился без оплаты — остановлена.
merchant.balance_lowБаланс комиссии ниже порога.
merchant.depletedБаланс комиссии исчерпан.

Маппинг статусов Kaspi → 1pay

Поллер опрашивает Kaspi каждые ~3 с и нормализует статусы.

QR / платёжные ссылки
ProcessedCOMPLETED
CancelledByUser, NotConfirmedByUser, Rejected, Error, Insufficient*, Iris*FAILED
QrTokenDiscarded, ExpiredEXPIRED
QrTokenCreated, WaitPENDING
Счета (invoice)
ProcessedCOMPLETED
RemotePaymentCanceled, RemotePaymentRejectedFAILED
ExpiredEXPIRED
RemotePaymentCreatedPENDING