Skip to content

Платежи и YooKassa

Пополнение баланса проходит через YooKassa. Сценарий:

  1. Создание платежа → получение confirmation_url.
  2. Перенаправление пользователя на confirmation_url.
  3. YooKassa присылает подписанный вебхук об успехе → баланс зачисляется атомарно.

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

bash
curl -b cookies.txt -X POST https://api.runne.run/v1/payments \
  -H 'Content-Type: application/json' \
  -d '{"workspace_id":"0191…","amount_rubles":"500.00","description":"Top up my-app"}'

Тело запроса:

ПолеТипОбязательноПримечания
workspace_idstring (UUID)дадолжен принадлежать сессии
amount_rublesstringда^\d+(\.\d{1,2})?$, минимум 100.00
descriptionstringнетмакс. 500 символов

Ответ (HTTP 201):

json
{
  "payment_id": "0191…",
  "confirmation_url": "https://yoomoney.ru/checkout/payments/v2/contract?orderId=…",
  "amount_rubles": "500.00",
  "tokens_credited": "500.00",
  "status": "pending"
}

tokens_credited равен amount_rubles по фиксированному курсу beta (1 токен = 1 ₽). Минимальная сумма — 100.00 ₽.

Перенаправление и оплата

Отправьте пользователя на confirmation_url. По завершении YooKassa возвращает на страницу успеха кабинета и присылает вебхук.

Вебхук

POST /webhooks/yookassa — единственный канал уведомлений. Аутентификация — через заголовок X-YooKassa-Signature:

X-YooKassa-Signature = HMAC-SHA256(raw_body, YOOKASSA_WEBHOOK_SECRET)

Сравнение выполняется за постоянное время. Отсутствующая или неверная подпись возвращает 401, и событие игнорируется.

События

СобытиеЭффект
payment.succeededЗачисляет баланс (атомарно), затем отправляет чек 54-ФЗ
payment.canceledПомечает платёж как cancelled (только если ещё pending)
receipt.succeededФиксирует номера фискального документа/накопителя
receipt.canceledПомечает чек как failed

Идемпотентность

Вебхук защищён от повторной доставки тремя уровнями:

  1. Проверка статуса — уже succeeded платёж пропускается.
  2. Условный UPDATE … WHERE status='pending' внутри транзакции — побеждает только один параллельный обработчик.
  3. Уникальный индекс на transactions.payment_id — строка зачисления может существовать только один раз.

Повторный вебхук поэтому никогда не зачислит воркспейс дважды. Сумма дополнительно сверяется со строкой платежа; несовпадение аудируется и игнорируется.

Чеки (54-ФЗ)

Чеки выпускаются только для клиентов-физлиц, как того требует 54-ФЗ:

  • Чек создаётся после успешного платежа и отправляется через YooKassa со стабильным ключом идемпотентности (идентификатор платежа).
  • vat_code равен 1 (без НДС) в beta.
  • Отправка чека — best-effort: сбой отправки аудируется и повторяется cron-задачей, но не роняет вебхук.

Юридическим лицам вместо чека выдаётся акт/счёт (в beta ещё не реализовано).

Отмена

Если пользователь бросает оплату, YooKassa присылает payment.canceled; платёж переходит в cancelled, баланс не зачисляется.

Список платежей

bash
curl -b cookies.txt 'https://api.runne.run/v1/payments?workspace_id=0191…'
json
{
  "payments": [
    { "payment_id": "0191…", "amount_rubles": "500.00", "tokens_credited": "500.00", "status": "succeeded", "created_at": "…" }
  ]
}

workspace_id — обязательный query-параметр (HTTP 400, если отсутствует). Ответ ограничен только воркспейсом вызывающего.

Связанное