Skip to main content

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

TierRequests per MinuteApplies To
Default25Unauthenticated requests (missing or invalid API key)
Authenticated60Authenticated requests without an active subscription
Premium100Authenticated requests with an active subscription (trialing or active)
Admin200Internal 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.
EndpointLimit
POST /v1/posts30 req/min
POST /v1/media30 req/min
POST /v1/ai/transcribe10 req/min
POST /v1/templates20 req/min
POST /v1/media/render-og20 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.

Rate Limit Headers

Every API response includes headers that report your current rate limit status:
HeaderDescription
X-RateLimit-LimitThe maximum number of requests allowed per minute for your tier
X-RateLimit-RemainingThe number of requests remaining in the current window
X-RateLimit-ResetUnix timestamp (in seconds) when the rate limit window resets
X-RateLimit-TierYour 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

Monitor rate limit headers

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));
  }
}

Respect the Retry-After header

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

SymptomLikely CauseSolution
Receiving 429 responses frequentlyRequest volume exceeds your tier’s limitImplement backoff and request throttling. Check if you can batch operations.
X-RateLimit-Tier shows defaultAPI key is missing or invalidVerify the soku-api-key header is included and the key is valid
X-RateLimit-Tier shows authenticated instead of premiumSubscription is not activeCheck your subscription status in the Soku dashboard
Burst requests succeed, then suddenly failSliding window caught up to sustained high volumeDistribute requests more evenly over time

Next Steps

TopicDescription
Error HandlingFull reference of all API error codes
AuthenticationEnsure your API key is configured correctly
Code ExamplesExamples with rate limit handling built in