Setting Up Fund Holding on 1C-Bitrix
The buyer paid for the order — money debited, but the item is out of stock. Refunds take 3 to 10 business days, and each such case undermines trust. Holding (two-stage payment) solves this: the bank reserves the amount on the buyer's card, and actual debit occurs only after confirming availability. This is standard for high-volume online stores with large catalogs. Our experience: over 10 years in Bitrix development and 50+ projects with holding.
What problems does holding solve?
The most common mistake is selling out-of-stock items. If money already went to the store account, refund takes 3–10 business days. Hold allows instant cancellation without fees — the bank just removes the block. Additionally, two-stage payment halves return rates compared to one-stage (based on our project statistics).
Another issue is incorrect payment status mapping. In Bitrix, the Y (paid) status should be assigned only after hold confirmation. If set immediately, cancellation causes accounting confusion. We configure the status model so that PAID changes only after capture, with a custom 'held' status before.
How does two-stage payment work in practice?
Stage 1 — hold (authorization): the store sends a request to the payment system to reserve the amount. Money is not debited but blocked on the card. The acquiring bank returns a pre_auth_code or similar authorization ID.
Stage 2 — confirmation (capture): the store confirms debit when the item is ready for shipment. Money transfers to the store account. Or cancellation (void/cancel): if out of stock, the reserve is released without fees.
Bitrix implements this via the sale module, class \Bitrix\Sale\PaySystem\Manager and specific payment system handlers. For more on the mechanism, see Wikipedia.
Comparison of payment systems with hold support in Bitrix
| Payment system | Two-stage payment out-of-box | Hold duration | Additional features |
|---|---|---|---|
| Sberbank (SberPayment) | Yes | up to 30 days | Apple Pay, Google Pay |
| Tinkoff (TinkoffPayment) | Yes | up to 30 days | Partial hold return |
| YooKassa (YandexMoney) | Yes | up to 7 days | Auto capture |
| Alfa-Bank (AlfaPayment) | Yes | up to 30 days | Manual limit setting |
If your acquirer is not listed, customization is needed. We integrated holding with 15+ payment gateways — from CDEK to foreign aggregators.
How to configure holding in Bitrix?
- Select a payment system in "Store" → "Payment". Ensure it supports holding.
- Enable two-stage mode: in the system settings find the "Two-stage payment" or "Holding mode" parameter and set to "Yes".
- Set up order statuses: create a "Awaiting confirmation" status (or use existing
C) where hold is active. The "Confirmed" status will trigger capture. - Check database configuration. Parameters are stored in tables
b_sale_pay_systemandb_sale_pay_system_params. For example, to find the payment system ID by name:
SELECT ID, NAME, HANDLER_TYPE FROM b_sale_pay_system WHERE ACTIVE = 'Y'; Example: automatic hold confirmation on status change
The OnSaleStatusOrderChange event allows automatic capture on transition to a confirmation status:
// /bitrix/php_interface/init.php use Bitrix\Main\EventManager; EventManager::getInstance()->addEventHandler( 'sale', 'OnSaleStatusOrderChange', function(\Bitrix\Main\Event $event) { $order = $event->getParameter('ENTITY'); $value = $event->getParameter('VALUE'); // Status "confirmed" (e.g. 'C') — confirm the hold if ($value === 'C') { $paymentCollection = $order->getPaymentCollection(); foreach ($paymentCollection as $payment) { if (!$payment->isPaid()) { \Bitrix\Sale\PaySystem\Manager::confirm($payment); } } } // Status "cancelled" (e.g. 'F') — release the hold if ($value === 'F') { $paymentCollection = $order->getPaymentCollection(); foreach ($paymentCollection as $payment) { \Bitrix\Sale\PaySystem\Manager::cancel($payment); } } } ); An agent for monitoring expired holds:
// Agent: ProccessExpiredHolds() function ProccessExpiredHolds() { $cutoffDate = new \Bitrix\Main\Type\DateTime(); $cutoffDate->add('-5D'); $res = \Bitrix\Sale\Internals\PaymentTable::getList([ 'filter' => [ 'PAID' => 'N', '<DATE_BILL' => $cutoffDate, '!SUM' => 0 ], 'select' => ['ID', 'ORDER_ID'] ]); while ($row = $res->fetch()) { \CEvent::Send('HOLD_EXPIRING', 's1', [ 'ORDER_ID' => $row['ORDER_ID'] ]); } return 'ProccessExpiredHolds();'; } We use this solution in all projects. It reduces manager workload and eliminates money loss. Average hold time is 5 days, with 80% of holds confirmed within 48 hours. Savings on fees from cancelling unfulfilled orders reach 2%.
What's included in turnkey holding setup
- Audit of current payment systems and status model.
- Configuration of the
salemodule for two-stage payment. - Development of handlers for non-standard acquirers.
- Integration with business processes (Bizproc) and Bitrix24 robots.
- Writing and configuring an agent for expired holds.
- Testing on live environment and documentation.
Timeline and how to order
Setup takes 1 to 5 business days depending on integration complexity. Cost is determined individually after audit. We guarantee: all holds processed correctly, statuses synchronized, agents working. We'll assess your project within 24 hours. Contact us — we'll show case studies on live stores.
Why trust us with setup?
10+ years of commercial development on 1C-Bitrix. Certified specialists (Bitrix Certified). Over 50 successful holding implementations in stores with turnovers from 1 million RUB/month. Warranty: 12 months of support for changes in the sale module. Holding setup is not just a checkbox in admin — it's a guarantee that buyers' money won't be lost and refunds will be instant. Request an audit of your store — we'll check if holds are correctly configured. Contact us for a consultation on implementing two-stage payment.

