🔧 ЮKassa • API • Python

Интеграция ЮKassa API: полное руководство разработчика

Полное техническое руководство по интеграции ЮKassa API: Python SDK, webhook, рекуррентные платежи, возвраты, тестирование в sandbox.

Интеграция ЮKassa API: полное руководство разработчика
20 мин чтения ~5500 слов 25 августа 2026 г. Дмитрий Малышев

Интеграция ЮKassa API: пошаговое руководство разработчика

В 2025 году ЮKassa обработала более 2,3 миллиарда транзакций на сумму свыше 8 триллионов рублей. Это платёжный провайдер №1 в России — и каждый третий разработчик Telegram-ботов интегрирует его API. Но 80% допускают одни и те же ошибки: не проверяют подпись webhook, не обрабатывают идемпотентность, не учитывают edge cases с отложенными платежами.

Я интегрировал ЮKassa API в 40+ проектов — от простых ботов с одной кнопкой «Оплатить» до сложных систем с рекуррентными платежами, частичными возвратами и мультивалютными расчётами. В этой статье — полное техническое руководство с примерами кода на Python, которые можно скопировать и использовать.

Разберём: аутентификацию, создание платежей, обработку webhook, рекуррентные платежи, возвраты, тестирование в sandbox и типичные ошибки, которые я встречал в продакшене.

Если нужна интеграция ЮKassa в Telegram-бота под ключ — это от 15 000 ₽ и 3–5 дней.

Полезные материалы по теме
Интеграция ЮKassa API за 3–5 дней от 15 000 ₽заказать интеграцию ЮKassa
Обзор всех платёжных провайдеровинтеграция платежей в Telegram
Практические сценарии приёма оплатыприём оплаты через Telegram-бота
Альтернативный провайдер — Robokassaинтеграция Robokassa
Подключение внешних сервисов к ботуразработка API интеграций

Аутентификация и безопасность ЮKassa API

ЮKassa использует Basic Auth для аутентификации API-запросов. Ключи можно получить в личном кабинете после верификации.

Получение API-ключей

  1. 1.Зайдите в личный кабинет ЮKassa: https://yookassa.ru/my
  2. 2.Перейдите в раздел «Интеграция» → «Ключи API»
  3. 3.Нажмите «Создать новый ключ»
  4. 4.Скопируйте shopId (идентификатор магазина) и secretKey (секретный ключ)

Важно: ЮKassa генерирует два набора ключей — для production и sandbox. Не смешивайте их.

ПараметрProductionSandbox
shopIdВаш реальный IDТестовый ID
secretKeyРеальный ключТестовый ключ
API URLhttps://api.yookassa.ru/v3https://api.yookassa.ru/v3
ПлатежиРеальные деньгиВиртуальные деньги

Настройка SDK для Python

Официальный SDK ЮKassa для Python:

Bash
 1pip install yookassa

Базовая настройка:

Python
 1from yookassa import Configuration, Payment, Refund, Webhook
 2
 3# Production
 4Configuration.account_id = "YOUR_SHOP_ID"
 5Configuration.secret_key = "YOUR_SECRET_KEY"
 6
 7# Sandbox (для тестирования)
 8Configuration.account_id = "YOUR_SANDBOX_SHOP_ID"
 9Configuration.secret_key = "YOUR_SANDBOX_SECRET_KEY"

Альтернатива — через переменные окружения:

Python
 1import os
 2from yookassa import Configuration
 3
 4Configuration.account_id = os.getenv("YOOKASSA_SHOP_ID")
 5Configuration.secret_key = os.getenv("YOOKASSA_SECRET_KEY")

Рекомендация: храните ключи в переменных окружения (.env), никогда не коммитьте их в git.

Прямые HTTP-запросы (без SDK)

Если не хотите использовать SDK — можно делать прямые HTTP-запросы:

Python
 1import requests
 2import base64
 3import json
 4
 5SHOP_ID = "YOUR_SHOP_ID"
 6SECRET_KEY = "YOUR_SECRET_KEY"
 7
 8def make_yookassa_request(method: str, endpoint: str, data: dict = None):
 9    """Прямой HTTP-запрос к ЮKassa API"""
