ДокументацияВведение
Коды ошибок

Справочник

Переход с v1 на v2

Что изменилось и сроки sunset

API v1 (/v1/*) объявлен deprecated и будет отключён 31 декабря 2026 года; на замену пришёл v2 (/v2/*) с обязательной идемпотентностью и чистыми JSON-ответами вместо legacy-обёртки. Чтобы мигрировать, замените пути по таблице ниже, начните слать заголовок Idempotency-Key на всех мутирующих POST и перестаньте разбирать конверт {StatusCode, Data, Message} — v2 отдаёт данные напрямую. Авторизация не меняется: тот же заголовок X-API-Key.

Каждый ответ v1 уже несёт предупреждающие заголовки Deprecation: true, Sunset: Wed, 31 Dec 2026 23:59:59 GMT и Link: ; rel="successor-version". Полный справочник новых путей — в API Reference, детали по QR и счетам — в QR и счета.

Таблица соответствий путей v1 → v2

Каждому пути v1 соответствует преемник в v2. Один путь (/v1/status) прямого аналога не имеет.

Методv1 (deprecated)Методv2 (актуальный)
POST/v1/qr/createPOST/v2/qr
GET/v1/qr/status/{op_id}GET/v2/qr/{op_id}
POST/v1/invoice/createPOST/v2/invoices
POST/v1/invoice/cancelPOST/v2/invoices/{op_id}/cancel
POST/v1/historyGET/v2/payments
POST/v1/refundPOST/v2/refunds
GET/v1/client/{phone}GET/v2/client?phone=
GET/v1/statusнет прямого аналога (см. ниже)

Обратите внимание: /v1/history был POST, а его преемник GET /v2/payments — обычный GET с query-параметрами и курсорной пагинацией. /v1/client/{phone} переехал с path-параметра на query ?phone=.

Что нового в v2

Ключевые отличия, которые нужно учесть при переносе кода.

  • Idempotency-Key обязателен на POST /v2/qr, POST /v2/invoices, POST /v2/invoices/{op_id}/cancel, POST /v2/refunds. Без него — 400 idempotency_key_required. Генерируйте один ключ на намерение пользователя. Подробно — Идемпотентность.
  • Чистые JSON-ответы вместо legacy-обёртки {StatusCode, Data, Message}. POST /v2/qr сразу возвращает {operation_id, qr_token, deep_link, expires_at, status}.
  • Единый формат ошибок: объект {error: {type, code, message, request_id, param, category}} вместо Message. Ветвление по category — см. Ошибки.
  • Курсорная пагинация в списках: конверт {data[], next_cursor, has_more} вместо плоского массива. См. Пагинация.
  • Мультиаккаунт Kaspi: заголовок X-Kaspi-Account: для выбора аккаунта при создании платежа.

Что делать с /v1/status

GET /v1/status возвращал {session_alive, usage_today, usage_month, rate_limit_per_minute} и прямого аналога в v2 не имеет. В кабинете те же данные доступны через JWT: живость сессии — в поле session_alive ответа GET /me, счётчики использования — в GET /me/usage. Если интеграция опиралась на /v1/status только ради проверки жив ли Kaspi-аккаунт, перенесите её на GET /me или следите за ошибкой 503 session_expired от рабочих вызовов.

curl: до и после

Создание QR на v1 (legacy-обёртка в ответе):

bash
Скачать
curl -X POST https://api.paybot.kz/v1/qr/create \
  -H "X-API-Key: kp_live_0123456789abcdef0123456789abcdef" \
  -H "Idempotency-Key: 6f9619ff-8b86-d011-b42d-00cf4fc964ff" \
  -H "Content-Type: application/json" \
  -d '{"amount": 5000}'
json
Скачать
{
  "StatusCode": 0,
  "Data": { "operation_id": "op_3fa8", "qr_token": "kzqr_9d8f" },
  "Message": "OK"
}

То же самое на v2 (данные напрямую, без обёртки):

bash
Скачать
curl -X POST https://api.paybot.kz/v2/qr \
  -H "X-API-Key: kp_live_0123456789abcdef0123456789abcdef" \
  -H "Idempotency-Key: 6f9619ff-8b86-d011-b42d-00cf4fc964ff" \
  -H "Content-Type: application/json" \
  -d '{"amount": 5000, "comment": "Заказ #1042"}'
json
Скачать
{
  "operation_id": "op_3fa85f6457174562",
  "qr_token": "kzqr_9d8f7a6b5c4d",
  "deep_link": "https://kaspi.kz/pay/9d8f7a6b5c4d",
  "expires_at": "2026-07-16T12:05:00Z",
  "status": "created"
}

Как изменился формат ответа

В v1 успех и данные заворачивались в конверт {StatusCode, Data, Message}, а ошибка передавалась текстом в Message. В v2 данные приходят объектом верхнего уровня, а любая ошибка — единым объектом {error: {type, code, message, request_id, param, category}}.

  • Уберите распаковку Data — читайте поля прямо из корня ответа (response.operation_id, а не response.Data.operation_id).
  • Перестаньте парсить Message для определения ошибки — проверяйте HTTP-статус и, при ошибке, ветвитесь по error.category (auth | validation | rate_limit | temporary | permanent).
  • Сохраняйте error.request_id в логах — по нему поддержка находит запрос.
  • Поле error.param подсказывает конкретное поле ввода при validation — подсвечивайте именно его.

Полная таблица кодов и правило показа по category — в Ошибки.

Как изменились списки

Списочные эндпоинты v2 отдают курсорную пагинацию вместо плоского массива. POST /v1/history возвращал массив записей; преемник GET /v2/payments возвращает конверт {data[], next_cursor, has_more}.

  • Признак «есть ещё страница» — поле has_more, а не длина массива.
  • next_cursor — opaque-строка: передавайте её как есть в параметр cursor следующего запроса, не парсите и не собирайте вручную.
  • Нумерованных страниц и total нет — стройте «Загрузить ещё» или бесконечный скролл.

Детали пагинации и лимиты limit — в Пагинация.

Рекомендация по срокам

Мигрируйте на v2 сейчас, не дожидаясь sunset. v1 продолжает работать до 31 декабря 2026 года, но новых возможностей (платёжные ссылки, hosted checkout, единый формат ошибок и событий) в нём нет и не будет. После даты sunset вызовы /v1/* перестанут отвечать. Проверяйте заголовок Deprecation: true в логах, чтобы найти код, всё ещё зовущий старые пути.

FAQ

Изменится ли мой API-ключ при переходе на v2?

Нет. Тот же ключ kp_live_... работает и на /v1/*, и на /v2/* — авторизация идентична (X-API-Key). Перевыпускать ключ для миграции не нужно.

Что вернёт v1 после даты sunset?

После 31 декабря 2026 пути /v1/* выводятся из эксплуатации и перестают обслуживать запросы. До этой даты они работают, но помечены заголовком Deprecation: true. Планируйте перенос заранее — полный список преемников есть в API Reference.

Нужно ли переписывать обработку ответов?

Да, в части структуры. v1 заворачивал данные в {StatusCode, Data, Message}, а v2 отдаёт объект напрямую и использует единый формат ошибок {error: {...}}. Уберите распаковку Data и перенесите ветвление ошибок на поле category — см. Ошибки.

Что делать, если один и тот же ключ идёт на v1 и v2?

Так делать можно на переходный период: авторизация общая. Но помните, что мутирующие v1-вызовы для enterprise-плана раньше генерировали Idempotency-Key автоматически, а v2 требует его всегда и от всех планов. Приведите клиентский код к единому правилу — «один ключ на намерение пользователя» для обеих версий, чтобы поведение не расходилось.

Как проверить, что миграция завершена?

Убедитесь, что в логах интеграции больше нет ответов с заголовком Deprecation: true — он присутствует только на путях /v1/*. Отсутствие этого заголовка на протяжении полного цикла нагрузки означает, что старые пути больше не вызываются и можно спокойно дожидаться sunset.