# Интеграцияны қалай сынау керек

> Sandbox-та өтуге тиіс сценарийлер тізімі: сәтті төлем, болдырмау, мерзімі өту, толық және ішінара қайтару, кеш төлем. Webhook-ты қалай сынау, қандай шекті жағдайларды тексеру керек және автоматты тестті қалай жазу керек.

## Қысқаша

Sandbox (`qp_test_…` кілті) — нақты ақша жүрмейтін, Kaspi шақырылмайтын толық жұмыс істейтін режим. Төлемді өзіңіз `POST /api/v1/invoices/{id}/simulate` арқылы «орындайсыз». Sandbox үшін Kaspi кассирі керек емес және sandbox счёттары тариф лимитіне кірмейді.

Продакшенге шықпас бұрын кемінде **алты сценарийді** өткізіңіз: сәтті төлем, болдырмау, мерзімі өту, толық қайтару, ішінара қайтару, кеш төлем. Соңғысын ұмытып кетеді де, іс жүзінде сол бұзады.

## Дайындық

1. Кабинетте режимді sandbox-қа қойыңыз
2. `qp_test_…` кілтін жасаңыз, қажет scope-тарды беріңіз
3. Webhook адресін қосыңыз және құпиясын сақтаңыз (бір рет көрсетіледі)

Sandbox пен live айырмашылығы: [Sandbox пен нақты режим](/kb/sandbox-vs-live).

## Алты негізгі сценарий

`simulate` эндпоинті үш күйді қабылдайды: `paid`, `failed`, `expired`. Болдырмау бөлек эндпоинтпен, қайтару да бөлек эндпоинтпен жасалады.

| № | Сценарий | Қалай жасайсыз | Не тексересіз |
|---|---|---|---|
| 1 | Сәтті төлем | Счёт жасау → `simulate {"status":"paid"}` | `invoice.paid` webhook келді, тапсырыс «төленді» болды, тауар/қызмет берілді |
| 2 | Болдырмау | Счёт жасау → `POST /invoices/{id}/cancel` | Күй `cancelled`, `invoice.cancelled` келді, тапсырыс жабылды |
| 3 | Мерзімі өту | Счёт жасау → `simulate {"status":"expired"}` | Күй `expired`, `invoice.expired` келді, себет босатылды немесе тауар қоймаға қайтты |
| 4 | Толық қайтару | Төленген счёт → `POST /invoices/{id}/refund` сомасыз | Күй `refunded`, `refund.done` және `invoice.refunded` келді |
| 5 | Ішінара қайтару | Төленген счёт → `refund {"amount": жартысы}` | Күй `partially_refunded`, қалған сома дұрыс есептелді |
| 6 | Кеш төлем | Счётты `cancel` немесе `simulate expired` қылып жабыңыз, сосын `simulate {"status":"paid"}` | `invoice.paid` оқиғасы **`late: true`** белгісімен келді, жүйеңіз жабылған тапсырысты қалай өңдейтінін көресіз |

Алтыншы сценарий ең маңыздысы. Нақты өмірде клиент QR-ды сканерлеп, ойланып отырып, счёт өтіп кеткеннен кейін растап жіберуі мүмкін. Сіздің жүйеңіз не істейді: қызметті береді ме, әлде ақшаны автоматты қайтарады ма? Шешімді алдын ала қабылдаңыз, әйтпесе бірінші сондай жағдайда қолмен шешуге тура келеді. Толығы: [Кеш келген төлем](/kb/late-payment).

`simulate` толық сипаттамасы: [Sandbox-та төлемді симуляциялау](/kb/sandbox-simulate).

## Webhook-ты сынау

Webhook — интеграцияның ең нәзік бөлігі, өйткені ол сіздің серверіңізге сырттан кіреді. Үш тәсіл бар.

**1. Жергілікті сервер + туннель.** Әзірлеу кезінде ыңғайлы: туннель қызметі (ngrok сияқты) жергілікті портыңызды сыртқы адреске шығарады. Sandbox-та бұл жұмыс істейді.

**Бірақ продакшенде туннель адресі қабылданбайды** — `webhook_url_tunnel_forbidden` қатесін аласыз. Продакшенде тек тұрақты домен және `https`. Сондықтан туннельді тек әзірлеуге пайдаланыңыз, live адрес ретінде қалдырмаңыз.

**2. Сыртқы қабылдағыш (webhook.site сияқты).** Қолтаңбаның, тақырыптардың, дененің қалай келетінін өз көзіңізбен көру үшін жақсы. Бірақ **құпияңызды сондай қызметке салмаңыз** — тек sandbox құпиясымен, тек қарап көру үшін пайдаланыңыз.

**3. Қолтаңбаны офлайн тексеру.** Ең сенімдісі. Келген денені файлға сақтап, юнит-тест жазыңыз: `timestamp + "." + rawBody` жолынан HMAC-SHA256 есептеп, `X-Webhook-Signature` мәнімен салыстырыңыз.

Webhook өңдеуіңізде міндетті түрде тексеретін тізім:

- Қолтаңба сәйкес келмесе — 401 қайтарып, өңдемеу
- `X-Webhook-Timestamp` 5 минуттан ескі болса — қабылдамау
- Қолтаңба дұрыс болса — **алдымен 200 қайтару**, ауыр жұмысты содан кейін істеу
- Сол `(invoice.id, status)` жұбы екінші рет келсе — қайта өңдемеу

