ЮKassa API: интеграция приёма платежей на сайт — полное руководство 2026

Flow Masters13 марта 2026 г.15 мин

ЮKassa API: интеграция приёма платежей на сайт — полное руководство 2026

ЮKassa API — это способ принимать оплату на сайте или в приложении без redirection на стороннюю страницу (хотя можно и так). Интеграция ЮKassa API занимает 1-2 дня, если вы знаете, что делаете. Если нет — потратите неделю на отладку webhook-ов и поиск ошибок в подписи. Я прошёл этот путь и пишу руководство, которого мне не хватало.

Подготовка: регистрация и ключи

Регистрация

  1. Зайдите на yookassa.ru и нажмите «Подключить ЮKassa»
  2. Заполните данные: ИНН, название компании, телефон
  3. Дождитесь модерации — обычно 1-3 рабочих дня
  4. После одобрения вы получите доступ к личному кабинету

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

В личном кабинете перейдите в «Настройки» → «Интеграция». Вам понадобятся два ключа:

  • shop_id — идентификатор магазина (число, например 123456)
  • secret_key — секретный ключ (начинается с test_ для sandbox или live_ для production)

Важно: никогда не коммитьте secret_key в репозиторий. Храните в переменных окружения.

Sandbox

ЮKassa предоставляет тестовое окружение. Ключи начинаются с test_. Платежи не реальные, но API работает идентично production.

Архитектура: как работает API

Схема оплаты через ЮKassa API:

1. Ваш сервер → POST /payments → ЮKassa
2. ЮKassa → возвращает payment с подтверждением
3. Ваш фронтенд → перенаправляет клиента на страницу оплаты
4. Клиент оплачивает
5. ЮKassa → webhook на ваш сервер
6. Ваш сервер → обрабатывает webhook → выдаёт товар/услугу
```text

Ключевой момент: **опирайтесь на webhook, не на ответ браузера.** Клиент может закрыть вкладку до редиректа обратно. Webhook гарантированно приходит.

## Создание платежа

### Endpoint

```text
POST https://api.yookassa.ru/v3/payments
```text

### Заголовки

```text
Content-Type: application/json
Idempotence-Key: <уникальный-ключ>
Authorization: Basic <base64(shop_id:secret_key)>
```text

**Idempotence-Key** — важная штука. ЮKassa использует его, чтобы не создать два платежа при повторном запросе (например, если клиент нажал «Оплатить» дважды). Генерируйте UUID для каждого нового платежа.

### Пример на Python

```python
import requests
import uuid
import base64

SHOP_ID = "123456"
SECRET_KEY = "test_xxxxxxxxxxxxx"

# Авторизация
auth = base64.b64encode(f"{SHOP_ID}:{SECRET_KEY}".encode()).decode()

# Создание платежа
headers = {
    "Content-Type": "application/json",
    "Idempotence-Key": str(uuid.uuid4()),
    "Authorization": f"Basic {auth}"
}

payload = {
    "amount": {
        "value": "1500.00",
        "currency": "RUB"
    },
    "confirmation": {
        "type": "redirect",
        "return_url": "https://yoursite.ru/payment/success"
    },
    "capture": True,
    "description": "Заказ #1234",
    "metadata": {
        "order_id": "1234",
        "user_id": "5678"
    }
}

response = requests.post(
    "https://api.yookassa.ru/v3/payments",
    json=payload,
    headers=headers
)

payment = response.json()

# URL для перенаправления клиента
payment_url = payment["confirmation"]["confirmation_url"]
payment_id = payment["id"]

