Developers / API Reference

GET Premium · 2× credits Production

Economic Calendar API Reference

Query upcoming and recent economic events — interest rate decisions, employment reports, GDP releases, and more. Essential for risk-aware algorithmic trading: know what is coming before it moves the market.

Base URL https://tickatlas.com Auth X-API-Key Format JSON Timestamps UTC
calendar.request 200 OK
GET /v1/calendar?currencies=USD&impact=high&next_hours=24&limit=100
{
  "success": true,
  "data": {
    "events": [{
      "datetime": "2026-09-08T23:50:04+00:00",
      "currency": "JPY",
      "event": "BoJ M2 Money Stock y/y",
      "impact": "low",
      "forecast": "2.0%",
      "previous": "2.2%",
      "actual": "2.0%",
      "source": "primary",
      "series_id": "3f8a21c07d9e5b46"
    }],
    "pagination": { "has_more": false }
  }
}

Endpoint overview

One endpoint for before, during and after an economic release.

The Calendar API is built around software workflows rather than a static calendar UI. Query forward for scheduled events, backward for recently released values, or straddle the current time in a single request.

GET https://tickatlas.com/v1/calendar

Send your API key in the X-API-Key header. The endpoint is paid-only: a key on a plan the gate treats as unpaid receives 403 PLAN_UPGRADE_REQUIRED. Calls are metered at the premium 2× rate.

30 daysMaximum resolved window
96 hoursReleased-event lookback ceiling
500Events per page ceiling
UTCAll release timestamps

The mental model: next_hours is the “what is coming?” window. prev_hours is the “what just released?” window. Combine them when an application needs context on both sides of now.

Request builder

Build the query visually, then copy the exact request.

This builder is deliberately local to the page — it teaches the contract without sending your API key anywhere.

Generated request

https://tickatlas.com/v1/calendar?currencies=USD%2CEUR&impact=high&next_hours=24&limit=100

curl -H "X-API-Key: YOUR_API_KEY" \
  "https://tickatlas.com/v1/calendar?currencies=USD%2CEUR&impact=high&next_hours=24&limit=100"

Query parameters

Filter narrowly, page predictably.

No query parameter is required. With neither rolling-window shortcut set, the endpoint falls back to from/to, and with neither of those to a default window of today 00:00 UTC plus seven days.

Parameter Type Required Default / limits Description
from string No today, 00:00 UTC Start date in ISO 8601 or YYYY-MM-DD format. Ignored when next_hours or prev_hours is set. An unparseable value returns 400 INVALID_DATE.
to string No from + 7 days End date of an explicit range. The resolved window may not span more than 30 days.
currencies string No comma-separated Currency codes to filter by, e.g. USD,EUR,GBP. Matched case-insensitively.
country string No alias Alias for currencies, accepting the same comma-separated codes. If both are supplied, currencies wins.
impact string No high · medium · low Return only events of one impact level. Any other value returns 400 INVALID_IMPACT with the accepted values echoed.
q string No max 100 characters Case-insensitive substring search on the event title, e.g. interest rate. Longer values are rejected by validation (422).
next_hours integer No 1–720 Look forward from the current server time. Overrides from/to when set.
prev_hours integer No 1–96 Look backward over already released events. Overrides from/to when set, and on its own returns newest-first.
source string No primary · secondary Restrict results to one stream. Omit it to receive the combined default view. Lowercase, exactly one value: anything else, including an empty value or a repeated key, returns 400 INVALID_SOURCE.
offset integer No 0 and up Number of results to skip before the current page.
limit integer No 100 (max 500) Maximum events returned on the current page.

The country alias. country and currencies accept the same comma-separated currency codes and can be used interchangeably — country simply reads better when you think in terms of the country of origin rather than the currency pair. If both are supplied, currencies takes precedence.

Time-window shortcuts

Three common ways to ask the calendar a question.

