CloudPayments Payment System Integration
CloudPayments is Russian processor with good documentation, built-in cash register (54-ФЗ), recurring payment support, and convenient widget. Differs from competitors: payment form opens over site, not redirecting customer away — higher conversion.
Integration Variants
CloudPayments offers three embedding methods:
- Widget — JavaScript popup, fastest to implement
- Checkout — embedded form via iframe
- API — direct processing without third-party redirects (requires PCI DSS SAQ A-EP or higher)
For most sites widget fits. API needed if fully controlling form UI or implementing tokenization.
Widget Integration
<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: 'Order #12345',
amount: 1500,
currency: 'RUB',
accountId: '[email protected]',
invoiceId: 'order-12345',
skin: 'mini',
data: {
// arbitrary metadata, returned in webhook
orderId: 12345,
},
},
(options) => {
// success — don't trust without server check
console.log('payment success', options);
},
(reason, options) => {
console.error('payment failed:', reason);
},
);
};
publicId — public key from personal account. Secret key (apiSecret) — server only, never frontend.
Webhook
After payment CloudPayments sends POST to URL specified in personal account (Notifications section). Notification type — payment:
public function handleWebhook(Request $request): Response
{
// Check HMAC-signature
$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 expects code 200 with body {"code":0}
return response()->json(['code' => 0]);
}
If return {"code": 13}, CloudPayments resends notification up to 10 times. Useful for temporary DB errors.
Fiscalization
CloudPayments has built-in cash register. Receipt data passed in cloudPayments.customerReceipt within widget data object:
data: {
cloudPayments: {
customerReceipt: {
Items: [
{
label: 'Product 1',
price: 1500.00,
quantity: 1.0,
amount: 1500.00,
vat: null, // null=no VAT
method: 0, // 0=full payment
object: 1, // 1=commodity
},
],
taxationSystem: 1, // 1=USN income
email: '[email protected]',
amounts: {
electronic: 1500.00,
advancePayment: 0.00,
credit: 0.00,
provision: 0.00,
},
},
},
}
Card Tokenization
For repeat payments without entering details CloudPayments returns Token in first successful payment. Save in DB and use for subsequent debits:
// Repeat debit via token through 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' => 'Auto debit',
]);
Refunds via API
Http::withBasicAuth(env('CP_PUBLIC_ID'), env('CP_API_SECRET'))
->post('https://api.cloudpayments.ru/payments/refund', [
'TransactionId' => 123456789,
'Amount' => 750, // partial
]);
Performance and Features
CloudPayments widget loads external script ~180 KB. Load lazily — only on user interaction with payment button, not page load. Production account activation after application — 1 to 3 business days, faster than most Russian competitors.







