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

Обновлено 6 июля 2026 · Начало работы · Версия в Markdown
Содержание
  1. Машинная дорожка
  2. Что такое ApiPay (контекст для ИИ)
  3. Автономный sandbox-тест-цикл
  4. Готовые промпты для вашего ИИ
  5. Проверка вебхуков и HMAC
  6. Обработка ошибок
  7. Sandbox vs Production и предупреждения
  8. Краткий справочник
  9. In English
  10. Частые вопросы

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

Дайте ИИ-ассистенту любой из этих 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.

Фраза-подсказка: «Скопируй ИИ-ассистенту ссылку 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.
  • Если счёт не в pending400 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 (опционально). Проверить возврат. При paidPOST /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 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). Настройка и код проверки подписи — в разборе настройки вебхуков.

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

  • Определяйте тип ошибки по стабильному полю 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 (организация не верифицирована или заблокирована), 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. Переключение в рабочий режим — через личный кабинет; ключи и вебхуки переносятся автоматически. Что именно меняется — в разборе песочница и рабочий режим.
  • simulate-status доступен только для sandbox-счетов — в проде недоступен ни при каких условиях.
  • Гигиена ключа: X-API-Key не коммитьте в репозиторий, храните в переменных окружения или секретах. В примерах — только YOUR_API_KEY. Разница ключа и секрета подписи — в разборе API-ключ и вебхук-секрет.
  • Запрет массового перебора POST /clients/check: сервер детектит аномалии (honeypot, всплеск, низкая конверсия) и деактивирует ключ без предупреждения. Sandbox-режим: 87770000001has_kaspi: true, "Иван И."; 87770000002has_kaspi: false; любой другой → false.
  • Отмена в проде асинхронна: POST /invoices/{id}/cancel202 + статус 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 и платформ, которые онбордят чужих мерчантов: см. разбор как партнёру подключить организацию мерчанта.
  • Как ставится приём Kaspi целиком (регистрация, кассир, первый счёт) — в разборе настройки за 15 минут.

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

Интеграция с ИИ

Не настраивайте вручную — поручите ИИ

Скопируйте готовый промпт и вставьте своему ИИ-ассистенту — он подключит приём платежей примерно за 15 минут. Настраивает ИИ, а не вы.

Для разработчика. Полная спецификация API — apipay.kz/docs. Эта статья в Markdown — /guides/integratsiya-apipay-s-pomoshchyu-ii.md. Справочник фактов для ИИ-агента — apipay.kz/llms.txt.