Машинная дорожка
Дайте ИИ-ассистенту любой из этих URL — этого достаточно, чтобы он понял весь API и построил интеграцию:
https://apipay.kz/llms.txt— компактный контекст для LLM: методы, проверенные факты, чейнджлог.https://apipay.kz/openapi.json— полная OpenAPI 3.0 спецификация (для генерации типизированного клиента).https://apipay.kz/apipay-api-docs.md— полный Markdown с примерами на разных языках (для парсинга).https://apipay.kz/docs.html— HTML-документация для людей.- Пошаговый плейбук для ИИ — apipay.kz/for-ai; готовые промпты — apipay.kz/prompts.
Что такое ApiPay (контекст для ИИ)
ApiPay — приём платежей Kaspi Pay по номеру телефона в Казахстане через REST API. Мерчант создаёт счёт → покупатель платит в приложении Kaspi → приходит вебхук об оплате. Деньги идут напрямую на Kaspi-счёт мерчанта.
Автономный sandbox-тест-цикл
Это ядро интеграции: ИИ-агент проверяет всё end-to-end сам, без Kaspi и без телефонов. Схема: создать sandbox-счёт → simulate-status → проверить вебхук через webhook-logs → (при paid) возврат.
Шаг 1. Создать sandbox-счёт. POST /invoices (по номеру) или POST /invoices/qr (QR). Если организация в песочнице, счёт помечается is_sandbox: true. Ответ — 201, статус сначала processing, затем вебхук переводит его в pending. Дождитесь pending (поллингом GET /invoices/{id} или по вебхуку), прежде чем симулировать статус.
Шаг 2. Симулировать статус — POST /invoices/{invoice}/simulate-status:
- Работает только для sandbox-счёта (
is_sandbox: true). Для не-sandbox счёта →403 not_sandbox. - Тело:
{ "status": <enum> }, гдеstatus ∈ { paid, cancelled, expired, error, qr_scanned }. paid/cancelled/expired— счёт уходит в терминальный статус, отправляется вебхукinvoice.status_changed. Опционально можно задатьkaspi_source_type(GOLD|RED|LOAN|BUSINESSACCOUNT|BANKINTEGRATIONACCOUNT) иkaspi_sale_type(Remote|QR|Static|Restaurant); иначе приpaidони выбираются случайно.error— счёт получаетerror_code: sandbox_simulated_errorиerror_message(свой текст можно передать в необязательном параметреerror_message). Вебхук уходит как при реальной ошибке.qr_scanned— только для QR-счёта: статус остаётсяpending, уходит вебхукinvoice.qr_scannedсqr_substate: "scanned". Повтор →400 already_scanned; для не-QR счёта →400 not_qr_invoice.- Если счёт не в
pending→400 invalid_status_transition(в ответеcurrent_statusиallowed_from: ["pending"]). - Успех —
200 { "message": "Invoice status simulated", "invoice": {…} }.
Шаг 3. Проверить доставку вебхука — GET /webhook-logs:
- Read-only логи доставок вашей организации. Пишутся доставки по счетам, возвратам и QR-возвратам; у событий
subscription.*иreceipt.*строк доставки нет вообще — проверять их черезwebhook-logsбесполезно, тестируйте приёмом на своей стороне. События каталога живут в отдельном журналеGET /api/v1/catalog/webhook-logs. Фильтры:invoice_id,event(invoice.status_changed,invoice.qr_scanned,invoice.refunded),status(success|failed),date_from/date_to. - Пагинация плоская:
{ current_page, data, total }. GET /webhook-logs/{id}— одна доставка с полнымиrequest_body/response_body; чужой лог →404(защита от перебора).- Логи хранятся 14 дней; повторная отправка (retry) через API недоступна — только из кабинета.
- Критерий успеха цикла: по каждому симулированному статусу в
/webhook-logsпоявляется записьstatus: successс ожидаемымevent.
Шаг 4 (опционально). Проверить возврат. При paid — POST /invoices/{id}/refund (полный или частичный amount), затем GET /invoices/{id}/refunds.
Полный воспроизводимый цикл (замените YOUR_API_KEY; номер — маска или sandbox-константа, не реальный):
BASE="https://api.apipay.kz/api/v1"
KEY="YOUR_API_KEY"
ID=$(curl -s -X POST "$BASE/invoices" -H "X-API-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{"amount":10000,"phone_number":"87770000001","description":"Sandbox test"}' \
| jq -r '.id')
curl -s -X POST "$BASE/invoices/$ID/simulate-status" -H "X-API-Key: $KEY" \
-H "Content-Type: application/json" -d '{"status":"paid"}'
curl -s "$BASE/webhook-logs?invoice_id=$ID&event=invoice.status_changed" \
-H "X-API-Key: $KEY" | jq '.data[] | {event, status, response_status}'
Готовые промпты для вашего ИИ
Скопируйте нужный промпт своему ассистенту. Каждый дан на русском и английском.
1. Сгенерировать клиент по OpenAPI.
RU: «Открой
https://apipay.kz/openapi.jsonи сгенерируй типизированный клиент для ApiPay: base URLhttps://api.apipay.kz/api/v1, заголовок авторизацииX-API-Key. РеализуйPOST /invoices(счёт по номеру),GET /invoices/{id}(статус),POST /invoices/{id}/refund(возврат). Ключ бери из переменной окружения, не хардкодь.» EN: “Openhttps://apipay.kz/openapi.jsonand generate a typed client for ApiPay: base URLhttps://api.apipay.kz/api/v1, auth headerX-API-Key. ImplementPOST /invoices(invoice by phone),GET /invoices/{id}(status),POST /invoices/{id}/refund. Read the key from an environment variable, never hardcode it.”
2. Вебхук-приёмник с проверкой HMAC.
RU: «Построй HTTP-эндпоинт-приёмник вебхуков ApiPay. Проверяй подпись
X-Webhook-Signature: sha256=<hex>=hash_hmac('sha256', <сырое тело>, webhook_secret)по сырому телу запроса (до парсинга JSON). Отвечай HTTP 2xx в пределах 5 секунд. Дедуплицируй по(invoice.id, invoice.status). Обработай событияinvoice.status_changed,invoice.qr_scanned,invoice.refunded.» EN: “Build an ApiPay webhook receiver. Verify theX-Webhook-Signature: sha256=<hex>header =hash_hmac('sha256', <raw body>, webhook_secret)against the raw request body (before JSON parsing). Reply HTTP 2xx within 5 seconds. Deduplicate by(invoice.id, invoice.status). Handleinvoice.status_changed,invoice.qr_scanned,invoice.refunded.”
3. Полный sandbox-цикл с проверкой.
RU: «В песочнице: создай счёт через
POST /invoices, дождисьpending, затем прогониPOST /invoices/{id}/simulate-statusдляpaid,errorи (для QR-счёта)qr_scanned; после каждого убедись черезGET /webhook-logs?invoice_id=…, что доставкаstatus: successс ожидаемымevent. Учти:simulate-statusработает только для sandbox-счетов.» EN: “In sandbox: create an invoice viaPOST /invoices, wait forpending, then runPOST /invoices/{id}/simulate-statusforpaid,errorand (for a QR invoice)qr_scanned; after each, confirm viaGET /webhook-logs?invoice_id=…that delivery isstatus: successwith the expectedevent. Note:simulate-statusworks only for sandbox invoices.”
4. Обработка ошибок по error_code.
RU: «Реализуй ветвление по полю
error_code(каталог —/errors): для асинхронной ошибки счёта (вебхукinvoice.status_changed,status=error) читайerror_code/error_message; на429уважай заголовокRetry-After; на422разбирайerrors. „Повтор“ приstatus=errorозначает создать новую операцию, а не повторять ту же.» EN: “Branch on theerror_codefield (catalog at/errors): for an async invoice error (webhookinvoice.status_changed,status=error) readerror_code/error_message; on429respect theRetry-Afterheader; on422parseerrors. A ‘retry’ onstatus=errormeans creating a new operation, not retrying the same one.”
Проверка вебхуков и HMAC
- Заголовок подписи:
X-Webhook-Signature: sha256=<hex>=hash_hmac('sha256', <тело запроса>, webhook_secret)— верифицируйте по сырому телу (raw body), а не по перепарсенному JSON. Заголовок присылается, только если у ключа заданwebhook_secret. - Успех доставки — любой HTTP 2xx; приёмник должен ответить в пределах 5 секунд, тяжёлую работу выносите в фон. Эндпоинт не должен отвечать редиректом — в настройках указывайте конечный URL.
- Дедуп обязателен (ретрай после частичной доставки уходит всем приёмникам). Ключи дедупа:
(invoice.id, invoice.status),(refund.id, refund.status),(event, subscription.id, invoice_id). - Ретраи, circuit breaker, список событий и код проверки подписи — в разборе настройки вебхуков.
Обработка ошибок
- Определяйте тип ошибки по стабильному полю
error_code(snake_case), а не по тексту;message/errorоставлены для обратной совместимости. Каталог кодов — на странице apipay.kz/errors, у каждой ошибки естьdoc_url. - Асинхронные ошибки Kaspi.
POST /invoicesиPOST /invoices/qrотвечают201соstatus=processing. Если Kaspi не смог, статус станетerror, причина — вerror_message, код — вerror_code(напримерclient_not_found,network_unavailable,kaspi_throttled). Забирайте черезGET /invoices/{id}или из вебхукаinvoice.status_changed(status=error). Не пересоздавайте счёт, пока он вprocessing— получите два живых счёта. - HTTP-статусы:
401(ключ отсутствует/невалиден/деактивирован),403(tariff_inactive,kyc_rejected, организация не верифицирована),404,409(duplicate_idempotency_key— в телеinvoice_idиstatusуже существующего счёта),422(валидация — детали вerrors),429(Retry-After; кодыkyc_daily_limit_reached,tariff_limit_reached,qr_rate_limit),502(сторона Kaspi),503(kaspi_session_invalidнаPOST /invoices/qr— QR-счёт не создан, помогает только переавторизация кассира;invoices_disabled— счёт НЕ создан, повтор позже безопасен).
Sandbox vs Production и предупреждения
- При регистрации создаётся sandbox-организация; тестовые счета и подписки помечены
is_sandbox: true. Переключение в рабочий режим — переключатель в личном кабинете. Что именно меняется — в разборе песочница и рабочий режим. - Гигиена ключа:
X-API-Keyне коммитьте в репозиторий, храните в переменных окружения или секретах. В примерах — толькоYOUR_API_KEY. Разница ключа и секрета подписи — в разборе API-ключ и вебхук-секрет. - Запрет массового перебора
POST /clients/check: проверять можно номера своих покупателей, а не базу целиком. При злоупотреблении ключ деактивируется без предупреждения. Sandbox-режим:87770000001→has_kaspi: true,"Иван И.";87770000002→has_kaspi: false; любой другой →false. - Отмена в проде асинхронна:
POST /invoices/{id}/cancel→202+ статусcancelling, реальный итог придёт вебхуком.
Краткий справочник
- Статусы счёта:
processing,pending,cancelling,paid,cancelled,expired,error,partially_refunded— что означает каждый, в разборе жизненного цикла счёта. - Ключевые эндпоинты цикла:
POST /invoices,POST /invoices/qr,GET /invoices/{id},POST /invoices/{id}/simulate-status(sandbox),GET /webhook-logs,GET /webhook-logs/{id},POST /invoices/{id}/refund. - Partner API (
X-Partner-Key,/api/partner) — отдельная тема для CRM и платформ, которые онбордят чужих мерчантов: см. разбор как партнёру подключить организацию мерчанта. - Как ставится приём Kaspi целиком (регистрация, кассир, первый счёт) — в разборе настройки за 15 минут.
In English
ApiPay accepts Kaspi Pay payments through the merchant's own Kaspi Pay account: create an invoice, the buyer pays in the Kaspi app, a webhook confirms it. Money goes straight to the merchant's Kaspi account.
Give your AI assistant one of the machine files and it can build the integration: https://apipay.kz/llms.txt, https://apipay.kz/openapi.json, or https://apipay.kz/apipay-api-docs.md. Base URL: https://api.apipay.kz/api/v1; auth header X-API-Key; Content-Type: application/json; 200 req/min per key.
Autonomous sandbox test loop (no Kaspi, no phone numbers): create a sandbox invoice with POST /invoices (wait for pending), drive its status with POST /invoices/{id}/simulate-status (paid|cancelled|expired|error|qr_scanned, sandbox only — 403 not_sandbox otherwise; 400 invalid_status_transition if not pending), then verify webhook delivery via GET /webhook-logs?invoice_id=… (flat pagination {current_page, data, total}). Success = a status: success row with the expected event. Optionally refund with POST /invoices/{id}/refund.
Webhooks: signature X-Webhook-Signature: sha256=<hex> = hash_hmac('sha256', <raw body>, webhook_secret) — verify against the raw body, reply 2xx within 5 seconds, deduplicate by (invoice.id, invoice.status). Your endpoint must not redirect. Errors: branch on the stable error_code (catalog at /errors); POST /invoices is async (201 status=processing); respect Retry-After on 429. Never hardcode X-API-Key; don't bulk-probe POST /clients/check — check your own customers' numbers only, abuse deactivates the key. The ready-made prompts above are provided in English too.
Частые вопросы
Работает ли simulate-status в рабочем режиме?
Нет. simulate-status доступен только для sandbox-счетов (is_sandbox: true); в проде вызов вернёт 403 not_sandbox.
Почему POST /invoices вернул 201, но статус processing?
Это не ошибка: создание счёта асинхронное. Счёт перейдёт в pending вебхуком; при сбое Kaspi станет error с error_code/error_message. Не пересоздавайте счёт в processing — иначе получите два живых счёта.
Как отличить X-API-Key от X-Partner-Key?
X-API-Key — обычный мерчантский ключ для /api/v1 (счета, вебхуки, возвраты). X-Partner-Key — для Partner API (/api/partner), которым платформы онбордят чужих мерчантов; это отдельная тема.