> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nomiq.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Nomiq API Rate Limits by Plan Tier and Endpoint Type

> Rate limits per Nomiq plan tier, response headers for tracking usage, and strategies for handling 429 errors with exponential backoff.

To maintain high availability and consistent performance for all users, the Nomiq API enforces per-minute request limits at the workspace level. Rate limits are shared across all API keys within a single workspace — if you have multiple keys active under one workspace, their combined usage counts toward the same quota. When you exceed a limit, the API returns an HTTP `429 Too Many Requests` response and you must wait before retrying.

## Rate Limits by Plan Tier

Rate limits differ between endpoint categories. Standard endpoints that read or write database records are lightweight and carry generous limits. Generation endpoints that trigger GPU-backed AI processing are more computationally expensive and are strictly limited to protect overall service quality.

### Generation Endpoints

Generation endpoints (for example, `POST /v1/brands/generate`) trigger the AI engine and require significant compute allocation. These are the limits most backend integrations need to account for when designing request queues or job schedulers.

| Plan   | Generation Requests per Minute |
| ------ | ------------------------------ |
| Free   | 10 req / min                   |
| Pro    | 60 req / min                   |
| Agency | 300 req / min                  |

### Standard Endpoints

Standard endpoints (for example, `GET /v1/projects`, `GET /v1/brands`, `PATCH /v1/projects/{id}`) are read/write operations against the Nomiq database and carry much higher limits.

| Plan   | Standard Requests per Minute |
| ------ | ---------------------------- |
| Free   | 100 req / min                |
| Pro    | 1,000 req / min              |
| Agency | 5,000 req / min              |

## Rate Limit Response Headers

Every API response — whether successful or not — includes three rate limit headers. Reading these headers in your application lets you implement proactive throttling before you hit a `429`, rather than reacting to one after the fact.

| Header                  | Type    | Description                                                                                                                           |
| ----------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `X-RateLimit-Limit`     | integer | The maximum number of requests allowed per minute for the endpoint you just called, based on your workspace's plan tier.              |
| `X-RateLimit-Remaining` | integer | The number of requests remaining in the current one-minute window. When this reaches `0`, the next request will return `429`.         |
| `X-RateLimit-Reset`     | integer | A Unix epoch timestamp indicating when the current rate limit window resets and `X-RateLimit-Remaining` returns to its maximum value. |

When a `429` is returned, the response also includes a `Retry-After` header:

| Header        | Type    | Description                                                                         |
| ------------- | ------- | ----------------------------------------------------------------------------------- |
| `Retry-After` | integer | The number of seconds you must wait before making another request to this endpoint. |

A `429` response looks like this:

```
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1716001260
Retry-After: 14
```

```json theme={null}
{
  "error": {
    "type": "rate_limit_error",
    "message": "Rate limit exceeded. Please wait 14 seconds before trying again.",
    "code": "rate_limit_exceeded"
  }
}
```

## Handling 429 Errors with Exponential Backoff

The correct response to a `429` is to pause and retry — not to retry immediately. Immediate retries during a rate limit window will all fail, wasting requests and potentially triggering secondary limits. Use **exponential backoff with jitter**: double your wait time on each successive failure, and add a small random delay to prevent a "thundering herd" of clients all retrying at the same instant.

The following implementation reads the `Retry-After` header when present (for `429` responses) and falls back to exponential backoff for `500` errors:

```javascript Node.js theme={null}
import { Nomiq } from '@nomiq/node';

const nomiq = new Nomiq({ apiKey: process.env.NOMIQ_API_KEY });

async function generateWithBackoff(params, maxRetries = 5) {
  let attempt = 0;

  while (attempt <= maxRetries) {
    try {
      const result = await nomiq.brands.generate(params);
      return result;
    } catch (error) {
      const isRetryable =
        error.status === 429 || (error.status >= 500 && error.status < 600);

      if (!isRetryable || attempt === maxRetries) {
        throw error;
      }

      // Respect Retry-After for 429s; use exponential backoff for 5xx.
      const retryAfterMs =
        error.status === 429 && error.headers?.['retry-after']
          ? parseInt(error.headers['retry-after'], 10) * 1000
          : Math.pow(2, attempt) * 1000;

      // Add jitter: ±200ms random offset to desynchronize concurrent retries.
      const jitter = Math.random() * 400 - 200;
      const waitMs = retryAfterMs + jitter;

      console.warn(
        `Request failed with ${error.status}. Retrying in ${Math.round(waitMs)}ms (attempt ${attempt + 1}/${maxRetries}).`
      );

      await new Promise((resolve) => setTimeout(resolve, waitMs));
      attempt++;
    }
  }
}
```

This pattern handles both `429 Too Many Requests` and transient `5xx` server errors with a single retry loop. The key behaviors are:

* Only `429` and `5xx` responses trigger a retry. A `400`, `401`, `403`, or `404` is thrown immediately because retrying it will never succeed.
* The `Retry-After` header is honored exactly for `429` responses so you do not wait longer than necessary.
* Jitter prevents synchronized retry storms when many workers are running concurrently.

<Tip>
  The most effective way to reduce generation rate limit pressure is to use webhooks instead of polling. There is no status-polling endpoint — when you register a webhook URL on your project, Nomiq pushes the completed generation payload to your server the moment it is ready. A single webhook delivery costs zero additional requests against your quota. See the [Webhooks guide](/api-reference/webhooks) to set one up.
</Tip>

## Proactive Throttling

Rather than waiting to hit a `429`, you can read `X-RateLimit-Remaining` after each successful response and slow down your request queue proactively. If `X-RateLimit-Remaining` drops below a configurable threshold (for example, 10% of your `X-RateLimit-Limit`), introduce a brief pause before the next request. This technique is especially useful in batch processing jobs that iterate over large lists of projects.

```javascript Node.js theme={null}
async function throttledBatchGenerate(projectIds) {
  for (const projectId of projectIds) {
    const response = await nomiq.brands.generate({ project_id: projectId, prompt: '...' });

    const remaining = parseInt(response.headers['x-ratelimit-remaining'], 10);
    const limit = parseInt(response.headers['x-ratelimit-limit'], 10);

    // If we're below 10% capacity, pause for 2 seconds before the next request.
    if (remaining / limit < 0.1) {
      console.log(`Approaching rate limit. Pausing 2s (${remaining}/${limit} remaining).`);
      await new Promise((resolve) => setTimeout(resolve, 2000));
    }
  }
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Errors" icon="triangle-exclamation" href="/api-reference/errors">
    Review the full error response format and the complete list of HTTP status codes returned by the Nomiq API.
  </Card>

  <Card title="Generation API" icon="wand-magic-sparkles" href="/api-reference/generation">
    Learn how to trigger brand generation requests and receive completed assets via webhook.
  </Card>
</CardGroup>
