ChartnautDocs

Getting started

This reference has one page per endpoint and one per object the API returns. This page covers what every call shares and indexes the endpoints. Limits says how limits behave, and Errors and exit codes says which errors to retry. For a working client, read the open-source Chartnaut CLI on GitHub: src/client.ts makes every call on these pages.

Base URL

https://api.chartnaut.com/v1

Every path in this reference is relative to it. GET /runs means GET https://api.chartnaut.com/v1/runs. The API is included on Starter and above.

Authentication

Send an API key in the Authorization header on every call except Start a sign-in and Poll a sign-in, which create a key:

curl https://api.chartnaut.com/v1/me \
  -H "Authorization: Bearer cn_live_XXXX"

The header must read Bearer, one space, then the key. Chartnaut checks each call in this order, and the first check that fails answers:

Check

Answer

More than 30 failed key checks from your IP address in the last minute

429 rate_limited, Retry-After: 60

No Authorization header, or it does not start with Bearer

401 unauthorized, Missing bearer token

The key is wrong, expired or revoked

401 unauthorized, with Invalid API token., API token expired. or API token revoked.

The account is on the waitlist

403 forbidden

The account is on Free

403 plan_limit

Past your plan's requests a minute

429 rate_limited, Retry-After: 10

The key lacks the endpoint's scope

403 forbidden_scope

A call refused for its scope has already counted toward your requests a minute. Most endpoint pages leave these answers out of their status tables.

Scopes

A key carries one or more scopes. Each endpoint needs exactly one, shown in the index below and on its page.

Scope

Lets the key

scripts:read

Read your account, instruments, docs, scripts, versions, a definition's events and runs, search the library, and validate a script

scripts:write

Create, save, rename and delete scripts

runs:write

Start and cancel runs, and run a definition over history

Revoke the current key works with any valid key, whatever its scopes.

Requests and responses

Send request bodies as JSON with Content-Type: application/json. Responses are JSON, except GET /docs/{topic} (markdown), format=csv on run results and a definition's events (CSV), and the two 204 answers, which have no body.

A request body can be up to 2.25 MB; a larger one gets 413 invalid_request. A script's files can total 2 MB, with at most 50 files of 512 KB each.

Heavy calls and long polls

Every call that carries a key counts toward your plan's requests a minute, across all your keys. API limits has the numbers for each plan.

Five calls are heavy: they validate code or start work, and only a few can be in flight at once. Past your plan's heavy calls at once, the next one gets 429 busy with Retry-After: 2.

  • POST /scripts/validate

  • POST /scripts

  • PUT /scripts/{slug}

  • POST /scripts/{slug}/collect

  • POST /runs

Two calls can be long polls: POST /runs and GET /runs/{run_id} with wait above 0. A long poll holds until the run finishes or wait seconds pass. Past your plan's long polls at once, the call answers straight away with the run as it is, and nothing fails. POST /runs with wait keeps its heavy place for as long as it holds, so start runs with wait at 0 and wait on GET /runs/{run_id} instead.

Pagination

List endpoints take limit and cursor and answer with a page:

{
  "data": [],
  "next_cursor": "50"
}

Pass next_cursor back as cursor for the next page, and stop when it is null. Treat it as opaque. A limit of 0, a negative one or one that is not a number falls back to the default, and one above the most is cut to the most. Run results and a definition's events put their rows under outputs or events instead of data.

Endpoint

Default limit

Most

GET /scripts, GET /scripts/{slug}/versions, GET /instruments

50

500

GET /runs, GET /library

50

200

GET /runs/{run_id}/results

5,000

50,000

GET /scripts/{slug}/events

100

1,000

Errors

Every refused call answers with the same envelope:

{
  "error": {
    "code": "version_conflict",
    "message": "ema-cross is at version 5, not 4. Pull it, re-apply your change, and save again.",
    "details": {
      "latest_version": 5
    }
  }
}

Field

Type

Description

error.code

string

Stable. Branch on this

error.message

string

For people. It can change

error.details

object

Present only when there is something extra to act on. Today only version_conflict sets it, with latest_version

diagnostics

array of Diagnostic

Present only beside 422 script_invalid

Errors and exit codes lists every code, its status and whether to retry it.

Timestamps and units

Times in JSON are RFC 3339 strings in UTC, such as 2026-09-01T00:00:00Z. Times Chartnaut stamps itself, such as created_at, can carry fractions of a second. Times you send in query parameters must be RFC 3339.

Indicator points carry t in Unix seconds. Durations are in seconds. Bar counts are at the run's timeframe. One compute unit is 1,000 bars evaluated, warmup and dependencies included.

Idempotency

POST /runs reads an Idempotency-Key header: any string up to 128 characters. A second POST /runs from your account with the same key returns the first run instead of starting another. The key has no expiry and is not checked against the body, so use a new key for each run you mean to start.

No other endpoint reads the header, and retrying them is still safe: a retried POST /scripts gets 409 conflict once the first one landed, and a retried PUT /scripts/{slug} gets 409 version_conflict. Read the script and carry on.

Endpoints

Account

Method

Path

Scope

Summary

GET

/me

scripts:read

Get the current key

GET

/usage

scripts:read

Get usage

GET

/timeframes

scripts:read

List timeframes

Instruments

Method

Path

Scope

Summary

GET

/instruments

scripts:read

Search instruments

GET

/instruments/{symbol}

scripts:read

Get an instrument

Docs

Method

Path

Scope

Summary

GET

/docs

scripts:read

List doc topics

GET

/docs/{topic}

scripts:read

Get a doc topic

Scripts

Method

Path

Scope

Summary

GET

/scripts

scripts:read

List scripts

GET

/scripts/{slug}

scripts:read

Get a script

GET

/scripts/{slug}/versions

scripts:read

List versions

POST

/scripts/validate

scripts:read

Validate a script

POST

/scripts

scripts:write

Create a script

PUT

/scripts/{slug}

scripts:write

Save a script version

PATCH

/scripts/{slug}

scripts:write

Update script details

DELETE

/scripts/{slug}

scripts:write

Delete a script

Definition events

Method

Path

Scope

Summary

GET

/scripts/{slug}/events

scripts:read

List events

GET

/scripts/{slug}/events/summary

scripts:read

Summarise events

POST

/scripts/{slug}/collect

runs:write

Run a definition over history

Runs

Method

Path

Scope

Summary

POST

/runs

runs:write

Create a run

GET

/runs

scripts:read

List runs

GET

/runs/{run_id}

scripts:read

Get a run

GET

/runs/{run_id}/results

scripts:read

Get run results

POST

/runs/{run_id}/cancel

runs:write

Cancel a run

Library

Method

Path

Scope

Summary

GET

/library

scripts:read

Search the library

GET

/library/{author}/{slug}

scripts:read

Get a library script

Sign-in

Method

Path

Scope

Summary

POST

/auth/device

None

Start a sign-in

POST

/auth/token

None

Poll a sign-in

POST

/auth/revoke

Any key

Revoke the current key

Not yet available

Method

Path

Scope

Summary

GET, POST, DELETE

/webhooks, /webhooks/{webhook_id}

scripts:read

Webhooks, 501 today

Objects

Instrument, Script, File, Interface, Dependency, Version, Diagnostic, Event, Run, Failure, Summary and Library script.