# Fix Crowdin API 429 too many requests on sync

## TL;DR

You are hitting Crowdin's rate limit, so slow down with backoff and fewer parallel requests. Read the retry-after header the 429 carries and honor it instead of hammering. Drop your concurrency to a handful of parallel calls and queue the rest. Sync scripts that fire dozens of requests at once always trip this.

## The error

```text
HTTP 429 Too Many Requests
{"error":{"code":429,"message":"Rate limit exceeded, retry after 12 seconds"}}
during crowdin sync of 400 source files
```

## Fix it

### Step 1: Confirm the 429 and read the retry-after value

```bash
curl -s -D - -o /dev/null -H "your auth header https://api.crowdin.com/api/v2/projects/1 | grep -i "retry-after\|x-ratelimit"
```

Expected: You see the rate limit headers and how long to wait.

### Step 2: Add exponential backoff with jitter to the sync script

```bash
node -e "console.log('pattern: on 429, sleep retry-after seconds, then retry with backoff 2s, 4s, 8s plus random jitter')"
```

Expected: Retries space out instead of piling on.

### Step 3: Cut parallel requests to 4 or fewer

```bash
grep -n "Promise.all\|concurrency" scripts/crowdin-sync.js | head -5
```

Expected: The sync runs at most 4 requests in flight.

### Step 4: Re-run the sync and watch for 429s

```bash
node scripts/crowdin-sync.js | grep -c "429"
```

Expected: Zero 429s in the output and the sync completes.

## When to use this

- Crowdin API returns 429 during a sync or bulk upload
- A script uploads hundreds of files in parallel

## When NOT to use this

- The API returns 401, that is an auth problem not a rate problem
- Single requests 429, check whether your plan allows API access at all

## Tool and version compatibility

- Crowdin API v2, crowdin-api-client-js
- Rate limits apply per account, not per project

## Variant phrasings

### 429 on the strings API but not the projects API

Different endpoints have different buckets. Back off per endpoint, not globally.

### 429 in CI only

CI runs the sync on every push. Sync on a schedule or only when sources change.

## Why it happens

Crowdin throttles API calls per account to protect the service. Bulk syncs that fire one request per file, plus status polling on top, exhaust the bucket fast. The 429 with retry-after is the signal to slow down, not a failure to work around.

## Edge cases

- Webhooks do not count against the limit, prefer them over polling status
- The translations download endpoints are the tightest bucket, batch them
- Jitter matters, synchronized retries from many workers re-trigger the limit

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_Ip6D1Q_FVLq0-_HVXbz4BQ
