Limits
The CLI and the API run inside limits set by your plan. This page covers how they behave when you reach one, and how to retry. The numbers for each plan are on API limits and Runs at once. Free has no API access.
Every limit is per account. All of your keys share it, so a second key never buys more capacity.
Limit | Counts | Past it |
|---|---|---|
Requests a minute | Every call from every key |
|
Heavy calls at once | Validate, create, save, running a definition over history, and starting a run |
|
Long polls at once | Calls holding with | The call answers straight away instead of holding |
Runs at once | Runs executing for your account, from the app and the API | The run waits for a slot, or fails with |
See your limits
chartnaut usage prints your plan's caps with their current counts. The concurrent_runs row is how many runs your account has going right now, against your runs at once.
The request limits print only with --json, under api_limits: requests_per_minute, concurrent_heavy and concurrent_waits. From your own code, GET /usage returns the same.
Requests a minute
Every call counts, over a rolling minute. Past the limit, calls get 429 rate_limited with Retry-After: 10.
A separate guard stops key guessing. After 30 failed key checks within a minute from one IP address, calls from that address get 429 rate_limited with Retry-After: 60, whatever key they carry.
Heavy calls at once
Validating, creating and saving a script, running a definition over history and starting a run all do real work, so only a few can be in flight at once. One more gets 429 busy with Retry-After: 2, and the place frees as soon as one of the others answers.
POST /runs with wait keeps its heavy place for as long as it holds. To start several runs at once, send them with wait at 0, then poll each with GET /runs/{id}?wait=30, which is not a heavy call. Heavy calls and long polls lists every heavy call.
Long polls at once
A long poll is POST /runs or GET /runs/{id} with wait, holding until the run finishes. Past your plan's number, the call answers at once with the run as it is. Nothing fails; poll again.
Runs at once
Runs at once are shared with the app. Runs you start through the API, the agent's test runs in the app and every study run take from the same pool. Another account's runs never touch it.
When every slot is taken:
An indicator or definition run waits in
queuedfor a slot, within its time limit. If none frees, it fails withfailure.kindbusyandretryable: true.A study run does not wait. If no slot is free when the study starts, the run fails with
busyandretryable: true.Your account can have its runs at once plus 4 API runs queued or running. The next
POST /runsgets429 busywithRetry-After: 15.
If your runs start queuing, check whether the agent is busy in the app. The app has no runs-at-once display; chartnaut usage shows it.
Retrying
rate_limited and busy clear on their own. Wait for Retry-After, then send the same call again.
The CLI does this for you. Starting a run, it keeps retrying 429, 503 and network failures for up to 3 minutes, waiting for Retry-After each time or up to 15 seconds when there is none, then polls the run until it finishes without holding a heavy-call place. Every other command retries up to 3 times, waiting for Retry-After (up to 60 seconds) or 1, 2 and then 4 seconds. If the call still fails, it exits with code 5. Errors and exit codes covers every code.
In your own code, send the same Idempotency-Key when you retry POST /runs, so a retry never starts a second run.
Per-run bounds
These are the same on every plan:
Bound | Value |
|---|---|
Bars in one run's window | 50,000 at the run's timeframe |
Events a definition run keeps | 10,000. |
Indicator and definition results kept | 7 days |
Study results in one response | 1 MB |
Script files | 50 files, 512 KB each, 2 MB in all |
API keys | 20, not counting expired ones |
Your plan also sets how far back a run reaches. A window that starts earlier is moved to your history start, and one that ends before it is refused with out_of_coverage. The caps on scripts and events are on Plans and limits.
