TickAtlas

Troubleshooting

We know debugging API issues can be frustrating. This guide covers the most common problems and how to fix them quickly. If your issue is not listed here, reach out to our support team and we will help you get back on track.

1. Authentication Issues

401

Missing X-API-Key Header

Symptom: You receive HTTP 401 with the error code MISSING_API_KEY and the message "API key is required."

Cause: The request did not include the X-API-Key header, or the header name is misspelled (it is case-insensitive, but must be exact).

Fix: Add the X-API-Key header to every request. See the code example below, or read the full Authentication guide.

401

Invalid, Expired, or Revoked API Key

Symptom: HTTP 401 with error code INVALID_API_KEY.

Cause: The key does not exist, was revoked, or was regenerated. If you regenerated your key from the dashboard, the previous key is permanently invalid. Keys are hashed on storage, so there is no way to recover a lost key from the server side.

Fix: Check for leading/trailing whitespace or newline characters in your key value. If unsure, log in to your dashboard and regenerate the key under Account > API Key.

403

Account Suspended

Symptom: HTTP 403 with error code ACCOUNT_SUSPENDED.

Cause: An administrator has suspended the account, typically for policy violations or non-payment.

Fix: Contact [email protected] to resolve the suspension.

Correct way to send your API key:

auth header
# Correct: API key in the X-API-Key header
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://tickatlas.com/v1/quotes?symbol=EURUSD"

# Python
import requests

response = requests.get(
    "https://tickatlas.com/v1/quotes",
    params={"symbol": "EURUSD"},
    headers={"X-API-Key": "YOUR_API_KEY"},
)

2. Rate Limiting (429)

429

Rate Limit Exceeded

Symptom: HTTP 429 with error code RATE_LIMITED. The response includes a Retry-After header indicating how many seconds to wait.

Common causes:

  • Polling faster than the 2-second cache TTL (you get the same cached result and waste quota).
  • Making individual calls per symbol instead of using the /v1/multi batch endpoint.
  • Using heavy endpoints like /v1/indicator/history (5x cost) or /v1/screener (3x cost) without accounting for their weight.

Fix: Respect the Retry-After header. Monitor X-RateLimit-Remaining on every response to throttle proactively. See the Rate Limits page for plan-specific limits.

429

Daily Quota Exhausted

Symptom: HTTP 429 with error code SPENDING_CAP_REACHED or INSUFFICIENT_CREDITS, and Retry-After: 3600.

Cause: This is a daily credit quota issue, not a per-minute rate limit. Your plan's daily allowance is fully consumed.

Fix: Wait until the quota resets at midnight UTC, or upgrade to a higher-tier plan.

How to check rate limit headers:

Python
import requests

response = requests.get(
    "https://tickatlas.com/v1/quotes",
    params={"symbol": "EURUSD"},
    headers={"X-API-Key": "YOUR_API_KEY"},
)

# Inspect rate limit headers on every response
print("Limit:", response.headers.get("X-RateLimit-Limit"))
print("Remaining:", response.headers.get("X-RateLimit-Remaining"))
print("Resets at:", response.headers.get("X-RateLimit-Reset"))

if response.status_code == 429:
    retry_after = int(response.headers.get("Retry-After", 60))
    print(f"Rate limited. Wait {retry_after} seconds.")

Exponential backoff with jitter:

Python · backoff
import time
import random

def request_with_backoff(url, headers, params, max_retries=5):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers, params=params)

        if response.status_code == 200:
            return response.json()

        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", 60))
            time.sleep(retry_after)
            continue

        if response.status_code >= 500:
            wait = min(2 ** attempt + random.uniform(0, 1), 60)
            time.sleep(wait)
            continue

        # 4xx client error — do not retry
        response.raise_for_status()

    raise Exception("Max retries exceeded")

3. Empty or Missing Data

Symbol Not Found

Symptom: API returns 200 OK with an empty data array, or 404 with "Symbol not found."

Cause: The symbol name does not match any canonical or broker-specific symbol in the database. Broker naming varies (e.g., XAUUSD vs XAUUSD.SD).

Fix: Call GET /v1/symbols to list all available symbols and use the canonical name. The symbol resolver handles broker-specific mapping internally.

Market Closed or Weekend

Symptom: Queries return empty results for recent time ranges.

Cause: The market is closed (weekend, holiday). There are no new candles during these periods. For forex, the market closes Friday evening and reopens Sunday evening (UTC).

Fix: For real-time quotes, the last known price is still returned from cache. For OHLC with a date range, make sure the from and to parameters cover a period when the market was open. Check /v1/sessions for market hours.

