Official clients · v0.1.0

Four packages, one contract, and the plumbing already written.

Python, JavaScript/TypeScript, PHP and Go, published to their own registries and built against the same API contract. Typed models, typed errors, and backoff that honours Retry-After — so the only code you write is the code that uses the data.

21 REST routes coveredMIT licensedX-API-Key from the environment
docs · sdks
Packages
Python
JavaScript / TS
PHP
Go
Agents
Skill
MCP server
CLI
install · call

Two lines to a typed value

The client reads the key from the environment, so nothing about the key appears in your code.

$ pip install tickatlas
from tickatlas import TickAtlas

client = TickAtlas()
ind = client.get_indicator("EURUSD", "RSI_14", timeframe="H1")
print(ind.value)   # 58.43
4Published packages
21REST routes covered
v0.1.0Current release
MITLicence
Install

One command per ecosystem.

Each package is published independently to its own registry from a single monorepo, so the four move together but install the way your ecosystem expects.

Python pip install tickatlas Usage →
JavaScript / TypeScript npm install tickatlas Usage →
PHP composer require tickatlas/php-sdk Usage →
Go go get github.com/abuzant/tickatlas-sdk/go Usage →
Language Package Registry Requires
Python tickatlas PyPI Python 3.9+
JavaScript / TypeScript tickatlas npm Node 18+, or a modern browser
PHP tickatlas/php-sdk Packagist PHP 8.1+
Go github.com/abuzant/tickatlas-sdk/go Go modules Go 1.21+

Exact ids matter: the PHP package is tickatlas/php-sdk, and the Go module path ends in /go because the repository is a monorepo.

Authentication

Set one variable. Never pass a key again.

All four clients resolve the key in the same order: an explicit constructor argument, then TICKATLAS_API_KEY, then failure at construction time — which is a better place to find out than a 401 in production.

  • The wire format is a single X-API-Key request header.
  • Keys start with tk_. Create one in the dashboard.
  • TICKATLAS_BASE_URL repoints a client without a code change.
  • No client logs, prints or persists the key.
Environment
any language
export TICKATLAS_API_KEY="tk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# Optional — point a client at staging or a self-hosted deployment
export TICKATLAS_BASE_URL="https://tickatlas.com/v1"
Shared design

Six behaviours you would otherwise write four times.

The packages are idiomatic for their own ecosystems but agree on these, so porting a service from one language to another does not change how it fails.

Parsing

Typed response models

Every method returns a typed model parsed out of the success/data envelope, so you never index into a raw dict. The original payload stays reachable, which means a field the API adds later is not lost.

Failure

One exception per failure class

HTTP status maps to a distinct type: 401 authentication, 403 permission, 404 not-found, 400/422 validation, 429 rate-limit, 5xx server, and a separate transport error when there was no HTTP response at all.

Retries

Backoff with jitter, Retry-After aware

Retries are automatic on 429, 5xx and network errors, with exponential backoff plus full jitter, and a 429 honours the server-advised delay rather than guessing. Attempt count and backoff are configurable.

Quota

Rate-limit headers surfaced

The clients read the X-RateLimit-Limit, -Remaining and -Reset headers and the X-Request-ID correlation id, so your own logs can carry the same id the API logged.

Config

One resolution order

Explicit constructor argument, then TICKATLAS_API_KEY, then failure. The base URL follows the same order via TICKATLAS_BASE_URL, so pointing a client at staging needs no code change.

Secrets

The key is never written down

No client logs, prints or persists the key. Missing configuration raises at construction time rather than producing a 401 somewhere further down your stack.

Python 3.9+

Python

A sync TickAtlas client and an async AsyncTickAtlas with an identical surface. Fully typed and ships py.typed, so your editor and mypy see the models. One runtime dependency: httpx.

  • Responses are frozen dataclasses; the decoded payload stays on .raw
  • Enums for timeframes, indicator keys and categories — or pass plain strings
  • Client options: timeout, max_retries, backoff_base, jitter, or bring your own httpx client

Source and the full per-endpoint reference: github.com/abuzant/tickatlas-sdk/python

quickstart.py
sync
from tickatlas import TickAtlas