print(f"Payment ID: {payment_id}")
print(f"Payment URL: {payment_url}")
```text

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

| Параметр | Обязательный | Описание |
|----------|-------------|----------|
| amount.value | Да | Сумма платежа |
| amount.currency | Да | Валюта (RUB) |
| confirmation.type | Да | Способ подтверждения: `redirect`, `embedded` |
| confirmation.return_url | Для redirect | URL возврата после оплаты |
| capture | Нет | Автоматическое подтверждение (True) или двухстадийная оплата (False) |
| description | Нет | Описание платежа (до 128 символов) |
| metadata | Нет | Произвольные данные (возвратятся в webhook) |
| receipt | Нет | Данные для чека (фискализация) |

## Способы оплаты

ЮKassa поддерживает 20+ способов. Вот основные:

### Банковские карты «Мир»

Самый распространённый способ. Комиссия 2.8-3.5%.

```python
payload = {
    "amount": {"value": "1500.00", "currency": "RUB"},
    "payment_method_data": {"type": "bank_card"},
    "confirmation": {"type": "redirect", "return_url": "..."},
    "capture": True
}
```text

### СБП (Система быстрых платежей)

Самый дешёвый способ. Комиссия 0.4-0.7%.

```python
payload = {
    "amount": {"value": "1500.00", "currency": "RUB"},
    "payment_method_data": {"type": "sbp"},
    "confirmation": {"type": "redirect", "return_url": "..."},
    "capture": True
}
```text

### ЮMoney

Комиссия 5-6%. Подходит, если у клиента есть кошелёк ЮMoney.

```python
payload = {
    "amount": {"value": "1500.00", "currency": "RUB"},
    "payment_method_data": {"type": "yoo_money"},
    "confirmation": {"type": "redirect", "return_url": "..."},
    "capture": True
}
```text

### Apple Pay и Google Pay

Для мобильных приложений и сайтов. Требует дополнительной настройки (merchant ID, сертификаты).

### SberPay

Оплата через приложение Сбера. Комиссия ~2.5%.

### Рекомендация

Показывайте клиенту СБП первым — дешевле для вас, удобно для клиента. Если клиент хочет платить картой — пусть платит. Но мотивируйте СБП: «Оплата через СБП — быстрее и без комиссии для вас».

## Webhooks: обработка уведомлений

### Настройка

В личном кабинете ЮKassa → «Настройки» → «Webhooks». Укажите URL вашего endpoint и выберите события:

- **payment.succeeded** — платёж успешен
- **payment.waiting_for_capture** — платёж ожидает подтверждения (двухстадийная)
- **payment.canceled** — платёж отменён
- **refund.succeeded** — возврат выполнен

### Обработка webhook на Python (Flask)

```python
from flask import Flask, request, jsonify
import hashlib
import hmac

app = Flask(__name__)
WEBHOOK_SECRET = "your_webhook_secret"

def verify_signature(payload, signature):
    """Проверка подписи webhook"""
    computed = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(computed, signature)

@app.route("/webhooks/yookassa", methods=["POST"])
def yookassa_webhook():
    payload = request.get_data(as_text=True)
    signature = request.headers.get("Content-Signature", "").replace("sha256=", "")

    if not verify_signature(payload, signature):
        return "Invalid signature", 403

    event = request.get_json()
    event_type = event.get("type")

    if event_type == "payment.succeeded":
        payment = event["object"]
        payment_id = payment["id"]
        order_id = payment.get("metadata", {}).get("order_id")
        amount = payment["amount"]["value"]
        # Логика: выдать доступ, отправить email, обновить статус
        print(f"Payment {payment_id} for order {order_id}: {amount} RUB")

    elif event_type == "payment.canceled":
        payment = event["object"]
        order_id = payment.get("metadata", {}).get("order_id")
        # Логика: отменить заказ
        print(f"Payment canceled for order {order_id}")

    return jsonify({"status": "ok"}), 200

if __name__ == "__main__":
    app.run(port=5000)
```text

### Важные правила webhook-ов

1. **Проверяйте подпись.** Без этого кто угодно может отправить фейковый webhook.
2. **Возвращайте 200 OK быстро.** Если обработка долгая — ставьте в очередь (Celery, RabbitMQ). ЮKassa повторит отправку, если не получит 200.
3. **Обрабатывайте повторения идемпотентно.** ЮKassa может отправить один webhook дважды. Проверяйте по payment_id, не обрабатывайте дважды.
4. **Логируйте все webhook-ы.** На продакшене логируйте payload и результат обработки. Это спасёт при разборе инцидентов.

## Двухстадийная оплата (hold)

Если вы хотите списать деньги только после подтверждения (например, после отгрузки товара):

```python
# Создание с capture=False
payload = {
    "amount": {"value": "1500.00", "currency": "RUB"},
    "capture": False,
    "confirmation": {"type": "redirect", "return_url": "..."}
}

