API Documentation

Integrate exchange holiday calendars into your ETRM system via our REST API. Available formats include JSON, CSV, and XML (Endur-compatible).

Base URL: https://api.excaltracker.io/v1

All endpoints return data over HTTPS. HTTP requests are redirected.

Authentication

All API requests require an API key passed in the X-API-Key header. You can generate and manage API keys in your portal dashboard.

curl -H "X-API-Key: your_api_key_here" \
  https://api.excaltracker.io/v1/exchanges

Requests without a valid API key receive a 401 Unauthorized response. Free-tier keys are limited to 100 requests/hour.

List Exchanges

GET/v1/exchanges

Returns all supported exchanges with metadata including region, timezone, and available years.

Response

{
  "exchanges": [
    {
      "code": "ICE_EU",
      "name": "ICE Futures Europe",
      "region": "EU",
      "timezone": "Europe/London",
      "website": "https://www.ice.com",
      "supported_years": [2025, 2026, 2027],
      "products": ["Brent Crude", "Gas Oil", "UK Natural Gas"],
      "active": true
    },
    {
      "code": "CME",
      "name": "CME Group / NYMEX",
      "region": "US",
      "timezone": "America/Chicago",
      "website": "https://www.cmegroup.com",
      "supported_years": [2025, 2026, 2027],
      "products": ["WTI Crude", "Henry Hub Natural Gas", "RBOB Gasoline"],
      "active": true
    }
  ],
  "count": 7,
  "last_updated": "2026-03-15T08:00:00Z"
}

Get Calendar

GET/v1/calendars/:exchange/:year

Returns the holiday calendar for a specific exchange and year.

Path Parameters

ParameterTypeDescription
exchangestringExchange code (e.g., ICE_EU, CME, EEX, LME)
yearintegerCalendar year (2025–2027)

Query Parameters

ParameterDefaultDescription
formatjsonResponse format: json, csv, or xml

Example Response (JSON)

{
  "exchange": "ICE_EU",
  "exchange_name": "ICE Futures Europe",
  "year": 2026,
  "generated_at": "2026-03-15T08:00:00Z",
  "entry_count": 10,
  "entries": [
    {
      "date": "2026-01-01",
      "day_of_week": "Thursday",
      "holiday_name": "New Year's Day",
      "type": "FULL_CLOSE",
      "markets_affected": ["All"],
      "trading_hours": null,
      "notes": null
    },
    {
      "date": "2026-04-03",
      "day_of_week": "Friday",
      "holiday_name": "Good Friday",
      "type": "FULL_CLOSE",
      "markets_affected": ["All"],
      "trading_hours": null,
      "notes": null
    },
    {
      "date": "2026-12-24",
      "day_of_week": "Thursday",
      "holiday_name": "Christmas Eve",
      "type": "EARLY_CLOSE",
      "markets_affected": ["All"],
      "trading_hours": "08:00-12:30",
      "notes": "Early close at 12:30 GMT"
    }
  ]
}

Example Response (CSV)

date,day_of_week,holiday_name,type,markets_affected,trading_hours,notes
2026-01-01,Thursday,New Year's Day,FULL_CLOSE,All,,
2026-04-03,Friday,Good Friday,FULL_CLOSE,All,,
2026-12-24,Thursday,Christmas Eve,EARLY_CLOSE,All,08:00-12:30,Early close at 12:30 GMT

Response Formats

Calendar data is available in three formats, optimized for different integration scenarios:

JSON (default)

Best for programmatic integration. Used by most REST API consumers and custom scripts.

CSV

Compatible with Allegro ETRM import and spreadsheet tools. Includes header row with column names.

XML

Compatible with Endur/OpenLink ETRM import. Schema follows Endur holiday calendar XML specification.

Webhooks

Get notified when calendar data changes. Configure webhook endpoints in your portal dashboard.

Events

EventDescription
calendar.updatedA holiday was added, modified, or removed
calendar.publishedNew calendar year published for an exchange
exchange.addedNew exchange added to ExCalTracker

Payload

POST https://your-server.com/webhooks/excaltracker
Content-Type: application/json
X-ExCalTracker-Signature: sha256=a1b2c3d4...

{
  "event": "calendar.updated",
  "timestamp": "2026-03-15T08:00:00Z",
  "data": {
    "exchange": "ICE_EU",
    "year": 2026,
    "change_type": "holiday_added",
    "holiday": {
      "date": "2026-06-01",
      "holiday_name": "Spring Bank Holiday",
      "type": "FULL_CLOSE"
    }
  }
}

Signature Verification

Verify webhook authenticity using HMAC-SHA256. The signature is sent in the X-ExCalTracker-Signature header.

import hmac
import hashlib

def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

Rate Limits

Rate limits vary by plan. Exceeding the limit returns 429 Too Many Requests with a Retry-After header.

PlanRequests/HourBurst
Starter (Free)10010/min
Professional50050/min
Enterprise2,000200/min

Error Handling

The API uses standard HTTP status codes. Error responses include a JSON body with details.

CodeDescription
400Invalid parameters (bad year, unsupported format)
401Missing or invalid API key
404Exchange or year not found
429Rate limit exceeded
500Internal server error
{
  "error": {
    "code": "EXCHANGE_NOT_FOUND",
    "message": "Exchange 'INVALID' not found. Valid codes: ICE_EU, ICE_US, CME, EEX, LME, TOCOM, SGX",
    "status": 404
  }
}

Code Examples

cURL

# List all exchanges
curl -H "X-API-Key: your_api_key" \
  https://api.excaltracker.io/v1/exchanges

# Get ICE Europe 2026 calendar as JSON
curl -H "X-API-Key: your_api_key" \
  https://api.excaltracker.io/v1/calendars/ICE_EU/2026

# Get CME calendar as CSV
curl -H "X-API-Key: your_api_key" \
  "https://api.excaltracker.io/v1/calendars/CME/2026?format=csv" \
  -o cme_2026.csv

# Get EEX calendar as Endur XML
curl -H "X-API-Key: your_api_key" \
  "https://api.excaltracker.io/v1/calendars/EEX/2026?format=xml" \
  -o eex_2026.xml

Python

import requests

API_KEY = "your_api_key"
BASE_URL = "https://api.excaltracker.io/v1"
headers = {"X-API-Key": API_KEY}

# List exchanges
exchanges = requests.get(f"{BASE_URL}/exchanges", headers=headers).json()
for ex in exchanges["exchanges"]:
    print(f"{ex['code']}: {ex['name']} ({ex['region']})")

# Get calendar data
resp = requests.get(
    f"{BASE_URL}/calendars/ICE_EU/2026",
    headers=headers,
    params={"format": "json"}
)
calendar = resp.json()
for entry in calendar["entries"]:
    print(f"{entry['date']} - {entry['holiday_name']} ({entry['type']})")

JavaScript / Node.js

const API_KEY = "your_api_key";
const BASE_URL = "https://api.excaltracker.io/v1";

// List exchanges
const exchangesRes = await fetch(`${BASE_URL}/exchanges`, {
  headers: { "X-API-Key": API_KEY },
});
const { exchanges } = await exchangesRes.json();
exchanges.forEach((ex) => console.log(`${ex.code}: ${ex.name}`));

// Get calendar as JSON
const calendarRes = await fetch(
  `${BASE_URL}/calendars/CME/2026?format=json`,
  { headers: { "X-API-Key": API_KEY } }
);
const calendar = await calendarRes.json();
calendar.entries.forEach((entry) => {
  console.log(`${entry.date} - ${entry.holiday_name}`);
});

Ready to integrate?

Get your free API key and start pulling exchange holiday data in minutes.