# CloudPayments API: Принять оплату картой на сайте

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

Одностадийная оплата: данные карты шифрует скрипт CloudPayments на странице, сервер магазина проводит платёж по криптограмме.

1. На странице оплаты подключи скрипт Checkout: он принимает данные карты и отдаёт криптограмму — сами данные карты на твой сервер не попадают.
2. С сервера проведи платёж: POST /payments/cards/charge с Amount, Currency, IpAddress плательщика, CardCryptogramPacket, InvoiceId (номер заказа) и AccountId. Авторизация — Basic: Public ID и API Secret. Передай заголовок X-Request-ID, чтобы повтор запроса не создал второй платёж.
3. Если банку нужна 3-D Secure, ответ придёт с Success: false и Model с AcsUrl, PaReq и TransactionId. Отправь покупателя POST-формой на AcsUrl с MD = TransactionId, PaReq и TermUrl — адресом возврата на твой сайт.
4. Когда покупатель вернётся на TermUrl с MD и PaRes, заверши оплату: POST /payments/cards/post3ds с TransactionId и PaRes.
5. Успех запроса (Success) — не то же самое, что успех оплаты: статус транзакции смотри в Model.Status, причину отказа — в коде ошибки (например, 5051 — недостаточно средств).

```bash
curl -X POST https://api.cloudpayments.ru/payments/cards/charge \
  -u '<Public ID>:<API Secret>' \
  -H 'Content-Type: application/json' \
  -H 'X-Request-ID: order-1042-try-1' \
  -d '{
        "Amount": 1500.00,
        "Currency": "RUB",
        "IpAddress": "203.0.113.7",
        "CardCryptogramPacket": "<криптограмма из Checkout>",
        "InvoiceId": "1042",
        "AccountId": "user_42",
        "Description": "Оплата заказа № 1042",
        "Email": "buyer@example.ru"
      }'
```

## Базовые 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/cards/charge — Оплата по криптограмме (одностадийная)

Оплата по криптограмме платёжных данных, сформированной скриптом Checkout. Для двухстадийной схемы тот же набор параметров отправляется на `/payments/cards/auth`. Если нужна 3-D Secure аутентификация, в ответе будет `Success: false` и в `Model` — `AcsUrl`, `PaReq`, `TransactionId`.

Пример ответа (некорректный запрос):

Пример ответа (требуется 3-D Secure):

Пример ответа (транзакция принята, сокращён):

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `Amount` | body | Number | да | Сумма платежа, разделитель точка, не больше 2 знаков после точки; не меньше 0.01 |
| `Currency` | body | String | нет | Валюта: RUB/USD/EUR/GBP, по умолчанию RUB |
| `IpAddress` | body | String | да | IP-адрес плательщика |
| `CardCryptogramPacket` | body | String | да | Криптограмма платёжных данных |
| `Name` | body | String | нет | Имя держателя карты латиницей |
| `PaymentUrl` | body | String | нет | Адрес сайта, с которого вызывается скрипт checkout |
| `InvoiceId` | body | String | нет | Номер счёта или заказа |
| `Description` | body | String | нет | Описание оплаты в свободной форме |
| `CultureName` | body | String | нет | Язык уведомлений: ru-RU, en-US |
| `AccountId` | body | String | нет | Идентификатор пользователя; нужен для создания подписки и получения токена |
| `Email` | body | String | нет | E-mail для квитанции об оплате |
| `Payer` | body | Object | нет | Данные плательщика: FirstName, LastName, MiddleName, Birth, Street, Address, City, Country, Phone, Postcode |
| `JsonData` | body | Json | нет | Произвольные данные транзакции; инструкции для подписки или онлайн-чека оборачиваются в объект cloudpayments |
| `SaveCard` | body | bool | нет | Вернуть карточный токен после успешной оплаты (работает при включённой настройке «Сохранение токена карты» в ЛК) |
| `X-Request-ID` | header | String | нет | Уникальный ключ для идемпотентности |

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

```
{
    "Amount":10,
    "Currency":"RUB",
    "InvoiceId":"1234567",
    "IpAddress": "123.123.123.123",
    "Description":"Оплата товаров в example.com",
    "AccountId":"user_x",
    "Name":"CARDHOLDER NAME",
    "CardCryptogramPacket":"01492500008719030128SM...",
    "Payer":
      {
        "FirstName":"Тест",
        "LastName":"Тестов",
        "Phone":"+71234567890"
    }
}
```

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

```json
{"Success":false,"Message":"Amount is required"}
```

### POST /payments/cards/post3ds — Завершение оплаты после 3-D Secure

Плательщика отправляют POST-формой на `AcsUrl` с параметрами `MD` (= `TransactionId`), `PaReq` и `TermUrl`. После аутентификации он возвращается на `TermUrl` с `MD` и `PaRes`, после чего вызывается этот метод. В ответ приходит информация об успешной или отклонённой транзакции.

| Параметр | Где | Тип | Обяз. | Описание |
|---|---|---|---|---|
| `TransactionId` | body | Long | да | Значение параметра MD |
| `PaRes` | body | String | да | Значение одноимённого параметра |

## Нюансы

- `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/dvuhstadiynaya-oplata-zablokirovat.md)
- [Подписка и списания по сохранённой карте](https://mcp-everything.ru/integrations/cloudpayments/scenarios/podpiska-i-spisaniya-po-sohranennoy.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