with TickAtlas() as client:            # reads TICKATLAS_API_KEY
    quote = client.get_quote("EURUSD")
    print(quote.symbol, quote.bid, quote.ask, quote.spread_pips)

    ind = client.get_indicator("EURUSD", "RSI_14", timeframe="H1")
    print(ind.value, ind.updated_at)

    summary = client.get_summary("EURUSD", timeframe="H4")
    print(summary.bias, summary.bias_strength, summary.confidence)

    screen = client.screen("RSI_14", timeframe="H1", max_val=30, limit=50)
    for r in screen.results:
        print(r.symbol, r.value)
async.py
asyncio
import asyncio
from tickatlas import AsyncTickAtlas

async def main():
    async with AsyncTickAtlas() as client:
        quote, summary = await asyncio.gather(
            client.get_quote("EURUSD"),
            client.get_summary("EURUSD", timeframe="H4"),
        )
        print(quote.bid, summary.bias)

asyncio.run(main())
errors.py
typed exceptions
from tickatlas import (
    TickAtlas,
    TickAtlasError,
    AuthenticationError,
    NotFoundError,
    RateLimitError,
    ValidationError,
)

client = TickAtlas()

try:
    client.get_quote("NOPE")
except NotFoundError as e:
    print(e.status_code, e.code, e.message)
except RateLimitError as e:
    print("back off for", e.retry_after)
except (AuthenticationError, ValidationError) as e:
    print("fix the request:", e.code)
except TickAtlasError:
    raise
Node 18+, or a modern browser

JavaScript / TypeScript

TypeScript source shipped as ESM, CommonJS and full declarations. Zero runtime dependencies — it uses the platform fetch, which is why Node 18 is the floor.

  • Every request parameter and response model is typed, as is the exception hierarchy
  • Runs in the browser — but a key in browser JavaScript is a published key, so proxy it
  • Automatic retries with exponential backoff and jitter, honouring Retry-After

Source and the full per-endpoint reference: github.com/abuzant/tickatlas-sdk/javascript

quickstart.ts
TypeScript
import { TickAtlas, Indicators, Timeframes } from "tickatlas";

const client = new TickAtlas({ apiKey: process.env.TICKATLAS_API_KEY });

const quote = await client.getQuote("EURUSD");
console.log(`${quote.symbol}: ${quote.bid} / ${quote.ask} (${quote.spread_pips} pips)`);

const rsi = await client.getIndicator("EURUSD", Indicators.RSI_14, {
  timeframe: Timeframes.H1,
});
console.log(rsi.value);

const strength = await client.getHeatmap({ type: "strength", timeframe: "H4" });
console.log(strength.strongest, strength.weakest);

const batch = await client.getQuotes(["EURUSD", "GBPUSD", "XAUUSD"], ["bid", "ask"]);
console.log(batch.count, batch.quotes);
PHP 8.1+

PHP

A Composer package with readonly response models and a typed exception tree. Because PHP’s Exception::getCode() is final and integer-only, the string error.code is exposed as getErrorCode().

  • Readonly models, each with toArray() for forward-compatible fields
  • Options for timeout, maxRetries, backoffBase and backoffCap; a Guzzle handler can be injected
  • ConfigurationException at construction when no key is resolvable

Source and the full per-endpoint reference: github.com/abuzant/tickatlas-sdk/php

quickstart.php
Composer
<?php
require 'vendor/autoload.php';

use TickAtlas\Client;
use TickAtlas\Exception\NotFoundException;
use TickAtlas\Exception\RateLimitException;
use TickAtlas\Exception\TickAtlasException;

$client = new Client();                      // reads TICKATLAS_API_KEY

try {
    $quote = $client->getQuote('EURUSD');
    printf("EURUSD  bid=%s ask=%s spread=%s pips\n",
        $quote->bid, $quote->ask, $quote->spreadPips);

    $rsi = $client->getIndicator('EURUSD', 'RSI_14', ['timeframe' => 'H1']);
    printf("RSI(14) = %s\n", $rsi->value);
} catch (NotFoundException $e) {
    echo $e->getErrorCode(), "\n";           // the string error.code
} catch (RateLimitException $e) {
    echo "retry after ", $e->retryAfter, "s\n";
} catch (TickAtlasException $e) {
    fwrite(STDERR, $e->getMessage() . "\n");
}
Go 1.21+

Go

Standard library only — net/http, encoding/json, context, and nothing else. Functional options, a context.Context first argument on every call, and typed results and errors.

  • Nullable numbers are pointers, so a JSON null is distinguishable from a real 0
  • Models tolerate unknown fields, so a new API field does not break a decode
  • Import path is the module path; the package name is tickatlas

Source and the full per-endpoint reference: github.com/abuzant/tickatlas-sdk/go