# Подтверждение (после отгрузки)
capture_url = f"https://api.yookassa.ru/v3/payments/{payment_id}/capture"
capture_payload = {"amount": {"value": "1500.00", "currency": "RUB"}}
response = requests.post(capture_url, json=capture_payload, headers=headers)
```text

Если не подтвердить в течение 7 дней — деньги автоматически вернутся клиенту.

## Возвраты

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

```python
refund_url = "https://api.yookassa.ru/v3/refunds"
refund_payload = {
    "payment_id": payment_id,
    "amount": {"value": "1500.00", "currency": "RUB"}
}
response = requests.post(refund_url, json=refund_payload, headers=headers)
```text

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

```python
refund_payload = {
    "payment_id": payment_id,
    "amount": {"value": "500.00", "currency": "RUB"}
}
```text

**Лимиты:** возврат можно сделать в течение 3 лет с момента оплаты. Но чем быстрее — тем лучше для отношений с клиентом.

## Безопасность

### HTTPS

API работает только по HTTPS. На localhost для разработки — нормально. На проде — SSL-сертификат обязателен.

### Проверка подписи webhook

Обязательно. Используйте HMAC-SHA256 с секретом из личного кабинета.

### Idempotence-Key

Используйте UUID для каждого нового платежа. Это защитит от дублей при сетевых ошибках и повторных запросах.

### Хранение данных

Не храните номера карт, CVV и CVC — это запрещено. ЮKassa возвращает только masked.pan (первые 6 и последние 4 цифры). Этого достаточно для идентификации способа оплаты.

### IP-адреса webhook-ов

В настройках webhook можно ограничить отправку по IP. Рекомендую — лишняя защита не помешает.

## Тестирование в sandbox

### Тестовые карты

| Номер карты | Сценарий |
|------------|----------|
| 5555 5555 5555 4444 | Успешная оплата |
| 5555 5555 5555 4443 | Недостаточно средств |
| 5555 5555 5555 4442 | Ошибка банка |

**CVV:** любой трёхзначный (например, `123`)
**Срок:** любая будущая дата (например, `12/28`)

### Тестовый поток

1. Используйте ключи с префиксом `test_`
2. Создайте платеж
3. Перейдите по confirmation_url
4. Оплатите тестовой картой
5. Проверьте webhook на вашем endpoint
6. Проверьте статус платежа в личном кабинете

## Готовые SDK

ЮKassa предоставляет официальные SDK:

- **PHP:** `composer require yoomoney/yookassa-sdk-php`
- **Python:** `pip install yookassa`
- **Node.js:** `npm install yookassa-sdk`
- **Java:** Maven dependency (смотрите в документации)
- **Kotlin:** для Android-приложений

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

### Пример с Python SDK

```python
from yookassa import Configuration, Payment

Configuration.account_id = "123456"
Configuration.secret_key = "test_xxxxxxxxxxxxx"

payment = Payment.create({
    "amount": {
        "value": "1500.00",
        "currency": "RUB"
    },
    "confirmation": {
        "type": "redirect",
        "return_url": "https://yoursite.ru/success"
    },
    "capture": True,
    "description": "Заказ #1234"
})

