/integration/subscriptionsПодписки создаются только в RUB. Все примеры выполняются с вашего сервера с API-ключом мерчанта, которому подключён метод sbp_recurring. Комиссии в примерах ответов иллюстративные: при 5% за счёт мерчанта платёж 100 ₽ даёт 95 ₽ после комиссии. Для вашей кассы используйте суммы ответа.
Параметры запроса
| Поле | Тип | Описание |
|---|---|---|
agreement_mode | string | h2h по умолчанию или hosted. В обоих режимах клиент открывает confirmation_url |
email | string | Email плательщика до 254 символов. Обязателен в h2h; при hosted можно не передавать. Переданный непустой email должен быть корректным |
amountобязательное | integer | Базовая сумма каждого списания в копейках, от 1 до 9007199254740991. Например, 1999 означает 19,99 ₽. Фактическая сумма ограничивается настройками метода, комиссиями и холдом. Передавайте JSON-число, не строку |
external_idобязательное | string | Ваш уникальный ID подписки, до 255 символов. Разрешены латинские буквы, цифры, точка, дефис и подчёркивание |
intervalобязательное | string | daily, weekly, monthly или yearly |
interval_count | integer | Количество единиц периода между списаниями. По умолчанию 1. Для daily: 1–31, weekly: 1–4, monthly: 1–12, yearly: 1–3. Передавайте целое JSON-число, не строку |
descriptionобязательное | string | Назначение регулярного платежа, до 255 символов |
callback_url | string (https) | URL для вебхуков. Если поле не передано, используется callback URL из настроек мерчанта. URL должен быть публичным и использовать HTTPS |
Пример
curl -X POST https://api.cashera.cash/api/v1/integration/subscriptions \-H "X-Api-Key: $CASHERA_API_KEY" \-H "Content-Type: application/json" \-d '{"amount": 10000,"external_id": "subscription-pro-10428","interval": "monthly","interval_count": 1,"description": "Тариф Pro","email": "customer@example.com"}'
Два способа подключения
h2h сохраняет существующий процесс с email плательщика.hosted направляет клиента на страницу подтверждения провайдера; email в запросе необязателен. В обоих случаях открывайте только возвращённыйconfirmation_url, не собирайте ссылку самостоятельно и не запрашивайте у клиента банковские коды на вашем сервере.
curl -X POST https://api.cashera.cash/api/v1/integration/subscriptions \-H "X-Api-Key: $CASHERA_API_KEY" \-H 'Accept: application/json' \-H 'Content-Type: application/json' \-d '{"agreement_mode": "hosted","amount": 1999,"external_id": "subscription-hosted-10428","interval": "monthly","interval_count": 1,"description": "Тариф 19,99 ₽ в месяц"}'
До выдачи ссылки Cashera подтверждает финансовые параметры у провайдера. В обоих режимах сумма клиента gross_amount может превышать базовуюamount из-за комиссии. Не вычисляйте её на клиенте из фиксированного процента: показывайте значения ответа. Email в ответ не включается.
Подписки на 3, 6, 9 и 24 месяца
Отправляйте эти тела на тот же POST /integration/subscriptions с тем же заголовком X-Api-Key. Меняются только параметры периода и ваш уникальный external_id. Сумма 29900 — 299 ₽ за одно списание; interval_count не умножает сумму или комиссию автоматически.
{"amount": 29900,"external_id": "subscription-3-months-10428","interval": "monthly","interval_count": 3,"description": "Доступ на 3 месяца","email": "customer@example.com"}
Если interval_count не передан, используется 1: старый запрос с monthly по-прежнему создаёт ежемесячную подписку. Для 24 месяцев используйте yearly и 2; сочетание monthly и 24 вернёт 422. Расписание определяет провайдер; период не означает отсрочку первого списания.
Для новой подписки ответ 201 ещё не означает, что она активна. Перенаправьте клиента наconfirmation_url и дождитесь статуса active через вебхукили запрос состояния.
При повторе создания уже действующей подписки может вернуться 200со статусом active или past_due и сохранённой ссылкой. Это та же подписка, а не новая привязка. Не просите клиента подтверждать её повторно: проверьте состояние и историю платежей. Сам повтор создания не является новым списанием.
Ссылка подтверждения
Поле confirmation_url имеет тип string | null. В ответе подписки нет поля payment_url. Для cancelled и failed ссылка равна null. Email не возвращается в ответе.
Ответ 200 OK с confirmation_url: null и all_providers_unavailable: true означает, что провайдеры подтверждения недоступны. Повторите тот же запрос с тем же external_id и параметрами. При наличии сохранённой ссылки повтор вернёт её, а не создаст новую.
Точный срок действия ссылки API не возвращает. Открывайте её сразу после получения. Ошибка банка при открытии не означает успешной привязки или оплаты.
Ошибка получения ссылки подтверждения
Запись подписки, подтверждение её финансовых параметров и получение ссылки выполняются последовательно. Ошибка внешнего запроса может прийти после сохранения подписки, поэтому ответ 5xx не означает, что подписка не создана.
{"message": "Subscription status lookup failed."}
- Запросите подписку через GET по external_id. Ответ с ошибкой содержит только
message, а не объект подписки. pending_agreementсconfirmation_url: nullозначает, что подтверждение ещё не завершено и доступной ссылки нет. Это не доказательство оплаты или окончательного отказа. Не перенаправляйте клиента на пустую ссылку.- Не создавайте замену с новым
external_idи не запускайте бесконечные повторы. Повтор исходного POST продолжает незавершённый этап: проверку параметров или получение ссылки h2h. Hosted не запускает h2h-подтверждение. GET только читает сохранённое состояние. При повторяющихся ошибках передайте поддержке UUID, external_id и время ошибки с часовым поясом.
all_providers_unavailable: false не доказывает, что ссылка получена: при ошибке запроса это поле может остаться false. Для открытия подтверждения нужна непустая confirmation_url. Статусы failed и cancelledокончательные — повторный POST их не возобновляет.
Идемпотентность
- первый успешный запрос возвращает
201 Created - повтор с тем же
external_idи теми же параметрами использует существующую подписку. При успешной обработке ответ —200 OK; если ссылка ещё не получена, повтор может снова завершиться ошибкой провайдера - тот же
external_idс другим режимом подключения, email, суммой, интервалом, количеством периодов (interval_count), описанием или callback URL возвращает409 Conflict
Отсутствующий interval_count и явно переданный 1 эквивалентны при повторе. Период существующей подписки изменить повторным POST нельзя.
После смены тарифа повтор создания по-прежнему должен содержать первоначальные параметры, а не новую цену. Для изменения используйте отдельный endpoint update иIdempotency-Key. Полный сценарий перехода с пробной оплаты есть на странице «Триал и смена тарифа».
При статусе creation_unknown провайдер мог создать подписку, даже если Cashera не получила окончательный ответ. Не создавайте замену автоматически: повторите запрос с тем же external_idи, если статус не изменился, обратитесь в поддержку.
Ошибки
| Поле | Тип | Описание |
|---|---|---|
400 | Bad Request | Провайдер отклонил запрос. Явный отказ создания сохраняется как failed. При получении ссылки h2h финальный статус устанавливается только для распознанной отмены или истечения окна согласия. Другой 400 на этом этапе не доказывает отмену; получите текущее состояние подписки |
401 | Unauthorized | Отсутствует или неверен X-Api-Key |
403 | Forbidden | Мерчант отключён, заморожен или не может создавать подписки |
409 | Conflict | Конфликт параметров для существующего external_id |
422 | Unprocessable Entity | Нет обязательного email в h2h либо передан некорректный email, ошибка других полей, небезопасный callback URL, неподдерживаемый интервал, некорректный interval_count (null, строка, дробь или выход за пределы выбранного периода), неподходящая итоговая сумма или неверная конфигурация метода |
500 | Internal Server Error | В том числе ошибка провайдера при получении ссылки подтверждения: Subscription agreement request failed. Проверьте подписку по тому же external_id; она могла сохраниться до ошибки |
502 | Bad Gateway | Провайдер не дал корректный однозначный ответ. Получите подписку GET-запросом по тому же external_id |