Wrong Timeframe

Symptom: OHLC endpoint returns empty for a specific timeframe but works for others.

Cause: Not all terminals publish all timeframes. The requested timeframe may not have data for that symbol.

Fix: Check which timeframes are available via GET /v1/symbols. Common timeframes: M1, M5, M15, M30, H1, H4, D1, W1, MN1.

Data Outside Retention Window

Symptom: Queries for dates far in the past return empty results.

Cause: The date range falls before the EA started collecting data for that symbol, or the from/to parameters specify future dates.

Fix: Widen the date range or check the earliest available data point for the symbol using the symbols endpoint.

4. Subscription and Billing

403

Premium Endpoint Access Denied

Symptom: HTTP 403 with error code PLAN_RESTRICTION when calling certain endpoints.

Cause: Your current plan does not include access to this endpoint. Some endpoints (such as the screener, advanced indicators, and tick data) are restricted to Pro and Enterprise plans.

Fix: Check the pricing page to see which endpoints are included in each plan. Upgrade from your dashboard billing page.

403

Expired Subscription or Zero Credits

Symptom: HTTP 403 with error code PAYMENT_REQUIRED or INSUFFICIENT_CREDITS.

Cause: Your subscription has lapsed or your pay-as-you-go credit balance has reached zero.

Fix: Check your billing status in the dashboard. Renew your subscription or add credits via the Billing page. Access is restored automatically once the payment webhook confirms.

Checking Your Current Plan

To see your current plan, quota usage, and remaining credits:

  • Log in to your dashboard and visit the Account or Billing section.
  • The X-RateLimit-Limit header on any API response reflects your plan's per-minute request cap.
  • For programmatic checks, the response headers on every API call include your current usage status.

5. WebSocket Connection Issues

Authentication Message Format

Symptom: WebSocket connection is accepted but immediately closed, or you receive an auth_failed message.

Cause: The authentication message must be the first message sent after the connection opens. It must be a JSON object with type: "auth" and your api_key.

Fix: Send the auth message immediately after connecting. See the code example below.

Connection Limit Reached

Symptom: New WebSocket connections are rejected.

Cause: Each API key is limited to a maximum of 2 concurrent WebSocket connections. If you have two connections already open, the third will be rejected.

Fix: Close unused connections before opening new ones. Ensure your code properly closes WebSocket connections on shutdown or error. If a previous connection was not closed cleanly, it may take a few minutes for the server to detect and release it.

Quota Exhaustion (Close Code 4029)

Symptom: The WebSocket connection is closed by the server with close code 4029.

Cause: Your API key's usage quota has been fully consumed. The server closes the connection to prevent further usage.

Fix: Do not attempt to reconnect after a 4029 close code. Wait for your quota to reset at midnight UTC, or upgrade your plan.

WebSocket authentication example:

Python · WS auth
import json
import websockets

async def connect():
    uri = "wss://tickatlas.com/ws"
    async with websockets.connect(uri) as ws:
        # Send auth message immediately after connecting
        await ws.send(json.dumps({
            "type": "auth",
            "api_key": "YOUR_API_KEY"
        }))

        auth_response = json.loads(await ws.recv())
        if auth_response.get("type") != "auth_success":
            raise Exception(f"Auth failed: {auth_response}")

        # Subscribe to symbols
        await ws.send(json.dumps({
            "type": "subscribe",
            "symbols": ["EURUSD", "XAUUSD"]
        }))

        async for message in ws:
            data = json.loads(message)
            print(data)

Reconnection strategy with backoff:

Python · reconnect
import asyncio
import json
import websockets

async def connect_with_reconnect():
    uri = "wss://tickatlas.com/ws"
    backoff = 1

    while True:
        try:
            async with websockets.connect(uri) as ws:
                await ws.send(json.dumps({
                    "type": "auth",
                    "api_key": "YOUR_API_KEY"
                }))
                backoff = 1  # Reset on successful connection

                async for message in ws:
                    data = json.loads(message)
                    process(data)

        except websockets.ConnectionClosed as e:
            if e.code == 4029:
                print("Quota exhausted. Stopping.")
                break
            print(f"Disconnected (code {e.code}). Reconnecting in {backoff}s...")
            await asyncio.sleep(backoff)
            backoff = min(backoff * 2, 60)

        except Exception as e:
            print(f"Error: {e}. Reconnecting in {backoff}s...")
            await asyncio.sleep(backoff)
            backoff = min(backoff * 2, 60)

6. SDK and Integration Issues

Request Timeouts

Symptom: Requests hang or fail with a timeout error.

