Server-Sent Events
SSE release streams
Reference documentation for the FXMacroData live announcement stream. Use SSE when your application needs a low-latency signal that a scheduled macro release has landed, then fetch the canonical release payload from the matching announcements endpoint.
- Stream URL
- https://api.fxmacrodata.com/v1/stream/events
- Content type
- text/event-stream; charset=utf-8
- Event name
- announcement
- Auth
- Active trial or subscription API key
Endpoint contract
Connect directly to the streaming API.
The stream is a long-lived HTTP GET request that returns W3C EventSource frames. Use the direct API host
for the stream itself so the connection is not buffered by website routing. The server sends comment frames
to confirm the connection; announcement events arrive only when a release is ingested.
| Property | Value | Notes |
|---|---|---|
| Method | GET |
Keep the request open until your client reconnects or closes it. |
| URL | https://api.fxmacrodata.com/v1/stream/events |
Use api.fxmacrodata.com for SSE. Avoid website-proxied API paths for streaming clients. |
| Response content type | text/event-stream; charset=utf-8 |
The response body is an EventSource stream, not JSON. |
| Event type | announcement |
Each event announces that a currency and indicator have new release data available. |
| Payload mode | payload=compact or payload=full |
Compact is the default trigger payload. Full mode includes the latest stored announcement row fields in the event. |
| REST follow-up | /v1/announcements/{currency}/{indicator} |
Use REST for confirmation, logging, historical rows, and fields that are not present in the SSE event. |
Minimal stream probe:
curl -N -H "X-API-Key: YOUR_API_KEY" "https://api.fxmacrodata.com/v1/stream/events?currencies=usd&indicators=inflation&payload=full"
Authentication and filters
Use filters to keep the stream focused.
Live SSE delivery requires an active trial or subscription API key. Public no-key REST access remains available for supported cacheable endpoints, but persistent stream connections require authenticated access.
| Parameter | Required | Example | Behavior |
|---|---|---|---|
currencies |
No | usd,eur,gbp |
Comma-separated currency codes. Omit to receive every currency available to your plan. |
indicators |
No | inflation,policy_rate,non_farm_payrolls |
Comma-separated indicator slugs. Omit to receive every indicator available to your plan. |
api_key |
No | ?api_key=YOUR_API_KEY |
Legacy. Prefer the X-API-Key header; keys in URLs end up in logs. |
payload |
No | full |
Use compact for trigger-only events or full to receive the latest release value and row metadata in the SSE payload. |
| Request header | Use | Notes |
|---|---|---|
Accept: text/event-stream |
Recommended | Declares that the client expects an SSE response. |
X-API-Key: YOUR_API_KEY |
Required | Your trial or subscription API key. Send it on every stream and REST request. |
Last-Event-ID: {event_id} |
Reconnect replay | Requests buffered events that were published after the event ID your client last processed. |
401 or 403. Trial keys and active
subscription keys can use the same live-delivery stream.
Response headers
Streaming responses are sent without cache buffering.
| Header | Value | Purpose |
|---|---|---|
Content-Type |
text/event-stream; charset=utf-8 |
Identifies the response as an SSE stream. |
Cache-Control |
no-cache, no-transform |
Prevents caches and intermediaries from holding or rewriting event frames. |
X-Accel-Buffering |
no |
Disables response buffering in compatible reverse proxies. |
Connection |
keep-alive |
Keeps the stream open for incremental event delivery. |
Event schema
Each SSE frame is a release notification.
The default compact payload gives enough information to route and deduplicate the release signal, plus an
optional latest value for fast display. Use payload=full when your client needs the latest
release value, prior value, and any forecast snapshot captured before the official release in the SSE event itself.
id: usd_inflation_1772109000
event: announcement
data: {"event_id":"usd_inflation_1772109000","currency":"usd","indicator":"inflation","records_written":1,"timestamp":1772109002,"latest_announcement":{"date":"2026-02-28","val":3.1,"announcement_datetime":1772109000}}
Full payload mode:
id: usd_unemployment_1782995400
event: announcement
data: {"event_id":"usd_unemployment_1782995400","currency":"usd","indicator":"unemployment","records_written":1,"timestamp":1782995400,"latest_announcement":{"date":"2026-06-30","val":4.2,"announcement_datetime":1782995400},"date":"2026-06-30","val":4.2,"forecast":4.3,"forecast_available":true,"forecast_captured_at":1782907200,"forecast_is_pre_release":true,"previous":4.3,"announcement_datetime":1782995400,"announcement_datetime_local":"2026-07-02T08:30:00-04:00","collected_at_iso":"2026-07-02T12:30:00.123456Z"}
| Field | Type | Meaning |
|---|---|---|
event_id |
string | Stable ID used for replay and client-side deduplication. |
currency |
string | Lowercase currency code such as usd, eur, or aud. |
indicator |
string | FXMacroData indicator slug such as inflation, policy_rate, or non_farm_payrolls. |
records_written |
integer | Number of rows saved by the ingest event. Do not assume one event always means one value. |
timestamp |
integer | Unix timestamp for when the event was published onto the stream. |
latest_announcement |
object | omitted | Optional compact latest value with date, val, and announcement_datetime. |
date, val |
string, number | omitted | Top-level latest release observation fields included when payload=full and the values are available. |
forecast, forecast_available, previous |
number | boolean | omitted | In full mode, forecast is included only when FXMacroData captured a forecast before the official release. forecast_available is false when no point-in-time forecast was available; previous remains the prior observed value when available. |
announcement_datetime |
integer | omitted | Stored announcement timestamp associated with the latest value when available. Verify its publication status and precision through the announcements endpoint before treating it as confirmed publication. |
collected_at_iso |
string | omitted | UTC collection timestamp for the stored row when the ingest event recorded it. |
date field is the observation or reference date for the value.
announcement_datetime alone does not establish confirmed publication or historical availability.
The event timestamp and row collected_at_iso are separate delivery and collection clocks.
REST remains the canonical interface for historical windows, publication evidence, retained revisions, and post-release reconciliation.
REST follow-up
Use full SSE for execution and REST for confirmation.
Full payload mode can remove the pre-execution REST round trip when the fields your client needs are present in the event. The announcements endpoint remains the source of record for confirmation, storage, metadata, and historical rows.
async function fetchLatestRelease(currency, indicator) {
const url = new URL(
`https://api.fxmacrodata.com/v1/announcements/${currency}/${indicator}`
);
url.searchParams.set("limit", "1");
const response = await fetch(url, {
headers: { "X-API-Key": process.env.FXMD_API_KEY },
});
if (!response.ok) {
throw new Error(`Announcement fetch failed: ${response.status}`);
}
const body = await response.json();
const rows = Array.isArray(body) ? body : (body.data ?? []);
return rows[0] ?? null;
}
Reconnects and replay
Expect clean reconnects and dedupe by event ID.
Initial replay
When a client connects, the server can replay recent buffered events that match the requested filters.
Last-Event-ID
Send Last-Event-ID on reconnect to request events published after the last event your client processed.
Heartbeat comments
Idle connections receive : heartbeat comments about every 15 seconds. Ignore comment frames in application logic.
Stream rotation
The service may end a stream cleanly with : reconnect. Treat this as normal and open a new connection.
event_id, store a short local dedupe cache,
and reconcile with REST after any long outage.
Status and errors
Handle the stream like a long-lived network connection.
| Status or frame | Meaning | Client action |
|---|---|---|
200 |
The stream is open and will emit EventSource frames. | Keep reading until your client closes or reconnects. |
401 |
The stream was requested without an active trial or subscription API key. | Send your key in the X-API-Key header. |
403 |
The supplied key is valid but not eligible for live delivery. | Use a trial key or an active subscriber key. |
: heartbeat |
Keep-alive comment frame. | Ignore it and keep the connection open. |
: reconnect |
Clean stream rotation comment. | Reconnect and include Last-Event-ID if you have one. |
5xx or network close |
Temporary network or service interruption. | Reconnect with bounded backoff and reconcile tracked indicators through REST. |
Client examples
Connect, parse, execute, and reconcile.
These examples show the full-payload loop: subscribe with filters, parse announcement events,
use the event value immediately when present, and keep reconnect state.
Node.js
Use the built-in fetch with an X-API-Key header and parse frames as they arrive.
Server worker
Use explicit headers and persist Last-Event-ID between reconnects.
Node.js worker
Stream with fetch and an X-API-Key header.
Node.js 18 and later can read the stream with the built-in fetch. Send the key as a header, keep the
last processed event ID, and pass it back as Last-Event-ID when you reconnect.
const API_KEY = process.env.FXMD_API_KEY;
const streamUrl = new URL("https://api.fxmacrodata.com/v1/stream/events");
streamUrl.searchParams.set("currencies", "eur,gbp");
streamUrl.searchParams.set("indicators", "inflation,policy_rate");
streamUrl.searchParams.set("payload", "full");
let lastEventId = null;
async function fetchLatestRelease(currency, indicator) {
const url = `https://api.fxmacrodata.com/v1/announcements/${currency}/${indicator}?limit=1`;
const response = await fetch(url, { headers: { "X-API-Key": API_KEY } });
if (!response.ok) {
throw new Error(`Announcement fetch failed: ${response.status}`);
}
const body = await response.json();
const records = Array.isArray(body) ? body : (body.data ?? []);
return records[0] ?? null;
}
async function handleFrame(frame) {
const event = {};
for (const line of frame.split("\n")) {
if (!line || line.startsWith(":")) continue;
const index = line.indexOf(":");
const field = index === -1 ? line : line.slice(0, index);
event[field] = index === -1 ? "" : line.slice(index + 1).trimStart();
}
if (event.event !== "announcement" || !event.data) return;
const payload = JSON.parse(event.data);
lastEventId = event.id ?? payload.event_id;
const latest = payload.val === undefined
? await fetchLatestRelease(payload.currency, payload.indicator)
: payload;
process.stdout.write(`${JSON.stringify({ payload, latest })}\n`);
}
async function consumeStream() {
const headers = { Accept: "text/event-stream", "X-API-Key": API_KEY };
if (lastEventId) {
headers["Last-Event-ID"] = lastEventId;
}
const response = await fetch(streamUrl, { headers });
if (!response.ok) {
throw new Error(`Stream request failed: ${response.status}`);
}
const decoder = new TextDecoder();
let buffer = "";
for await (const chunk of response.body) {
buffer += decoder.decode(chunk, { stream: true }).replace(/\r/g, "");
let boundary;
while ((boundary = buffer.indexOf("\n\n")) !== -1) {
const frame = buffer.slice(0, boundary);
buffer = buffer.slice(boundary + 2);
await handleFrame(frame);
}
}
}
async function run() {
while (true) {
try {
await consumeStream();
} catch (error) {
process.stderr.write(`Stream disconnected: ${error.message}\n`);
}
await new Promise((resolve) => setTimeout(resolve, 3000));
}
}
run();
Python worker
Send Last-Event-ID when you control reconnects yourself.
Server-side workers can manage reconnect timing explicitly. Persist last_event_id somewhere durable if missing an event would matter after a process restart.
import json
import time
import requests
API_KEY = "YOUR_API_KEY"
STREAM_URL = "https://api.fxmacrodata.com/v1/stream/events"
PARAMS = {
"currencies": "eur,gbp",
"indicators": "inflation,policy_rate",
"payload": "full",
}
def fetch_latest_release(currency: str, indicator: str) -> dict | None:
url = f"https://api.fxmacrodata.com/v1/announcements/{currency}/{indicator}"
response = requests.get(
url,
params={"limit": 1},
headers={"X-API-Key": API_KEY},
timeout=20,
)
response.raise_for_status()
body = response.json()
records = body if isinstance(body, list) else body.get("data", [])
return records[0] if records else None
def consume_stream() -> None:
last_event_id = None
while True:
headers = {"Accept": "text/event-stream", "X-API-Key": API_KEY}
if last_event_id:
headers["Last-Event-ID"] = last_event_id
try:
with requests.get(
STREAM_URL,
params=PARAMS,
headers=headers,
stream=True,
timeout=90,
) as response:
response.raise_for_status()
event = {}
for raw_line in response.iter_lines(decode_unicode=True):
if raw_line is None:
continue
line = raw_line.strip()
if not line:
if event.get("event") == "announcement" and event.get("data"):
payload = json.loads(event["data"])
last_event_id = event.get("id") or payload["event_id"]
latest = payload
if "val" not in payload:
latest = fetch_latest_release(
payload["currency"],
payload["indicator"],
)
print(payload, latest)
event = {}
continue
if line.startswith(":"):
continue
field, _, value = line.partition(":")
event[field] = value.lstrip()
except requests.RequestException as exc:
print(f"Stream disconnected: {exc}; reconnecting in 3 seconds")
time.sleep(3)
if __name__ == "__main__":
consume_stream()
Troubleshooting
Common integration checks.
| Symptom | Likely cause | Check |
|---|---|---|
| No frames arrive after connecting | No matching releases have been ingested yet, or filters are too narrow. | Confirm currencies and indicators, then reconcile with REST for the indicators you track. |
| Connection fails from a web page | The stream is for server-side clients. Browser EventSource cannot send the X-API-Key header, and the API does not send CORS headers to browser origins. |
Connect from your backend and forward events to your front end. |
| Connection opens but closes regularly | Normal stream rotation or network timeout. | Reconnect automatically and send Last-Event-ID when available. |
| Duplicate event after reconnect | Replay returned an event your client already processed. | Dedupe by event_id before writing downstream state. |
| Stream works with curl but not behind a proxy | The proxy may buffer streaming responses. | Connect to https://api.fxmacrodata.com/v1/stream/events directly and disable buffering in your proxy layer. |
Related docs
Use SSE with the rest of the API surface.
AI Answer-Ready
Key Facts
- Page
- Sse Streams
- Section
- Documentation
- Canonical URL
- https://fxmacrodata.com/documentation/sse-streams
- Source
- FXMacroData editorial and official publisher references
- Last Updated
- See page metadata
Provenance And Trust
Cite the canonical URL and source field above. Where available, this page maps to official publisher releases and timestamped updates.
Quick Q&A
What is this page about? This page explains Sse Streams with directly usable context for trading, research, and API workflows.
What source should be cited? Use the canonical URL and the listed source field; cite official publisher references when available.
How fresh is this content? The last updated value above reflects the page metadata or latest available data timestamp.
Can this be used in AI assistants? Yes. This section is intentionally structured for retrieval and citation in chat assistants.
Prompt Packs
Use these in ChatGPT, Claude, Gemini, Mistral, Perplexity, or Grok for consistent source-aware outputs.