Quickstart · 5 minutes

One header, one endpoint, one JSON body.

Create a key, send it as X-API-Key, and read a response whose shape every other endpoint repeats. No SDK, no OAuth exchange, no card.

X-API-Key header200 requests/day to start7 timeframes
docs · quickstart
This page
Five steps
Five languages
Response fields
Errors
Then
Endpoint catalogue
Production checklist
01 · first request

Your first authenticated call

Two lines of request. The data object below is the whole success body — nothing is nested behind a second call.

GET /v1/indicator?symbol=EURUSD&indicator=RSI_14&timeframe=H1
X-API-Key: tk_…
{
  "success": true,
  "data": {
    "symbol": "EURUSD",
    "timeframe": "H1",
    "indicator": "RSI_14",
    "value": 58.43,
    "bid": 1.08432,
    "ask": 1.08445
  }
}
1Header to authenticate
$2.50Starting credit
200Requests/day to start
7Timeframes
Five steps

From signup to a parsed value.

01

Create an account

Signup mints an API key and 200 requests a day against $2.50 of prepaid credit. No card, and no overage — when the credit runs out the key returns 429, it does not bill you.

02

Copy the key out of the dashboard

Keys start with tk_. Put it in an environment variable, not in source control — the snippets below all read TICKATLAS_API_KEY.

03

Send it as X-API-Key

One header on every REST call. There is no OAuth exchange, no bearer token and no refresh cycle to implement.

04

Read the envelope

Success is {"success": true, "data": {…}}. Every non-2xx is {"success": false, "error": {"code", "message"}} — one shape to deserialise for the whole API.

05

Change one parameter, not your integration

Swapping indicator=RSI_14 for ATR_14, or timeframe=H1 for M15, reaches all 42 indicator series through the same request.

cURL
GET /v1/indicator
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://tickatlas.com/v1/indicator?symbol=EURUSD&indicator=RSI_14&timeframe=H1"
200 OK
{
  "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"
  }
}
Five languages

The same request, in whatever you are already writing.

No client library is involved in any of these — each one uses its language's own HTTP facility and reads the key from an environment variable. Copy one, set TICKATLAS_API_KEY, and run it.

Python
requests
import os, requests

response = requests.get(
    "https://tickatlas.com/v1/indicator",
    headers={"X-API-Key": os.environ["TICKATLAS_API_KEY"]},
    params={"symbol": "EURUSD", "indicator": "RSI_14", "timeframe": "H1"},
    timeout=10,
)
response.raise_for_status()

data = response.json()["data"]
print(f"{data['indicator']} = {data['value']} at {data['server_time']}")
JavaScript
fetch
const url = new URL("https://tickatlas.com/v1/indicator");
url.search = new URLSearchParams({
  symbol: "EURUSD",
  indicator: "RSI_14",
  timeframe: "H1",
});

const res = await fetch(url, {
  headers: { "X-API-Key": process.env.TICKATLAS_API_KEY },
});
if (!res.ok) throw new Error((await res.json()).error.code);

const { data } = await res.json();
console.log(`${data.indicator} = ${data.value} at ${data.server_time}`);
PHP
cURL extension
<?php
$query = http_build_query([
    'symbol'    => 'EURUSD',
    'indicator' => 'RSI_14',
    'timeframe' => 'H1',
]);

$ch = curl_init("https://tickatlas.com/v1/indicator?$query");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['X-API-Key: ' . getenv('TICKATLAS_API_KEY')],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);

printf("%s = %s at %s\n",
    $body['data']['indicator'], $body['data']['value'], $body['data']['server_time']);
Go
net/http
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "os"
)

type indicatorResponse struct {
    Success bool `json:"success"`
    Data    struct {
        Indicator  string  `json:"indicator"`
        Value      float64 `json:"value"`
        ServerTime string  `json:"server_time"`
    } `json:"data"`
}

func main() {
    req, _ := http.NewRequest("GET",
        "https://tickatlas.com/v1/indicator?symbol=EURUSD&indicator=RSI_14&timeframe=H1", nil)
    req.Header.Set("X-API-Key", os.Getenv("TICKATLAS_API_KEY"))

    res, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()

    var out indicatorResponse
    json.NewDecoder(res.Body).Decode(&out)
    fmt.Printf("%s = %.2f at %s\n", out.Data.Indicator, out.Data.Value, out.Data.ServerTime)
}
Response anatomy

Nine keys, and that is the whole body.

This is the complete success payload of GET /v1/indicator — not an excerpt. The indicator arrives with its price context and its timestamps, so a consumer can judge freshness without a second call.

FieldTypeWhat it carries
success boolean true on a 2xx. Present on every response, including errors, where it is false.
data.symbol string The canonical symbol.
data.timeframe string The timeframe served, upper-cased. Defaults to H1 when the request omits it.
data.indicator string The indicator key echoed back, e.g. RSI_14, MACD_main, EMA_20.
data.value number The computed value. Its scale is the indicator’s own — RSI is 0–100, ATR is in price units.
data.bid number | null Live bid at read time, so the value arrives with its price context. null when no price is cached for the symbol.
data.ask number | null Live ask at read time. null under the same condition as bid.
data.updated_at integer Unix epoch seconds of the last indicator recalculation. Use it to decide whether a value is fresh enough for your purpose.
data.server_time string The same instant in ISO-8601 UTC, e.g. 2024-03-27T14:00:00+00:00.

