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

# 요청 제한

> API 요청 제한 이해하고 활용하기

## 요청 제한 등급

| 등급         | 요청/분  | 요청/일    | 월 비용  |
| ---------- | ----- | ------- | ----- |
| Free       | 10    | 100     | \$0   |
| Starter    | 60    | 1,000   | \$29  |
| Pro        | 300   | 10,000  | \$99  |
| Business   | 1,000 | 100,000 | \$499 |
| Enterprise | 협의    | 협의      | 문의    |

## 요청 제한 헤더

모든 응답에 요청 제한 정보가 포함됩니다:

```
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1705315200
```

| 헤더                      | 설명                   |
| ----------------------- | -------------------- |
| `X-RateLimit-Limit`     | 해당 등급의 분당 최대 요청 수    |
| `X-RateLimit-Remaining` | 현재 구간에서 남은 요청 수      |
| `X-RateLimit-Reset`     | 제한이 초기화되는 Unix 타임스탬프 |

## 요청 제한 응답

요청 제한을 초과하면 `429 Too Many Requests` 응답을 받습니다:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "rate_limited",
    "message": "요청 제한 초과",
    "retryAfter": 42
  }
}
```

`Retry-After` 헤더는 재시도까지 대기할 초를 나타냅니다:

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

## 요청 제한 처리하기

### 지수 백오프

```javascript theme={null}
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);

    if (response.status === 429) {
      const retryAfter = parseInt(response.headers.get('Retry-After')) || 60;
      const delay = retryAfter * 1000 * Math.pow(2, i);  // 지수 백오프
      console.log(`요청 제한됨. ${delay}ms 후 재시도...`);
      await new Promise(resolve => setTimeout(resolve, delay));
      continue;
    }

    return response;
  }
  throw new Error('최대 재시도 횟수 초과');
}
```

### 요청 큐잉

```javascript theme={null}
import PQueue from 'p-queue';

// 초당 1개 요청으로 제한
const queue = new PQueue({ interval: 1000, intervalCap: 1 });

// 모든 운세 요청을 큐에 추가
async function getFortune(saju, userName) {
  return queue.add(() =>
    fetch('/api/daily-fortune', {
      method: 'POST',
      body: JSON.stringify({ saju, userName })
    })
  );
}
```

## 엔드포인트별 추가 제한

일부 엔드포인트는 추가 제한이 있습니다:

| 엔드포인트                             | 추가 제한  | 이유                |
| --------------------------------- | ------ | ----------------- |
| `/api/daily-fortune?type=compare` | 10회/시간 | 높은 비용 (9번의 AI 호출) |
| `/api/daily-fortune-stream`       | 30회/분  | 장기 연결             |
| `/api/saju`                       | 120회/분 | 연산 집중적            |

## 제한 상향하기

### 플랜 업그레이드

[dashboard.sajuapi.dev/billing](https://dashboard.sajuapi.dev/billing)에서 업그레이드하세요.

### Enterprise 제한 요청

Business 등급 이상의 제한이 필요한 경우:

```bash theme={null}
curl -X POST https://api.sajuapi.dev/api/support/limit-increase \
  -H "X-API-Key: bs_live_xxx" \
  -d '{
    "requestedLimit": 5000,
    "useCase": "DAU 10만의 고트래픽 트레이딩 앱",
    "expectedVolume": "일 50만 요청"
  }'
```

## 모범 사례

<AccordionGroup>
  <Accordion title="응답을 적극적으로 캐시하세요">
    운세 결과는 24시간 동안 유효합니다. 클라이언트 측에서 캐시하세요:

    ```javascript theme={null}
    const cacheKey = `fortune_${userId}_${date}`;
    const cached = localStorage.getItem(cacheKey);
    if (cached) return JSON.parse(cached);
    ```
  </Accordion>

  <Accordion title="같은 사주를 가진 사용자를 일괄 처리하세요">
    같은 날 태어난 사용자는 같은 일간(日干)을 공유합니다. 요청을 일괄 처리하세요:

    ```javascript theme={null}
    // 100명의 사용자에 대해 100번 요청하는 대신:
    // 고유한 일간(日干)당 1번 요청 (최대 10번)
    const uniqueDayMasters = [...new Set(users.map(u => u.dayMaster))];
    ```
  </Accordion>

  <Accordion title="긴급하지 않은 업데이트에는 웹훅을 사용하세요">
    일일 운세 알림의 경우, 폴링 대신 웹훅 시스템을 사용하세요:

    ```javascript theme={null}
    // 웹훅을 한 번만 등록
    await registerWebhook({
      url: 'https://your-app.com/webhooks/fortune',
      events: ['fortune.daily']
    });
    ```
  </Accordion>

  <Accordion title="비피크 시간대에 미리 생성하세요">
    한국 시간 오전 2-6시에 API 지연 시간이 낮습니다. 해당 시간에 일괄 작업을 예약하세요.
  </Accordion>
</AccordionGroup>

## 사용량 모니터링

실시간으로 사용량을 추적하세요:

```bash theme={null}
curl https://api.sajuapi.dev/api/usage \
  -H "X-API-Key: bs_live_xxx"
```

```json theme={null}
{
  "usage": {
    "today": {
      "requests": 847,
      "limit": 1000,
      "cost": 11.01
    },
    "thisMonth": {
      "requests": 15420,
      "cost": 200.46
    }
  },
  "rateLimit": {
    "current": 45,
    "limit": 60,
    "resetsAt": "2024-01-15T10:05:00Z"
  }
}
```
