Stock Sync in Headless Bitrix: Three Patterns and Why Boring Polling Wins
Three warehouses. 28,000 SKUs. A promise to the client: real-time stock data.
The first two months we built a webhook chain using Bitrix Events API. Then I opened the logs. Out of 1,000 events, around 800 arrived. The other 200 disappeared somewhere in the queue. Silently. No alerts.
That's 20% of inventory updates going missing. With active 1C restocking happening daily, that's not a rounding error.
We rewrote everything to use polling. Zero lost updates since.
The webhook instinct — and why it makes sense
The logic is clean. Stock changes in Bitrix, event fires, frontend updates. No wasted requests. No polling overhead. Real-time.
On paper — yes. Our production looked different.
Bitrix fires webhooks synchronously at the moment an iblock element changes. If your endpoint doesn't respond within 3 seconds, the event is considered delivered. No retry mechanism in the standard b24.userwebhook setup. No dead-letter queue. No delivery monitoring out of the box.
For small projects with infrequent updates, you'll never notice. For 28K SKUs across three warehouses with daily 1C sync cycles — it's a structural leak.
How Bitrix Events API actually behaves under load
Bitrix Events API fires webhooks synchronously: the event goes out the moment an iblock element changes, with no built-in retry if your endpoint fails to respond within 3 seconds. When 1C pushes a batch of stock updates, iblock elements update sequentially. For hundreds or thousands of simultaneous updates, the event queue becomes unreliable.
There's also the REST API rate limit: 2 requests per second per endpoint on a standard plan. Not a problem for polling with batch requests — but critical if you're trying to acknowledge each incoming webhook event with a callback to Bitrix.
The third issue: if your endpoint accepts an event but writes to Redis under load, and Redis responds slower than 3 seconds, Bitrix won't wait. Event lost.
None of this is a Bitrix bug. It's an architectural constraint that rarely makes it into the tutorials.
Three inventory sync patterns
I mapped out three approaches that hold up in production.
Webhooks as the primary channel
Bitrix fires an event on stock change → endpoint receives it, writes to Redis → Next.js reads at render time. Fast. Nearly real-time.
Without a reliable queue (Redis Streams, RabbitMQ), this works only at low load. With a queue, it's production-ready — but now you're maintaining a whole infrastructure layer: retry logic, dead-letter handling, lag alerts.
This works well if you have a team ready to own that infrastructure.
Polling
Polling-based inventory sync runs a cron job every 60–120 seconds to fetch changed products via CatalogProduct.list filtered by DATE_MODIFIED, writes results into a Redis Hash, and lets Next.js read at ISR render time or via revalidateTag.
You don't need a webhook endpoint or a separate queue. Lost updates: zero. The 2 req/sec rate limit isn't a factor: a batch request for 50 products with pagination handles hundreds of changes in a few seconds.
Max delay: 60–120 seconds. Acceptable for most B2B ecommerce.
Hybrid
Webhooks trigger revalidatePath or revalidateTag for fast updates on specific pages. Polling every 60–120 seconds covers missed events and restores eventual consistency.
Webhooks give speed where it matters. Polling guarantees nothing gets lost.
Why 60 seconds is an honest answer
"Polling every 60 seconds" sounds like a compromise. It isn't — it's the right answer when the requirements actually call for it.
Does the buyer need true real-time?
Here's a realistic scenario: a customer opens a product page. If stock changed 30 seconds ago, they'll see the updated number on the next load. That only becomes a problem during flash sales with live countdown timers. For a standard B2B catalog with daily restocking, it doesn't.
ISR in Next.js pairs well with polling here. Calling revalidateTag from a cron job is exactly what ISR was designed for. Pages update within N seconds of a data change. Predictable. Monitorable. We covered ISR-based cache invalidation separately — that article is about content cache rather than inventory, but the mechanics are the same.
Our production setup
This is what it looks like in practice:
Bitrix (1C sync → iblock) → cron every 60 seconds → CatalogProduct.list filtered by DATE_MODIFIED >= now() - 120s → Redis Hash (sku → quantity) → Next.js reads at ISR render.
If a webhook endpoint is configured, it calls revalidatePath for top-category pages on each incoming event. That speeds up updates for key pages — but the webhook is supplementary here, not the source of truth.
The DATE_MODIFIED field in iblocks updates automatically when stock changes. No custom mechanism needed.
Monitoring: the cron job writes a JSONL log with the last successful poll timestamp and the number of records updated. If three consecutive polls fail, a Telegram alert fires.
What we measured
Before switching to polling:
- Webhook event loss: ~20% (200 out of 1,000 over one week of monitoring)
- Detected only via manual audit, no alerts
- Recovery: full sync once per day on a schedule
After switching to polling + hybrid:
- Lost updates: 0
- Max update delay: 60 seconds
- Infrastructure: Redis + cron, no additional queue
LCP didn't change. The client didn't notice the 60-second delay. They weren't supposed to.
When polling isn't enough
Polling stops being sufficient in three situations.
First — flash sales with live countdown timers and a hard "right now" requirement. You need webhooks plus a reliable queue with guaranteed delivery.
Second — thousands of SKUs updating simultaneously from multiple sources, where the REST API rate limit becomes a real constraint rather than a theoretical one.
Third — a business-imposed SLA under 30 seconds, not just habit.
In these cases, you need a proper queue. The specifics of Bitrix REST API in headless — there are some non-obvious limits worth knowing before you design the sync.
Decision checklist
Polling works when updates stay under 1,000 records per hour and a 60–120 second window is acceptable. If the team doesn't want to maintain a queue, polling is the right call, not the lazy one.
Hybrid makes sense when you want faster updates for key categories: a day or two to set up a webhook endpoint, with polling as the backstop. That's what we run.
Full webhook + queue only when you have flash sales with hard timing requirements or a team experienced with running queues in production. Without that experience, the complexity isn't worth it.
We picked hybrid. Polling covers eventual consistency. Webhooks speed things up where it counts. Simple infrastructure, zero lost updates.