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 MinuteBurst AllowanceApplies To
Default2510Unauthenticated requests (missing or invalid API key)
Authenticated6030Authenticated requests without an active subscription
Premium100100Authenticated requests with an active subscription (trialing or active)
Admin200500Internal 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 / 60 seconds
POST /v1/media30 req / 60 seconds
POST /v1/ai/transcribe10 req / 60 seconds
POST /v1/templates20 req / 60 seconds
POST /v1/media/render-og20 req / 60 seconds

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

Each tier includes a burst allowance that lets you temporarily exceed the stated per-minute rate in short bursts. This accommodates normal traffic patterns where requests may cluster around specific operations (for example, publishing a batch of posts).
TierSustained RateBurst Allowance
Default25 / minUp to 10 additional
Authenticated60 / minUp to 30 additional
Premium100 / minUp to 100 additional
Admin200 / minUp to 500 additional
Burst allowance is not a guaranteed additional capacity. If you consistently exceed your tier’s sustained 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-ResetISO 8601 timestamp indicating when the rate limit window resets (for example, 2026-03-07T14:30:45.123Z)
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: 2026-02-28T12:01:00.000Z
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: 2026-02-28T12:01:12.000Z
X-RateLimit-Tier: premium
Content-Type: application/json
Response body:
{
  "error": {
    "type": "invalid_request_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
}

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