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

# Rate Limits

> Tier-aware rate limiting for the public API

## Overview

demeterrr enforces public API rate limits per organization, not per API key. All API keys in the same organization share the same limit pool.

The current implementation applies two windows:

| Policy                 | Purpose                                        |
| ---------------------- | ---------------------------------------------- |
| **Per-minute burst**   | Smooth short spikes from automation or retries |
| **Per-hour sustained** | Cap ongoing system-to-system traffic           |

<Info>
  API access and API rate-limit profile are related but separate concerns. An organization can have API access disabled, and an enabled organization can still use a custom rate-limit profile.
</Info>

## Default Profiles

These are the deployment defaults used when no organization-specific override is configured:

| Profile        | Per Minute | Per Hour |
| -------------- | ---------- | -------- |
| **starter**    | 100        | 1,000    |
| **pro**        | 250        | 5,000    |
| **business**   | 500        | 10,000   |
| **enterprise** | 1,000      | 25,000   |

<Note>
  Enterprise organizations commonly use an override above the default profile. The default exists so enterprise traffic can be raised without a code change even before a per-org override is set.
</Note>

## Organization Overrides

Operations can raise or lower a specific organization's limits without editing code by setting `API_V1_RATE_LIMIT_ORGANIZATION_OVERRIDES`.

Example:

```json theme={null}
{
  "00000000-0000-4000-8000-000000000123": {
    "profile": "enterprise",
    "perMinute": 1500,
    "perHour": 30000
  }
}
```

Supported override fields:

| Field       | Description                                                          |
| ----------- | -------------------------------------------------------------------- |
| `profile`   | Optional base profile: `starter`, `pro`, `business`, or `enterprise` |
| `perMinute` | Optional custom burst cap                                            |
| `perHour`   | Optional custom sustained cap                                        |

## Tier Defaults By Environment

Each default profile can also be tuned through environment variables:

| Profile      | Per Minute Env                            | Per Hour Env                            |
| ------------ | ----------------------------------------- | --------------------------------------- |
| `starter`    | `API_V1_RATE_LIMIT_STARTER_PER_MINUTE`    | `API_V1_RATE_LIMIT_STARTER_PER_HOUR`    |
| `pro`        | `API_V1_RATE_LIMIT_PRO_PER_MINUTE`        | `API_V1_RATE_LIMIT_PRO_PER_HOUR`        |
| `business`   | `API_V1_RATE_LIMIT_BUSINESS_PER_MINUTE`   | `API_V1_RATE_LIMIT_BUSINESS_PER_HOUR`   |
| `enterprise` | `API_V1_RATE_LIMIT_ENTERPRISE_PER_MINUTE` | `API_V1_RATE_LIMIT_ENTERPRISE_PER_HOUR` |

This lets operations tune a whole class of customers without changing application code.

## Headers On Limit Responses

When a request is throttled, the API returns:

```http theme={null}
Retry-After: 60
X-RateLimit-Limit: 500
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1762679700
X-RateLimit-Policy: minute
X-RateLimit-Profile: business
```

| Header                  | Description                                  |
| ----------------------- | -------------------------------------------- |
| `Retry-After`           | Seconds to wait before retrying              |
| `X-RateLimit-Limit`     | Max requests allowed in the triggered window |
| `X-RateLimit-Remaining` | Always `0` on a throttled response           |
| `X-RateLimit-Reset`     | Unix timestamp for the current window reset  |
| `X-RateLimit-Policy`    | Which policy triggered: `minute` or `hour`   |
| `X-RateLimit-Profile`   | Resolved profile name for the organization   |

## Throttled Response Shape

When a request exceeds the active policy, the API returns `429 Too Many Requests`:

```json theme={null}
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "API per-minute burst rate limit exceeded for this organization.",
    "retryAfter": 60,
    "details": {
      "profile": "business",
      "policy": "minute",
      "limit": 500,
      "scope": "organization",
      "recommendedAction": "Honor Retry-After and retry with exponential backoff plus jitter."
    }
  }
}
```

## Retry Guidance

### 1. Always honor `Retry-After`

If the API returns `429`, wait at least the number of seconds in `Retry-After` before retrying.

### 2. Add jitter

Do not have all workers retry at the same instant. Add randomized delay on top of your backoff.

```javascript theme={null}
async function waitForRetry(response, attempt) {
  const retryAfter = Number(response.headers.get("Retry-After") || "1");
  const jitterMs = Math.floor(Math.random() * 500);
  const backoffMs = Math.pow(2, attempt) * 250;

  await new Promise((resolve) => {
    setTimeout(resolve, retryAfter * 1000 + backoffMs + jitterMs);
  });
}
```

### 3. Prefer batching over bursts

Use the bulk sequence execute path instead of many single-contact calls when possible.

<CodeGroup>
  ```javascript Bad: Many small writes theme={null}
  for (const contact of contacts) {
    await executeSequence(sequenceId, {
      contacts: [contact],
    });
  }
  ```

  ```javascript Good: One bounded bulk call theme={null}
  await executeSequence(sequenceId, {
    contacts: contacts.slice(0, 100),
  });
  ```
</CodeGroup>

### 4. Treat 429s as backpressure, not as hard failures

High-volume clients should queue and retry rather than surfacing every 429 directly to end users.

## Increasing Limits

Need a higher API profile for a pilot or an enterprise rollout?

<Card title="Contact Sales" icon="envelope" href="mailto:sales@demeterrr.com">
  Enterprise customers can use per-org overrides or higher deployment defaults during rollout planning.
</Card>

## Next Steps

<CardGroup cols={2}>
  <Card title="Error Handling" icon="triangle-exclamation" href="/errors">
    Learn how to handle API errors
  </Card>

  <Card title="Quick Start" icon="rocket" href="/guides/quickstart">
    Make your first API call
  </Card>
</CardGroup>