main.go
net/http
package main

import (
    "context"
    "fmt"
    "log"

    tickatlas "github.com/abuzant/tickatlas-sdk/go"
)

func main() {
    client, err := tickatlas.NewClient() // reads TICKATLAS_API_KEY
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()

    quote, err := client.Quote(ctx, "EURUSD", nil)
    if err != nil {
        log.Fatal(err)
    }
    if quote.Bid != nil {
        fmt.Printf("%s bid=%.5f ask=%.5f\n", quote.Symbol, *quote.Bid, *quote.Ask)
    }

    rsi, err := client.Indicator(ctx, "EURUSD", tickatlas.RSI14,
        &tickatlas.IndicatorParams{Timeframe: tickatlas.TimeframeH1})
    if err != nil {
        log.Fatal(err)
    }
    if rsi.Value != nil {
        fmt.Printf("RSI(14) = %.2f\n", *rsi.Value)
    }
}
Coverage

All 21 REST routes, in all four packages.

Not a popular subset — every route under /v1, including the one write route. Each package also wraps the unauthenticated /health probe.

Group Method Route Returns
Symbols GET /v1/symbols Instrument list with category, digits and base/quote currency.
GET /v1/symbols/{symbol} One instrument’s full contract specification.
Quotes GET /v1/quote Bid, ask, spread and spread_pips for one symbol.
POST /v1/quotes Many symbols in one body, with a not_found list for the misses.
History GET /v1/ohlc OHLCV candles for a symbol and timeframe.
GET /v1/ticks Raw tick bid/ask over a bounded window.
Indicators GET /v1/indicator One indicator value, with its live price context.
GET /v1/indicators Every cached indicator for a symbol, optionally by category.
GET /v1/indicators/list The catalogue of indicator keys you can ask for.
GET /v1/indicator/history A time series of one indicator. PAYG and up.
GET /v1/multi Several indicators across several symbols in one call.
GET /v1/screener Symbols filtered by one indicator’s value.
Analytics GET /v1/summary Market-state summary: bias, confidence, scores, key levels.
GET /v1/heatmap Currency strength, or the correlation matrix.
GET /v1/spread Spread statistics over a chosen period.
GET /v1/spread/compare The same statistics across a symbol list.
GET /v1/sessions Which sessions are open, and their overlaps.
Calendar GET /v1/calendar Economic events with impact, forecast, previous and actual.
Account GET /v1/monitor/account Plan, prepaid credit and quota consumption.
GET /v1/monitor/layout The saved dashboard layout, or null.
PUT /v1/monitor/layout The one write route the clients expose.
AI agents

Three ways to hand this API to an agent.

A separate repository packages the API for agent runtimes: a Claude Agent Skill that carries the knowledge, a read-only MCP server that carries the typed execution path, and a dependency-free CLI for anything that can run a shell. It installs from a clone — it is not on a package registry.

Agent Skill

SKILL.md is the knowledge half: when this API is relevant, which enum values exist, and how to read a response. It carries no secrets and works with either calling path. Copy it into a skill folder your client loads.

Claude Codeno secrets

MCP server

A Python MCP server exposing the endpoints as typed tools with JSON-schema inputs, auth, retries and clean errors. Deliberately read-only: the one write route is not exposed. Works with any MCP client.

read-onlyPython 3.10+

Zero-dependency CLI

One standard-library Python script, JSON on stdout and meaningful exit codes, for agents and CI runners with no MCP support. 21 subcommands cover the same surface as the MCP tools.

quotequotesohlcticksindicatorindicators

Worked examples

The repo ships end-to-end agent workflows rather than snippets — reading an oversold RSI scan, a currency-strength heatmap, a screener pass and a calendar plus bias lookup.

examples/MIT
Install
Claude Code
git clone https://github.com/abuzant/tickatlas-skills.git
cd tickatlas-skills

# Claude Code — registers the read-only MCP server
claude mcp add tickatlas \
  --env TICKATLAS_API_KEY=tk_xxxxxxxx \
  -- uvx --from ./mcp-server tickatlas-mcp
claude_desktop_config.json
any MCP client
{
  "mcpServers": {
    "tickatlas": {
      "command": "uvx",
      "args": ["--from", "/absolute/path/to/tickatlas-skills/mcp-server", "tickatlas-mcp"],
      "env": { "TICKATLAS_API_KEY": "tk_xxxxxxxx" }
    }
  }
}
CLI
stdlib only
export TICKATLAS_API_KEY=tk_xxxxxxxx

