FXMacroData uses a stable announcement path and query parameters to select the exact macro series variant.
This keeps existing URLs working while exposing the basis fields customers need for cross-currency comparison:
seasonal adjustment, real or nominal basis, returned frequency, source series ID, revision view, and pagination.
Existing v1 clients keep receiving the canonical series when selectors are omitted.
Endpoint model
Use parameters instead of endpoint sprawl.
The public route stays /v1/announcements/{currency}/{indicator}. Customers then add selectors
only when they need a non-default variant. For example, GDP can be requested as real or nominal and unemployment
can expose whether the selected source is seasonally adjusted. We do not create parallel slugs such as
real_gdp, gdp_nominal_yoy, or unemployment_sa.
Canonical by default
/usd/gdp returns the current canonical GDP series. For GDP, FXMacroData uses a real official series where one is available.
Selectors are explicit
basis=nominal, seasonality=sa, frequency=yoy, and revisions=first make the requested variant auditable.
Unsupported requests fail clearly
If a selector is not available for that endpoint, the API returns 400 unsupported_series_option with supported values.
Query parameters
Selectors available on announcement endpoints.
These parameters are available on the announcement endpoint family. Not every indicator supports every selector.
Read supported_options in the response, or the data catalogue, before building a selector UI.
Parameter
Values
Default
Purpose
seasonality
sa, nsa
Canonical endpoint series
Selects seasonally adjusted or not seasonally adjusted data when both are available. The response metadata reports seasonal_adjustment as SA, NSA, UNKNOWN, or NOT_APPLICABLE.
frequency
level, yoy, qoq, mom
Canonical endpoint series
Selects the returned observation basis. Use level for the level/index/rate itself, or a change basis when the endpoint supports one.
revisions
latest, first, final, all
latest
latest adopts the newest eligible retained value. all preserves the stored head. Both full views retain the eligible ledger. first and final select the earliest and latest eligible retained entry and omit the ledger; these names alone do not prove a publisher first print or finality.
basis
real, nominal
Canonical endpoint series
Selects inflation-adjusted real data or current-price nominal data where both are available. The response metadata reports price_basis as REAL, NOMINAL, or UNKNOWN.
series_mode
raw, canonical
raw
Controls whether configured continuity remaps are applied. Use canonical when you want FXMacroData's continuity rules across source methodology transitions.
start_date, end_date
YYYY-MM-DD
Endpoint default window
Restricts rows by observation period date. Rows are still sorted most-recent-first.
limit, offset, page
limit 1 to 100, offset 0+, page 1+
limit=20, offset=0
Paginates most-recent-first data[] after date filters are applied. page is one-based and derives offset as (page - 1) * limit.
X-API-Key header
Your FXMacroData key
Not required for public USD freemium windows up to 100 requests/day, delivered on a 15-minute delay
Required for non-USD, paid-only, higher-volume, or full-history requests. Authorization: Bearer YOUR_API_KEY is also accepted.
api_key
Your FXMacroData key
Not set
Legacy query form. Prefer the X-API-Key header.
Pagination and sparse windows
Use the built-in pagination contract for long histories.
Announcement endpoints support broad historical windows. Date filters are applied first, rows are sorted
most-recent-first, and the response page is controlled by limit plus either offset or
page. To fetch the next page, reuse the same filters and pass
offset=pagination.next_offset. Do not split broad ranges into custom shorter-window retries unless
your application is intentionally sampling a specific sub-period.
Latest-row signal
page_includes_latest_available appears at the top level and inside
pagination. It is true when the current page contains
latest_available_date. If it is false, the latest observation is on another page
or the current response is a historical page.
Sparse windows
Monthly, quarterly, and irregular series can be valid but have no observations inside a narrow recent
date window. That is an empty result, not a missing series: the API returns 200 with
data: [] and a no_data object carrying the coverage the series actually has,
so you can widen the window without guessing. A 404 on this endpoint always means the
currency or indicator slug is wrong.
{
"currency": "NZD",
"indicator": "core_inflation",
"requested_start_date": "2026-04-01",
"requested_end_date": "2026-06-22",
"requested_window_has_data": false,
"earliest_available_date": "1999-03-31",
"latest_available_date": "2026-03-31",
"no_data": {
"error_code": "NO_DATA_IN_REQUESTED_WINDOW",
"message": "No observations available for NZD/core_inflation in requested range (2026-04-01 to 2026-06-22).",
"earliest_available_date": "1999-03-31",
"latest_available_date": "2026-03-31",
"recommended_start_date": "2026-03-31",
"available_observation_count": 109
},
"data": []
}
Anonymous callers: USD access without an API key returns the most recent 90 days, and a release becomes readable 15 minutes after publication. A
quarterly or annual series whose latest observation is older than that window returns the same empty
200, with no_data.freemium_clamped=true. Supply an API key to read it.
Daily market-level exception: some daily level series, such as government bond yields, may
return the latest eligible official observation before the requested window when it is recent enough. Those
responses set requested_window_has_data=false and mark the row with
outside_requested_window=true.
Examples
Common request shapes.
Canonical GDP
GET https://api.fxmacrodata.com/v1/announcements/usd/gdp
Real GDP growth
GET https://api.fxmacrodata.com/v1/announcements/usd/gdp?basis=real&frequency=yoy&limit=20
Nominal GDP level
GET https://api.fxmacrodata.com/v1/announcements/usd/gdp?basis=nominal&frequency=level
X-API-Key: YOUR_API_KEY
Seasonally adjusted unemployment
GET https://api.fxmacrodata.com/v1/announcements/sek/unemployment?seasonality=sa
X-API-Key: YOUR_API_KEY
First-published release values
GET https://api.fxmacrodata.com/v1/announcements/usd/gdp?basis=real&revisions=first
Second page of history
GET https://api.fxmacrodata.com/v1/announcements/usd/gdp?limit=20&offset=20
Python requests
Copyable Python selector examples
Use these snippets when testing announcement selectors from a notebook, job, or service. The params dict mirrors the query string exactly.
Canonical USD GDP
Default announcement series with pagination controls.
Treat the top-level metadata as part of the data contract. It tells downstream systems exactly which source
series, seasonal adjustment basis, price basis, and selector combination produced the rows in data[].
Field
Type
Meaning
currency, indicator, name, value_name
String
Identity fields for the requested currency and indicator.
Official source metadata. source_url is optional; when present, source_url_scope identifies it as an exact release, broader dataset, or underlying series link. source_series_id is the audit key customers should store when comparing variants.
seasonal_adjustment
Enum
SA, NSA, UNKNOWN, or NOT_APPLICABLE. This field makes SA/NSA comparability explicit.
price_basis
Enum
REAL, NOMINAL, or UNKNOWN. This distinguishes inflation-adjusted series from current-price series.
filters
Object
Echoes the selector parameters that were applied to the response.
selected_series_id, selected_series
String, object
The resolved source-series variant. Use this for audit logs and stable downstream joins.
supported_options
Object
Lists valid selector values for this endpoint. Build client dropdowns from this object rather than assuming every indicator supports every value.
pagination
Object
Contains limit, offset, returned_count, total_count, has_more, next_offset, and page_includes_latest_available.
Coverage and requested-window dates for the selected series.
requested_start_date, requested_end_date
Date string
The effective date window used for the request after endpoint defaults are resolved.
requested_window_has_data
Boolean
False when the response returns the latest eligible observation before the requested window rather than an observation inside the window.
page_includes_latest_available
Boolean
True when the current page contains latest_available_date. Also mirrored in pagination.page_includes_latest_available.
data_quality
Object
Standardized source, freshness, fallback/proxy, timestamp-completeness, and point-in-time safety diagnostics. Announcement endpoints may also add requested-window and pagination flags.
provenance
Object
Machine-readable provenance such as storage layer, timestamp field, value field, source URL, and source series ID.
Additional comparability fields used on policy-rate or proxy-backed series where relevant.
Source-link availability
A supported indicator does not guarantee an exact official release permalink on every row. Display source_url only when present and use source_url_scope to label its precision honestly. If your product requires an exact BLS, BEA, central-bank, or other agency release link for every event, probe the required series before launch and provide a clear unavailable state.
Data quality
Quality flags are standardized across source-backed endpoints.
Use data_quality before treating a payload as analysis-ready. It describes the whole requested window,
not the current page, so the same object is returned for every page of one query.
point_in_time_safe is true when no row in that window can surface earlier than it was actually public.
Official release calendars do not reach the full length of most macro series. Where a calendar stops, the publication
timestamp is derived from the largest publication lag and the latest release clock that same series has shown,
snapped to a valid trading day, and the row is flagged release_time_assumed. Because that bound is the
slowest release the series has ever produced, a derived row cannot appear before the real one did, and it does not
clear point_in_time_safe. Those rows also carry release_time_upper_bound.
A derived timestamp is still not an observed one: it is calibrated, not exact, and it is deliberately late rather
than early. Read assumed_release_time_count against row_count to size how much of the window
is derived, and gate per row on release_time_assumed when a study needs captured timestamps only.
point_in_time_safe still goes false when a row has no timestamp at all, or when its timestamp predates
the upper-bound rule and may land early; unbounded_release_time_count counts those. For reporting, also
store source_type, source_name, latest_available_date, and the fallback/proxy
flags.
Worked example:/v1/announcements/usd/inflation over its full history returns
row_count 1349 with assumed_release_time_count 997. Those 997 rows are dated from the
slowest release this series has shown, so none of them can appear early and the response stays point-in-time safe.
The count is what tells you how much of the window is calibrated rather than captured; gate on
release_time_assumed if your study needs only the 352 captured rows.
A missing timestamp and a derived timestamp both clear point_in_time_safe. The two counts separate them: missing_announcement_datetime_count is rows with no publication time, assumed_release_time_count is rows whose publication time was derived.
Observation rows
Each row states how its publication time was established.
Required row fields
announcement_iddateval
date is the economic period, while announcement_datetime is when the value became known to the market.
Backtests should gate on the announcement timestamp, not the period date. release_time_assumed is present and true only when that timestamp was derived from the series' measured publication lag rather than captured from the release; a captured row omits the field.
These fields refer to the preceding observation in the selected chronological series when one is available. They are distinct from revisions to the current observation.
Revision fields
revisions[]epochval
Full latest and all responses preserve eligible captures and source vintages, including equal values with different clocks or artifacts. all keeps the stored head value; latest may adopt a newer eligible entry. Page through the complete history and preserve accepted downloads. This retained ledger does not certify every publisher revision.
Flagged incorrect source captures remain available for audit with value_mode=source&series_mode=raw&revisions=all; they are excluded from economic selection. fields=compact is a presentation summary and must not replace a consumer's retained capture history.
capture_time_basis describes a capture clock when one exists. A basis label without observed_at_ns does not supply the missing time. Preserve unknown publication timing and missing capture clocks without synthesizing either.
publication_time_basis=official_schedule identifies a planned instant, not confirmed publication. In release_timing, published_at is the observed upper publication bound, picked_up_at is accepted capture, and available_at is store commit. Null latency fields mean insufficient measurement. The SLO is a threshold, not a measurement or proof that it was met. The legacy latency diagnostic remains optional with its original reference.
source identifies the publisher when known. source_url_scope distinguishes a period-specific release from a rolling dataset or series page. A valid release citation may improve over time; the URL is not an immutable identifier or publication clock. Retain individual revision citations and artifact hashes for audit.
Sample payload
USD GDP real-basis response shape.
Values below are illustrative of the contract. Always read supported_options from the live response
before requesting a non-default variant.
Call the canonical endpoint first, inspect supported_options, then request only the variant needed by the application. Store source_series_id, seasonal_adjustment, and price_basis with downstream observations.
Pagination flow
Read pagination.has_more and request the next page with offset=pagination.next_offset. Use page_includes_latest_available to know whether the latest observation is on the current page.
Design rule: there is no public "return all series variants" selector. Customers choose one series variant per request, which keeps responses predictable and prevents large repeated pulls of slow-moving macro history.
Errors and compatibility
What changes for existing users.
Additive v1 change
Existing calls such as /v1/announcements/usd/inflation continue to work. New metadata fields are additive, so clients should ignore unknown fields they do not use.
Selector errors
400 unsupported_series_option means the selector value is valid globally but not available for that specific currency and indicator. Read supported_options and retry.
Auth and limits
401 or 403 indicates missing or insufficient API access. 429 indicates rate limiting. Send your key in the X-API-Key: YOUR_API_KEY request header.
Missing data
A plain availability 404 means the requested currency, indicator, or selected series is not published. Use the coverage pages or /v1/data_catalogue/{currency} to check availability.
No rows in window
200 with data: [] and a no_data object (error_code=NO_DATA_IN_REQUESTED_WINDOW) means the series exists but the requested date range has no observations. Use latest_available_date or no_data.recommended_start_date, or broaden the date window. This is not an error and does not need a retry.
Client parsing: do not assume every row has every derived field. GDP may expose pct_change_qoq and pct_change_yoy; monthly inflation may expose val_mom; some level series have no meaningful change field.