Qut Pay Сайт Кабинет Білім базасы Нұсқаулықтар API құжаттамасы ҚАЗРУС
Басты бетБілім базасы → Анықтамалық

Python SDK

Жаңартылды: 2026-09-14 · Markdown нұсқасы

Қысқаша

Python SDK — бір ғана модуль: qutpay.py. Python 3.8 және одан жоғары нұсқада жұмыс істейді, тек стандартты кітапхананы пайдаланады (urllib, hmac, hashlib) — requests те, басқа тәуелділік те керек емес.

Модульден үш нәрсе экспортталады:

АтауыНе үшін
QutPayAPI клиенті: счёт жасау, оқу, болдырмау, қайтару
verify_webhookКіріс хабарламаның қолтаңбасын тексеру
QutPayErrorҚате: .status (HTTP) және .code (машиналық код)

Архив: https://api.qut.kz/downloads/qutpay-sdk-python.zip

Орнату

Архивті ашып, ішінде pip арқылы орнатыңыз:

unzip qutpay-sdk-python.zip -d qutpay-sdk
pip install ./qutpay-sdk

Немесе qutpay.py файлын жобаңызға көшіріп қойыңыз — сыртқы тәуелділігі болмағандықтан, ол солай да жұмыс істейді. Дистрибутив атауы — qutpay, импорттайтын модуль де qutpay.

Инициализация

import os
from qutpay import QutPay, QutPayError, verify_webhook

qp = QutPay(
    api_key=os.environ["QUTPAY_API_KEY"],   # qp_live_… немесе qp_test_…
    base_url="https://api.qut.kz",          # әдепкі мән
    timeout=20.0,                            # секунд
)

api_key бос болса ValueError шығады. Кілт орта айнымалысында тұруы керек — кодқа да, репозиторийге де жазбаңыз.

Счёт жасау

Барлық аргументтер snake_case түрінде беріледі, SDK оларды API күткен camelCase-ке өзі аударады.

inv = qp.create_invoice(
    amount=12500,
    kind="qr",                               # "qr" (әдепкі) немесе "phone"
    description="Тапсырыс №4471",
    external_order_id="4471",
    customer={"name": "Айгүл", "phone": "77011234567", "email": "a@b.kz"},
    success_url="https://site.kz/ok",
    fail_url="https://site.kz/fail",
    metadata={"branch": "almaty-abay"},
    idempotency_key="order-4471",            # Idempotency-Key тақырыбына кетеді
)

print(inv["id"], inv["status"], inv["payUrl"], inv["expiresAt"])

amount — бірінші позициялық аргумент, қалғаны тек атауымен беріледі. Жауап — қарапайым dict: id, status, payUrl, qrUrl, deepLink, qrImageUrl, expiresAt. Жауап өрістері camelCase күйінде қалады.

Қалған әдістер

ӘдісНе істейді
qp.get_invoice(invoice_id)Счётты оқиды. qp.get_invoice(invoice_id, live=True) — күйді Kaspi-ден сұрап жаңартады
qp.list_invoices(status="paid", limit=50)Тізім. Сүзгілер: status, external_order_id, search, from_, to, limit, offset
qp.cancel_invoice(invoice_id)Ашық счётты болдырмайды
qp.refund_invoice(invoice_id, amount=None, reason=None)Қайтару. amount=None — толық қайтару
qp.simulate_invoice(invoice_id, "paid")Тек sandbox: төлемді имитациялау
qp.account()Ұйым туралы қысқа ақпарат — кілттің жарамдылығын тексеруге ыңғайлы
fresh = qp.get_invoice(inv["id"], live=True)
if fresh["status"] == "paid":
    mark_order_paid("4471")

qp.refund_invoice(inv["id"], 5000, "Тауардың бір бөлігі қайтарылды")

SDK-да жазылым, bulk және форма-хук әдістері жоқ. Оларды тікелей HTTP арқылы шақырыңыз:

import json, urllib.request

req = urllib.request.Request(
    "https://api.qut.kz/api/v1/invoices/bulk",
    data=json.dumps({"invoices": [{"amount": 1000, "externalOrderId": "a-1"}]}).encode(),
    headers={"X-API-Key": os.environ["QUTPAY_API_KEY"], "Content-Type": "application/json"},
    method="POST",
)
with urllib.request.urlopen(req) as resp:
    result = json.loads(resp.read())   # HTTP 207, әр элемент бойынша нәтиже

Webhook қолтаңбасын тексеру

verify_webhook(secret, raw_body, headers, tolerance_sec=300)  # → True / False

raw_bodyөзгертілмеген байттар немесе жол. request.json арқылы алынған объект жарамайды: қолтаңба дәл сол байттар бойынша есептеледі. Функция X-Webhook-Signature пен X-Webhook-Timestamp тақырыптарын регистрге қарамай оқиды, sha256= префиксін тексереді, 5 минуттан ескі жеткізілімді қабылдамайды және hmac.compare_digest арқылы салыстырады.

Flask мысалы

import json, os
from flask import Flask, request, abort, redirect
from qutpay import QutPay, QutPayError, verify_webhook

app = Flask(__name__)
qp = QutPay(api_key=os.environ["QUTPAY_API_KEY"])
SECRET = os.environ["QUTPAY_WEBHOOK_SECRET"]


@app.post("/buy")
def buy():
    order = create_order(request.form)
    try:
        inv = qp.create_invoice(
            amount=order.total,
            description=f"Тапсырыс №{order.id}",
            external_order_id=str(order.id),
            success_url=f"https://site.kz/orders/{order.id}",
            idempotency_key=f"order-{order.id}",
        )
    except QutPayError as e:
        app.logger.error("qutpay %s %s %s", e.status, e.code, e)
        abort(502)
    save_invoice_id(order.id, inv["id"])
    return redirect(inv["payUrl"], code=303)


@app.post("/qutpay-webhook")
def hook():
    raw = request.get_data()                 # bytes, өзгертілмеген
    if not verify_webhook(SECRET, raw, request.headers):
        abort(401)

    e = json.loads(raw)
    invoice = e["invoice"]

    # Идемпотенттілік: бір оқиға екі рет келуі мүмкін
    if not already_handled(invoice["id"], invoice["status"]):
        if e["event"] == "invoice.paid":
            mark_order_paid(invoice["externalOrderId"], invoice)
        elif e["event"] == "invoice.refunded":
            mark_order_refunded(invoice["externalOrderId"])
        remember_handled(invoice["id"], invoice["status"])

    return "", 200                           # 2xx бермесеңіз 11 рет қайталанады

Django мысалы

Django-да дене request.body өрісінде тұрады, тақырыптар — request.headers. Маршрутты CSRF тексеруінен босату міндетті.

# views.py
import json, os
from django.http import HttpResponse, HttpResponseForbidden
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from qutpay import verify_webhook

SECRET = os.environ["QUTPAY_WEBHOOK_SECRET"]


@csrf_exempt
@require_POST
def qutpay_webhook(request):
    raw = request.body                       # bytes, өзгертілмеген
    if not verify_webhook(SECRET, raw, request.headers):
        return HttpResponseForbidden(status=401)

    e = json.loads(raw)
    invoice = e["invoice"]
    handle_event.delay(e["event"], invoice)  # ауыр жұмысты Celery-ге беріңіз
    return HttpResponse(status=200)
# urls.py
from django.urls import path
from .views import qutpay_webhook

urlpatterns = [path("qutpay-webhook", qutpay_webhook)]

ATOMIC_REQUESTS қосулы болса, ұзақ жұмысты транзакция ішінде жасамаңыз: webhook 8 секундтан ұзақ жауап берсе, жеткізілім сәтсіз деп есептеліп, қайталанады.