10    url = f"https://api.yookassa.ru/v3/{endpoint}"
11    
12    # Basic Auth
13    credentials = base64.b64encode(
14        f"{SHOP_ID}:{SECRET_KEY}".encode()
15    ).decode()
16    
17    headers = {
18        "Authorization": f"Basic {credentials}",
19        "Content-Type": "application/json",
20        "Idempotence-Key": str(uuid.uuid4())
21    }
22    
23    response = requests.request(
24        method=method,
25        url=url,
26        headers=headers,
27        json=data
28    )
29    
30    return response.json()

SDK удобнее, но прямые запросы дают больше контроля. В сложных проектах я использую прямые запросы — проще дебажить.

Создание платежа через ЮKassa API

Создание платежа — основная операция. Разберём все параметры и сценарии.

Базовое создание платежа

Минимальный запрос на создание платежа:

Python
 1from yookassa import Payment
 2import uuid
 3
 4payment = Payment.create({
 5    "amount": {
 6        "value": "1500.00",
 7        "currency": "RUB"
 8    },
 9    "confirmation": {
10        "type": "redirect",
11        "return_url": "https://t.me/your_bot"
12    },
13    "capture": True,
14    "description": "Курс по йоге — базовый уровень",
15    "metadata": {
16        "user_id": "123456789",
17        "order_id": str(uuid.uuid4())
18    }
19}, idempotency_key=str(uuid.uuid4()))
20
21# Ссылка на оплату
22print(payment.confirmation.confirmation_url)
23# https://yoomoney.ru/checkout/payments/v2/contract?orderId=...

Параметры запроса:

ПараметрТипОбязательныйОписание
amount.valuestringСумма (формат: "1500.00")
amount.currencystringВалюта ("RUB")
confirmation.typestringТип подтверждения ("redirect")
confirmation.return_urlstringURL возврата после оплаты
capturebooleanАвтоматическое подтверждение
descriptionstringОписание платежа (до 128 символов)
metadataobjectМетаданные (до 16 ключей)
receiptobjectДанные для чека

Типы подтверждения (confirmation types)

ЮKassa поддерживает несколько типов подтверждения оплаты:

ТипОписаниеИспользование
redirectПеренаправление на страницу оплатыСтандартный сценарий
embeddedВстроенная форма (iframe)WebApp, встраиваемые формы
externalВнешнее подтверждениеСБП, наличные
qrQR-кодСБП через QR
mobile_applicationМобильное приложениеDeep linking

Для Telegram-ботов чаще всего используется redirect — бот отправляет ссылку, пользователь переходит и оплачивает.

Для СБП используется external или qr:

Python
 1# Платёж через СБП
 2payment = Payment.create({
 3    "amount": {"value": "500.00", "currency": "RUB"},
 4    "confirmation": {
 5        "type": "qr",
 6        "return_url": "https://t.me/your_bot"
 7    },
 8    "capture": True,
 9    "payment_method_data": {
10        "type": "sbp"
11    },
12    "description": "Оплата через СБП"
13})

Отложенные платежи (capture: false)

По умолчанию capture: True — платёж подтверждается автоматически. Но иногда нужно сначала заблокировать сумму, а подтвердить позже.

Сценарий: клиент заказал товар, но вы хотите проверить наличие на складе перед списанием.

Python
 1# Шаг 1: Создаём платёж с блокировкой
 2payment = Payment.create({
 3    "amount": {"value": "3000.00", "currency": "RUB"},
 4    "confirmation": {"type": "redirect", "return_url": "https://t.me/your_bot"},
 5    "capture": False,  # НЕ подтверждаем автоматически
 6    "description": "Товар на складе — проверка"
 7})
 8
 9# Шаг 2: Проверяем наличие
10if check_stock(payment.metadata['order_id']):
11    # Шаг 3: Подтверждаем платёж
12    Payment.capture(payment.id, {
13        "amount": {"value": "3000.00", "currency": "RUB"}
14    })
15else:
16    # Шаг 4: Отменяем платёж
17    Payment.cancel(payment.id)

Важно: если не подтвердить платёж в течение 7 дней — он автоматически отменяется. Деньги разблокируются на карте клиента.

