ChartnautDocs

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

429 rate_limited, Retry-After: 10

Heavy calls at once

Validate, create, save, running a definition over history, and starting a run

429 busy, Retry-After: 2

Long polls at once

Calls holding with wait

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 busy

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 queued for a slot, within its time limit. If none frees, it fails with failure.kind busy and retryable: true.

  • A study run does not wait. If no slot is free when the study starts, the run fails with busy and retryable: true.

  • Your account can have its runs at once plus 4 API runs queued or running. The next POST /runs gets 429 busy with Retry-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. events_total in the summary counts all of them

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.