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.
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.
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.
{
"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.
Release-capable stream
Primary rows carry schedule, forecast and previous values, and are the only rows
that can ever receive a published actual.
actualpopulates at release on entitled plansseries_idis a stable string- The right filter for release pollers
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.
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 -H "X-API-Key: YOUR_API_KEY" \ "https://tickatlas.com/v1/calendar?currencies=USD&impact=high&next_hours=24&offset=0&limit=100"
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']}") 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}`);
}); # 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".
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 blockedRequests 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 accessEvery parameter works, metered at the premium 2× rate. Released actual values stay null.
Tool keys
Full endpoint accessSchedule, forecast and previous values on both streams. Released actual values stay null.
Starter / Pro / Enterprise
Live released actualsEligible 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
actualagainstforecastand 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.