Cause: The default timeout in many HTTP libraries is either too short or infinite. Large queries (tick data, long OHLC date ranges) can take several seconds.

Fix: Set an explicit timeout of 30 seconds for most requests. For large data exports, increase to 120 seconds. In Python: requests.get(url, timeout=30).

Connection Pooling

Symptom: Performance is poor when making many sequential requests, or you see "too many open connections" errors.

Cause: Each request opens a new TCP connection instead of reusing an existing one.

Fix: Use a requests.Session() object in Python (or equivalent in your language) to reuse TCP connections via HTTP keep-alive. Check our SDK documentation for best practices.

Proxy or Firewall Blocking Requests

Symptom: Requests fail with connection refused, connection reset, or SSL handshake errors.

Cause: A corporate proxy, firewall, or VPN is intercepting or blocking outbound HTTPS traffic to tickatlas.com.

Fix: Ensure outbound HTTPS (port 443) to tickatlas.com is allowed. If behind a proxy, configure your HTTP client to use it. Test connectivity with: curl -v https://tickatlas.com/health.

CORS Errors in Browser Requests

Symptom: Browser console shows "blocked by CORS policy" when calling the API from client-side JavaScript.

Cause: Browser-based API calls are subject to Cross-Origin Resource Sharing (CORS) restrictions. The API only allows requests from whitelisted origins.

Fix: For production browser apps, make API calls from your backend server instead of directly from the browser. This avoids CORS issues and prevents exposing your API key in client-side code. If you must call from the browser, contact support to have your origin whitelisted.

7. Data Quality Questions

Stale Data or Delayed Prices

Symptom: The price data appears outdated. The timestamp field shows a time significantly in the past.

Cause: The broker terminal feeding data may be disconnected, or the market is closed. Real-time data is cached with a 2-second TTL, so during market hours the data should be at most a few seconds old.

Fix: Always check the timestamp field in the response. If the timestamp is more than a few seconds old during market hours, the data source may be experiencing issues. Check our status page for any ongoing incidents.

Spread Spikes During News Events

Symptom: The spread values returned by the API are abnormally wide for a brief period.

Cause: This is expected behavior. During high-impact news events (NFP, FOMC, ECB decisions), liquidity providers widen spreads. The data accurately reflects what the broker's broker feed reports.

Fix: No action needed. This is real market data. If you are building a trading algorithm, account for spread variability by using the /v1/spread endpoint to monitor current spreads before placing trades.

Symbol Name Differences Across Brokers

Symptom: A symbol works with one query but not another, or you see unexpected symbol names in response data.

Cause: Different brokers use different names for the same instrument. For example, gold might appear as XAUUSD, XAUUSD.SD, GOLD, or XAUUSDm depending on the broker. The API normalizes these via the symbol resolver.

Fix: Always use the canonical symbol name (e.g., EURUSD, XAUUSD) in your API requests. The symbol resolver maps it to all broker-specific variants internally. Call GET /v1/symbols for the full list of canonical names.

8. Common Mistakes

Using HTTP instead of HTTPS

All API requests must use https://. Plain HTTP requests will be rejected or redirected, and your API key would be transmitted in the clear. Always use https://tickatlas.com.

Sending the API Key in the URL

Never pass your API key as a query parameter (e.g., ?api_key=...). URL parameters are logged in server access logs, browser history, and proxy logs. Always use the X-API-Key header instead. See the Authentication guide.

Not URL-Encoding Query Parameters

If your parameter values contain special characters (spaces, plus signs, ampersands), they must be URL-encoded. Most HTTP libraries handle this automatically when you pass parameters as a dictionary, but if you are building URLs manually, use proper encoding: from=2026-01-01T00%3A00%3A00Z.

Ignoring Response Headers

Rate limit headers (X-RateLimit-Remaining, Retry-After) are essential for building robust integrations. Always read them. Proactive throttling based on remaining quota is far more reliable than reacting to 429 errors after the fact.

Hardcoding API Keys in Source Code

Store your API key in environment variables or a secrets manager, never in source code. If your key is accidentally committed to a repository, regenerate it immediately from your dashboard.

Not Handling Empty Responses

The API may return 200 OK with an empty data array when no results match your query (market closed, symbol not available, date range with no data). Always check that data is non-empty before processing.

Still Need Help?

If you have worked through the relevant sections above and are still stuck, we are happy to help. When contacting support, please include the following to speed up resolution:

  • The HTTP status code and full error response body.
  • The endpoint URL and request parameters.
  • The timestamp of the failed request (UTC preferred).
  • Your programming language and HTTP library version.