Қате өңдеу

Кез келген сәтсіз жауапта SDK QutPayError лақтырады:

ӨрісМәні
.statusHTTP күйі. Желі қатесі мен таймаутта 0
.codeМашиналық код: invalid_amount, invoice_not_found, request_rate_limited… Таймаутта timeout, желі үзілсе network_error
str(e)Адамға арналған мәтін
try:
    inv = qp.create_invoice(amount=amount, external_order_id=order_id)
except QutPayError as e:
    if e.code == "kaspi_session_expired":
        notify_admin("Кассир байланысы үзілді")
    elif e.code in ("tariff_limit_reached", "tariff_daily_burst"):
        notify_admin("Лимит")                # қайталамаңыз
    elif e.code in ("request_rate_limited", "timeout", "network_error"):
        retry_later()                         # 1, 2, 4, 8 секунд бэкоффпен
    else:
        raise

Логиканы әрқашан .code мәніне қарап жазыңыз: мәтін өзгеруі мүмкін, код өзгермейді. Барлық кодтар: Қателер каталогы.

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

PyPI-дан орнатуға бола ма? Жоқ, пакет жария тізілімде емес. Архивті жүктеп, pip install ./qutpay-sdk жасаңыз немесе файлды көшіріп алыңыз.

async нұсқасы бар ма? Жоқ, клиент синхронды. FastAPI-де run_in_threadpool арқылы шақырыңыз немесе өз httpx клиентіңізді жазыңыз — verify_webhook функциясын бөлек пайдалана бересіз.

FastAPI-де raw body қалай аламын? raw = await request.body(), тақырыптар — request.headers.

Жауап өрістері неге snake_case емес? Кіріс аргументтер ыңғай үшін snake_case, ал жауап API-ден келген күйінде қайтады: payUrl, externalOrderId, expiresAt.

Сынауды қалай бастаған дұрыс? Sandbox кілтімен счёт жасап, qp.simulate_invoice(inv["id"], "paid") шақырыңыз — webhook шынайы жіберіледі: Sandbox-та төлемді симуляциялау.

Байланысты мақалалар

Счёт жасау: барлық өрістерPOST /api/v1/invoices эндпоинтінің толық анықтамасы — әр өрістің типі мен шектеуі, жауаптағы барлық өріс, curl мен Node мысалдары, qr мен phone айырмашылығы және жиі кездесетін қателер.Webhook қауіпсіздігі және қолтаңбаны тексеруҚолтаңба қалай құралады, неге raw body міндетті, timestamp-ты қалай тексеру керек, Express, Laravel, Django және таза Node үшін код мысалдары, идемпотентті өңдеу және жиі кездесетін қателер.Қайтару API — толық және ішінара қайтаруPOST /invoices/{id}/refund әдісінің толық анықтамасы: сұрау өрістері, толық және ішінара қайтару, сома шектеуі, барлық қате коды, refund_unknown келгенде не істеу керек және қандай оқиғалар жіберіледі.Қателер каталогы — API не қайтарады және не істеу керекQut Pay API-інің барлық негізгі қате кодтары топтап берілген: авторизация, Kaspi байланысы, счёт, қайтару, тариф лимиті, webhook, жазылым. Әрқайсысының себебі және шешімі.Sandbox-та төлемді симуляциялауsimulate эндпоинті арқылы sandbox счётының күйін өзгерту: paid, failed, expired. Kaspi шақырылмайды, webhook нағыз төлемдегідей келеді. Сынау циклі және автоматты тест жазу.

Сұрағыңыз қалды ма? WhatsApp +77788813333 · kazprose@gmail.com
Кабинеттен де жазуға болады: Қолдау.

Qut Pay — тәуелсіз сервис, «Kaspi Bank» АҚ-мен аффилирленбеген. Kaspi және Kaspi Pay — құқық иесінің тауар белгілері.