> Источник: https://apipay.kz/guides/integratsiya-apipay-s-pomoshchyu-ii · Обновлено: 2026-07-06 · apipay.kz
> ApiPay — независимый сервис приёма платежей поверх вашего Kaspi Pay.

# Интеграция с ApiPay с помощью ИИ

**TL;DR.** Дайте своему ИИ-ассистенту (Claude, GPT, Cursor, Copilot) любую из машинных ссылок — `https://apipay.kz/llms.txt` или `https://apipay.kz/openapi.json` — и он построит приём платежей Kaspi без ваших вопросов: base URL `https://api.apipay.kz/api/v1`, авторизация заголовком `X-API-Key`. Отличие ApiPay — **автономный sandbox-цикл из 3 шагов**: агент сам создаёт тестовый счёт, симулирует его статус через `POST /invoices/{id}/simulate-status` и проверяет доставку вебхука через `GET /webhook-logs` — без реального Kaspi и без единого телефонного номера. Общий лимит — 200 запросов в минуту на ключ.

## Коротко

| Параметр | Значение |
|---|---|
| Base URL API | `https://api.apipay.kz/api/v1` (это не сайт apipay.kz) |
| Авторизация | Заголовок `X-API-Key`, `Content-Type: application/json` |
| Машинные файлы | `/llms.txt`, `/openapi.json`, `/apipay-api-docs.md`, `/docs.html` |
| Тест без Kaspi | `POST /invoices/{id}/simulate-status` — только sandbox |
| Проверка вебхука | `GET /webhook-logs?invoice_id=…`, пагинация `{current_page, data, total}` |
| Подпись вебхука | `X-Webhook-Signature: sha256=<hex>` — HMAC-SHA256 от сырого тела |
| Лимиты | 200 req/min на ключ; `simulate-status` и `/clients/check` — по 60/min |

## Машинная дорожка

Дайте ИИ-ассистенту любой из этих 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](/for-ai); готовые промпты — [apipay.kz/prompts](/prompts).

Фраза-подсказка: «Скопируй ИИ-ассистенту ссылку `https://apipay.kz/llms.txt` (или `openapi.json`) и попроси построить приём платежей ApiPay — дальше следуй промптам из этой статьи».

## Что такое ApiPay (контекст для ИИ)

ApiPay — независимый сервис приёма платежей Kaspi Pay по номеру телефона в Казахстане через REST API; он не аффилирован с Kaspi и не является «официальной интеграцией Kaspi». Мерчант создаёт счёт → покупатель получает уведомление в приложении Kaspi и платит → приходит вебхук об оплате. Деньги идут напрямую на Kaspi-счёт мерчанта, без договора с банком и без процента с продаж. Два способа: кабинет (без кода) и REST API (`X-API-Key`, `/api/v1`).

## Автономный 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`, ≤255 символов; по умолчанию «Симулированная ошибка (sandbox).»). Вебхук уходит как при реальной ошибке.
- `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": {…} }`. Свой лимит — 60/мин на ключ (не расходует общий лимит 200/мин).

**Шаг 3. Проверить доставку вебхука — `GET /webhook-logs`:**
- Read-only логи доставок вашей организации. Фильтры: `invoice_id`, `event` (`invoice.status_changed`, `invoice.qr_scanned`, `invoice.refunded`), `status` (`success|failed`), `date_from`/`date_to`, `sort_by` (`created_at|response_time_ms|response_status`), `sort_order`, `per_page` ≤ 100.
- Пагинация плоская: `{ current_page, data, total }`.
- `GET /webhook-logs/{id}` — одна доставка с полными `request_body`/`response_body`; чужой лог → `404` (защита от перебора).
- Поля записи `WebhookLogEntry`: `id`, `event`, `invoice_id`, `url`, `request_body` (полный payload JSON-строкой), `response_body` (обрезан до 4096 байт), `response_status`, `status` (`success|failed`), `response_time_ms`, `error_message`, `created_at`, `retry_of`. Логи хранятся 14 дней; повторная отправка (retry) через API недоступна — только из кабинета.
- **Критерий успеха цикла:** по каждому симулированному статусу в `/webhook-logs` появляется запись `status: success` с ожидаемым `event`.

**Шаг 4 (опционально). Проверить возврат.** При `paid` — `POST /invoices/{id}/refund` (полный или частичный `amount`), затем `GET /invoices/{id}/refunds`.

Полный воспроизводимый цикл (замените `YOUR_API_KEY`; номер — маска или sandbox-константа, не реальный):

```bash
BASE="https://api.apipay.kz/api/v1"
KEY="YOUR_API_KEY"

# 1) sandbox-счёт
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')

# 2) дождаться pending, затем симулировать оплату (только sandbox)
curl -s -X POST "$BASE/invoices/$ID/simulate-status" -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" -d '{"status":"paid"}'

# 3) проверить, что вебхук ушёл
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 URL `https://api.apipay.kz/api/v1`, заголовок авторизации `X-API-Key`. Реализуй `POST /invoices` (счёт по номеру), `GET /invoices/{id}` (статус), `POST /invoices/{id}/refund` (возврат). Ключ бери из переменной окружения, не хардкодь.»
> EN: “Open `https://apipay.kz/openapi.json` and generate a typed client for ApiPay: base URL `https://api.apipay.kz/api/v1`, auth header `X-API-Key`. Implement `POST /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 the `X-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)`. Handle `invoice.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 via `POST /invoices`, wait for `pending`, then run `POST /invoices/{id}/simulate-status` for `paid`, `error` and (for a QR invoice) `qr_scanned`; after each, confirm via `GET /webhook-logs?invoice_id=…` that delivery is `status: success` with the expected `event`. Note: `simulate-status` works 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 the `error_code` field (catalog at `/errors`): for an async invoice error (webhook `invoice.status_changed`, `status=error`) read `error_code`/`error_message`; on `429` respect the `Retry-After` header; on `422` parse `errors`. A ‘retry’ on `status=error` means creating a new operation, not retrying the same one.”

