요청 한도
API는 (키가 아니라) 팀당 초당 요청 수를 제한합니다.
| 요금제 | 초당 요청 수 |
|---|---|
| Free | 10 |
| Pro | 10 |
| Scale | 25 |
| Enterprise | 협의 |
Resend의 한도는 초당 2건입니다. 이메일 최대 100통의 배치는 요청 한 건이므로 한도 안에서 초당 수천 통을 보낼 수 있습니다.
한도는 1초 단위의 구간에 적용됩니다. 대시보드 세션에는 요청 한도가 적용되지 않습니다. 발송 할당량(요금제 및 할당량)은 요청 한도와 별개입니다.
모든 응답에는 다음이 포함됩니다.
| 헤더 | 의미 |
|---|---|
ratelimit-limit |
구간당 허용되는 요청 수(예: 10). |
ratelimit-remaining |
현재 구간에 남은 요청 수. |
ratelimit-reset |
구간이 초기화될 때까지 남은 초(1). |
retry-after |
429에서만: 재시도하기 전에 기다릴 초(1). |
HTTP/1.1 429 Too Many Requestsratelimit-limit: 10ratelimit-remaining: 0ratelimit-reset: 1retry-after: 1
{ "statusCode": 429, "name": "rate_limit_exceeded", "message": "Too many requests. You can only make 10 requests per second." }429 처리하기
섹션 제목: “429 처리하기”import { SpacePost, type SendEmailOptions } from "@spacepost/node";
const spacepost = new SpacePost();
async function sendWithRetry(email: SendEmailOptions, key: string, attempts = 5) { for (let i = 0; i < attempts; i++) { const { data, error } = await spacepost.emails.send(email, { idempotencyKey: key }); if (!error) return data; if (error.name !== "rate_limit_exceeded") throw new Error(`${error.name}: ${error.message}`); await new Promise((r) => setTimeout(r, 1000 * (i + 1))); } throw new Error("rate limited");}import time, requests
def post_with_retry(url, headers, json, attempts=5): for _ in range(attempts): r = requests.post(url, headers=headers, json=json, timeout=15) if r.status_code != 429: return r time.sleep(float(r.headers.get("retry-after", 1))) return r실제로는 성공한 요청이 반복되지 않도록 재시도할 때는 항상 같은 Idempotency-Key를 재사용하세요.
- 개별 발송을 여러 번 하는 대신 배치를 사용하세요.
- 발송은 백그라운드 워커의 큐에 넣고 동시성을 한도에 맞춰 제한하세요.
- 가져오기 작업(예: 연락처 생성)은 일정한 속도로 분산하세요.