Developing RFQ (Request for Quotation) Functionality for 1C-Bitrix

On B2B websites, prices often aren't public—they depend on volume, region, and contract terms. Instead of a 'Buy' button, you need a 'Request Price' button: an RFQ (Request for Quotation). The standard `sale` module doesn't support this logic; it requires a public price and instant payment. We've bu

Our competencies:

Frequently Asked Questions

On B2B websites, prices often aren't public—they depend on volume, region, and contract terms. Instead of a 'Buy' button, you need a 'Request Price' button: an RFQ (Request for Quotation). The standard sale module doesn't support this logic; it requires a public price and instant payment. We've built a custom RFQ module from scratch that processes up to 200 requests per day for an industrial equipment distributor. In this case, response time dropped from 3 days to 4 hours, and request loss fell from 25% to under 1%. Get a consultation with our engineer to discuss how to implement RFQ on your project.

What pain does the RFQ module solve?

Without RFQ, managers lose requests in email, response times stretch to 2–3 days, and customers go to competitors. For the industrial equipment distributor, we saw this firsthand: 4,000 SKUs without public prices, manual email exchange led to 25% request loss. The RFQ module automates the entire process: request → processing → quote → order.

RFQ architecture: tables and state machine

An RFQ request goes through several statuses: new → processing → quoted → accepted → rejected → ordered. After accepted, the customer can place an order at the agreed price via the standard sale module.

Request table bl_rfq:

CREATE TABLE bl_rfq ( id SERIAL PRIMARY KEY, user_id INT REFERENCES b_user(ID), status VARCHAR(30) DEFAULT 'new', manager_id INT, comment TEXT, manager_note TEXT, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), expires_at TIMESTAMP, order_id INT ); 

Request items table bl_rfq_items:

CREATE TABLE bl_rfq_items ( id SERIAL PRIMARY KEY, rfq_id INT REFERENCES bl_rfq(id) ON DELETE CASCADE, product_id INT NOT NULL, sku_id INT, quantity NUMERIC(10,3), unit VARCHAR(20), price_requested NUMERIC(12,2), price_quoted NUMERIC(12,2), comment TEXT ); 

The state machine is implemented as a finite automaton: each status has transition rules and access rights. For example, transition from new to processing is available only to the manager, and to quoted only after all price_quoted fields are filled. For accepted and rejected statuses, notifications are sent to the customer.

How does the RFQ process work?

  1. The customer adds products to the RFQ cart and submits a request.
  2. The manager receives a notification and processes the request in the admin panel.
  3. The manager sets prices for each item and transitions the request to the quoted status.
  4. The customer receives a notification, logs into their personal account, and accepts or rejects the proposal.
  5. Upon acceptance, an order is created with the agreed prices.

The 'Request Price' button replaces the 'Add to Cart' button on product cards—or coexists if some products have public pricing. The logic is determined in the result_modifier.php of the catalog.element component:

$showRFQ = ($arResult['ITEM_PRICES'][0]['PRICE'] ?? 0) === 0 || $arResult['ITEM']['PROPERTIES']['PRICE_ON_REQUEST']['VALUE'] === 'Y'; $arResult['SHOW_RFQ'] = $showRFQ; 

RFQ cart data is stored in the session or in the bl_rfq table with status draft. On submission, the status changes to new, and the manager receives a notification.

Integration with CRM and notifications

When a request transitions to new, a deal is created in CRM via the REST API method crm.deal.add. Product rows are passed via crm.deal.productrows.set. Manager notification is done through \Bitrix\Im\Notify::send() and an email with the template RFQ_NEW_REQUEST.

In the admin interface, the manager fills in price_quoted, sets the status to quoted. The customer receives an email with a link to their personal account. Upon acceptance, the status becomes accepted, then an order is created in b_sale_order with fixed prices.

Why RFQ is better than manual processing?

Criteria Manual email exchange Our RFQ module
Response time 2–3 days 4 hours
Request loss 25% <1%
CRM integration Manual Automatic
State machine None 6 statuses

Real case: industrial equipment distributor

Situation: 4,000 SKUs without public prices, managers handled requests manually via email—response time 2–3 days, 25% of requests lost.

Implementation:

  • RFQ cart with the ability to add multiple products
  • Automatic deal creation in Bitrix24 CRM on request submission
  • Customer personal account with request history and statuses
  • Email notifications to the manager (immediate) and customer (on status change)
  • One-click conversion of an accepted quote into an order

Result: request processing time reduced to 4 hours (12x faster), request loss down to 0%. The system handles up to 200 daily requests without failures.

Development process and timeline

Stage Timeline
Schema and state machine design from 2 days
Backend: tables, controllers, agents from 4 days
Frontend: button, RFQ cart, personal account from 4 days
CRM integration from 2 days
Email notifications and testing from 2 days

What's included in the development

  • Design of the RFQ state machine and data model
  • Replacement/addition of the 'Add to Cart' button for products without public price
  • RFQ cart with AJAX management of items
  • Admin interface for processing requests with price setting
  • Integration with Bitrix24 CRM module (deals, product rows)
  • Request history section in the customer's personal account

We guarantee a stable solution based on years of experience developing for Bitrix. Order an RFQ module development—it will save your managers hours of manual work. We'll evaluate your project and propose a turnkey timeline. Contact us to discuss the details.