python scripts/tickatlas_cli.py --help          # works without a key
python scripts/tickatlas_cli.py quote EURUSD
python scripts/tickatlas_cli.py summary EURUSD H1
python scripts/tickatlas_cli.py screener RSI_14 --max-val 30
python scripts/tickatlas_cli.py heatmap
python scripts/tickatlas_cli.py account
What these clients do not do

The limits, before you find them yourself.

Three things worth knowing while you are choosing whether to depend on a package or call the API directly.

The WebSocket stream is not in a client yet

All four packages are REST-only. GET /v1/... is covered; the /ws/v1/quotes socket is out of scope for 0.1.0 and tracked for a later release. Stream over a raw WebSocket client until then — the protocol is four JSON actions.

WebSocket protocol

One published version, not a release train

0.1.0 is the only version on any registry. It follows SemVer against the v1 API, so a 0.x pin is the honest pin. Watch the repo rather than expecting a cadence.

Repo and releases

No Postman or Insomnia collection

There is no maintained collection file for either. What does exist is the OpenAPI description behind the API explorer, which both tools can import.

API explorer
No package for your language

Then you already have everything you need.

Nothing in the API requires a client library. Send X-API-Key to the REST base URL and read the success + data envelope — the packages exist to save keystrokes, not to unlock anything. The API reference carries every parameter and response schema, and the explorer publishes an OpenAPI description you can generate from.

cURL
no client
curl -H "X-API-Key: $TICKATLAS_API_KEY" \
  "https://tickatlas.com/v1/indicator?symbol=EURUSD&indicator=RSI_14&timeframe=H1"

# {"success":true,"data":{"symbol":"EURUSD","timeframe":"H1",
#  "indicator":"RSI_14","value":58.43,"bid":1.08432,"ask":1.08445,
#  "updated_at":1711548000,"server_time":"2024-03-27T14:00:00+00:00"}}

Found a bug in a client?

All four packages live in one public MIT-licensed monorepo. Open an issue with the package, the version and the failing call — or a pull request, which is faster. Each package ships unit tests that run against recorded payloads plus read-only integration tests behind an opt-in flag.

Is it the client or the API?

Reproduce the call with curl and the same key. If the raw call succeeds, it is the client; if it fails the same way, the error code and the error reference will name the cause.

Every response carries an X-Request-ID worth quoting
Frequently asked questions

Clients, clarified.

What is published, what is in this version, and when calling the API directly is the better answer.

Do I need an SDK at all?

No. The API is plain REST with one header and one response envelope, so any HTTP client works — /docs/quickstart shows the first call in five languages using nothing but each language’s standard facilities. The packages exist to save you writing retry, backoff and error-mapping code, not because the API requires them.

Which version am I installing?

0.1.0, on every registry. It is the only published version, released 2026-06-16, and it follows SemVer against the v1 API. Pin it if you want reproducible builds; a 0.x minor bump may move the surface.

Can a client stream quotes?

Not in this version. All four packages cover the REST surface only; the WebSocket quote stream is explicitly out of scope for 0.1.0. Use a WebSocket client directly against /ws/v1/quotes — authenticate with one JSON message, then subscribe to symbols.

How does a client find my API key?

Explicit constructor argument first, then the TICKATLAS_API_KEY environment variable, then it fails at construction. The base URL resolves the same way through TICKATLAS_BASE_URL, so staging needs no code change. No client logs, prints or persists the key.

What happens on a 429?

The client retries with exponential backoff and jitter, and honours the Retry-After header rather than guessing the delay. If it exhausts its attempts you get the rate-limit exception type, carrying the server-advised delay so you can decide what to do at the application level.

Is there anything for AI agents?

Yes, in a separate repo: a Claude Agent Skill (SKILL.md), a read-only MCP server exposing the endpoints as typed tools, and a zero-dependency Python CLI for any agent that can run a shell. It installs from a git clone, not from a package registry.

My language is not on the list.

Send X-API-Key to the REST base URL with your language’s ordinary HTTP client. The API reference carries every parameter and response schema, and the API explorer publishes an OpenAPI description you can generate a client from.

What licence are they under?

MIT, all of them, in one public monorepo with a package per language. Issues and pull requests are welcome.

Install, then forget about the transport

One install. One environment variable.

Get a key, export it, and the client handles auth, retries, backoff and error typing from there. What you write next is the part that only you can write.