QUERY_LIMIT_EXCEEDED is Bitrix24 (Alaio) telling you that something is calling the portal's REST API faster than it will accept. It arrives as an HTTP 503 with that code in the body — not a broken token or a permissions problem, but a deliberate throttle. Here is what the counter measures, why bulk operations trip it first, and which fixes change the outcome.

What does QUERY_LIMIT_EXCEEDED actually mean?

Bitrix24 shapes REST traffic with a leaky bucket. Every call adds to a virtual counter that drains at a fixed rate; calls go through while the counter stays under a threshold, and past it they are refused until it drains. The documented figures differ by plan: on Enterprise the counter drains at 5 per second against a threshold of 250, on other plans at 2 per second against a threshold of 50.

Short bursts are therefore tolerated up to the bucket size — that is why a script looks fine for a few seconds and then fails — while sustained throughput is capped by the drain rate, which the documentation works out to roughly 172,800 requests per day at 2 per second. It is a separate mechanism from OPERATION_TIME_LIMIT (HTTP 429), which measures accumulated method execution time rather than request count. The full map of REST failures lives in the REST API error codes guide.

Why do bulk operations and loops burn the counter fastest?

Because the counter counts HTTP requests, not records. A per-record loop is the worst shape: 300 contacts each needing a read and a write is 600 calls, and the bucket only absorbs the opening burst before the drain rate becomes the ceiling. Reading a large table is expensive before you write anything, since list methods return one page at a time. The same shape hides in imports, nightly syncs and migration scripts: one job to you, a wall of requests to the portal.

How much do batch requests actually help?

A lot, for this error. The batch method packs up to 50 method calls into one HTTP request, so the 600-call loop above becomes 12 requests against the rate counter — the highest-leverage change in most integrations.

What batch does not do is make the work cheaper. Nested calls execute as separate methods, so each one's execution time is checked against its own limit, while the outer batch call is not counted in operating. Batching relieves rate pressure and leaves resource-intensity pressure untouched: if you are hitting 429 rather than 503, the queries need to get lighter.

Why are parallel workers a typical cause?

Because the counter is tracked per portal, not per worker, per token or per integration. Four queue workers each pacing at 2 requests per second produce 8 per second at the portal. The documentation adds a second trap: several applications running on one server against the same Bitrix24 share a common rate limit, and it advises against running multiple parallel series of requests from a single IP address.

The rate budget therefore has to be global: a shared counter, such as a token bucket in Redis, or one outbound path everything funnels through. Pacing applied independently inside each worker is not pacing.

What does a sane backoff strategy look like?

The official recommendation is to decrease request frequency and retry with an increasing delay. In practice: treat 503 QUERY_LIMIT_EXCEEDED as retryable, back off exponentially with jitter so parallel workers do not resynchronise into a fresh burst, and cap the attempts so a stuck job surfaces. Retrying in a tight loop keeps the bucket full and extends the outage.

Distinguish the two: a 503 drains in seconds, while OPERATION_TIME_LIMIT runs on minute-long baskets and needs a far longer wait. And make writes idempotent before adding retries, or a retry becomes a duplicate.

How do I find out what is eating the limit?

Every REST response carries a time block: start, finish, duration, processing, date_start, date_finish, plus operating and operating_reset_at. The operating value is accumulated method execution time across ten one-minute baskets, and operating_reset_at says when the oldest basket drops out. Log both alongside the method name and you can aggregate by method, integration and hour.

Then enumerate every consumer, because the budget is shared: marketplace apps, inbound webhooks, custom scripts, scheduled syncs, and workflows firing outbound calls. A nightly import overlapping with business-hours traffic is the classic case — fine alone, over the threshold together. If automation stopped at the same time, this troubleshooting guide covers the neighbouring causes.

Can workflow robots help here?

They do not raise the portal's limit — nothing you install can — but they shape the calls a workflow makes so they stop arriving as a spike. Reliable webhook retries a failed delivery on a configurable interval, lets you choose which status codes count as success, reports the attempt count and can notify people when delivery fails. Short pause waits a set number of seconds and continues, spacing steps apart in a mass launch. HTTP request GET/POST returns the body and status code so the workflow can branch. They smooth the burst; the ceiling stays put.

What should I change first?

Batch what loops, pace globally rather than per worker, back off with increasing delays, and measure operating to find the consumer to fix first. For surrounding patterns see the workflow automation guide and the robot catalog. If your scenario is not covered, describe the task — we build the robot for free and add it to the shared library.