## Проверка вебхуков и HMAC

- Заголовок подписи: `X-Webhook-Signature: sha256=<hex>` — присылается **только если** у ключа задан `webhook_secret`.
- Подпись = `sha256=` + `hash_hmac('sha256', <тело запроса>, webhook_secret)`. Верифицируйте по **сырому телу** (raw body), а не по перепарсенному JSON.
- Успех доставки — любой HTTP 2xx; приёмник должен ответить **в пределах 5 секунд**, тяжёлую работу выносите в фон.
- Ретраи: до 11 попыток (1 + 10) с экспоненциальным backoff (~2 часа суммарно); в sandbox для invoice-вебхуков — 3 попытки. Ретраятся только HTTP ≥ 500, ровно `429` и сетевые ошибки; `3xx`/`4xx` (кроме `429`) считаются доставленными.
- Circuit breaker на ключ: 5 подряд неудач → пауза 5 мин, 10 → 30 мин, 20 → 2 ч, 50 → полная остановка до ручного вмешательства.
- **Дедуп обязателен** (ретрай после частичной доставки уходит всем приёмникам). Ключи дедупа: `(invoice.id, invoice.status)`, `(refund.id, refund.status)`, `(event, subscription.id, invoice_id)`.
- Даты в вебхуках — ISO 8601 UTC (`+00:00`). У каждого payload есть `source` (имя ключа, может быть `null`) и `is_sandbox`. Всего 12 событий вебхуков (перечислены в `llms.txt`). Настройка и код проверки подписи — в разборе [настройки вебхуков](/guides/nastroyka-webhookov-apipay).

## Обработка ошибок

- Определяйте тип ошибки по стабильному полю `error_code` (snake_case), а не по тексту; `message`/`error` оставлены для обратной совместимости. Каталог кодов — на странице [apipay.kz/errors](/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` (организация не верифицирована или заблокирована), `404`, `409` (дубль идемпотентности), `422` (валидация — детали в `errors`), `429` (`Retry-After`/`retry_after`), `502` (сторона Kaspi), `503` (сессия Kaspi).
- `sandbox_simulated_error` — тестовый код: появляется только в песочнице через `simulate-status` со `status=error`, в бою его не бывает.

## Sandbox vs Production и предупреждения

- При регистрации создаётся sandbox-организация; тестовые счета и подписки помечены `is_sandbox: true`. Переключение в рабочий режим — через личный кабинет; ключи и вебхуки переносятся автоматически. Что именно меняется — в разборе [песочница и рабочий режим](/guides/pesochnitsa-i-rabochiy-rezhim).
- `simulate-status` доступен **только для sandbox-счетов** — в проде недоступен ни при каких условиях.
- **Гигиена ключа:** `X-API-Key` не коммитьте в репозиторий, храните в переменных окружения или секретах. В примерах — только `YOUR_API_KEY`. Разница ключа и секрета подписи — в разборе [API-ключ и вебхук-секрет](/guides/api-klyuch-i-webhook-secret).
- **Запрет массового перебора `POST /clients/check`:** сервер детектит аномалии (honeypot, всплеск, низкая конверсия) и деактивирует ключ **без предупреждения**. 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`. Статуса `refunded` нет — полный возврат оставляет `paid` + `is_fully_refunded: true`.
- **Ключевые эндпоинты цикла:** `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`.
- **Машинные файлы:** `/llms.txt`, `/openapi.json`, `/apipay-api-docs.md`, `/docs.html`.
- **Partner API** (`X-Partner-Key`, `/api/partner`) — отдельная тема для CRM и платформ, которые онбордят чужих мерчантов: см. разбор [как партнёру подключить организацию мерчанта](/guides/partner-connect-organization).
- Как ставится приём Kaspi целиком (регистрация, кассир, первый счёт) — в разборе [настройки за 15 минут](/guides/nastroyka-apipay-za-15-minut).

## In English

ApiPay is an independent Kazakhstani service for accepting Kaspi Pay payments over the merchant's own Kaspi Pay — not affiliated with Kaspi, and never an "official Kaspi integration". A merchant creates an invoice, the buyer pays inside the Kaspi app, and 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)`. Up to 11 delivery attempts; circuit breaker at 5/10/20/50 failures. **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` — anomaly detection deactivates the key. The ready-made prompts above are provided in English too.

## Частые вопросы

**Что дать ИИ-агенту, чтобы он начал интеграцию?**
Любую машинную ссылку: `https://apipay.kz/llms.txt` (компактный контекст) или `https://apipay.kz/openapi.json` (полная спека для генерации клиента). Base URL API — `https://api.apipay.kz/api/v1`, авторизация заголовком `X-API-Key`.

**Можно ли проверить интеграцию без реального Kaspi и без телефонов?**
Да, в этом суть sandbox-цикла: создаёте sandbox-счёт, гоните `POST /invoices/{id}/simulate-status` и проверяете вебхук через `GET /webhook-logs`. Настоящий Kaspi и SMS не задействуются, номера — только маска или sandbox-константы.

**Работает ли `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`), которым платформы онбордят чужих мерчантов; это отдельная тема.

---

ApiPay — независимый сервис и не аффилирован с АО «Kaspi Bank». Kaspi и Kaspi Pay — товарные знаки их правообладателя.
База знаний: https://apipay.kz/guides