Other endpoints add their own keys — /v1/summary returns bias, confidence and key levels; /v1/heatmap returns strongest, weakest and a strength map — but the success + data wrapper never changes.

When it fails

One error shape, eleven codes worth knowing.

Every non-2xx — including a 404 from the router itself and a 422 from parameter validation — is folded into the same envelope, so you deserialise one type for the whole API. Branch on error.code: it is the contract, while error.message is prose that may be reworded.

401 Unauthorized
no X-API-Key
HTTP/1.1 401 Unauthorized
X-Request-ID: 9f3c1a7e52b64d0e8a17c4d3b6e09f21

{
  "success": false,
  "error": {
    "code": "MISSING_API_KEY",
    "message": "API key is required. Include it in the X-API-Key header.",
    "docs": "https://tickatlas.com/docs#authentication"
  }
}
Statuserror.codeCause, and what to do
401 MISSING_API_KEY No X-API-Key header. The message names the header and links to the authentication docs.
401 INVALID_API_KEY The key is not recognised. Check you copied the whole tk_ string.
403 IP_NOT_ALLOWED The key has an IP allowlist and the caller is not on it.
403 PERMISSION_DENIED The key exists but lacks the permission the endpoint requires.
403 PLAN_UPGRADE_REQUIRED The endpoint is gated above your plan — how GET /v1/ticks answers a pay-as-you-go or Starter key.
400 INVALID_TIMEFRAME Not one of the seven timeframes. The body lists the valid set, so you can surface it directly.
404 DATA_NOT_FOUND The symbol resolved but no cached data exists for that symbol and timeframe.
404 INDICATOR_NOT_FOUND The symbol has data but not that indicator key. The body lists the available keys.
422 VALIDATION_ERROR A parameter failed its bounds check. error.details carries the field-level diagnostics.
429 RATE_LIMIT_EXCEEDED Per-minute limit hit. Retry-After and X-RateLimit-Reset both tell you when to retry.
429 QUOTA_EXCEEDED Daily quota or prepaid credit exhausted. error.details says which, so you can alert rather than blindly retry.
Where to go next

Everything else is the same call with a different path.

The badge is the endpoint's weight: what one call costs in pay-as-you-go credit units. Every call counts once against a daily quota. This is the whole REST surface, plus the one socket.

Production checklist

From 200 OK to something you can leave running.

Six behaviours the API already gives you, each one cheaper to use than to reimplement.

Secrets

Keep the key server-side

A key in browser JavaScript is a published key. Call the API from your own backend and pass the result down.

Throughput

Read the rate-limit headers

Every /v1 response carries X-RateLimit-Limit, -Remaining and -Reset. The starting grant is 30 requests a minute; do not hardcode it.

Retries

Honour Retry-After

A 429 tells you exactly how long to wait. Back off on that number rather than on a guess, and never retry a 4xx that is not 429.

Failure

Branch on error.code

The code is the contract; the message is prose and may be reworded. INVALID_API_KEY needs a human, QUOTA_EXCEEDED needs a top-up, DATA_NOT_FOUND needs neither.

Support

Log X-Request-ID

It is set on every /v1 response and echoed from your request if you send one. Quote it and a failure becomes traceable instead of anecdotal.

Cost

Know what a call weighs

Quota is charged per weight, not per request: one /v1/summary costs five, one /v1/quote costs one. Budget the mix, not the count.

Documentation map

Everything has a clear home.

Four groups, ordered the way an integration actually grows.

Stuck on the first call?

Almost every first-request failure is one of four things: no header, a truncated key, a timeframe that is not in the valid set, or a symbol with no cached data yet. Troubleshooting walks them in that order.

Escalate with the request id

Include the endpoint, the HTTP status, the X-Request-ID from the response headers and a redacted request. That turns a report into something traceable in the logs.

Check status before chasing an integration bug
Frequently asked questions

Before you start.

The questions that come up between reading the first snippet and running it against your own key.

What do I actually need before the first request?

An account and the API key it mints. That is all — the key works immediately against 200 requests a day and $2.50 of prepaid credit, with no card on file and no approval step.

Which timeframes can I pass?

M1, M5, M15, M30, H1, H4, D1. Omitting the parameter gives you H1. Anything else returns 400 INVALID_TIMEFRAME with the valid set in the body.

How do I get more than the latest value?

GET /v1/indicator returns one point — the current one. A time series comes from GET /v1/indicator/history, which takes from, to and limit; its limit parameter defaults to 500 and is then bounded per timeframe by how far back that timeframe is retained. It is available on pay-as-you-go, Starter, Pro and Enterprise; it counts once against a daily quota and costs five weighted units of pay-as-you-go credit.

Do I need an SDK?

No. The API is plain REST with one header, so any HTTP client works — the five snippets above use nothing but the standard library of each language. See /docs/sdks for what is packaged.

What happens when I run out of quota?

The next call returns 429 with error.code QUOTA_EXCEEDED and error.details naming the limit that was reached. Nothing is billed past your prepaid credit, so a runaway loop costs you availability rather than money.

Can I call this from the browser?

You can, but the key would ship to every visitor. Keep the key on a server you control and expose your own endpoint to the browser instead.

Five minutes, one header

Get the key. Make the call.

Signup mints a working key and $2.50 of prepaid credit. Paste one of the snippets above, and the next thing you read is your own data.