Stairoids enforces rate limits on every API key to ensure fair use across all customers and to protect the stability of the platform. Limits are applied on a per-key basis using a sliding one-minute window, so bursting briefly above the per-minute threshold will trigger throttling even if your daily usage is well within quota. Understanding how limits work — and building retry logic into your integration from the start — ensures your pipelines stay resilient under load.
Rate Limits by Plan
Your plan determines the maximum number of requests you can make per minute and per day. If you consistently approach these limits, consider upgrading your plan or reducing request volume by batching signals.
| Plan | Requests / Minute | Requests / Day |
|---|
| Starter | 60 | 10,000 |
| Growth | 300 | 100,000 |
| Agency | 1,000 | Unlimited |
Rate limits apply per API key, not per account. If you have multiple keys on the same plan, each key gets its own independent quota.
Stairoids returns three rate limit headers on every API response, regardless of whether the request succeeded or was throttled. Read these headers to implement proactive throttling in your client before you hit the limit.
| Header | Type | Description |
|---|
X-RateLimit-Limit | Integer | The total number of requests allowed in the current window. |
X-RateLimit-Remaining | Integer | The number of requests remaining in the current window. |
X-RateLimit-Reset | Unix timestamp | The time at which the current window resets and your quota is restored. |
Example headers on a successful response:
HTTP/1.1 200 OK
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 247
X-RateLimit-Reset: 1728985860
Content-Type: application/json
Handling a 429 Response
When you exceed your rate limit, the API returns a 429 Too Many Requests response. The response body follows the standard error envelope and includes a Retry-After header indicating how many seconds to wait before retrying.
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1728985920
Retry-After: 14
Content-Type: application/json
{
"error": {
"code": "rate_limit_exceeded",
"message": "You have exceeded the rate limit for your plan. Retry after 14 seconds."
},
"meta": {
"request_id": "req_429toomany"
}
}
Do not immediately retry a request after receiving a 429. Retrying without waiting will count against your quota and may extend the period before your window resets. Always respect the Retry-After value.
Retry Strategy: Exponential Backoff
The recommended approach when you encounter a 429 is exponential backoff — each successive retry waits progressively longer before attempting again. The example below reads the Retry-After header and multiplies it by an exponential factor on each retry, giving the rate limit window time to reset.
async function sendWithRetry(payload, retries = 3) {
for (let i = 0; i < retries; i++) {
const res = await fetch('https://api.stairoids.com/v1/signals', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + process.env.STAIROIDS_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
if (res.status !== 429) return res;
const retryAfter = parseInt(res.headers.get('Retry-After') || '1', 10);
await new Promise(r => setTimeout(r, retryAfter * 1000 * Math.pow(2, i)));
}
throw new Error('Rate limit exceeded after retries');
}
This pattern works well for low-to-moderate volume pipelines. For high-throughput integrations, pair it with a client-side token bucket or leaky bucket algorithm that respects X-RateLimit-Remaining proactively — before a 429 is issued.
If you’re sending multiple signals in quick succession, use the POST /v1/signals/batch endpoint to bundle them into a single request. Batching reduces your request count significantly and is the most effective way to stay within your plan’s per-minute limit without dropping signal coverage.