Rate Limits

The Schedulala API enforces rate limits to ensure fair usage and platform stability. The API, MCP connector and CLI are included with every Schedulala plan, so your limits match your plan. Request limits are applied per API key.

Limits by Plan

PlanRequests / MinutePosts / MonthConnected Accounts
Free3042
Personal ($29/mo)120Unlimited10
Team ($49/mo)120Unlimited25
Agency ($99/mo)120Unlimited100

Daily Posting Limits

To comply with each social platform's own rate limits, daily posts per profile are capped. These limits apply to all plans:

PlatformDaily Limit
X / Twitter20 posts/day
Instagram100 posts/day
Facebook100 posts/day
Threads250 posts/day
All other platforms50 posts/day

Rate Limit Headers

Every API response includes headers that tell you your current rate limit status:

Response headers
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
X-RateLimit-Reset: 1704825060000
HeaderDescription
X-RateLimit-LimitMaximum number of requests allowed per minute for your plan
X-RateLimit-RemainingNumber of requests remaining in the current window
X-RateLimit-ResetUnix timestamp (milliseconds) when the rate limit window resets

Tip: Check the X-RateLimit-Remaining header before making requests in tight loops. This lets you throttle proactively instead of hitting 429 errors.

When You Hit the Limit

If you exceed the rate limit, the API returns a 429 Too Many Requests response:

429 response headers
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704825060000

Use the X-RateLimit-Reset header (a Unix timestamp in milliseconds) to determine when you can make requests again. The response body will also include an error message:

429 response body
{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Please retry after the reset period."
}
}

Unauthenticated endpoints (key registration, OAuth, and the device flow) are rate limited per IP instead of per key. They return 429 with a Retry-After header telling you how many seconds to wait.

Handling Rate Limits

The recommended approach is exponential backoff: wait progressively longer between retries, and use the X-RateLimit-Reset header to calculate how long to wait.

async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) {
return response;
}
// Use X-RateLimit-Reset header (ms timestamp), otherwise exponential backoff
const resetMs = response.headers.get('X-RateLimit-Reset');
const waitMs = resetMs
? Math.max(0, parseInt(resetMs, 10) - Date.now())
: Math.pow(2, attempt) * 2000; // 2s, 4s, 8s
const waitSeconds = Math.ceil(waitMs / 1000);
console.log(`Rate limited. Retrying in ${waitSeconds}s (attempt ${attempt + 1}/${maxRetries})`);
await new Promise(resolve => setTimeout(resolve, waitMs));
}
throw new Error('Max retries exceeded');
}
// Usage
const response = await fetchWithRetry(
'https://schedulala.com/api/v1/posts',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SCHEDULALA_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
content: 'Hello world!',
platforms: [{ platform: 'twitter', accountId: 'acc_123' }],
publishNow: true
})
}
);

Best Practices

Use exponential backoff

When retrying after a 429, increase the wait time exponentially (e.g., 2s, 4s, 8s). Use the X-RateLimit-Reset header to calculate the exact wait time — it's a Unix timestamp in milliseconds indicating when your rate limit window resets.

Check X-RateLimit-Remaining

Monitor this header on every response. If you see it approaching zero, slow down your request rate before you get rate limited. This is especially important for batch operations.

Cache responses when possible

Endpoints like GET /accounts and GET /posts/:id return data that doesn't change frequently. Cache these responses locally to reduce the number of API calls you need to make.

Spread requests over time

If you need to create many posts, spread them across multiple minutes rather than sending them all at once. This avoids bursting through your per-minute limit.

Note: Repeatedly ignoring rate limits and sending requests without backoff may result in your API key being temporarily suspended. Always implement proper retry logic.

Next Steps