Қысқаша
Таксопаркте күнделікті немесе апталық жинау — бір типтегі көп счёт. POST /api/v1/invoices/bulk бір сұрауда 1-ден 100-ге дейін счёт жасайды: жүргізушінің нөмірін берсеңіз, счёт оның Kaspi қосымшасына push болып барады. Тізім қайталанып жіберілсе де дубль шықпауы үшін Idempotency-Key қолданылады. Әр элементтің қатесі бөлек келеді — біреуі құласа қалғаны жасалады.
Сценарий
Паркте 80 жүргізуші. Әрқайсысы күнделікті жалдау ақысын немесе комиссиясын төлейді. Бұрын бұл қалай жүретін: жүргізуші паркке келеді, диспетчерге қолма-қол береді немесе өз картасынан аударады, диспетчер кестеге белгілейді, ай соңында ешкім кімнің қанша төлегенін дәл білмейді.
Керегі: таңертең 80 жүргізушіге бірден счёт шықсын, әрқайсысының телефонына келсін, кім төлегені кабинетте көрінсін, есеп өздігінен жиналсын.
Жұмыс схемасы қадамдап
- Тізім дайындау. Сіздің жүйеңіз (өз базаңыз, кесте, диспетчерлік бағдарлама) бүгін төлеуі керек жүргізушілердің тізімін құрайды: телефон, сома, ішкі нөмір.
- Бір сұрау.
POST /api/v1/invoices/bulk— денесінде счёттар массиві, 1-100 элемент. 80-нен көп болса пакетке бөлесіз. - Идемпоттылық. Сұрауға
Idempotency-Keyтақырыбын қосасыз, мәні күнге байланған тұрақты жол (мысалы «парк-жинау-2026-09-14»). Тапсырма қайта іске қосылса да, счёттар екі есе шықпайды. - Жауапты талдау. Әр элемент бойынша нәтиже келеді. Сәтті болғандарын базаға жазасыз, қатесі барларын журналға шығарасыз.
- Жүргізушіге push.
kind: "phone"таңдасаңыз, счёт жүргізушінің Kaspi қосымшасына хабарлама болып келеді. Ол ашып, растайды. - Webhook. Төлем түскенде
invoice.paidкеледі, ішіндеexternalOrderIdбар — жүргізушіні сол арқылы табасыз да, оның балансын жабасыз. - Есеп. Күн соңында кім төледі, кім төлемеді — кабинеттен сүзіп көресіз немесе CSV экспорттайсыз.
Қандай API әдісі керек
| Не істейді | Әдіс |
|---|---|
| Тізім бойынша счёт | POST /api/v1/invoices/bulk (1-100) |
| Жеке жүргізушіге счёт | POST /api/v1/invoices |
| Күйін тексеру | GET /api/v1/invoices/{id} |
| Кезең бойынша тізім | GET /api/v1/invoices |
| Жүргізуші жұмысқа шықпаса | POST /api/v1/invoices/{id}/cancel |
| Артық алынғанды қайтару | POST /api/v1/invoices/{id}/refund |
| Төлем туралы хабар | Webhook invoice.paid, топтап шығару нәтижесі invoice.bulk |
Идемпоттылық — дубльден сақтайтын нәрсе
Күнделікті жинау — автоматты тапсырма, ал автоматты тапсырма қайталанады: cron екі рет қосылды, желі үзілді де сұрау қайта кетті, диспетчер батырманы екі рет басты. Идемпоттылықсыз әр жүргізушіге екі счёт барады, телефоны екі рет шырылдайды, кейбіреуі екі рет төлеп қояды.
Шешімі: Idempotency-Key тақырыбы. Мәні тұрақты болуы керек — күн мен пакет нөмірінен құраңыз, кездейсоқ сан алмаңыз. Сол кілтпен қайталасаңыз жаңа счёт жасалмайды, бұрынғысы қайтады (HTTP 200, idempotentReplay: true).
Webhook өңдеуі де идемпотентті болсын: (invoice.id, status) жұбын тексеріңіз, өйткені 2xx емес жауап берсеңіз біз 11 рет қайталаймыз. Толығы: Идемпоттылық.
Дубль шығып кетсе, шұғыл тоқтату жолы бар: Счёттар қосарланып жатыр.
Әр элементтің қатесін бөлек өңдеу
bulk әдісінде әр элемент өз алдына тексеріледі. Пакет толық құламайды: 80 счёттың 77-і жасалады, 3-еуі қате қайтарады.
Жиі кездесетін себептері:
| Себебі | Не істеу керек |
|---|---|
Телефон пішімі бұрыс (7XXXXXXXXXX емес) | Базадағы нөмірді тазалау |
| Сома нөл немесе теріс | Есептеу логикасын тексеру |
| Телефонға счётта тиын бар | Бүтін теңгеге дөңгелектеу |
| Сипаттама тым ұзын | Телефонға счётта 60 таңба, QR-да 100 |
| Айлық лимит бітті | Тарифті көтеру немесе жинауды бөлу |
| Тәуліктік қорғаныс іске қосылды | Пакеттерді уақыт бойынша жаю |
Жауаптағы жолдарды өз тізіміңіздің ретімен салыстырыңыз, қатесі барларын бөлек кезекке қойып, түзеген соң қайта жіберіңіз. Бүкіл пакетті қайта жібермеңіз — идемпоттылық кілті болса да, қажет емес жүктеме.
Айлық лимит tariff_limit_reached қатесін береді, тәуліктік қорғаныс tariff_daily_burst береді. Бұл екі басқа нәрсе: тәуліктік сан — бизнес лимиті емес, циклге түскен интеграциядан сақтандырғыш. Толығы: Лимитке жеттім — не істеу керек.
Күнделікті жинауды автоматтандыру
Тұрақты жұмыс реті:
- Таңғы белгіленген уақытта тапсырма іске қосылады.
- Бүгін төлеуі керек жүргізушілер тізімі құрылады (жұмысқа шыққандар, берешегі барлар).
- Тізім 100-ден аспайтын пакеттерге бөлінеді.
- Әр пакет
bulkарқылы жіберіледі,Idempotency-Key— күн мен пакет нөмірі. - Пакеттер арасына бірнеше секунд үзіліс қойылады — бірден жүздеген сұрау жібермеңіз.
- Нәтиже базаға жазылады, қатесі барлар қайта жіберу кезегіне түседі.
- Кешке қарай төлемегендерге еске салатын екінші толқын жіберіледі.
Алдымен бүкіл циклді sandbox кілтімен (qp_test_…) өткізіңіз: нақты ақша жүрмейді, төлемді simulate арқылы өзіңіз қоясыз.
Есеп пен экспорт
Счёт жасаған сәтте белгі қойыңыз, кейін есеп жинау оңай болады:
externalOrderId— жүргізушінің ішкі нөмірі немесе «күн + жүргізуші» түріндегі жол.metadata— көлік нөмірі, ауысым, диспетчер, парк бөлімшесі.description— жүргізуші көретін мәтін: «Жалдау ақысы, 14 қыркүйек».
Кабинеттегі Счёттар бөлімінен кезең мен күй бойынша сүзіп, CSV экспорттайсыз. Бухгалтерияға дәл сол файл беріледі. Толығы: CSV экспорт және есеп.
Бірнеше бөлімше болса, әрқайсысына жеке API кілт жасаңыз — есеп көзі бойынша бөлінеді.
Ерекше ескертулер
- Жүргізушінің нөмірі Kaspi-де тіркелген болуы керек. Kaspi қосымшасы жоқ адамға телефонға счёт бармайды, оған QR немесе
payUrlсілтемесін беріңіз. - Кассир нөмірі жүргізушіге көрінеді счёт хабарламасында. Бұл Kaspi-дің қалыпты жұмысы.
- Жүргізуші төлемей қойса счёт
expiredболады. Жүйеңізде берешекті келесі күнге көшіретін логика болсын. - Кеш төлем болады. Мерзімі өткен счётқа ақша кейін келсе,
invoice.paidоқиғасыlate: trueбелгісімен келеді — балансты қайта есептеңіз немесе қайтарыңыз. - Айлық лимитті алдын ала есептеңіз. 80 жүргізуші × 30 күн = 2 400 счёт, оған қайта жіберулерді қосыңыз.
Жиі қойылатын сұрақтар
Бір сұрауда неше счёт жіберуге болады? 1-ден 100-ге дейін. Одан көп болса пакетке бөліңіз.
Ақша жүргізушінің картасынан өзі шешіле ме? Жоқ. Біз тек счёт шығарамыз, жүргізуші әр төлемді Kaspi қосымшасында өзі растайды.
Тапсырма екі рет қосылып кетсе счёттар қосарлана ма? Idempotency-Key тақырыбын дұрыс берсеңіз — жоқ. Кілт мәні тұрақты, күнге байланған болуы керек.
Пакеттің бір элементі құласа, қалғаны жасала ма? Иә. Әр элемент бөлек тексеріледі, қалғаны сол күйі жасалады.
Ақша қайда түседі? Тіке паркіңіздің Kaspi шотына. Бізде ұсталмайды, транзакциядан пайыз алмаймыз — қызмет ақысы айлық жазылым.