Rate limits & the completion window
What throttles a call, what caps a job, and how long you wait for results.
Three different things can slow you down, and they fail in different ways. Rate limits are about how often you call the API and resolve on their own. Batch ceilings are about how much work you can have queued at once. The completion window is how long a job is allowed to take. Budgets are about money and don't resolve by waiting.
Rate limits
Limits are per project, per region, and returned on every response:
GET /v1/me HTTP/1.1
Host: REGION.api.lararouter.com
Authorization: Bearer $LARAROUTER_API_KEY
HTTP/1.1 200 OK
X-Lararouter-RateLimit-Limit: 3000
X-Lararouter-RateLimit-Remaining: 2847
X-Lararouter-RateLimit-Reset: 41Exceeding one returns 429 with error.code = rate_limit_exceeded and a Retry-After in seconds.
Back off and retry; this one does resolve by waiting.
These count HTTP calls, not inference. A single POST /v1/batches carrying 50,000 lines is one
request against this budget. In practice the only thing that gets near the limit is polling, which is
why a minute between GET /v1/batches/{id} checks is the right cadence.
Current allowances are on your identity:
curl https://REGION.api.lararouter.com/v1/me \
-H "Authorization: Bearer $LARAROUTER_API_KEY"Batch ceilings
How much work you can have in flight is capped separately, and reported under batches on
GET /v1/me.
Prop
Type
Splitting a large workload into several medium batches rather than one enormous one is worth doing anyway: results start landing sooner, and an expiry costs you less to recover from.
The completion window
completion_window is the contract on how long a job may take. It is a ceiling, not an estimate.
Most batches finish well inside it.
| Plan | Window | expires_at |
|---|---|---|
| Pay-as-you-go | 24h | created + 24 hours |
| Enterprise | 4h | created + 4 hours |
{
"completion_window": "24h",
"created": 1754150400,
"expires_at": 1754236800
}Requesting 4h without Enterprise returns 403 with error.code = completion_window_unavailable. It
fails loudly rather than quietly downgrading, so you never think you bought a shorter window than you
did.
What expiry actually costs
A batch that reaches the boundary with work outstanding ends in expired. Lines that finished are
in output_file_id and are billed; the rest are in error_file_id with code batch_expired and
are not. Resubmit those in the next job. See Batches.
Why everything is batched
There is no interactive tier to jump ahead of. Running every invocation as a scheduled job is what lets Lararouter fill capacity efficiently, and that pricing is the product. Per-token rates sit below OpenRouter batch inference.
The trade is straightforward: if a human is watching a spinner, Lararouter is the wrong tool. If the work is summarization, tagging, enrichment, classification, or embedding backfills (anything you were already dispatching to a queue), the wait costs you nothing you were going to spend anyway.
Checking what a job cost
Group usage by batch to see where the spend went.
curl -G https://REGION.api.lararouter.com/v1/usage/entities \
-H "Authorization: Bearer $LARAROUTER_API_KEY" \
-d "start=2026-07-01" \
-d "group_by=batch"{
"object": "usage",
"totals": { "cost_usd": 401.35, "invocations": 918442 },
"groups": [
{ "key": "batch_5Rj8Lm2Q", "cost_usd": 3.84, "invocations": 4187 },
{ "key": "batch_3Qn1Xv7B", "cost_usd": 291.02, "invocations": 764310 }
]
}cost_usd on the batch object itself is the same number, so reconciling a job against your own
records doesn't need the usage API at all.