2xx бермесеңіз, жеткізу **11 рет** қайталанады (10 секундтан 1 сағатқа дейін өсіп отырады). Ал қатар қате бере берсеңіз, адрес уақытша тоқтатылады. Сондықтан «200 қайтарып, кейін өңдеу» тәртібі маңызды.

Егжей-тегжейі: [Webhook қауіпсіздігі](/kb/webhook-security), [Webhook баптау](/kb/webhook-setup).

## Шекті жағдайлар

Негізгі сценарийлер өткен соң, мыналарды тексеріңіз — өндірісте құлататыны осылар.

| Не сынайсыз | Қалай | Күтілетін нәтиже |
|---|---|---|
| Дубль сұрау | Бір `Idempotency-Key` тақырыбымен екі рет счёт жасаңыз | Жаңа счёт жасалмайды, HTTP 200 және `idempotentReplay: true` |
| Бір тапсырыс екі рет | Бір `externalOrderId` бойынша екі счёт жасап көріңіз | Өз жағыңызда қалай өңдейсіз — шешімін жазып қойыңыз |
| Қате сома | `0`, теріс сан, мәтін, `phone` счётқа тиынды сома | `invalid_amount`, `amount_too_small`, `amount_must_be_whole_tenge` |
| Жоқ телефон | `kind: "phone"`, бірақ `customer.phone` жоқ немесе пішімі бұрыс | `invalid_phone` |
| Жоқ счёт | Ойдан шығарылған `id` бойынша `GET` | `invoice_not_found`, 404 |
| Жабық счёт | Төленген счётты `cancel` қылып көріңіз | `invoice_not_open`, 409 |
| Артық қайтару | Төленген сомадан көп қайтаруға тырысыңыз | `invalid_refund_amount` |
| Лимит | Sandbox-та көп счёт жасап көріңіз | Sandbox счёттары айлық лимитке кірмейді, бірақ сұрау жиілігі 429 беруі мүмкін |
| Жарамсыз кілт | Әдейі бұзылған кілтпен сұрау | `unauthorized`, 401 |
| Жетпейтін scope | `refunds:write` жоқ кілтпен қайтару | `insufficient_scope`, 403 |

Барлық қате кодтары: [Қателер каталогы](/kb/error-catalog).

## Автоматты тест жазу

Қолмен сынау бір рет жақсы, бірақ кодты өзгерткен сайын қайталау керек. Sandbox автоматты тестке жарайды: нақты ақша жоқ, Kaspi шақырылмайды, лимитке кірмейді.

Бір тесттің типтік циклі:

1. `POST /api/v1/invoices` — счёт жасау, `id` алу
2. `POST /api/v1/invoices/{id}/simulate` — `{"status":"paid"}`
3. Webhook келгенін күту (немесе тікелей `GET /api/v1/invoices/{id}` оқу)
4. Өз дерекқорыңызда тапсырыс күйі өзгергенін тексеру
5. Соңында тазалау

Практикалық кеңестер:

- **Тестте webhook күтіп қатып қалмаңыз.** Күтуге шек қойыңыз (мысалы 30 секунд), шек біткенде `GET /api/v1/invoices/{id}` арқылы күйді оқып, тестті сол бойынша аяқтаңыз
- **Әр тест өз счётын жасасын.** Ортақ счётқа сүйенген тест бір-бірін бұзады
- **`Idempotency-Key` мәнін кездейсоқ жасаңыз**, әйтпесе екінші жүргізуде ескі счёт қайтады да, тест «өтті» деп жалған көрсетеді
- **Қате сценарийлерін де тестке қосыңыз.** Дұрыс жағдайды бәрі тексереді, интеграция қате жағдайда құлайды
- **CI-да тек sandbox кілтін пайдаланыңыз.** Live кілт тест ортасында тұрмауы керек

Автоматты тест циклінің мысалдары SDK құжаттамасында: [Node.js SDK](/kb/sdk-node), [PHP SDK](/kb/sdk-php), [Python SDK](/kb/sdk-python).

## Live режимге өткенде

Sandbox-тағы тест live-та бәрі дұрыс дегенді білдірмейді. Live-та қосымша тексеретіндер:

- Кілт `qp_live_…` болып ауысты ма (жиі ұмытылатын нәрсе)
- Webhook адресі live үшін де қосулы ма
- Кассир белсенді ме
- Бірінші нақты төлем — **ең кіші сомамен**, өз телефоныңыздан

Толық тізім: [Продакшенге шығу чек-парағы](/kb/going-live-checklist).

## Жиі қойылатын сұрақтар

**Sandbox-та QR нағыз ба?** Жоқ. QR суреті жасалады, бірақ оны Kaspi қосымшасы сканерлемейді. Төлемді `simulate` арқылы жасайсыз.

**Sandbox счёттары тариф лимитін жей ме?** Жоқ. Айлық лимитке де кірмейді, 7 күндік сынақ мерзімін де бастамайды — сынақ бірінші **live** счёттан басталады.

**`simulate` арқылы `cancelled` күйін қоюға бола ма?** Жоқ, ол үш күйді ғана қабылдайды: `paid`, `failed`, `expired`. Болдырмау үшін `POST /invoices/{id}/cancel` эндпоинтін қолданыңыз.

**Live кілтпен `simulate` шақырсам не болады?** `not_sandbox` қатесі, 403. Симуляция тек sandbox-та.

**Тестте кассир керек пе?** Sandbox үшін керек емес. Kaspi кассирі тек live счёттар үшін қажет.
