GuidesAPI GuideChangelog
Log In
API Guide

호출 제한

짧은 시간에 요청이 몰리지 않도록 파트너별로 초당 호출 수를 제한합니다.

기본 한도

항목값
단위파트너별 (같은 파트너의 모든 클라이언트·API 호출을 합산)
한도초당 20회
순간 허용량최대 20회까지 한 번에 보낼 수 있고, 이후 초당 20회씩 다시 채워집니다
📘

한도는 서비스 상황에 따라 조정될 수 있습니다. 더 높은 한도가 필요하면 모비두 운영팀에 문의해 주세요.

한도를 넘으면

HTTP 429 Too Many Requests 를 돌려주고, 아래 헤더로 언제 다시 호출하면 되는지 알려 줍니다.

헤더예시뜻
Retry-After1다시 호출하기까지 기다릴 시간(초). 이 값을 기준으로 재시도하세요
X-RateLimit-Limit20적용된 한도(초당 호출 수)
X-RateLimit-Remaining0남은 호출 수. 429 응답에서는 항상 0
X-RateLimit-Reset1761634801다시 호출할 수 있는 시각(Unix 초)
X-Request-Id3f9c2a7e-5b1d-4c8a-9e6f-2d7b8a1c4e90요청 추적 ID. 모든 응답에 붙습니다

정상 응답(200)에는 X-RateLimit-* 헤더가 붙지 않습니다.

권장 처리 방법

  1. 429 를 받으면 Retry-After 초만큼 기다린 뒤 다시 보냅니다. 바로 다시 보내면 계속 429 가 납니다.
  2. 연속으로 429 가 나면 대기 시간을 늘립니다. 1초 → 2초 → 4초처럼 두 배씩 늘리고, 여러 서버가 동시에 재시도하지 않도록 0~1초 사이의 임의 시간을 더하세요. 5번 정도 실패하면 멈추고 원인을 확인하세요.
  3. 대량 조회는 미리 속도를 맞춥니다. 여러 방송·기간을 한꺼번에 조회할 때는 초당 20회를 넘지 않도록 요청 사이에 간격(예: 50ms 이상)을 두거나 동시 요청 수를 제한하세요. 같은 파트너의 여러 서버가 호출한다면 한도를 함께 나눠 씁니다.
  4. 바뀌지 않는 결과는 저장해 두고 재사용합니다. 지난 기간의 통계는 다시 바뀌지 않습니다. 같은 조건을 반복 조회하지 마세요.

재시도 예시

async function callWithRetry(url, options, maxRetry = 5) {
  for (let attempt = 0; ; attempt++) {
    const res = await fetch(url, options);
    if (res.status !== 429 || attempt >= maxRetry) return res;

    const retryAfter = Number(res.headers.get('Retry-After') ?? 1);
    const backoff = Math.max(retryAfter, 2 ** attempt);   // 1, 2, 4, 8 ...
    const jitter = Math.random();                          // 0~1초
    await new Promise(r => setTimeout(r, (backoff + jitter) * 1000));
  }
}
HttpResponse<String> sendWithRetry(HttpClient client, HttpRequest req, int maxRetry)
        throws IOException, InterruptedException {
    for (int attempt = 0; ; attempt++) {
        HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
        if (res.statusCode() != 429 || attempt >= maxRetry) return res;

        long retryAfter = res.headers().firstValueAsLong("Retry-After").orElse(1);
        long backoff = Math.max(retryAfter, 1L << attempt);              // 1, 2, 4, 8 ...
        long jitterMs = ThreadLocalRandom.current().nextLong(1000);      // 0~1초
        Thread.sleep(backoff * 1000 + jitterMs);
    }
}
fun sendWithRetry(client: HttpClient, req: HttpRequest, maxRetry: Int = 5): HttpResponse<String> {
    var attempt = 0
    while (true) {
        val res = client.send(req, HttpResponse.BodyHandlers.ofString())
        if (res.statusCode() != 429 || attempt >= maxRetry) return res

        val retryAfter = res.headers().firstValueAsLong("Retry-After").orElse(1)
        val backoff = maxOf(retryAfter, 1L shl attempt)                  // 1, 2, 4, 8 ...
        Thread.sleep(backoff * 1000 + Random.nextLong(1000))            // + 0~1초
        attempt++
    }
}
import random
import time

import requests


def get_with_retry(url, headers, max_retry=5):
    for attempt in range(max_retry + 1):
        res = requests.get(url, headers=headers)
        if res.status_code != 429 or attempt == max_retry:
            return res

        retry_after = int(res.headers.get('Retry-After', 1))
        backoff = max(retry_after, 2 ** attempt)   # 1, 2, 4, 8 ...
        time.sleep(backoff + random.random())      # + 0~1초
🏠 소스라이브 🎬 소스클립 🔗 소스링크 📢 소스애드
🧩 API 가이드
🆕 최근 업데이트
💬 도움이 더 필요하신가요?
메일로 문의 카카오톡 채널로 문의
담당자에게 문의하기

궁금한 점이나 불편했던 점을 남겨주시면 담당자가 확인 후 답변드릴게요.

가이드 챗봇
* AI를 활용해 답변해서 사실과 다를 수도 있어요. 더 궁금한 사항은 '담당자에게 문의하기'를 이용해주세요.
💡 궁금한 솔루션(예: 라이브, 링크 등)을 함께 적어주시면 더 정확한 답변을 받을 수 있어요.