Skip to Content
API ReferenceObservationsList observations

Observations

GET /v1/observations returns time-series rows for an indicator and optional region. This endpoint requires an API key or x402 payment.

Request

curl "https://api.creativeforesight.io/v1/observations?indicator=UNRATE&region=US&limit=12" \ -H "Authorization: Bearer $CF_API_KEY"

Query parameters

ParameterTypeRequiredDescription
indicatorstringYesIndicator code, such as UNRATE or cf:labor_composite.
sourcestringNoSource slug for duplicate provider codes.
regionstringNoRegion code. Uses the indicator default region when omitted.
start_datedateNoInclusive lower date bound.
end_datedateNoInclusive upper date bound.
include_revisionsbooleanNoInclude revision history instead of only latest revisions. Defaults to false. Cannot combine with transform.
transformstringNoQuery-time transform: yoy, mom, qoq, index:YYYY-MM-DD, or log. See Transforms.
frequencystringNoDownsample to monthly, quarterly, or annual calendar buckets. See Resampling.
resample_methodstringNoBucket aggregation: mean (default), last, or sum. Requires frequency.
limitintegerNoPage size, 0 to 1000. Defaults to 100.
offsetintegerNoPage offset. Defaults to 0.
orderasc or descNoSort order. Defaults to desc.

Observation object

FieldTypeDescription
datedateObservation date.
valuenumber or nullNumeric value.
indicatorstringIndicator code.
regionstringRegion code.
unitstring or nullUnit label.
sourcestring or nullSource slug.
source_updated_atdate-time or nullProvider update timestamp.
is_preliminarybooleanWhether the row is preliminary.
revisionintegerRevision number.

Response

{ "data": [ { "date": "2026-05-01", "value": 4.2, "indicator": "UNRATE", "region": "US", "unit": "percent", "source": "fred", "source_updated_at": "2026-06-06T12:00:00.000Z", "is_preliminary": false, "revision": 0 } ], "meta": { "indicator": "UNRATE", "region": "US", "unit": "percent", "total": 1, "limit": 12, "offset": 0 } }

Transforms

Add transform= to get derived values without post-processing:

TransformResultUnit
yoyPercent change vs the same period one year earlier.percent
momPercent change vs the previous period.percent
qoqPercent change vs the previous quarter (quarterly series only).percent
index:YYYY-MM-DDValues rescaled so the base date equals 100.index (BASE=100)
logNatural log of each value.log(unit)
curl "https://api.creativeforesight.io/v1/observations?indicator=UNRATE&region=US&transform=yoy" \ -H "Authorization: Bearer cf_live_REPLACE_ME"

Percent changes compare calendar periods, not row positions: a row whose comparator period is missing from the series — or falls outside the requested date window or page — returns null rather than a misleading number. The response meta.unit reflects the transform and meta.transform echoes what was applied. yoy is unavailable on daily series at their native frequency — add frequency=monthly to get monthly year-over-year from daily data. transform cannot combine with include_revisions.

Resampling

Add frequency= to downsample a series to calendar buckets before any transform runs:

curl "https://api.creativeforesight.io/v1/observations?indicator=DGS2&frequency=monthly&transform=yoy" \ -H "Authorization: Bearer cf_live_REPLACE_ME"

Buckets are labeled by their calendar start date (2026-07-01 for July, Q3, or 2026) and aggregated with resample_method — mean (default), last, or sum. Resampled rows are synthetic aggregates carrying only period_start, period_end, period_type, and value; per-row fields like revision don’t survive aggregation. Requesting a series’ own native frequency returns it unchanged.

Two honesty rules protect you from partial buckets: a trailing bucket the source hasn’t finished (say, July from daily data that ends July 14th) is dropped rather than served as if complete, and when a page is truncated by limit/offset, the buckets at the truncated edges are dropped because they may be missing source rows. meta.resample reports the method, the source and target frequencies, and both kinds of drops. Prefer start_date/end_date windows over pagination when resampling — a full window has no truncated edges.

Paying per request (x402 or Lightning)

Unauthenticated calls return HTTP 402 with two ways to pay:

  • x402 (USDC on Base): the JSON body’s accepts describes the payment; retry with X-PAYMENT.
  • Lightning (L402): the WWW-Authenticate header carries a macaroon and a bolt11 invoice. Pay the invoice from any Lightning wallet, then retry the same request with Authorization: L402 <macaroon>:<preimage> (your wallet shows the preimage after paying). The macaroon covers the requested indicator for 10 minutes.

Either proof settles the request.

Errors

StatusCodeMeaning
400INVALID_PARAMETERRequired or optional query parameters are invalid.
401INVALID_API_KEYThe request did not include a valid API key and was not a settled x402 request.
404RESOURCE_NOT_FOUNDThe requested indicator or region was not found.
429RATE_LIMIT_EXCEEDEDThe API key exceeded its one-minute request limit.
500INTERNAL_SERVER_ERRORObservation data could not be loaded.
Last updated on