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

# Rate Limits

> Understanding API rate limits and best practices

# Rate Limits

To ensure fair usage and platform stability, the Garmint API enforces rate limits on all requests.

## Current Limits

| Limit Type          | Value |
| ------------------- | ----- |
| Requests per minute | 60    |
| Requests per hour   | 1,000 |
| Concurrent requests | 10    |

<Info>
  Need higher limits? [Contact us](mailto:api@garmint.app) for enterprise plans.
</Info>

## Rate Limit Headers

Every API response includes headers showing your current rate limit status:

```
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1703001300
```

| Header                  | Description                       |
| ----------------------- | --------------------------------- |
| `X-RateLimit-Limit`     | Max requests per window           |
| `X-RateLimit-Remaining` | Requests left in current window   |
| `X-RateLimit-Reset`     | Unix timestamp when window resets |

## Handling Rate Limits

When you exceed the rate limit, you'll receive a `429 Too Many Requests` response:

```json theme={}
{
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Please slow down.",
    "details": {
      "retryAfter": 23
    }
  }
}
```

The `Retry-After` header indicates how many seconds to wait:

```
Retry-After: 23
```

### Retry Strategy

Implement exponential backoff:

```typescript theme={}
async function callWithRetry(fn: () => Promise<Response>, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fn();
    
    if (response.status !== 429) {
      return response;
    }
    
    const retryAfter = parseInt(response.headers.get('Retry-After') || '1');
    const backoff = Math.min(retryAfter * 1000, Math.pow(2, attempt) * 1000);
    
    await new Promise(resolve => setTimeout(resolve, backoff));
  }
  
  throw new Error('Rate limit exceeded after retries');
}
```

## Best Practices

<AccordionGroup>
  <Accordion title="Batch requests when possible">
    Instead of making many individual requests, batch operations where the API supports it.
  </Accordion>

  <Accordion title="Cache garment data">
    The garment catalog doesn't change frequently. Cache the response for at least an hour.

    ```typescript theme={}
    const CACHE_TTL = 60 * 60 * 1000; // 1 hour
    let cachedGarments: Garment[] | null = null;
    let cacheTime = 0;

    async function getGarments() {
      if (cachedGarments && Date.now() - cacheTime < CACHE_TTL) {
        return cachedGarments;
      }
      // Fetch fresh data...
    }
    ```
  </Accordion>

  <Accordion title="Use webhooks for async operations">
    For generation requests, use the `webhookUrl` parameter instead of polling:

    ```json theme={}
    {
      "designUrl": "...",
      "garmentId": "...",
      "webhookUrl": "https://your-server.com/webhook/garmint"
    }
    ```
  </Accordion>

  <Accordion title="Monitor your usage">
    Check the rate limit headers and log them to catch issues before they become problems.
  </Accordion>
</AccordionGroup>

## Rate Limit by Endpoint

Some endpoints have specific limits:

| Endpoint         | Limit                |
| ---------------- | -------------------- |
| `POST /generate` | 30/min (token-gated) |
| `POST /analyze`  | 60/min               |
| `GET /garments`  | 60/min               |
| `POST /upload`   | 20/min               |

## Token Limits

Separate from rate limits, generations consume **tokens** from your account:

* Each generation costs **1 token**
* Analysis and uploads are **free**
* Check your balance via the `X-Tokens-Remaining` header

```
X-Tokens-Remaining: 47
```

When tokens run out, you'll receive:

```json theme={}
{
  "error": {
    "code": "insufficient_tokens",
    "message": "You don't have enough tokens for this operation.",
    "details": {
      "required": 1,
      "available": 0
    }
  }
}
```

Status: `402 Payment Required`
