# Как автоматически узнать, что Kaspi QR оплачен

> Два способа подтвердить оплату Kaspi QR без ручной сверки — webhook invoice.paid на ваш сервер и запрос статуса счёта. Что приходит, как проверить подпись, как не отметить заказ оплаченным по ошибке, что делать на странице «спасибо».

## Коротко

Когда покупатель оплатил QR, Qut Pay замечает это сам и делает две вещи: присылает на ваш сервер webhook `invoice.paid` и меняет статус счёта на `paid`, который можно запросить. Правильная схема: заказ отмечается оплаченным **по webhook с проверенной подписью** или по ответу `GET /invoices/{id}` с сервера, но никогда — по тому, что покупатель вернулся на страницу «спасибо».

## Способ 1 — webhook (основной)

1. В кабинете → Интеграции укажите адрес на вашем сервере и получите секрет — [настройка вебхуков](/kb/ru/webhook-setup).
2. При оплате придёт `POST` с JSON `{ "event": "invoice.paid", "invoice": { "id", "status": "paid", "amount", "externalOrderId", "paidAt", "receiptUrl", … } }`.
3. Проверьте подпись: заголовок `X-Webhook-Signature: sha256=…` — это HMAC-SHA256 от строки `timestamp + "." + сырое тело`, где `timestamp` из `X-Webhook-Timestamp`. Считайте по сырым байтам тела, до разбора JSON — [почему не сходится подпись](/kb/ru/webhook-signature-mismatch).
4. Найдите заказ по `externalOrderId`, сверьте `amount`, отметьте оплаченным и ответьте `200` в течение 8 секунд.
5. Сделайте обработчик идемпотентным: один и тот же `(invoice.id, status)` может прийти дважды, повторный должен ничего не менять.

Если сервер не ответил `2xx`, Qut Pay повторяет доставку до 11 раз в течение примерно двух часов — [вебхук не приходит](/kb/ru/webhook-not-arriving).

## Способ 2 — запрос статуса (дополнительный)

```bash
curl https://api.qut.kz/api/v1/invoices/inv_… -H "X-API-Key: qp_live_…"
```

Ответ содержит `status`: `pending` — ждём, `paid` — оплачен, `expired` / `cancelled` / `failed` — не оплачен. Добавьте `?live=1`, чтобы сервис спросил Kaspi прямо сейчас, а не отдал последнее известное состояние. Опрашивать раз в 5–10 секунд, пока покупатель на странице оплаты, нормально; опрос каждую секунду упирается в [лимиты запросов](/kb/ru/rate-limits). Когда что выбирать: [вебхук или опрос](/kb/ru/polling-vs-webhook).

## Страница «спасибо»

После оплаты покупатель возвращается на ваш `successUrl`. Этот переход — не доказательство оплаты: ссылку можно открыть вручную. На этой странице запросите статус счёта с сервера и показывайте «оплачено» только при `paid`.

## Чего ещё ждать

- `invoice.expired` — QR истёк, покупатель не заплатил; можно создать новый счёт — [почему истекает QR](/kb/ru/qr-expired).
- Оплата после истечения срока — редкий случай, сервис её всё равно находит и присылает `invoice.paid` с пометкой `late` — [запоздавший платёж](/kb/ru/late-payment).
- Все статусы и переходы: [жизненный цикл счёта](/kb/ru/invoice-lifecycle).

## Проверить без реальных денег

В песочнице (`qp_test_…`) оплату имитирует запрос `POST /invoices/{id}/simulate` с телом `{"status":"paid"}` — webhook приходит настоящий, со всеми заголовками — [песочница](/kb/ru/sandbox-simulate).