Обработка webhook от ЮKassa

Webhook — уведомление от ЮKassa о событии (оплата, возврат, ошибка). Это основной способ узнать статус платежа.

Регистрация webhook'ов

Webhook'и регистрируются через API:

Python
 1from yookassa import Webhook
 2
 3# Регистрация webhook для успешной оплаты
 4Webhook.add({
 5    "event": "payment.succeeded",
 6    "url": "https://your-domain.com/webhook/yookassa"
 7})
 8
 9# Регистрация webhook для отмены
10Webhook.add({
11    "event": "payment.canceled",
12    "url": "https://your-domain.com/webhook/yookassa"
13})
14
15# Регистрация webhook для возврата
16Webhook.add({
17    "event": "refund.succeeded",
18    "url": "https://your-domain.com/webhook/yookassa"
19})

Доступные события:

СобытиеОписание
payment.succeededПлатёж успешно завершён
payment.canceledПлатёж отменён
payment.waiting_for_captureПлатёж ожидает подтверждения
refund.succeededВозврат успешно выполнен
refund.canceledВозврат отменён

Обработка webhook в aiohttp

Полный пример обработки webhook:

Python
 1from aiohttp import web
 2import hmac
 3import hashlib
 4import json
 5
 6YOOKASSA_SECRET = "YOUR_SECRET_KEY"
 7
 8async def handle_webhook(request: web.Request):
 9    """Обработка webhook от ЮKassa"""
10    # Читаем тело запроса
11    body = await request.read()
12    data = json.loads(body)
13    
14    # Проверяем подпись (важно для безопасности!)
15    signature = request.headers.get('Signature', '')
16    if not verify_signature(body, signature):
17        return web.Response(status=400, text="Invalid signature")
18    
19    event = data.get('event')
20    payment = data.get('object', {})
21    
22    if event == 'payment.succeeded':
23        user_id = int(payment['metadata']['user_id'])
24        order_id = payment['metadata']['order_id']
25        amount = payment['amount']['value']
26        
27        # Выдаём товар
28        await give_access(user_id, order_id)
29        
30        # Уведомляем пользователя
31        await bot.send_message(
32            user_id,
33            f"✅ Оплата получена! Сумма: {amount} ₽"
34        )
35        
36        # Уведомляем менеджера
37        await notify_manager(
38            f"💰 Новая оплата: {amount} ₽ от пользователя {user_id}"
39        )
40    
41    elif event == 'payment.canceled':
42        user_id = int(payment['metadata']['user_id'])
43        await bot.send_message(
44            user_id,
45            "❌ Оплата не прошла. Попробуйте ещё раз."
46        )
47    
48    elif event == 'payment.waiting_for_capture':
49        # Отложенный платёж — нужно подтвердить
50        payment_id = payment['id']
51        # Логика подтверждения/отмены
52    
53    return web.Response(status=200)
54
55def verify_signature(body: bytes, signature: str) -> bool:
56    """Проверка подписи webhook"""
57    expected = hmac.new(
58        YOOKASSA_SECRET.encode(),
59        body,
60        hashlib.sha256
61    ).hexdigest()
62    return hmac.compare_digest(expected, signature)
63
64# Настройка маршрутов
65app = web.Application()
66app.router.add_post('/webhook/yookassa', handle_webhook)

Критически важно: всегда проверяйте подпись webhook. Без проверки мошенники могут отправить поддельный webhook с «успешной оплатой».

Обработка webhook в FastAPI

Альтернативный пример на FastAPI:

Python
 1from fastapi import FastAPI, Request, HTTPException
 2import hmac
 3import hashlib
 4
 5app = FastAPI()
 6YOOKASSA_SECRET = "YOUR_SECRET_KEY"
 7
 8@app.post("/webhook/yookassa")
 9async def yookassa_webhook(request: Request):
10    body = await request.body()
11    data = await request.json()
12    
13    # Проверка подписи
14    signature = request.headers.get('signature', '')
15    expected = hmac.new(
16        YOOKASSA_SECRET.encode(), body, hashlib.sha256
17    ).hexdigest()
18    
19    if not hmac.compare_digest(expected, signature):
20        raise HTTPException(status_code=400)
21    
22    event = data.get('event')
23    payment = data.get('object', {})
24    
25    if event == 'payment.succeeded':
26        await process_successful_payment(payment)
27    
28    return {"status": "ok"}