The rolling windows remove the date math that usually makes event-monitoring code harder than it needs to be. Both start from the current server time, in UTC.

?next_hours=4

What is coming?

Starts at the current server time and looks forward. This is the pre-session check: query high-impact events four hours before the US open to decide whether to reduce exposure or pause an automated strategy.

next_hours accepts 1–720

?prev_hours=48

What just released?

Returns events that have already released, newest-first, so the latest print is on page 1. Pair it with source=primary when you are polling for published values. It is a live monitoring window, not a historical archive.

prev_hours accepts 1–96

?prev_hours=2&next_hours=6

What is around now?

Setting both builds one window spanning both sides of now, returned oldest-first — the ordering every other query path uses.

Combined span must stay within 30 days

Precedence rule: when either rolling window is present, from and to are ignored entirely. The 30-day ceiling applies to the resolved window, so the two maxima cannot be combined: prev_hours=96 with next_hours=720 resolves to 34 days and returns 400 RANGE_TOO_LARGE.

Response schema

The event object is deliberately compact.

Events live under data.events[]. The same data object also carries count, range and pagination.

id

Identifies one release row. Stable across polls: 16 hexadecimal characters. Treat it as opaque.

datetime UTC

ISO 8601 release timestamp with a +00:00 offset.

currency

Affected currency, e.g. USD, EUR, GBP or JPY.

event

Full event name, e.g. BoJ M2 Money Stock y/y.

impact

One of low, medium or high.

forecast

Consensus forecast. A string, because units differ by release.

previous

Prior-period reading, also a string.

actual Starter+

Released value on eligible primary rows. Null before release, on every secondary row, and on plans below the actuals entitlement.

source

Always primary or secondary. Never null.

series_id

Stable per-indicator key on primary rows; null on secondary rows.

data.count

Number of events on this page, after duplicate suppression.

data.range

The resolved from/to interval, echoed as naive UTC (no offset).

data.pagination

offset, limit, total and has_more for the filtered set.

200 OK
{
  "success": true,
  "data": {
    "events": [
      {
        "id": "acb808eac77e0bbe",
        "datetime": "2026-09-08T23:50:00+00:00",
        "currency": "JPY",
        "event": "M2 Money Stock y/y",
        "impact": "low",
        "forecast": "2.2%",
        "previous": "2.2%",
        "actual": null,
        "source": "secondary",
        "series_id": null
      },
      {
        "id": "7c1e9a04b2f35d68",
        "datetime": "2026-09-08T23:50:04+00:00",
        "currency": "JPY",
        "event": "BoJ M2 Money Stock y/y",
        "impact": "low",
        "forecast": "2.0%",
        "previous": "2.2%",
        "actual": "2.0%",
        "source": "primary",
        "series_id": "3f8a21c07d9e5b46"
      }
    ],
    "count": 2,
    "range": {
      "from": "2026-09-08T13:45:00",
      "to": "2026-09-12T19:45:00"
    },
    "pagination": {
      "offset": 0,
      "limit": 100,
      "total": 2,
      "has_more": false
    }
  }
}

Use series_id for history. The event id identifies one specific release row; series_id groups recurring releases of the same primary-stream indicator over time. Note that datetime is emitted with a +00:00 offset while data.range is echoed as naive UTC, preserving the original output contract.

Source semantics

Two streams, one normalized contract.

Every event carries source, and the distinction matters most when your software is waiting on a released value.

source = primary

Release-capable stream

Primary rows carry schedule, forecast and previous values, and are the only rows that can ever receive a published actual.

  • actual populates at release on entitled plans
  • series_id is a stable string
  • The right filter for release pollers
source = secondary

Schedule / reference stream

Secondary rows also carry schedule, forecast and previous values, but actual stays null permanently and series_id is null.

  • Broader scheduled-event coverage
  • Raw stream: may expose a duplicate the default view hides
  • Not suitable for polling released values

primary + secondaryThe default query returns the normalized combined view.