print(payment.confirmation.confirmation_url)
```text

## Распространённые ошибки

### 1. Неверная подпись webhook

**Симптом:** webhook приходит, но подпись не совпадает.

**Решение:** убедитесь, что используете тело запроса как есть (raw bytes), а не распарсенный JSON. Кодировка — UTF-8.

### 2. Idempotence-Key повторяется

**Симптом:** при повторном запросе с тем же ключом ЮKassa возвращает ответ первого запроса (даже если это был другой платёж).

**Решение:** генерируйте новый UUID для каждого платежа. Храните соответствие idempotence_key → payment_id в БД.

### 3. Currency mismatch

**Симптом:** ошибка «Invalid currency».

**Решение:** ЮKassa работает только с RUB. Убедитесь, что amount.currency = "RUB".

### 4. Webhook не доходит

**Симптом:** платёж прошёл, а webhook не пришёл.

**Решение:** проверьте, что ваш endpoint доступен извне (ngrok для локальной разработки), возвращает 200 OK, и URL в настройках ЮKassa правильный.

### 5. Capture timeout

**Симптом:** двухстадийный платёж автоматически отменяется через 7 дней.

**Решение:** ставьте таймер или cron-задачу для подтверждения платежей. Не оставляйте на потом.

## Производительность и лимиты

- **Максимальная сумма одного платежа:** 60 000 000 ₽ (для юрлиц)
- **Минимальная сумма:** 1 ₽
- **Частота запросов:** до 100 RPS (requests per second)
- **Время ожидания ответа API:** обычно 200-500 мс
- **Доступность:** 99.95% SLA

Для среднего бизнеса этих лимитов хватает с огромным запасом. Если вы обрабатываете 1000+ платежей в минуту — обсуждаете индивидуальные условия с ЮKassa.

## Заключение

Интеграция ЮKassa API — несложная задача, если знать подводные камни. Главные правила:

1. **Всегда проверяйте подпись webhook** — безопасность прежде всего
2. **Используйте Idempotence-Key** — защита от дублей
3. **Опирайтесь на webhook, не на redirect** — надёжнее
4. **Тестируйте в sandbox** — бесплатные тестовые карты, реальное API
5. **Используйте SDK** — меньше кода, меньше ошибок
6. **Логируйте всё** — поможет при разборе инцидентов

На интеграцию от нуля до рабочего приёма платежей уходит 1-2 дня. Если нужно быстрее — используйте готовые модули для CMS или SDK.

## Подписки и рекуррентные платежи

Один из самых прибыльных сценариев использования ЮKassa API. Если у вас подписочный сервис (SaaS, контент, клуб) — рекуррентные платежи обязательны.

### Как работают подписки в ЮKassa

1. Создаёте платёж с `save_payment_method: true`
2. При успешной оплате ЮKassa возвращает `payment_method_id`
3. Сохраняете его в БД вместе с датой следующего списания
4. По cron-задаче создаёте платёж с `payment_method_id` — без участия клиента

```python
# Первый платёж с сохранением способа
payload = {
    "amount": {"value": "990.00", "currency": "RUB"},
    "save_payment_method": True,
    "confirmation": {"type": "redirect", "return_url": "..."},
    "capture": True
}

# В ответе будет:
# payment["payment_method"]["id"] = "pm_xxxxx"
# payment["payment_method"]["saved"] = True

# Рекуррентный платёж (без участия клиента)
recurring_payload = {
    "amount": {"value": "990.00", "currency": "RUB"},
    "payment_method_id": "pm_xxxxx",
    "capture": True
}
```text

### Что делать при неудачном списании

Карта могла истечь, не хватить денег, банк заблокировал. План:

1. Первый отказ — повтор через 24 часа
2. Второй отказ — повтор через 3 дня + уведомление клиенту «Обновите платёжные данные»
3. Третий отказ — приостановка подписки + уведомление

ЮKassa отправляет webhook `payment.canceled` с причиной отказа. Логируйте причину и показывайте клиенту понятное сообщение.

### Тарифы на подписки

ЮKassa не берёт дополнительную комиссию за рекуррентные платежи. Те же 2.8-3.5% за карты, 0.4-0.7% за СБП.

## ЮKassa для маркетплейсов

Если вы строите маркетплейс — ЮKassa имеет специальное решение с расщеплением платежей.

### Как работает расщепление

1. Покупатель платит 1 000 ₽
2. ЮKassa автоматически: 50 ₽ → вам (комиссия площадки), 900 ₽ → селлеру, 50 ₽ → НДС
3. Каждый участник получает свой чек
4. Выплата селлеру — автоматически по расписанию

Для этого используется объект `deal` (сделка) вместо обычного платежа. API сложнее, но документация подробная.

### Когда нужен маркетплейс-режим

- У вас есть селлеры/подрядчики, которым нужно выплачивать деньги
- Вы — налоговый агент по НДС
- Нужно расщеплять платеж между несколькими получателями

Если вы просто продаёте свои товары — обычного API достаточно.

---

Нужна помощь с интеграцией ЮKassa или другой платёжной системы в ваш проект? **Flow Masters** внедряет платёжные решения, чат-боты и автоматизацию для бизнеса в России. [Заявка на flow-masters.ru](https://flow-masters.ru) — обсудим задачу и предложим решение.

💡 Нужна помощь с автоматизацией?

Обсудим ваш проект — консультация бесплатная

Обсудить проект
Все статьи

Начните экономить уже сегодня

Выберите удобный способ связи — ответим за 30 минут

Расчёт стоимости

Начните с самого популярного тарифа

Бесплатная консультация
Прототип за 3 дня
Гарантия результата