Rate limits
Four ceilings, the headers that report them, and how to back off.
On this page
There are four limits, because they protect two different things: this API, and the pool of workers behind it. Every one of them is set per organization, and the numbers below are what a deployment applies to an account that has not agreed its own.
| Limit | Scope | Default | Protects |
|---|---|---|---|
| Requests per minute | per API key | 300 | this API, from a client stuck in a retry loop |
| Concurrent batches | per organization | 5 | the worker pool, from one customer queueing fifty at once |
| Synchronous requests per minute | per organization | 60 | the worker pool, from a burst of live calls |
| Synchronous requests at once | per organization | 2 | the worker pool, from live calls holding every worker |
None of them is a plan feature. All of them are raised by asking, which is the same conversation that sets your allowance.
Why the synchronous ones are tighter #
A /sync request outranks every queued batch for a worker while it is running - that is what the doubled price buys. The last two limits are the bound on that: without them one account could hold the whole fleet with a loop of live calls, and everybody else, that account included, would watch their batches stop. The concurrency one usually binds first: at 2 in flight, lookups that take ten seconds are twelve a minute however generous the window is.
The batch endpoints are not bounded by either of them. A synchronous refusal is never a reason to stop working: drop /sync from the URL, send targets instead of target, and the same request goes through at half the price.
Headers #
Every authenticated response carries your request budget. Batch creates additionally carry the concurrency one, and the /sync routes carry theirs, because those are the only places a client can act on them.
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1788259260
X-Concurrent-Batch-Limit: 5
X-Concurrent-Batch-Remaining: 3
X-Sync-Limit: 60
X-Sync-Remaining: 58
X-Sync-Reset: 1788259260
X-Sync-Concurrent-Limit: 2
X-Sync-Concurrent-Remaining: 1A header is ABSENT when the ceiling it reports has been lifted for your organization. Read a missing X-RateLimit-Limit as "no limit" rather than as an error: the alternative spelling was 0, which reads as the opposite of what it means.
Over the limit #
{
"error": {
"type": "rate_limited",
"message": "rate limit exceeded",
"requestId": "req_8f2ka91x"
}
}A 429 carries Retry-After in seconds and is never metered. Wait what it tells you rather than retrying immediately - a tight retry loop against a rate limit is how a temporary slowdown becomes a sustained one. On the two concurrency refusals Retry-After is a floor rather than a prediction, because a slot frees when one of your own requests finishes.
The message says which ceiling you met, and they are not interchangeable. A synchronous refusal leaves the batch endpoints open; a request-budget refusal does not.
An agreed pace #
An account can also carry an agreed ceiling on credits per rolling hour. It is not the monthly allowance and it is not a request count: past it, new submissions answer 429 rate_limited until the hour rolls forward, while everything already accepted keeps draining and keeps being charged normally. GET /account reports it as rate_limit.credits_per_hour, and it is null unless one was agreed.
The limit you will not hit #
Because everything is a batch, the request rate is almost never what constrains you. One request submits 50,000 targets; polling a batch at the recommended 2 seconds is 30 requests a minute. If you are near 300, you are probably polling far harder than meta.recommendedPollMs suggests, or polling batches one at a time where GET /batches would list them in one call.
How fast a batch actually drains is a matter of pool capacity and LinkedIn pacing, not of your request rate. Submitting harder does not make it finish sooner.