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

# API Rate Limits and Quotas in Moonshadow

> Moonshadow enforces 1,000 requests per minute per workspace. Learn how rate limits work, how to read the headers, and how to handle 429 responses.

Moonshadow enforces rate limits per workspace to ensure stable performance for all customers. If your integration sends a high volume of requests, monitor the rate limit headers and implement backoff to avoid disruptions.

## Rate Limit Overview

The default limit is **1,000 requests per minute per workspace**. This applies across all API keys and integrations within a single workspace. Burst traffic that exceeds this limit is throttled. After exceeding the limit, your requests will receive a `429 Too Many Requests` response until the counter resets.

## Rate Limit Headers

Every API response includes headers that show your current rate limit status:

<ResponseField name="X-RateLimit-Limit" type="integer" required>
  The maximum number of requests allowed per minute for this workspace. Default is 1,000.
</ResponseField>

<ResponseField name="X-RateLimit-Remaining" type="integer" required>
  The number of requests remaining in the current minute window.
</ResponseField>

<ResponseField name="X-RateLimit-Reset" type="integer" required>
  A Unix timestamp indicating when the rate limit window resets and your quota is fully restored.
</ResponseField>

### Example Response Headers

```http theme={null}
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1755373200
Content-Type: application/json
```

## Reading Rate Limit Headers

You can read these headers after any API call to decide whether to pace your requests:

```javascript theme={null}
const res = await fetch('https://api.moonshadow.dev/v1/workspaces', {
  headers: { Authorization: 'Bearer msh_api_...' }
});

const limit = parseInt(res.headers.get('X-RateLimit-Limit'), 10);
const remaining = parseInt(res.headers.get('X-RateLimit-Remaining'), 10);
const reset = parseInt(res.headers.get('X-RateLimit-Reset'), 10);

console.log(`Remaining: ${remaining}/${limit}, resets at ${new Date(reset * 1000)}`);
```

## Handling 429 Responses

If you exceed the limit, Moonshadow responds with `429 Too Many Requests` and includes a `Retry-After` header:

```http theme={null}
HTTP/1.1 429 Too Many Requests
Retry-After: 45
Content-Type: application/json

{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded. Try again later.",
    "request_id": "req_9g3b2c4d5e6f7h8i"
  }
}
```

Use exponential backoff with a jitter to retry safely:

```javascript theme={null}
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function fetchWithBackoff(url, options, maxRetries = 5) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const res = await fetch(url, options);

    if (res.status !== 429) {
      return res;
    }

    const retryAfter = res.headers.get('Retry-After');
    const delay = retryAfter
      ? parseInt(retryAfter, 10) * 1000
      : Math.min(1000 * Math.pow(2, attempt), 60000);

    const jitter = Math.floor(Math.random() * 500);
    await sleep(delay + jitter);
  }

  throw new Error('Rate limit retries exhausted');
}
```

## Burst Limits and Best Practices

While the sustained limit is 1,000 requests per minute, short bursts above this threshold may still trigger throttling depending on traffic patterns. To stay within limits:

* Batch operations where possible instead of sending many individual requests.
* Cache responses for configuration and metadata that change infrequently.
* Use webhooks to receive updates instead of polling the API.
* Queue outgoing requests and pace them evenly across the minute window.

For questions about raising limits for high-volume workloads, [contact support](mailto:support@moonshadow.dev).
