ЮKassa API можно освоить на одном небольшом проекте, если сразу видеть вход, действие и результат. Тестовый магазин позволяет пройти полный цикл платежа без реального списания: создание, переход по ссылке, уведомление и проверка статуса. Ниже вы соберёте работающий пример и проверите обычный и граничный сценарии.
Опасно считать оплату успешной только после возврата браузера или доверять любому JSON, который пришёл на webhook. Поэтому отделим настройку, входные данные, основное действие и проверку. В этой статье вы соберёте FastAPI-приложение, которое создаёт платёж с idempotence key и принимает событие payment.succeeded. Проверка: два повтора одной операции не создают дубликат, confirmation URL открывается, а webhook сверяет платёж через API.
передать сумму, валюту и confirmation. Не расширяйте проект до первого успешного запуска.
повтор не создаёт второй платёж. Проверяйте значение, а не отсутствие ошибки.
После успеха добавьте локальную таблицу заказов и защиту от повторной выдачи. Так копирование станет практикой.
Как устроен учебный проект ЮKassa API
ЮKassa API разделяет подготовку, основное действие, проверку ответа и сохранение результата. Держите ввод, логику и отображение раздельно: тогда каждый этап можно проверить отдельно.
| Этап | Действие | Проверяемый результат |
|---|---|---|
| Создание | передать сумму, валюту и confirmation | API возвращает payment id и URL |
| Идемпотентность | использовать UUID для операции | повтор не создаёт второй платёж |
| Webhook | принять событие и извлечь object.id | endpoint быстро отвечает 200 |
| Проверка | запросить платёж по id через SDK | заказ меняется только при succeeded |
Контрольные точки: создание, идемпотентность, webhook и проверка. Следующий шаг начинается после совпадения с ожидаемым результатом.

От входных данных до видимого результата. Сначала проверяется вход, затем действие и только потом интерфейс.
Собираем рабочий пример шаг за шагом
Материал сверялся с официальной документацией сервиса 21 октября 2026 года. Установите yookassa, fastapi и uvicorn. SHOP_ID и SECRET_KEY задайте через окружение. Проверьте текущую папку через pwd или Get-Location. Вставьте пример целиком, выполните один раз, затем разбирайте по частям.
import os
import uuid
from fastapi import FastAPI, Request
from yookassa import Configuration, Payment
Configuration.account_id = os.environ["YOOKASSA_SHOP_ID"]
Configuration.secret_key = os.environ["YOOKASSA_SECRET_KEY"]
app = FastAPI()
@app.post("/payments")
def create_payment():
payment = Payment.create({
"amount": {"value": "100.00", "currency": "RUB"},
"confirmation": {"type": "redirect", "return_url": "https://example.test/thanks"},
"capture": True,
"description": "Учебный заказ CODIK-101",
"metadata": {"order_id": "CODIK-101"},
}, str(uuid.uuid4()))
return {"id": payment.id, "url": payment.confirmation.confirmation_url}
@app.post("/webhook/yookassa")
async def webhook(request: Request):
event = await request.json()
payment_id = event.get("object", {}).get("id")
if event.get("event") == "payment.succeeded" and payment_id:
payment = Payment.find_one(payment_id)
if payment.status == "succeeded":
print("paid order:", payment.metadata.get("order_id"))
return {"ok": True}- POST /payments возвращает id и ссылку confirmation_url для тестовой оплаты.
- После уведомления приложение повторно получает платёж и видит статус succeeded.
- Повторный запуск даёт тот же предсказуемый результат.
- Пустой ввод получает понятное сообщение вместо падения.
Код держит подготовку отдельно от внешнего действия, поэтому ошибку можно найти на конкретном шаге. Найдите в примере вход, проверку и место формирования результата.