your applicationFilter with ?source=primary when released values are the contract you care about.

Why the totals can look surprising: asking for each stream separately exposes the raw streams, and the default combined view hides a duplicate when both twins land on the same page. The invariant that always holds is primary.total + secondary.total == default.total, while the default count can be lower by exactly those hidden duplicates.

Pagination

Wide windows are expected to span more than one page.

Read pagination.has_more and advance offset until the window is exhausted. has_more is simply offset + limit < total, computed against the filtered set, so a source filter is already reflected in it.

Python · page a 30-day window
import requests

API_KEY = "YOUR_API_KEY"
BASE = "https://tickatlas.com"

offset = 0
page_size = 500  # the ceiling for limit

while True:
    page = requests.get(f"{BASE}/v1/calendar", headers={
        "X-API-Key": API_KEY
    }, params={
        "next_hours": 720,
        "offset": offset,
        "limit": page_size
    }).json()["data"]

    process(page["events"])

    if not page["pagination"]["has_more"]:
        break

    offset += page_size

Code examples

Copy the pattern in the language you already use.

The first three request high-impact USD events for the next 24 hours. Authentication is identical across languages: one X-API-Key header.

cURL
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://tickatlas.com/v1/calendar?currencies=USD&impact=high&next_hours=24&offset=0&limit=100"
Python
import requests

API_KEY = "YOUR_API_KEY"
BASE = "https://tickatlas.com"

# Get high-impact USD events for the next 24 hours
resp = requests.get(f"{BASE}/v1/calendar", headers={
    "X-API-Key": API_KEY
}, params={
    "currencies": "USD",
    "impact": "high",
    "next_hours": 24
})

data = resp.json()
for event in data["data"]["events"]:
    print(f"{event['datetime']} | {event['event']} | "
          f"Forecast: {event['forecast']} | Previous: {event['previous']}")
JavaScript
const API_KEY = "YOUR_API_KEY";
const BASE = "https://tickatlas.com";

const params = new URLSearchParams({
  currencies: "USD",
  impact: "high",
  next_hours: "24",
  offset: "0",
  limit: "100"
});

const resp = await fetch(`${BASE}/v1/calendar?${params}`, {
  headers: { "X-API-Key": API_KEY }
});

const { data } = await resp.json();
console.log(`${data.count} events found`);

data.events.forEach(ev => {
  console.log(`${ev.datetime} | ${ev.currency} | ${ev.event}`);
});
Released actuals
# What released in the last 48h, primary stream only
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://tickatlas.com/v1/calendar?prev_hours=48&impact=high&source=primary&limit=100"

# On plans that include live actuals, a released primary row carries
# its published "actual" alongside "forecast" and "previous".
Alert loop
import requests
import time
from datetime import datetime, timezone

API_KEY = "YOUR_API_KEY"
BASE = "https://tickatlas.com"

def check_upcoming_events(hours_ahead=4):
    """Check for high-impact events in the next N hours."""
    resp = requests.get(f"{BASE}/v1/calendar", headers={
        "X-API-Key": API_KEY
    }, params={
        "impact": "high",
        "next_hours": hours_ahead
    })

    events = resp.json()["data"]["events"]
    if events:
        print(f"[WARNING] {len(events)} high-impact event(s) "
              f"in the next {hours_ahead} hours:")
        for ev in events:
            print(f"  {ev['datetime']} - {ev['currency']} "
                  f"{ev['event']}")
        return True  # Signal to reduce position sizes or pause trading
    return False

# Poll every 30 minutes during trading hours
while True:
    risk_elevated = check_upcoming_events(hours_ahead=4)
    if risk_elevated:
        # Implement your risk reduction logic here
        pass
    time.sleep(1800)

The alert loop is the pattern most teams reach for first: poll for high-impact events on a timer and let the result drive the risk layer — reduce position sizes, widen stops, or pause new entries while a release is imminent. Pair it with the Sessions endpoint to correlate event times with market hours, and with the Quotes endpoint to watch the price reaction as the figure prints.

