Любой разработчик, который писал интеграцию с реальными деньгами, знает это чувство: код вроде работает, тесты зелёные, но кладёшь палец на «Deploy» — и сердце ёкает. Sandbox убирает этот стресс. В Pay Bot он встроен с первого дня и работает одинаково с live-окружением.
Чем Sandbox отличается от Live
Sandbox — это полноценная копия Pay Bot API, в которой:
- Деньги не двигаются. Никаких списаний, никакого баланса.
- QR-коды не открываются в Kaspi. Они «оплачиваются» через специальный эндпоинт-симулятор.
- Webhook'и приходят как обычно. Те же поля, та же HMAC-подпись, та же retry-политика.
- Rate-limits помягче. Можно прогонять стресс-тесты без блокировок.
- Логи хранятся 7 дней. В live — 30+.
Главное: код вашей интеграции работает в Sandbox и в live идентично. Меняется только ключ.
Получение Sandbox-ключа
После регистрации в кабинете вам сразу выдают kp_test_.... Дополнительные шаги не нужны. Этот ключ работает даже без подключения Kaspi Business — что удобно, если хотите потрогать API до коммерческой настройки.
# Тест: ключ работает
curl https://api.paybot.kz/v1/status \
-H "X-API-Key: kp_test_yourkey"
# {"status":"ok","worker_count":3,"queue_depth":0}
Если ответ 200 — всё, можно работать.
Базовый сценарий: создать платёж и «оплатить»
Создаём QR
import requests, uuid
resp = requests.post(
"https://api.paybot.kz/v1/qr/create",
headers={
"X-API-Key": "kp_test_yourkey",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"amount": 1000},
).json()
print(resp["operation_id"]) # op_test_8f3a...
Ответ от Sandbox идентичен live — qr_url, deep_link, expires_at. Просто QR-код не работает в реальном Kaspi.
Эмулируем оплату
В Sandbox есть специальный эндпоинт-симулятор:
curl -X POST https://api.paybot.kz/sandbox/payments/op_test_8f3a.../complete \
-H "X-API-Key: kp_test_yourkey"
Сразу после вызова:
- Статус операции меняется на
paid. - Срабатывает webhook
payment.completed(если настроен). - Sender name проставляется как
"Sandbox User".
Можно также эмулировать другие сценарии:
# Клиент отменил
POST /sandbox/payments/{op_id}/cancel
# QR протух
POST /sandbox/payments/{op_id}/expire
# Возврат
POST /sandbox/payments/{op_id}/refund -d '{"amount": 1000}'
Тестовые webhook'и
Если вы делаете локальную разработку без публичного URL, есть несколько подходов.
Туннели в локальную сеть
Самое простое — ngrok или Cloudflare Tunnel:
ngrok http 3000
# Forwarding https://ab12cd34.ngrok-free.app -> http://localhost:3000
Вписываете URL https://ab12cd34.ngrok-free.app/webhook в кабинете → Webhooks → готово. Все Sandbox-уведомления летят прямо в ваш локальный сервер.
Webhook receiver в кабинете
В UI Pay Bot есть встроенный приёмник webhook'ов с историей — отдельно регистрировать ngrok не обязательно. Удобно, чтобы посмотреть, как именно формируется payload, и скопировать пример в свои фикстуры.
Кнопка «Test webhook» в UI
В разделе Webhooks по каждой подписке есть кнопка «Test» — она шлёт фиктивный payload вашему обработчику и показывает HTTP-статус, время ответа и тело. Незаменимо для отладки HMAC-верификации.
Сценарии, которые имеет смысл протестировать
Минимальный набор:
- Happy path. Создал → оплатил → webhook → статус «paid».
- Идемпотентность. Дважды POST с одним
Idempotency-Key→ один платёж. - Webhook retry. Ваш обработчик первый раз отвечает 500 → второй раз 200 → данные обработаны ровно один раз (проверка дедупа по
event.id). - Expired payment. Истечение срока → webhook
payment.expired. - Частичный возврат. Платёж на 1000, возврат на 400 → статус остаётся
paid, появляется refund_id. - Невалидная подпись. Шлёте кривой webhook руками — ваш сервер должен ответить 401.
Каждый из этих сценариев можно прогнать без денег.
Интеграция в CI
Sandbox идеален для интеграционных тестов. Минимальный пример на pytest:
import os, uuid, requests, pytest
API = "https://api.paybot.kz"
KEY = os.environ["KASPI_TEST_KEY"]
def headers(idempotent=None):
h = {"X-API-Key": KEY}
if idempotent: h["Idempotency-Key"] = idempotent
return h
def test_create_and_pay():
op = requests.post(
f"{API}/v1/qr/create",
headers=headers(str(uuid.uuid4())),
json={"amount": 500},
).json()
op_id = op["operation_id"]
assert op["qr_url"]
# Симулируем оплату
requests.post(f"{API}/sandbox/payments/{op_id}/complete", headers=headers()).raise_for_status()
# Статус
status = requests.get(f"{API}/v1/qr/status/{op_id}", headers=headers()).json()
assert status["status"] == "paid"
def test_idempotency():
key = str(uuid.uuid4())
op1 = requests.post(f"{API}/v1/qr/create", headers=headers(key), json={"amount": 100}).json()
op2 = requests.post(f"{API}/v1/qr/create", headers=headers(key), json={"amount": 100}).json()
assert op1["operation_id"] == op2["operation_id"]
Запускается в GitHub Actions / GitLab CI как обычный pytest. Ключ кладёте в secrets, в pipeline:
- run: pytest tests/integration/
env:
KASPI_TEST_KEY: ${{ secrets.KASPI_TEST_KEY }}
Чего нельзя в Sandbox
Несколько ограничений, о которых стоит знать заранее:
- Реальные QR не открываются в Kaspi. Это by design.
- Имя плательщика всегда «Sandbox User» — реальный sender name эмулировать нельзя.
- Возвраты в Sandbox симулируются мгновенно. В live это занимает 1–3 минуты.
- Rate-limits — 30 запросов/секунду на ключ. В большинстве live-планов — 60+.
Когда переходить на Live
Достаточно надёжных признаков «готовности» три:
- Все сценарии из списка выше проходят. Особенно — идемпотентность и retry webhook'ов.
- HMAC-верификация работает строго. Кривая подпись → 401, никаких исключений.
- Логирование настроено. Каждое событие записывается с
event_id, timestamp и результатом обработки.
После этого подключаете Kaspi через SMS-онбординг, получаете kp_live_... ключ и меняете одну переменную окружения. Код не меняется.
Если что-то пошло не так
Большая часть «странного» поведения в Sandbox связана с одной из трёх причин:
- Старый Idempotency-Key — Sandbox-операции живут 24 часа, потом возвращают новый платёж.
- Webhook URL стал недоступным (например, ngrok-сессия завершилась) — переподпишитесь.
- HMAC-секрет был ротирован, а старый ещё захардкожен в коде.
Если совсем застряли — пишите в @paybotkz_bot, мы помогаем с интеграцией в Sandbox бесплатно. Или оставьте заявку, если нужен полный onboarding с менеджером.
Готовы попробовать Pay Bot?
Зарегистрируйтесь в кабинете — Sandbox доступен сразу. Или оставьте заявку, и менеджер настроит подключение Kaspi за вас.