# CloudPayments API: Подписка и списания по сохранённой карте

Сценарий из mcp-everything. Актуально на 2026-10-24.

Ежемесячная оплата сервиса или списание без участия покупателя по карте, сохранённой при первой оплате.

1. Первая оплата — обычная, по криптограмме, обязательно с AccountId (идентификатором пользователя у тебя). После успешной оплаты CloudPayments вернёт токен карты в данных транзакции и в Pay-уведомлении — сохрани его.
2. Для регулярных списаний создай подписку: POST /subscriptions/create с Token, AccountId, Description, Amount, Currency, RequireConfirmation, StartDate (в UTC, в будущем), Interval (Day, Week, Month) и Period. Сохрани Id подписки из ответа.
3. Для разовых списаний без подписки используй POST /payments/tokens/charge с Token, AccountId, Amount и TrInitiatorCode = 0 (списание инициирует магазин); для оплаты по расписанию — PaymentScheduled = 1.
4. Отключить подписку: POST /subscriptions/cancel с Id.
5. Токен работает только на том терминале (Public ID), где был получен.

```bash
curl -X POST https://api.cloudpayments.ru/subscriptions/create \
  -u '<Public ID>:<API Secret>' \
  -H 'Content-Type: application/json' \
  -d '{
        "Token": "<токен карты>",
        "AccountId": "user_42",
        "Description": "Подписка на сервис example.ru",
        "Email": "user@example.ru",
        "Amount": 399,
        "Currency": "RUB",
        "RequireConfirmation": false,
        "StartDate": "2026-11-01T09:00:00",
        "Interval": "Month",
        "Period": 1
      }'
```

## Базовые URL

- Боевой: `https://api.cloudpayments.ru`

## Авторизация

Тип: Basic Auth

HTTP Basic Auth: логин — Public ID, пароль — API Secret. Оба значения есть в личном кабинете. Без заголовка авторизации или с неверными данными API возвращает HTTP 401 Unauthorized. API Secret нужно хранить в защищённом месте.

Параметры передаются методом POST в теле запроса: `application/x-www-form-urlencoded` («ключ=значение») или `application/json`. Ответ всегда JSON и содержит как минимум `Success` и `Message`.

```
{ "Success": false, "Message": "Invalid Amount value" }
```

## Методы сценария

### POST /payments/tokens/charge — Оплата по токену (рекарринг)

Оплата по токену, полученному при оплате по криптограмме или через Pay-уведомление. Для двухстадийной схемы — `/payments/tokens/auth`. Токен работает только на том терминале (publicId), где был получен.

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `Amount` | body | Number | да | Сумма платежа, не больше 2 знаков после точки |
| `Currency` | body | String | нет | Валюта, по умолчанию RUB |
| `AccountId` | body | String | да | Идентификатор пользователя |
| `TrInitiatorCode` | body | Int | да | Инициатор списания: 0 — ТСП, 1 — держатель карты |
| `PaymentScheduled` | body | Int | нет | Оплата по расписанию: 0 — без расписания (по умолчанию), 1 — по расписанию |
| `Token` | body | String | да | Токен |
| `InvoiceId` | body | String | нет | Номер счёта или заказа |
| `Description` | body | String | нет | Назначение платежа |
| `IpAddress` | body | String | нет | IP-адрес плательщика |
| `Email` | body | String | нет | E-mail для квитанции |
| `Payer` | body | Object | нет | Данные плательщика |
| `JsonData` | body | Json | нет | Произвольные данные транзакции |

Пример запроса:

```
{
    "Amount":59,
    "Currency":"RUB",
    "InvoiceId":"1234567",
    "Description":"Оплата товаров в example.com",
    "AccountId":"user_x",
    "TrInitiatorCode": 0,
    "PaymentScheduled": 1,
    "Token":"success_1111a3e0-2428-48fb-a530-12815d90d0e8"
}
```

### POST /subscriptions/create — Создание подписки

Подписка на рекуррентные платежи по токену карты. В ответ возвращается идентификатор подписки.

