Vue.js and 1C-Bitrix: configuring interaction via REST API
Clients often come with a ready-made Vue.js SPA that cannot get data from 1C-Bitrix. The reason is an incorrect choice of API mechanism. We configure the integration so that the SPA works as part of the site: with authorization, caching, and security. For example, a typical mistake is trying to use the built-in REST API for a heavy catalog selection, which leads to exceeding the request limit and errors 429. In the article, we analyze three approaches and show which one to choose for your task.
Bitrix provides several mechanisms for working with data from Vue: the built-in REST API (/bitrix/rest/), ORM methods via AJAX controllers (Bitrix\Main\Engine\Controller), and direct AJAX requests to component handlers. The choice of mechanism affects performance, security, and code volume. Let's analyze each approach with practical examples and recommendations.
Built-in Bitrix REST API
Accessible at /rest/ for cloud Bitrix24 and requires configuration for the on-premise version (activating the REST API module). Methods — sale.basket.getlist, catalog.product.list, crm.deal.list and others. Authorization via OAuth 2.0 or via webhooks (webhook URL with token). For a public API on the site (not Bitrix24) — webhooks with limited rights.
Official 1C-Bitrix documentation recommends using webhooks for simple scenarios, but warns about request limits (50 per second for cloud). For on-premise version, there are no limits, but response speed may be low with complex selections.
const BX_WEBHOOK = window.BX_STATE.webhook; // passed from PHP async function getProducts(filter) { const res = await fetch(`${BX_WEBHOOK}catalog.product.list`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ filter, select: ['ID', 'NAME', 'PRICE'] }), }); return res.json(); } Limitations of built-in REST: request limits, not all entities are available, cannot execute arbitrary SQL queries.
Custom controllers via Engine\Controller
For projects on on-premise Bitrix, the main method is custom controllers via Engine\Controller. The controller lives in a custom module. Unlike REST API, you get full control over data, support for tagged caching, and the ability to combine requests.
// local/modules/project.api/lib/controller/product.php namespace Project\Api\Controller; use Bitrix\Main\Engine\Controller; use Bitrix\Main\Engine\ActionFilter; class Product extends Controller { public function configureActions(): array { return [ 'list' => [ 'prefilters' => [new ActionFilter\Authentication()], ], ]; } public function listAction(int $categoryId, int $page = 1): array { $pageSize = 20; $res = \CIBlockElement::GetList( ['SORT' => 'ASC'], ['IBLOCK_ID' => CATALOG_IBLOCK_ID, 'SECTION_ID' => $categoryId, 'ACTIVE' => 'Y'], false, ['nPageSize' => $pageSize, 'iNumPage' => $page], ['ID', 'NAME', 'DETAIL_PICTURE', 'PROPERTY_PRICE'] ); $items = []; while ($item = $res->GetNext()) { $items[] = $item; } return ['items' => $items, 'page' => $page]; } } Controller URL: /bitrix/services/main/ajax.php?action=project:api.product.list. Automatically adds CSRF protection when POST.
Axios in Vue: unified API service
// services/api.js import axios from 'axios'; const api = axios.create({ baseURL: '/bitrix/services/main/ajax.php', headers: { 'X-Requested-With': 'XMLHttpRequest' }, }); // Automatically add CSRF token api.interceptors.request.use(config => { if (config.method === 'post') { config.data = { ...config.data, sessid: window.BX.bitrix_sessid() }; } return config; }); // Handle 401 — redirect to authorization api.interceptors.response.use( res => res.data, err => { if (err.response?.status === 401) { window.location.href = '/auth/?backurl=' + encodeURIComponent(location.pathname); } return Promise.reject(err); } ); export const getProducts = (categoryId, page) => api.post('', { action: 'project:api.product.list', categoryId, page }); All Vue components use functions from services/api.js — they don't make fetch directly. Change URL or authorization mechanism — in one file.
Composable for data
// composables/useProducts.js export function useProducts(categoryId) { const items = ref([]); const loading = ref(false); const error = ref(null); const page = ref(1); async function load() { loading.value = true; error.value = null; try { const data = await getProducts(categoryId.value, page.value); items.value = page.value === 1 ? data.items : [...items.value, ...data.items]; } catch (e) { error.value = e.message; } finally { loading.value = false; } } watch(categoryId, () => { page.value = 1; load(); }, { immediate: true }); return { items, loading, error, page, loadMore: () => { page.value++; load(); } }; } Composable encapsulates loading logic; the component works only with reactive data.
CORS and security policy
For an SPA on a separate subdomain (app.example.com) to the API on (example.com), CORS configuration in PHP is required. Without proper headers, the browser blocks requests. Additionally, you need to pass session cookie with withCredentials: true in axios.
// at the beginning of controller or in OnPageStart event header('Access-Control-Allow-Origin: https://app.example.com'); header('Access-Control-Allow-Credentials: true'); Bitrix session cookie is sent with withCredentials: true — the authorization session works cross-domain.
How to choose between REST API and custom controller?
| Criteria | REST API | Custom Controller |
|---|---|---|
| Development speed | High (ready methods) | Medium (need to write code) |
| Flexibility | Low (only available methods) | High (any logic) |
| Request limits | 50/sec (cloud) | No limits |
| Security | OAuth / webhook | CSRF + session |
| Suitable for | Simple SPA, Bitrix24 | Complex catalogs, carts |
Custom controller wins in scalability: it is 2-3 times faster than REST API for large infoblock selections due to direct SQL queries via ORM.
Typical errors when integrating Vue.js with Bitrix
| Error | Consequence | Solution |
|---|---|---|
| Using REST API for large catalogs | Exceeding limit, 429 errors | Switch to custom controllers |
| Missing CSRF token in POST requests | Error 403, request blocking | Add sessid to request data |
| Incorrect CORS setup | Browser blocking, no data | Set proper headers and credentials |
| Direct fetch requests from components | Difficult debugging and API replacement | Use unified API service |
Why use custom controllers?
They give you full control over data. For example, you can combine requests to multiple infoblocks into one method, apply tagged caching, or add business logic. The built-in REST API does not allow this. When working with custom controllers, you can use all the features of Bitrix ORM, including filters, sorting, and pagination.
What's included in the work
- Source code of controllers, services, and API client.
- Complete documentation for all methods.
- Deployment instructions for your server.
- 30-day warranty on modifications.
- 2 weeks of support after project delivery.
Work process
- Analysis — we study your site architecture, SPA requirements, select the optimal mechanism.
- Design — design API, data schemas, protection.
- Development — write controllers, configure CORS, create composables.
- Testing — check load, security, caching.
- Deployment and documentation — publish API, provide instructions.
Timeframes and cost
Basic setup of one API method takes 2 to 3 days; the cost is calculated individually after analyzing your project. Full integration of SPA with catalog, cart, and authorization takes 1 to 2 weeks; the exact cost is determined at the design stage.
Our team consists of certified specialists with experience working with 1C-Bitrix and more than 50 successful Vue.js projects. We guarantee stability and security of the API. Contact us for a preliminary analysis — we will select the optimal integration method. Request a consultation on your project, and we will offer a solution.

