Five things Bitrix REST API doesn't tell you before you go headless
I've spent more time with Bitrix REST API than I expected. Not because the API is broken. Because the documentation covers syntax, not behavior.
You read the official docs before your first headless project. Methods look structured. Auth is described. Pagination exists. Everything looks manageable.
Then you hit production.
Here are five things I wish I'd known before spending several weeks debugging.
What Bitrix REST API documentation doesn't cover
Bitrix REST API is a REST interface built into Bitrix24 and self-hosted 1C-Bitrix. It works fine for typical tasks: fetching products, placing orders, checking order status.
Problems start at the intersection of several conditions: large catalog, concurrent requests, auth under load, composite pages. In those scenarios, the API behaves differently from what the docs describe. Not because the docs are wrong. Because those cases aren't described at all.
A 28,000-SKU project gave me this experience in full. Each of the five surprises below comes from production, not theory.
Surprise 1: iblock pagination loses records under concurrent writes
Bitrix REST API uses offset-based pagination for iblocks via the start parameter. It's a numeric offset, not a true cursor.
Typical call:
lists.element.get?IBLOCK_ID=21&start=50
Offset pagination is unstable when the catalog is being updated concurrently. If even one record changes between fetching page 1 and page 2, some items shift position — you get duplicates or gaps.
When we built a full Elasticsearch index from a 28,000-SKU catalog, early runs returned inconsistent counts. Variance was 3 to 40 records per run. The logs showed the cause: managers were updating prices during indexing.
What worked: run full indexing during a maintenance window at night, or use an export snapshot as the source. For real-time sync, use webhooks and a queue — not repeated full scans.
Surprise 2: OAuth breaks under concurrent load
Bitrix REST API supports three auth schemes: OAuth 2.0, server application token, and user token. All three work in tests. Under production load, the picture changes.
An OAuth access token expires after 1 hour. If a refresh happens while parallel requests are in flight, some requests get 401 errors before the new token is issued. We saw this as random 5-second API response drops, roughly once per hour.
The issue only reproduced under load — 50+ concurrent API requests. With a single thread in a test environment, never.
The fix: switch to a server application token for server-to-server integration. It doesn't expire, doesn't require refresh, and isn't tied to any user session. OAuth stayed only for cases that genuinely need per-user permissions.
One thing the documentation doesn't warn about: the application token only works while the app is installed and active in Bitrix. If someone accidentally deactivates it in the admin panel, the API stops responding — with no errors in the Next.js logs. The error only appears on the Bitrix request side.
Surprise 3: select: ["*"] is a trap
Passing select: ["*"] returns every field on an iblock element, including all custom properties. Those can number 40 to 60. Each custom property is a separate JOIN in the database.
For a 28,000-SKU catalog with 47 custom properties, that meant 47 additional JOINs per page of results.
The latency difference was roughly 4x:
select: ["*"]→ 1.8 seconds per page- Explicit list of 12 fields → 0.45 seconds per page
The rule I introduced: no select: ["*"] in production integrations. Always an explicit field list, documented as part of the API contract between Bitrix and Next.js. Adding a field is a contract change, not a quiet edit to select.
Surprise 4: rate limits during catalog cold start
Bitrix REST API enforces rate limits. For local API calls (from the same server where Bitrix runs), limits are looser but present. For external requests — typically 2 requests per second on Bitrix24, and configurable on self-hosted Bitrix.
A catalog cold start — the first full import when deploying the headless frontend — means thousands of requests in a short window. With 28,000 SKUs and pages of 50 items, that's 560 requests for base data alone, plus the same again for properties.
Naive code without throttling hit 429 errors around the 3-minute mark. The API doesn't block permanently — it adds latency. But that broke our CI/CD pipeline, which was waiting for the import to complete.
The fix: exponential backoff plus a hard rate limit in the importer (no more than 1 request per 600ms for external calls). For ongoing production sync, a controlled queue — not parallel fetch.
Surprise 5: composite pages and REST don't mix well
A typical e-commerce product page isn't one object. It's an SKU from the iblock, a price from the price list, stock from warehouses, related products, and reviews. In a Bitrix monolith, all of that comes from one query via D7 ORM with JOINs. In headless, it's 5–7 separate REST calls.
There's no batch endpoint. Bitrix REST API doesn't support a multi-request call like "give me everything for this product page." There's a batch method for Bitrix24 Cloud, but on self-hosted Bitrix it works differently and doesn't aggregate responses transactionally.
In theory, 7 parallel requests at 200ms each = 200ms total (assuming good network). In practice, some requests have higher latency than others, and the page's TTI ends up worse than you'd expect.
The approach that worked: a server-side aggregation layer. A Next.js route handler fetches all data for the page, caches the result via ISR, and the client receives one ready-made structure. Load shifts to the server, but you get full control over latency and caching. More on ISR cache invalidation in headless: Cache Invalidation in Headless.
What you fix in code vs what you fix in architecture
Looking at all five together, they fall into two buckets.
Surprises 3 and 4 (wildcard select and rate limits) are code problems. Explicit field lists and rate limiting at the importer level — fixable in a day.
Surprises 1 and 5 (unstable pagination and composite pages) are architectural. You can't patch them with a single function. They need an aggregation layer, a sync queue, and a deliberate caching strategy.
Surprise 2 (auth under load) sits in between. Switching to a server token is a code change. Understanding why OAuth doesn't fit server-to-server is an architectural insight.
Before starting any headless project on Bitrix, it's worth auditing the API layer upfront. What to check before you start: Three checks before any headless project.
Bitrix REST API is a working tool. It's optimized for the monolith scenario. Headless asks something different from it — and that something needs to be designed, not discovered in production.