---
title: "Limits and the 429 code"
url: https://lumean.app/es/developers/docs/guide/limits
locale: es
description: "Five different limits with five different remedies hide behind a single 429 code. How to tell them apart with one look at the response."
updated: 2026-09-04
source_locale: en
sources: [get-usage, post-orders, post-orders-order-retry]
errors: ["429", token-quota-exceeded, limit-exceeded, concurrency-limit-exceeded, policy-cooldown-active]
spec_version: 0.0.1
---

# Limits and the 429 code

A `429` in the Lumean API is not one limit but five. They have different causes, different response bodies
and, most importantly, different remedies: what fixes one is useless against the other four.
The generic “wait and retry” is guaranteed to work in exactly two cases out of five.

> [!WARNING]
> The key rate limit does **not** send a `Retry-After` header, contrary to the introductory text in the OpenAPI spec,
> which promises it for every `429`. The missing header and the missing `reason` in the body are
> the fastest way to tell the request-rate limit from the token quota.

## How to tell them apart at a glance

Two checks in this order are enough: does the body have a `reason` field, and did a `Retry-After`
header arrive. The first check separates the request-rate limit from the four order-related limits;
the second tells you whether you can simply wait.

```text
HTTP 429
│
├─ в теле НЕТ поля "reason"
│    └─ лимит частоты запросов ключа          Retry-After: нет
│       → свой backoff по окнам limits.requests.*
│
└─ в теле ЕСТЬ поле "reason"
     ├─ token_quota_exceeded                  Retry-After: ЕСТЬ
     │    → ждать retry_after сек; window/limit/used/reset_at в теле
     ├─ limit_exceeded                        Retry-After: нет
     │    → месячный объём плана исчерпан; сверить GET /usage
     ├─ concurrency_limit_exceeded            Retry-After: нет
     │    → ждать завершения СВОИХ активных заказов (limit_type: concurrent)
     └─ policy_cooldown_active                Retry-After: ЕСТЬ
          → править текст; 5 блокировок = 5 мин, далее 10, затем 15
```

## Five sources

| Source | `reason` | `Retry-After` | What to do |
| --- | --- | --- | --- |
| Key request rate | no | no | Your own backoff based on the key's windows |
| Key token quota | `token_quota_exceeded` | yes | Wait `retry_after` seconds |
| Subscription usage limit | `limit_exceeded` | no | Check `GET /usage`, buy more, or wait for the next period |
| Concurrent task slots | `concurrency_limit_exceeded` | no | Wait for **your own** orders to finish |
| Content policy cooldown | `policy_cooldown_active` | yes | Fix the text; don't retry it as is |

## Key request rate

A limit on the key's own `limits.requests.per_minute|per_hour|per_day` windows. The body is
a bare envelope `{ "success": false, "message": "…" }`: no `reason`, no `Retry-After`,
no `X-RateLimit-*`. Go by the key's configured windows and implement exponential
backoff yourself.

An important nuance: **by default a key has no request-rate limit at all**. A numeric default
applies only if the operator has set one in the environment. The effective windows are shown in your
dashboard. If you got this `429` while the windows are empty, you are almost certainly looking at one
of the four limiters below.

## Key token quota

It counts tokens, not requests: the accounting unit of work volume (this is **not** money and not LMC).
The `per_minute`, `per_hour`, `per_day`, `per_month` windows come from the key's `limits.tokens.*`.
The check happens **before** creation: the order is not created and not charged.

### 429 · `token_quota_exceeded` — token_quota_exceeded — key token quota exhausted

| Что произошло | Что делать |
| --- | --- |
| The order was not created. This is the only 429 with a detailed body: `window` (the first window violated), `limit`, `used`, `requested`, `reset_at`, `retry_after`. It comes together with a `Retry-After` header. | Wait until `reset_at` — or `retry_after` seconds; it is the same value. The presence of `Retry-After` is exactly how you tell this case apart from the key rate limit, which has no such header at all. If you cannot wait, reduce `requested`: split the text into parts so that each one fits into what remains in the window (`limit − used`). |

`Retry-After`: есть. Разбор: https://lumean.app/es/developers/docs/errors/token-quota-exceeded

The body contains `window` (the first window exceeded), `limit`, `used`, `requested`, `reset_at`
and `retry_after`, which is enough to queue the job until the exact moment
instead of polling the API blindly.

## Subscription usage limit

This is about your plan, not the key: the monthly generation volume is used up. The body contains only
`message` and `reason: "limit_exceeded"`, with no quota fields and no `Retry-After`. Pausing won't help:
the response won't change until the end of the billing period.

### GET /usage

Get Usage Limits

Справочник: https://lumean.app/es/developers/docs/api/get-usage

## Concurrent task slots

`concurrency_limit_exceeded` limits neither rate nor volume but the number of your orders
**in progress at the same time**. A batch of hundreds of orders sent in a single burst hits exactly
this limit. The fix is not a pause between requests but waiting for the already running orders to finish: a retry
right after any of them reaches a terminal status will go through.

The effective ceiling and the current number of active orders are in `GET /usage`, in the entry with
`limit_type: "concurrent"`. Its `period_start`, `period_end` and `resets_in` are `null`:
this limit has no period, so waiting for “the end of the month” is pointless.

## Content policy cooldown

Five tasks in a row blocked by the content policy restrict creating new ones for 5 minutes,
for 10 on repeat offenses, then for 15 (it goes no higher). This is the only
order-related `429` that carries `Retry-After`, along with the `retry_after` (seconds)
and `retry_at` (ISO-8601) fields.

Infrastructure failures don't move the counter: only content blocks count, and any
successful task resets both the counter and the level reached.

**Правильно**

Wait for `retry_at`, and before then fix the wording in the text that the policy rejected.

**Неправильно**

Retry the same text after the cooldown expires: it will hit the block again, raise the level
to 10 minutes, and cost money on every attempt.

## What to do as an integrator

1. Read `reason` **before** `Retry-After`: it alone answers the question “is this about
   rate, volume, plan, concurrency, or text”.
2. Respect `Retry-After` when it is present. When it is absent, a timer-based retry helps only
   with the request-rate limit; in the other cases you need `GET /usage` or a text fix.
3. Don't confuse `429` with `402`. The `402` code `payg_topup_required` is not a rejection but a payment
   fork: the server offers to pay for the missing tokens from your LMC balance. A blind retry
   is useless here; you need to repeat the request with `confirm_payg_topup` and `quote_token`.
4. Cap the number of attempts. Three of the five sources don't clear up on their own, and
   an endless retry loop won't bring the order a single second closer to completion.

> [!TIP]
> Not sure which of the five you got? Paste the response body into the diagnostic tool on the
> “Errors” page: it parses `reason` and the headers and shows the matching card.

---

- Esta página en el navegador: https://lumean.app/es/developers/docs/guide/limits
- Referencia completa legible por máquina: https://api.lumean.app/docs/llm.md