Prefer SDKs? TickAtlas publishes official clients for Python, JavaScript, PHP and Go. View SDK documentation →

Access & live actuals

The endpoint and the released value are gated separately.

This is the single most important plan behaviour to understand before you build against the endpoint.

Free / trial keys

Endpoint blocked

Requests return 403 PLAN_UPGRADE_REQUIRED. Self-serve signup issues a pay-as-you-go key, so this affects legacy keys only.

Pay as you go

Full endpoint access

Every parameter works, metered at the premium 2× rate. Released actual values stay null.

Tool keys

Full endpoint access

Schedule, forecast and previous values on both streams. Released actual values stay null.

Starter / Pro / Enterprise

Live released actuals

Eligible primary rows populate actual the moment the figure prints.

Building specifically around released values? Start at Starter or above. Pay as you go is the right tier for schedule and forecast workflows — it reads the whole calendar, it simply does not expose the released actual. Choosing a window does not change this: prev_hours only changes which events are listed, never which plans see a value.

Endpoint-specific errors

Fail loudly when the window or the source is invalid.

Shared authentication, quota and rate-limit behaviour follows the general API error contract. These are the Calendar-specific cases worth handling explicitly.

Status Code / condition What it means Fix
400 INVALID_DATE from or to is not a YYYY-MM-DD date or an ISO 8601 timestamp. Send a plain date or a full ISO 8601 value; both are read as UTC when no offset is given.
400 INVALID_IMPACT impact is not high, medium or low. Use one of the three documented values, lowercase.
400 INVALID_SOURCE source is empty, repeated, or not exactly primary or secondary. Omit the parameter for both streams, or send it once with one valid lowercase value.
400 RANGE_TOO_LARGE The resolved window is longer than 30 days. The response echoes requested_days. Narrow the explicit range, or the combined rolling window.
403 PLAN_UPGRADE_REQUIRED The key belongs to a plan the endpoint gate treats as unpaid. Use a paid key. Self-serve signup issues a pay-as-you-go key, which this gate accepts.
422 Validation error next_hours was sent outside 1–720. Clamp the value before sending, or drop the parameter and use from/to.
422 Validation error prev_hours was sent outside 1–96. Clamp the value before sending. The backward window is a live monitor, not a history archive.

General API errors: authentication, malformed requests and rate-limit responses are documented centrally. Open error handling →

Implementation patterns

Reference docs should end in something buildable.

These patterns map the raw contract onto the workflows teams actually ship.

?next_hours=4&impact=high

Pre-event guardrail

Check whether a high-impact release is approaching before running time-sensitive automation or publishing market context.

Poll → compare datetime → apply your own rule

?prev_hours=2&source=primary

Release monitor

Fetch the newest primary-stream rows and wait for actual to become non-null on an entitled plan.

Poll → detect actual → compare with forecast

?prev_hours=2&next_hours=6

Context window

Show what just happened beside what is still ahead — one request, one timeline, no date math.

One request → one timeline → less code

Use cases

  • News-aware trading — Adjust strategy parameters or widen stop-losses ahead of scheduled high-impact releases like NFP or FOMC decisions.
  • Risk management — Automatically reduce position sizes or halt new entries when high-impact events are imminent, so an unpredictable volatility spike never catches an open book.
  • Event-driven strategies — Trade the reaction to a release by comparing actual against forecast and entering on the deviation.
  • Economic dashboard — Render a full calendar view in your own product, filtered to the currencies your users actually trade.

Useful companions: pair the calendar with Trading Sessions to reason about market hours, and with Quotes to watch price behaviour around a release.

Economic Calendar API

From scheduled event to released actual, keep the contract simple.

One endpoint covers upcoming releases, recent actuals, impact and currency filtering and paginated event windows — then pair it with the rest of the platform when your application needs sessions, quotes or derived market context.