Что отличает устойчивый проект от случайного запуска. Явные границы делают ошибку локальной и понятной.
Что происходит внутри и почему это работает
Ключ идемпотентности связывает повтор запроса с одной операцией. Redirect нужен пользователю, webhook сообщает серверу событие, а финальная проверка API подтверждает состояние. Логику держите отдельно от вывода: функция получает аргумент и возвращает значение, а интерфейс показывает его. Секреты и персональные данные не должны попадать в репозиторий, журнал или публичный скриншот.
| Часть | За что отвечает | Что проверить |
|---|---|---|
| Payment.create | создаёт операцию с суммой и описанием | ключ идемпотентности уникален |
| Confirmation | переводит пользователя на оплату | return_url не считается доказательством |
| Webhook | сообщает об изменении | статус сверяется через API |
Webhook может прийти повторно или не по порядку. Храните payment id и текущий статус заказа, делайте обновление идемпотентным и не выдавайте товар повторно. Не прячьте поток в одном обработчике: сохраните вход, проверьте его, вызовите операцию и только затем обновите интерфейс.
Проверяем проект и добавляем свою функцию
Добавьте таблицу заказов со статусами pending и paid, затем свяжите metadata.order_id с конкретной записью. До правки запишите ожидаемое поведение одним предложением. После граничного теста повторите обычный сценарий.
- Сохраните ожидаемый результат: два повтора одной операции не создают дубликат, confirmation URL открывается, а webhook сверяет платёж через API.
- Измените правило: добавьте локальную таблицу заказов и защиту от повторной выдачи. Сначала предскажите итог.
- Передайте граничное значение и убедитесь, что приложение не падает.
- Верните корректные данные и объясните роли трёх основных частей.
- API возвращает payment id и URL
- повтор не создаёт второй платёж
- endpoint быстро отвечает 200
- заказ меняется только при succeeded
Полезное улучшение сохраняет исходный сценарий и добавляет одну новую проверяемую возможность. Полезная правка проходит от нового ввода до видимого результата.

Четыре проверки перед следующим шагом. Каждый следующий этап начинается после наблюдаемого результата.
Что запомнить и куда двигаться дальше
Перед боевым запуском настройте HTTPS, журнал событий без секретов, возвраты и сверку суммы, валюты и order_id. Для закрепления откройте в первом API на FastAPI, в REST API на Express и в проверке JSON через Pydantic.
Как изучить тему в Кодике
Сначала разберите входные данные и один успешный вызов, затем изучайте дополнительные параметры. Сначала восстановите главную функцию и проверьте её на трёх значениях.
| Шаг | Что разобрать | Мини-проверка |
|---|---|---|
| 1. Основа | HTTP, JSON, UUID и переменные окружения Python | Объясните вход и выход функции. |
| 2. Инструмент | SDK ЮKassa, Payment и confirmation | Повторите команду по памяти. |
| 3. Проект | FastAPI webhook и статусы заказа | Проверьте два сценария. |
| 4. Рефакторинг | Идемпотентность, хранение и сверку платежей | Разделите ввод, логику и вывод. |
Перепишите ключевую функцию по памяти и проверьте её на корректном, пустом и ошибочном вводе. Базовый синтаксис закрепите через курс Python.
Пользователь может не вернуться или открыть URL вручную. Смотрите серверный статус.
Повтор создаёт вторую операцию. Сохраняйте ключ вместе с заказом.
Сначала подтвердите payment id и статус через API.
Ключ магазина нельзя печатать или возвращать клиенту.
Что получится в итоге

Финальный экран показывает результат, состояние запроса и понятное сообщение об ошибке без раскрытия секретов.
Зачем нужен Idempotence-Key?
Чтобы безопасный повтор одного запроса не создавал новую платёжную операцию.
Почему одного webhook JSON недостаточно?
Сервер должен связать событие с заказом и подтвердить итоговый статус.
Что проверять первым, если ЮKassa API не запускается?
Версию среды, текущую папку, команду запуска и первую строку ошибки.
Как понять, что проект ЮKassa API работает?
Проверьте основной сценарий, неверный ввод, повторный запуск и один граничный случай.
Можно ли начать с готового кода?
Да. Добейтесь результата, измените одно правило и восстановите ключевую функцию без копирования.
Выберите одно улучшение и проведите его от ввода до результата.
Если не хватает основы, перейдите курс Python, затем восстановите ключевую функцию без подсказки.