API Rate Limits and Throttling
The Kibot API enforces concurrency and burst limits to keep the service responsive for every subscriber. This page documents the published numbers, what each error code means when a script trips a limit, and the backoff and parallelism patterns that work in practice. Most of the recurring "my script worked yesterday but is throwing errors today" cases trace back to one of three causes: too many concurrent connections, hitting the burst ceiling, or a stale session that re-authenticated mid-batch.
The Published Numbers
| Limit | Value | Scope |
|---|---|---|
| Recommended concurrent connections | 5 | Per account, across API + FTP + Kibot Agent |
| Hard ceiling, in-flight requests | 40 | Per account |
| Hard ceiling, new requests per 500 ms | 50 | Per account |
| Session idle timeout | 20 minutes | Per login session |
| IP whitelist | 1 active IP | Per subscription |
The 5-connection guideline is the safe number for any production script. The 40 and 50-per-500ms ceilings are the points above which the rate limiter trips and starts returning errors. A small handful of customers run with higher parallelism after coordinating with support; the default account is capped at the published numbers.
What the Error Codes Mean
The API uses HTTP-style numeric codes in the response body. The relevant ones for rate limiting:
| Code | Meaning | What to do |
|---|---|---|
| 401 Not Logged In | Session expired or no active session | Re-login and retry; check the 20-minute idle timeout |
| 403 Login Failed | Auth failed OR rate-limited; the code is overloaded | If credentials are correct, drop parallelism and retry with backoff |
| 403 Too many connections | Burst above the 40-in-flight or 50-per-500ms ceiling | Drop concurrent workers to 5; add 100 to 500 ms between requests |
| 407 | Authorization required for the requested symbol or endpoint | Confirm the symbol is in your purchased universe and the account has API access |
| 498 Not Allowed | Endpoint not allowed for this tier (e.g. tick from a guest session) | Upgrade to Premium for the full surface |
| 499 Not Allowed (account lacks full API access) | The symbol is licensed but the account is not on Premium | Upgrade or contact support |
The 403 code is reused for both authentication failure and rate-limiting, so a script that suddenly starts seeing 403 after a few hundred successful calls is almost always rate-limited rather than mis-authenticated. The disambiguation pattern: if a single test request from the same script with the same credentials succeeds after a 60-second pause, the prior batch was rate-limited.
Connections Are Shared Across API, FTP, and Agent
The concurrent-connection pool is per account, not per protocol. A scheduled Kibot Agent task pulling daily updates at 6 AM ET and a Python script running tick downloads in parallel against the same account consume the same five slots. The most common cause of "the Agent suddenly fails" on accounts that also run scripts is exactly this contention. If the script is running, the Agent's slot count drops, and vice versa.
The practical pattern is to schedule the Agent at a time when no script is running, or to drop the script's worker count by one or two for the duration of the Agent run.
Recommended Backoff Pattern
A simple worker-pool implementation that respects the limits:
# Python: bulk download with 5 workers and exponential backoff
import time
import concurrent.futures
import requests
MAX_WORKERS = 5
BASE_DELAY = 0.1 # 100 ms between requests per worker
def fetch(symbol, attempt=0):
url = f"http://api.kibot.com/?action=history&symbol={symbol}&interval=1&type=stocks"
r = requests.get(url, timeout=60)
if r.status_code in (401, 403):
if attempt >= 4:
return None
time.sleep(2 ** attempt) # 1s, 2s, 4s, 8s
# re-login here if 401
return fetch(symbol, attempt + 1)
return r.text
with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS) as pool:
results = list(pool.map(fetch, symbols))
Key points: cap workers at 5, retry on 401/403 with exponential backoff up to a few seconds, re-login before retrying on 401, and surface a hard failure after a small number of attempts so a sustained outage does not silently hang the batch.
Parallel Downloads Do Not Improve Throughput
A separate constraint that customers run into: more workers do not download faster. The bottleneck is the destination disk's write throughput, not the network or the API. Five concurrent file writes saturate most SSDs and NVMe drives; more than five workers create disk contention that slows the aggregate throughput. The 5-worker recommendation is a sweet spot for both the API limiter and the local disk, not just a server-side cap.
For bulk archive downloads (the full 20 GB stocks+ETFs package), a single download manager is often faster than 10 parallel API workers, because the manager's TCP window and disk buffering are optimised for sequential large files.
Session Handling for Long Batches
The API session times out after 20 minutes of idle. A batch that processes one slow symbol for 25 minutes will see the session expire mid-loop. Two strategies:
- Re-login at fixed intervals (every 15 minutes) regardless of activity.
- Catch 401 in the request loop, re-login, and retry once before failing the request.
The second pattern is cheaper because it only re-authenticates when needed, but the first is simpler if your batch is predictable. Both work; pick one and stick with it. See API authentication for the login endpoint and the explicit logout call.
How to Request a Higher Limit
Production workloads that genuinely need more than 5 concurrent connections can be reviewed case-by-case. Contact support with the account email, the use case, peak hours of operation, and a rough request-rate estimate. The team has lifted the cap for institutional users running synchronous reporting against fixed symbol panels; the cap stays in place by default to protect the rest of the subscriber base from a single-account burst.
Key Takeaways
- 5 concurrent connections is the safe per-account number. The hard ceilings are 40 in flight and 50 new requests per 500 ms.
- The connection pool is shared across API, FTP, and the Kibot Agent. Running all three at once on one account often triggers limits even when no single tool is over the per-tool guidance.
- 403 Login Failed is reused for rate-limiting. If credentials are correct and a single test request succeeds after a pause, the prior batch was throttled.
- Re-login on 401 and retry. Sessions expire after 20 minutes of idle.
- More workers do not increase throughput. Local disk write speed caps useful parallelism at roughly 5 streams.
- For genuinely high-volume institutional use, contact support to discuss raising the per-account cap.
Related
- How to get API access, plan tiers and per-tier endpoint matrix.
- API authentication, login, logout, status, and the 20-minute session timeout.
- Server responses, the full HTTP code table including responses outside the rate-limit context.
- Compression, gzip negotiation and the bandwidth tradeoffs that interact with concurrency.
- Data updates, scheduling the Kibot Agent and FTP refresh windows so they do not collide with scripted API work.
- API client examples, reference clients in curl, Python, Rust, Go, TypeScript, R, C++, and .NET, all using the 5-worker pattern.