Rate Limits
The Soku API enforces rate limits to ensure fair usage and platform stability. Rate limits are applied per account and vary based on your authentication status and subscription tier.
Rate Limit Tiers
| Tier | Requests per Minute | Applies To |
|---|
| Default | 25 | Unauthenticated requests (missing or invalid API key) |
| Authenticated | 60 | Authenticated requests without an active subscription |
| Premium | 100 | Authenticated requests with an active subscription (trialing or active) |
| Admin | 200 | Internal administrative accounts |
Most API users with an active Soku subscription operate at the Premium tier, which allows up to 100 requests per minute.
Endpoint-Specific Rate Limits
In addition to the global tier limits above, certain endpoints enforce their own per-user rate limits. These are applied on top of your tier limit — hitting an endpoint-specific limit will return a 429 even if your global tier allowance has not been exhausted.
| Endpoint | Limit |
|---|
POST /v1/posts | 30 req/min |
POST /v1/media | 30 req/min |
POST /v1/ai/transcribe | 10 req/min |
POST /v1/templates | 20 req/min |
POST /v1/media/render-og | 20 req/min |
How Rate Limiting Works
The Soku API uses a sliding window algorithm to enforce rate limits. Instead of resetting a counter at the start of each minute, the API tracks requests across a rolling 60-second window. This approach provides a more accurate and fair representation of request patterns.
Burst Allowance
The sliding window algorithm includes a built-in burst allowance. You can briefly exceed your tier’s stated limit in short bursts, as long as your average request rate over the window remains within the limit. This accommodates normal traffic patterns where requests may cluster around specific operations (for example, publishing a batch of posts).
Burst allowance is not a guaranteed additional capacity. If you consistently exceed your tier’s limit, requests will be throttled regardless of burst behavior.
Every API response includes headers that report your current rate limit status:
| Header | Description |
|---|
X-RateLimit-Limit | The maximum number of requests allowed per minute for your tier |
X-RateLimit-Remaining | The number of requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp (in seconds) when the rate limit window resets |
X-RateLimit-Tier | Your current rate limit tier (default, authenticated, premium, admin) |
Example response headers:
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1740744060
X-RateLimit-Tier: premium
Content-Type: application/json
Rate Limit Exceeded
When you exceed your rate limit, the API returns a 429 Too Many Requests response. The response includes a Retry-After header indicating how many seconds to wait before sending another request.
Response status: 429 Too Many Requests
Response headers:
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1740744072
X-RateLimit-Tier: premium
Content-Type: application/json
Response body:
{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Please retry after 12 seconds.",
"timestamp": "2026-02-28T12:00:00.000Z",
"requestId": "req_abc123def456",
"details": {
"retryAfter": 12,
"limit": 100,
"tier": "premium"
}
}
}
Best Practices
Check the X-RateLimit-Remaining header on every response. When remaining requests drop below a threshold (for example, 10% of your limit), slow down your request rate proactively.
const response = await fetch('https://api.mysoku.io/v1/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'soku-api-key': process.env.SOKU_API_KEY,
},
body: JSON.stringify(payload),
});
const remaining = parseInt(response.headers.get('X-RateLimit-Remaining'), 10);
const limit = parseInt(response.headers.get('X-RateLimit-Limit'), 10);
if (remaining < limit * 0.1) {
console.warn(`Rate limit approaching: ${remaining}/${limit} requests remaining`);
}
Implement exponential backoff
When you receive a 429 response, do not retry immediately. Use exponential backoff with jitter to space out retries:
async function requestWithBackoff(url, options, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) {
return response;
}
if (attempt === maxRetries) {
throw new Error('Rate limit exceeded after maximum retries');
}
const retryAfter = parseInt(response.headers.get('Retry-After'), 10) || 1;
const jitter = Math.random() * 1000;
const delay = retryAfter * 1000 + jitter;
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
When a 429 response includes a Retry-After header, wait at least that many seconds before retrying. The value is calculated by the server based on your current window and provides the most accurate retry timing.
Batch operations where possible
Instead of making many individual requests in rapid succession, consider batching work. For example, if you need to publish to multiple platforms, use a single POST /v1/posts call with multiple platform targets rather than separate calls per platform.
# One request to publish to three platforms
curl -X POST https://api.mysoku.io/v1/posts \
-H "Content-Type: application/json" \
-H "soku-api-key: sk_live_your_api_key_here" \
-d '{
"post": {
"content": {
"text": "New post",
"mediaType": "text",
"platform": ["threads", "x", "linkedin"]
}
}
}'
Distribute requests evenly
If you have a queue of API calls to make, spread them evenly over time rather than sending them all at once. A simple approach is to insert a small delay between requests:
const posts = [/* array of post payloads */];
for (const post of posts) {
await createPost(post);
await new Promise((resolve) => setTimeout(resolve, 100)); // 100ms between requests
}
Cache responses when appropriate
If you are calling GET /v1/repurposeLinks or similar read endpoints repeatedly, cache the response locally for a reasonable duration to reduce unnecessary API calls.
Troubleshooting
| Symptom | Likely Cause | Solution |
|---|
Receiving 429 responses frequently | Request volume exceeds your tier’s limit | Implement backoff and request throttling. Check if you can batch operations. |
X-RateLimit-Tier shows default | API key is missing or invalid | Verify the soku-api-key header is included and the key is valid |
X-RateLimit-Tier shows authenticated instead of premium | Subscription is not active | Check your subscription status in the Soku dashboard |
| Burst requests succeed, then suddenly fail | Sliding window caught up to sustained high volume | Distribute requests more evenly over time |
Next Steps
| Topic | Description |
|---|
| Error Handling | Full reference of all API error codes |
| Authentication | Ensure your API key is configured correctly |
| Code Examples | Examples with rate limit handling built in |