Зачем feed, если есть webhooks
Webhooks — это push: Pay Bot шлёт вам событие как только оно случилось. Удобно, но возможны пропуски (упал ваш endpoint, истёк ретрай, не подписались на нужное событие).
Журнал событий — это pull: вы запрашиваете «дай мне всё с курсора N». Никогда ничего не пропускаете, можно retro-обработать историю.
Хорошая практика: использовать webhooks как основной механизм, журнал — как backup и для аудита.
Получение событий
curl "https://payapi.aibot.kz/v2/events?cursor=&limit=50" \
-H "X-API-Key: kp_live_xxx"import requests
def fetch_events(cursor=None, kind=None):
params = {"limit": 100}
if cursor: params["cursor"] = cursor
if kind: params["type"] = kind
return requests.get(
"https://payapi.aibot.kz/v2/events",
headers={"X-API-Key": "kp_live_xxx"},
params=params,
).json()
# Все события с начала
data = fetch_events()
while True:
for e in data["data"]:
process(e)
if not data["has_more"]:
break
data = fetch_events(cursor=data["next_cursor"])async function* iterateEvents(type) {
let cursor = null;
do {
const url = new URL("https://payapi.aibot.kz/v2/events");
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("cursor", cursor);
if (type) url.searchParams.set("type", type);
const res = await fetch(url, {
headers: { "X-API-Key": "kp_live_xxx" },
});
const page = await res.json();
for (const e of page.data) yield e;
cursor = page.has_more ? page.next_cursor : null;
} while (cursor);
}
for await (const event of iterateEvents("payment.completed")) {
console.log(event);
}function fetchEvents($cursor = null, $type = null) {
$params = ["limit" => 100];
if ($cursor) $params["cursor"] = $cursor;
if ($type) $params["type"] = $type;
$url = "https://payapi.aibot.kz/v2/events?" . http_build_query($params);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ["X-API-Key: kp_live_xxx"],
CURLOPT_RETURNTRANSFER => true,
]);
return json_decode(curl_exec($ch), true);
}Фильтрация
| Query | Значение |
|---|---|
type | Тип события (см. ниже). Можно несколько через запятую. |
cursor | Cursor для следующей страницы |
limit | 1–100, по умолчанию 25 |
since | ISO-дата, события не раньше этой |
until | ISO-дата, события не позже этой |
# Только успешные платежи за май
GET /v2/events?type=payment.completed&since=2026-05-01&until=2026-06-01Каталог событий
payment.completed
Платёж успешно прошёл через Kaspi.
{
"id": "evt_a1b2c3d4",
"type": "payment.completed",
"created_at": "2026-05-11T12:30:00Z",
"data": {
"operation_id": 14837690870,
"amount": 5000,
"phone": "77001234567",
"sender_name": "Иван И.",
"source": "payment_link",
"metadata": {"order_id": "ord_1234"}
}
}payment.cancelled
Платёж отменён клиентом или Kaspi (например, недостаточно средств).
{
"id": "evt_x9y8z7",
"type": "payment.cancelled",
"created_at": "2026-05-11T12:35:00Z",
"data": {
"operation_id": 14837690870,
"amount": 5000,
"reason": "insufficient_funds"
}
}payment.expired
QR (5 мин) или счёт (24 ч) истёк без оплаты.
{
"id": "evt_e1x2p3",
"type": "payment.expired",
"created_at": "2026-05-11T12:35:00Z",
"data": {
"operation_id": 14837690870,
"amount": 5000,
"expired_at": "2026-05-11T12:35:00Z"
}
}payment.refunded
Возврат успешно проведён Kaspi.
{
"id": "evt_r1e2f3",
"type": "payment.refunded",
"created_at": "2026-05-11T15:05:00Z",
"data": {
"operation_id": 14837690870,
"refund_id": "ref_a1b2c3d4",
"amount": 5000,
"refunded_total": 5000,
"remaining_refundable": 0
}
}payment_link.created
Создана платёжная ссылка.
{
"id": "evt_pl1c2r3",
"type": "payment_link.created",
"created_at": "2026-05-11T12:00:00Z",
"data": {
"token": "pl_abc123def456",
"amount": 5000,
"description": "Заказ #1234"
}
}payment_link.paid
Платёжная ссылка получила оплату. Для allow_repeat: true может срабатывать многократно по одной ссылке.
{
"id": "evt_pl1p2a3",
"type": "payment_link.paid",
"created_at": "2026-05-11T12:30:00Z",
"data": {
"token": "pl_abc123def456",
"operation_id": 14837690870,
"amount": 5000
}
}webhook.delivery_failed
Webhook не доставлен после 5 попыток.
{
"id": "evt_wd1f2",
"type": "webhook.delivery_failed",
"created_at": "2026-05-11T15:00:00Z",
"data": {
"webhook_id": 42,
"event_id": "wh_evt_abc123",
"url": "https://yoursite.com/paybot",
"last_status": 500,
"attempts": 5
}
}plan.changed
Сменился тариф аккаунта.
{
"id": "evt_pc1",
"type": "plan.changed",
"created_at": "2026-05-11T10:00:00Z",
"data": {
"from": "starter",
"to": "professional",
"effective_at": "2026-05-11T10:00:00Z"
}
}Хранение
События хранятся 18 месяцев на тарифах ≥ Professional, 3 месяца на Starter, 30 дней на Trial. Для долгого хранения настройте экспорт через webhook → ваш warehouse.
Backup-обработка после downtime
Если ваш webhook-endpoint был недоступен:
last_seen = db.get("paybot_last_event_id")
data = requests.get(
"https://payapi.aibot.kz/v2/events",
headers={"X-API-Key": "kp_live_xxx"},
params={"since": last_seen_iso, "limit": 100},
).json()
for event in data["data"]:
if event["id"] > last_seen:
handle(event)
db.set("paybot_last_event_id", event["id"])Что дальше
- •Webhooks — push-канал для тех же событий
- •Пагинация — как работать с
cursorиhas_more - •API Reference — все эндпоинты