Интеграция платёжной системы CloudPayments на сайт
CloudPayments — российский процессинг с хорошей документацией, встроенной кассой (54-ФЗ), поддержкой рекуррентных платежей и удобным виджетом. Отличается от конкурентов тем, что платёжная форма открывается поверх сайта, не уводя покупателя на внешнюю страницу — конверсия выше.
Варианты интеграции
CloudPayments предлагает три способа встройки:
- Виджет — JavaScript-попап, максимально быстро в реализации
- Checkout — встроенная форма через iframe
- API — прямой процессинг без перехода на сторонние страницы (требует PCI DSS SAQ A-EP или выше)
Для большинства сайтов подходит виджет. API нужен, если нужно полностью контролировать UI формы или реализовывать токенизацию.
Подключение виджета
<script src="https://widget.cloudpayments.ru/bundles/cloudpayments.js"></script>
const pay = () => {
const widget = new cp.CloudPayments({ language: 'ru-RU' });
widget.charge(
{
publicId: 'pk_xxxxxxxxxxxxxxxxxxxx',
description: 'Заказ #12345',
amount: 1500,
currency: 'RUB',
accountId: '[email protected]',
invoiceId: 'order-12345',
skin: 'mini',
data: {
// произвольные метаданные, возвращаются в webhook
orderId: 12345,
},
},
(options) => {
// успех — не доверять этому коллбэку без серверной проверки
console.log('payment success', options);
},
(reason, options) => {
console.error('payment failed:', reason);
},
);
};
publicId — публичный ключ из личного кабинета. Секретный ключ (apiSecret) — только на сервере, никогда во фронтенде.
Webhook
После оплаты CloudPayments отправляет POST на URL, указанный в личном кабинете (раздел «Уведомления»). Тип уведомления — payment:
public function handleWebhook(Request $request): Response
{
// Проверяем HMAC-подпись
$hmac = base64_encode(
hash_hmac('sha256', $request->getContent(), env('CP_API_SECRET'), true)
);
if ($hmac !== $request->header('Content-HMAC')) {
return response('Invalid signature', 403);
}
$data = $request->all();
if ($data['Status'] === 'Completed') {
$orderId = $data['InvoiceId'];
$amount = $data['Amount'];
Order::where('id', $orderId)
->where('total', $amount)
->update(['status' => 'paid', 'transaction_id' => $data['TransactionId']]);
}
// CloudPayments ожидает код 200 с телом {"code":0}
return response()->json(['code' => 0]);
}
Если вернуть {"code": 13}, CloudPayments будет повторять уведомление по расписанию до 10 раз. Это полезно при временных ошибках БД.
Фискализация
CloudPayments имеет встроенную онлайн-кассу. Данные для чека передаются в параметре cloudPayments.customerReceipt внутри объекта data виджета:
data: {
cloudPayments: {
customerReceipt: {
Items: [
{
label: 'Товар 1',
price: 1500.00,
quantity: 1.0,
amount: 1500.00,
vat: null, // null=без НДС
method: 0, // 0=полный расчёт
object: 1, // 1=товар
},
],
taxationSystem: 1, // 1=УСН доход
email: '[email protected]',
amounts: {
electronic: 1500.00,
advancePayment: 0.00,
credit: 0.00,
provision: 0.00,
},
},
},
}
Токенизация карты
Для повторных платежей без ввода реквизитов CloudPayments возвращает Token в первом успешном платеже. Его сохраняют в БД и используют для последующих списаний:
// Повторное списание по токену через API
$response = Http::withBasicAuth(env('CP_PUBLIC_ID'), env('CP_API_SECRET'))
->post('https://api.cloudpayments.ru/payments/tokens/charge', [
'Amount' => 1500,
'Currency' => 'RUB',
'AccountId' => '[email protected]',
'Token' => $savedToken,
'InvoiceId' => 'order-12346',
'Description' => 'Автоматическое списание',
]);
Возвраты через API
Http::withBasicAuth(env('CP_PUBLIC_ID'), env('CP_API_SECRET'))
->post('https://api.cloudpayments.ru/payments/refund', [
'TransactionId' => 123456789,
'Amount' => 750, // частичный
]);
Производительность и особенности
Виджет CloudPayments подгружает внешний скрипт весом ~180 KB. Загружать его лучше лениво — только при взаимодействии пользователя с кнопкой оплаты, а не при загрузке страницы. Время активации боевого аккаунта после подачи заявки — от 1 до 3 рабочих дней, что быстрее большинства конкурентов на российском рынке.