FastAPI — отличный выбор для webhook-сервера: автоматическая валидация, async, документация из коробки.

Тестирование интеграции в sandbox

ЮKassa предоставляет sandbox для тестирования — все операции проходят без реальных денег.

Настройка sandbox

  1. 1.В личном кабинете ЮKassa переключитесь в режим «Тестовый»
  2. 2.Получите sandbox shopId и secretKey
  3. 3.Используйте те же API-эндпоинты (https://api.yookassa.ru/v3)
  4. 4.Для тестовых карт используйте специальные номера

Тестовые карты ЮKassa:

КартаРезультатНомер
Успешная оплата5555 5555 5555 4444
Отклонена5555 5555 5555 4477
Недостаточно средств5555 5555 5555 4488
3-D Secure🔐5555 5555 5555 4499

CVV для всех тестовых карт: 123 Срок действия: любая будущая дата

Тестирование webhook'ов

В sandbox webhook'и не отправляются автоматически. Нужно тестировать вручную:

Вариант 1: Локальный туннель (ngrok)

Bash
 1# Установка ngrok
 2npm install -g ngrok
 3
 4# Запуск туннеля
 5ngrok http 8080
 6
 7# Полученный URL: https://abc123.ngrok.io
 8# Регистрация webhook:
 9# https://abc123.ngrok.io/webhook/yookassa

Вариант 2: Тестовый запрос

Python
 1import requests
 2
 3# Отправка тестового webhook
 4test_payload = {
 5    "event": "payment.succeeded",
 6    "object": {
 7        "id": "test_payment_id",
 8        "status": "succeeded",
 9        "amount": {"value": "100.00", "currency": "RUB"},
10        "metadata": {
11            "user_id": "123456789",
12            "order_id": "test_order"
13        }
14    }
15}
16
17response = requests.post(
18    "https://your-domain.com/webhook/yookassa",
19    json=test_payload
20)

Вариант 3: Тестирование через API ЮKassa

Python
 1from yookassa import Payment
 2
 3# Создаём тестовый платёж
 4payment = Payment.create({
 5    "amount": {"value": "100.00", "currency": "RUB"},
 6    "confirmation": {"type": "redirect", "return_url": "https://t.me/test"},
 7    "capture": True,
 8    "description": "Тестовый платёж"
 9})
10
11# Оплачиваем тестовой картой через confirmation_url

Рекуррентные платежи (подписки) через ЮKassa

Рекуррентные платежи позволяют автоматически списывать оплату каждый месяц без участия клиента. Это основа подписных бизнес-моделей.

Как работают рекуррентные платежи

Схема: 1. Клиент оплачивает первый месяц → ЮKassa сохраняет токен карты 2. Каждый месяц бот создаёт новый платёж с сохранённым токеном 3. Деньги списываются автоматически, без участия клиента 4. Если карта отклонена — бот отправляет уведомление

Важно: для рекуррентных платежей нужно явное согласие клиента. В боте — кнопка «Согласен на автоматическое списание».

ПараметрЗначение
ПериодичностьЕжемесячно, ежеквартально, ежегодно
Retention75–85% (vs 40–50% ручных продлений)
LTV×3–5 раз выше
Комиссия2,8% (как обычная оплата)

Реализация рекуррентных платежей

Шаг 1: Первый платёж с сохранением токена

Python
 1from yookassa import Payment
 2
 3# Первый платёж — сохраняем payment_method_id
 4first_payment = Payment.create({
 5    "amount": {"value": "990.00", "currency": "RUB"},
 6    "confirmation": {"type": "redirect", "return_url": "https://t.me/your_bot"},
 7    "capture": True,
 8    "description": "Подписка — первый месяц",
 9    "save_payment_method": True,  # Сохраняем токен карты
10    "metadata": {
11        "user_id": "123456789",
12        "subscription": "monthly"
13    }
14})
15
16# После оплаты получаем payment_method_id из webhook
17# payment.payment_method.id — это токен для рекуррентов

Шаг 2: Автоматическое списание

Python
 1import asyncio
 2from datetime import datetime
 3
 4async def charge_subscription(user_id: int, payment_method_id: str, amount: float):
 5    """Автоматическое списание подписки"""
 6    payment = Payment.create({
 7        "amount": {"value": f"{amount:.2f}", "currency": "RUB"},
 8        "capture": True,
 9        "payment_method_id": payment_method_id,  # Токен карты
10        "description": f"Подписка — {datetime.now().strftime('%B %Y')}",
11        "metadata": {
12            "user_id": str(user_id),
13            "type": "recurring"
14        }
15    })
16    
17    if payment.status == 'succeeded':
18        await notify_user(user_id, "✅ Подписка продлена!")
19        await extend_subscription(user_id)
20    else:
21        await notify_user(user_id, "❌ Не удалось списать оплату. Обновите карту.")

Шаг 3: Планировщик (cron)

Python
 1from apscheduler.schedulers.asyncio import AsyncIOScheduler
 2
 3scheduler = AsyncIOScheduler()
 4
 5# Запуск каждый день в 10:00
 6@scheduler.scheduled_job('cron', hour=10)
 7async def process_subscriptions():
 8    """Обработка подписок, срок которых истекает сегодня"""
 9    subscriptions = await db.fetch(
10        "SELECT * FROM subscriptions WHERE expires_at::date = CURRENT_DATE"
11    )
12    
13    for sub in subscriptions:
14        await charge_subscription(
15            user_id=sub['user_id'],
16            payment_method_id=sub['payment_method_id'],
17            amount=sub['amount']
18        )
19
20scheduler.start()

Возвраты и частичные возвраты через ЮKassa API

Возвраты — неотъемлемая часть платёжной системы. ЮKassa поддерживает полные и частичные возвраты.

Полный возврат

Возврат всей суммы платежа:

Python
 1from yookassa import Refund
 2
 3refund = Refund.create({
 4    "amount": {
 5        "value": "1500.00",
 6        "currency": "RUB"
 7    },
 8    "payment_id": "2-34567-89012"
 9})
10
11print(refund.status)  # "succeeded" или "pending"

Сроки возврата: • Карты Visa/Mastercard: 1–5 рабочих дней • Карты МИР: 1–3 рабочих дня • ЮMoney: до 10 минут • СБП: 1–3 рабочих дня

Частичный возврат

Возврат части суммы (например, при возврате одного товара из заказа):

Python
 1from yookassa import Refund
 2
 3# Частичный возврат 500 ₽ из заказа на 1500 ₽
 4partial_refund = Refund.create({
 5    "amount": {
 6        "value": "500.00",  # Меньше суммы платежа
 7        "currency": "RUB"
 8    },
 9    "payment_id": "2-34567-89012",
10    "description": "Возврат за курс «Продвинутый уровень»"
11})

Ограничения: • Нельзя вернуть больше, чем было оплачено • Можно сделать несколько частичных возвратов • Сумма возвратов не может превышать сумму платежа • Возврат возможен в течение 365 дней после оплаты

Обработка возвратов в webhook

Webhook для возвратов:

Python
 1async def handle_webhook(request):
 2    data = await request.json()
 3    event = data['event']
 4    
 5    if event == 'refund.succeeded':
 6        refund = data['object']
 7        payment_id = refund['payment_id']
 8        amount = refund['amount']['value']
 9        
10        # Находим пользователя по payment_id
11        user = await db.fetchrow(
12            "SELECT user_id FROM payments WHERE payment_id = $1",
13            payment_id
14        )
15        
16        if user:
17            await bot.send_message(
18                user['user_id'],
19                f"✅ Возврат {amount} ₽ выполнен. Деньги поступят на карту в течение 1–5 дней."
20            )
21            
22            # Отзываем доступ к товару
23            await revoke_access(user['user_id'], payment_id)
24    
25    elif event == 'refund.canceled':
26        # Возврат отменён — уведомляем менеджера
27        await notify_manager(f"⚠️ Возврат отменён: {data['object']['id']}")
28    
29    return web.Response(status=200)

Типичные ошибки при интеграции ЮKassa API

За 40+ интеграций я собрал коллекцию ошибок, которые допускают разработчики. Вот самые частые.

Ошибки безопасности

Ошибка 1: Нет проверки подписи webhook. Критично. Без проверки мошенники могут подделать webhook и получить товар бесплатно.

Ошибка 2: Хранение secretKey в коде. Ключи должны быть в переменных окружения. Если secretKey попадёт в git — его нужно немедленно перевыпустить.

Ошибка 3: Нет HTTPS для webhook. ЮKassa отправляет webhook только на HTTPS. HTTP — не работает.

Ошибка 4: Игнорирование idempotency_key. Без него повторный запрос может создать дублирующий платёж.

Ошибки бизнес-логики

Ошибка 5: Выдача товара при статусе 'pending'. Статус 'pending' означает, что платёж создан, но не оплачен. Выдавайте товар только при 'succeeded'.

Ошибка 6: Нет обработки 'waiting_for_capture'. Если capture: False — платёж нужно подтвердить вручную. Иначе через 7 дней он отменится.

Ошибка 7: Нет обработки ошибок API. ЮKassa может вернуть 400 (неверные параметры), 401 (неверные ключи), 429 (rate limit), 500 (ошибка сервера). Обрабатывайте все.

Ошибка 8: Нет логирования. Без логов невозможно отследить проблемный платёж. Логируйте: ID платежа, статус, сумму, user_id, timestamp.

ОшибкаПоследствиеКак избежать
Нет проверки подписиМошенничествоhmac.new() + compare_digest
Ключи в кодеКомпрометация.env + gitignore
HTTP webhookНе работаетHTTPS + SSL сертификат
Нет idempotencyДубли платежейuuid4() для каждого запроса
Выдача при pendingБесплатный товарПроверять status === 'succeeded'
Нет обработки ошибокПотеря клиентовTry/except + retry

Чек-лист запуска ЮKassa в продакшен

Перед переключением из sandbox в production проверьте все пункты.

Чек-лист

#ПунктСтатус
1Production shopId и secretKey настроены
2Webhook зарегистрирован на HTTPS
3Подпись webhook проверяется
4Idempotency_key генерируется для каждого запроса
5Обработка всех статусов: succeeded, canceled, waiting_for_capture
6Обработка ошибок API (400, 401, 429, 500)
7Фискализация настроена (чеки)
8Логирование всех операций
9Retry-логика для webhook (повторная обработка)
10Мониторинг: алерты при ошибках
11Тестовые платежи пройдены
12Возвраты протестированы

Если все 12 пунктов отмечены — можно запускать в production.

🔧 Нужна помощь с интеграцией ЮKassa? Напишите мне — интегрирую за 3–5 дней от 15 000 ₽.

Читайте также

Нужна интеграция ЮKassa API в вашего бота?

✅ Полная интеграция: платежи, webhook, возвраты, подписки

✅ Тестирование в sandbox + запуск в production

✅ Бесплатная поддержка 30 дней

Написать мне в Telegram →

Частые вопросы

Ответы на самые популярные вопросы о интеграция юkassa api

Нужна интеграция ЮKassa API? От 15 000 ₽

Интегрирую ЮKassa в Telegram-бота за 3–5 дней. Webhook, возвраты, подписки. Поддержка 30 дней

Или посмотрите наши услуги по разработке ботов

Примеры реализованных проектов

Посмотрите мои работы: Telegram-боты, сервисы, CRM и автоматизация для бизнеса

Похожие статьи

Telegram бот для приёма заявок

Telegram бот для приёма заявок от 7 000 ₽. Автоматическая обработка заявок 24/7, уведомления, интеграция с CRM. ROI 300%...

Читать далее

Telegram бот для интернет-магазина

Telegram бот для интернет-магазина от 50 000 ₽. Каталог, корзина, оплата, интеграция с 1С и складом. Бесплатная оценка з...

Читать далее

Как сделать Telegram бота на Python

Разработка Telegram бота на Python от 7 000 ₽. Пошаговое руководство с кодом, aiogram, webhook. Бесплатная оценка за 24 ...

Читать далее