Пример ответа (сокращён):

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `Token` | body | String | да | Токен карты, выданный после первого платежа |
| `AccountId` | body | String | да | Идентификатор пользователя |
| `Description` | body | String | да | Назначение платежа |
| `Email` | body | String | нет | E-mail плательщика |
| `Amount` | body | Number | да | Сумма платежа |
| `Currency` | body | String | да | Валюта: RUB/USD/EUR/GBP |
| `RequireConfirmation` | body | Bool | да | true — платежи по двухстадийной схеме |
| `StartDate` | body | DateTime | да | Дата и время первого платежа в UTC, в будущем |
| `Interval` | body | String | да | Интервал: Day, Week, Month |
| `Period` | body | Int | да | Период; вместе с интервалом: 1 Month — раз в месяц, 2 Week — раз в две недели |
| `MaxPeriods` | body | Int | нет | Максимальное количество платежей |
| `CustomerReceipt` | body | json | нет | Состав онлайн-чека |

Пример запроса:

```
{
   "token": "477BBA133C182267FE5F086924ABDC5DB71F77BFC27F01F2843F2CDC69D89F05",
   "accountId": "user_x",
   "description": "Ежемесячная подписка на сервис example.com",
   "email": "user@example.com",
   "amount": 399,
   "currency": "RUB",
   "requireConfirmation": false,
   "startDate": "2021-11-02T21:00:00",
   "interval": "Day",
   "period": 5
}
```

Пример ответа:

```json
{
    "Model": {
        "Id": "sc_221da6421dc44dbd2cc3464f6f083",
        "AccountId": "user_x",
        "Amount": 399,
        "Currency": "RUB",
        "Interval": "Day",
        "Period": 5
    },
    "Success": true,
    "Message": null
}
```

### POST /subscriptions/cancel — Отмена подписки

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `Id` | body | String | да | Идентификатор подписки |

Пример запроса:

```
{"Id":"sc_cc673fdc50b3577e60eee9081e440"}
```

Пример ответа:

```json
{"Success":true,"Message":null}
```

## Нюансы

- `Success` в ответе показывает только успешность запроса, а не статус транзакции. Статус транзакции смотрят в поле `Model.Status` или в уведомлениях.
- Идемпотентность включается заголовком `X-Request-ID` с уникальным значением; результат хранится 1 час, новый запрос требует нового значения.
- Если в целочисленное поле передать дробное число, ошибки не будет: значение математически округлится.
- Токен работает только на том терминале (publicId), где был получен.
- Финальный статус оплаты по токену СБП приходит только в Pay- и Fail-уведомлениях, а не в ответе на запрос.
- Для ТСП с MCC 4814 обязателен телефон плательщика в `Payer.Phone` (только цифры, например `+71234567890`), иначе банки отклоняют операции.
- Pay, Fail, Recurrent, Cancel, Confirm, Refund-уведомления повторяются до 100 раз (интервалы 1, 2, 5, 10, 30 минут), если сервер магазина недоступен или ответил кодом, отличным от нуля; таймаут ответа — 30 секунд.
- Подлинность уведомлений проверяют по заголовкам `X-Content-HMAC` и `Content-HMAC`: HMAC-SHA256 от тела запроса (для GET — от строки параметров) в UTF-8, ключ — API Secret, результат в base64.
- Уведомления приходят с адресов 185.98.81.0/28, 87.251.91.160/27, 46.46.175.96/27, 46.46.168.160/27, 162.55.174.97/32, 91.216.178.243/32.
- Ответ на Check-уведомление: `{"code":0}` — принять платёж; коды 10, 11, 12, 13, 20 отклоняют его (неверный InvoiceId, AccountId, сумма, платёж не принят, просрочен).

## Другие сценарии

- [Принять оплату картой на сайте](https://mcp-everything.ru/integrations/cloudpayments/scenarios/prinyat-oplatu-kartoy-na-sayte.md)
- [Двухстадийная оплата: заблокировать и списать позже](https://mcp-everything.ru/integrations/cloudpayments/scenarios/dvuhstadiynaya-oplata-zablokirovat.md)
- [Вернуть деньги покупателю](https://mcp-everything.ru/integrations/cloudpayments/scenarios/vernut-dengi-pokupatelyu.md)
- [Выставить счёт ссылкой на оплату](https://mcp-everything.ru/integrations/cloudpayments/scenarios/vystavit-schet-ssylkoy-na-oplatu.md)
- [Принимать уведомления об оплате и сверять платежи](https://mcp-everything.ru/integrations/cloudpayments/scenarios/prinimat-uvedomleniya-ob-oplate.md)

---

Если этого недостаточно — официальная документация: https://developers.cloudpayments.ru/#api
Вся интеграция одним документом: https://mcp-everything.ru/integrations/cloudpayments.md
