Skip to main content
Observations are the heart of Conduit. An observation is a single value a series describes for a single period: May 2026 US CPI, the latest UK policy rate, last quarter’s German GDP growth. Every observation carries the value, its unit and period, a freshness label, source attribution, and a link to its full provenance chain. This guide covers the four observation endpoints, the filters they share, the two time axes that make Conduit point-in-time, and the fields you get back.

Public observations

/v1/public/observations and /v1/public/observations/latest return only redistribution-safe official and public-domain data. Start here.

Full observation surface

/v1/observations, /v1/observations/latest, and /v1/observations/changes add attribution, rights metadata, and revision tracking for a data:read key.

The four endpoints

GET /v1/public/observations

Time series of public observations across vintages, by Conduit canonical indicator IDs. Paginated.

GET /v1/public/observations/latest

The single latest public reading per canonical indicator. The fastest way to get “where are things now.”

GET /v1/observations

The full observation surface: every series, with source attribution, freshness, and rights metadata inline.

GET /v1/observations/changes

Observations that changed (new prints and revisions), for incremental sync.
/v1/observations/latest is the latest-per-series counterpart of /v1/observations, exactly as /v1/public/observations/latest is to /v1/public/observations.
The /v1/public/* surface returns only redistribution-safe official and public-domain data. Licensed vendor and market price data is classified internal_only and never appears on /v1/public. If you are unsure which surface to use, prefer /v1/public/*.

Quickstart

Get the latest US CPI inflation reading. All requests go to https://data.quantoraresearch.com and send your key in the x-api-key header.
curl -s "https://data.quantoraresearch.com/v1/public/observations/latest?country=USA&indicator=cpi_inflation_yoy" \
  -H "x-api-key: $CONDUIT_API_KEY"
A public observation looks like this:
{
  "data": [
    {
      "observationId": "obs_bls_cpi_us_2026_05",
      "indicatorId": "cpi_inflation_yoy",
      "indicatorName": "CPI inflation, year over year",
      "category": "inflation",
      "country": "USA",
      "currency": "USD",
      "actual": 3.1,
      "previous": 3.4,
      "forecast": 3.2,
      "consensus": 3.2,
      "surprise": -0.1,
      "unit": "percent",
      "frequency": "monthly",
      "importance": "high",
      "period": "2026-05",
      "periodEnd": "2026-05-31",
      "releaseDate": "2026-06-10T12:30:00.000Z",
      "observedAt": "2026-05-31",
      "retrievedAt": "2026-06-10T12:31:00.000Z",
      "revised": false,
      "vintage": "2026-06-10",
      "freshnessStatus": "fresh",
      "sourceUrl": "https://www.bls.gov/cpi/",
      "attribution": "U.S. Bureau of Labor Statistics",
      "provider": "U.S. Bureau of Labor Statistics",
      "sourceId": "source_bls_public_api",
      "rawAvailable": true,
      "preferredForFactor": true
    }
  ],
  "meta": {
    "api_version": "v1",
    "pagination": { "limit": 100, "cursor": null, "next_cursor": null, "has_more": false }
  },
  "requestId": "c96e85f1-4c3e-40d1-b4b3-d9ca8c580ebf"
}

Observation fields

These are the fields on a public observation. The /v1/observations surface returns a richer record with raw value fields (valueNumeric, valueText), source and provider IDs, the full rights object, and revision status; see The full observation surface below.
observationId
string
Stable ID for this observation. Pass it to /v1/provenance/observations/{observationId} for the full source chain.
indicatorId
string
Conduit canonical indicator slug, for example cpi_inflation_yoy. Use this to query and join across countries.
indicatorName
string
Human-readable indicator name.
category
string
Indicator family, for example inflation, labor, rates, growth.
country
string
ISO 3166-1 alpha-3 country code, for example USA, GBR, JPN. Null for instrument-keyed series.
currency
string
Currency context for the reading, where applicable.
actual
number
The headline numeric value of the reading.
previous
number
The prior-period value. revisedPrevious and previousType describe whether the prior was revised.
forecast
number
Forecast or consensus expectation for the release, where one exists. consensus, surprise, and surprisePercent accompany it.
unit
string
Unit of the value, for example percent, index, USD.
frequency
string
Publication cadence: daily, weekly, monthly, quarterly, or annual.
importance
string
Indicator importance: low, medium, or high.
period
string
Label for the period the value describes, for example 2026-05 or a start/end range.
periodEnd
string
End of the described period (YYYY-MM-DD). This is the value’s place on the period axis.
releaseDate
string
When the source officially released the value, where known (ISO 8601).
observedAt
string
The point on the period axis the value is observed at.
retrievedAt
string
Knowledge-time: when Conduit ingested the value (ISO 8601).
revised
boolean
True if this observation is a revision of a previously published value.
vintage
string
Vintage date of the value. Revisions are retained as separate vintages, never overwritten.
freshnessStatus
string
Freshness label: fresh, stale, or unknown. Computed against a per-frequency age gate, independent of any source self-report.
sourceUrl
string
The official source URL for the series.
attribution
string
Required attribution string for the source, for example U.S. Bureau of Labor Statistics.
provider
string
The provider name behind the source.
sourceId
string
Conduit source identifier. Use it in the source_id filter.
rawAvailable
boolean
Whether a raw payload reference is exposed for this observation through the provenance endpoint.
preferredForFactor
boolean
Within a response, marks the single best row for a given (country, indicator): the highest-quality, most-comparable, most-recent reading. Use it to dedupe when a fallback and an official series both appear.

Filters

All four observation endpoints accept the same filter set. Combine filters freely; they are AND-ed. Unknown query parameters are rejected with bad_request (Conduit fails closed rather than silently ignoring typos).

Identity filters

FilterDescription
countryISO alpha-3 country code, for example USA, GBR.
indicator / indicator_idCanonical indicator slug, for example cpi_inflation_yoy.
entityResolve an entity by id, slug, name, ticker, CIK, LEI, FIGI, ISIN, or CUSIP.
entity_idExact Conduit entity id, for example country_usa.
source_idConduit source id, for example source_bls_public_api.
provider_id / providerConduit provider id or name.

Shape filters

FilterValuesDescription
frequencydaily, weekly, monthly, quarterly, annualPublication cadence.
currencyISO currency codeFilter by currency context.
importancelow, medium, highIndicator importance.
freshnessfresh, stale, unknownKeep only readings with a given freshness label.
typemacroRestrict to macro observations.
numeric_onlybooleanDrop rows that carry no numeric value.

Time filters

Conduit is bi-temporal. Two independent axes describe every value. Mixing them precisely is what makes the data point-in-time.
The period is the calendar window a value is about: May 2026 CPI, Q1 2026 GDP.
FilterDescription
periodConvenience filter accepting YYYY, YYYY-MM, or YYYY-Qn.
period_startLower bound on the described period (YYYY-MM-DD).
period_endUpper bound on the described period (YYYY-MM-DD).
as_of currently approximates the ingestion timestamp, not full provider-vintage reconstruction. Revisions are retained and never overwritten, so you can see the revision history, but reconstructing the exact value a provider published at an arbitrary historical instant is future work. Treat as_of as “what Conduit knew by this time,” not “what the provider had published by this time.”

Pagination and sorting

ParamDefaultDescription
limit100Page size, 1 to 500.
cursornoneOpaque cursor from meta.pagination.next_cursor.
sortendpoint defaultField to sort by, where supported.
orderascasc or desc.
Follow next_cursor while meta.pagination.has_more is true. The TypeScript SDK does this for you with paginate().

Worked examples

# Full vintage history of US CPI inflation, oldest first
curl -s "https://data.quantoraresearch.com/v1/public/observations?country=USA&indicator=cpi_inflation_yoy&period_start=2020-01-01&order=asc&limit=500" \
  -H "x-api-key: $CONDUIT_API_KEY"

Paginate a long series

import os, requests

BASE = "https://data.quantoraresearch.com"
HEADERS = {"x-api-key": os.environ["CONDUIT_API_KEY"]}

def all_observations(**params):
    params = {"limit": 500, **params}
    cursor = None
    while True:
        page = requests.get(
            f"{BASE}/v1/public/observations",
            headers=HEADERS,
            params={**params, "cursor": cursor},
        ).json()
        yield from page["data"]
        pagination = page["meta"]["pagination"]
        if not pagination["has_more"]:
            break
        cursor = pagination["next_cursor"]

rows = list(all_observations(country="GBR", indicator="cpi_inflation_yoy"))
print(len(rows), "observations")

The full observation surface

/v1/observations, /v1/observations/latest, and /v1/observations/changes require a data:read key and return a richer record than /v1/public/*. The same filters apply. The shape uses raw value fields and inline rights:
{
  "id": "obs_bls_cpi_us_2026_05",
  "entityId": "country_usa",
  "indicatorId": "indicator_cpi",
  "sourceId": "source_bls_public_api",
  "providerId": "provider_bls",
  "valueNumeric": 0.4,
  "valueText": null,
  "unit": "percent",
  "frequency": "monthly",
  "periodStart": "2026-05-01",
  "periodEnd": "2026-05-31",
  "observedAt": "2026-05-31",
  "releasedAt": "2026-06-10T12:30:00.000Z",
  "ingestedAt": "2026-06-10T12:31:00.000Z",
  "vintageDate": "2026-06-10",
  "revisionStatus": "initial",
  "sourceUrl": "https://www.bls.gov/cpi/",
  "attribution": "U.S. Bureau of Labor Statistics",
  "freshnessStatus": "fresh",
  "rights": {
    "exposureClass": "public",
    "redistributionAllowed": "allowed",
    "rawPayloadExposure": "restricted"
  }
}
Every observation carries a rights object whose exposureClass is one of public, internal_only, restricted, or blocked. Raw provider payload bodies are never exposed by the API; verbatim bodies from sources marked internal_only, or with redistributionAllowed set to blocked, are redacted even on this data:read surface.

Incremental sync with /changes

/v1/observations/changes returns new prints and revisions, so you can pull only what moved since your last sync rather than re-fetching whole series. Bound it on the knowledge axis with start_date and end_date.
# Everything that changed after a watermark timestamp
curl -s "https://data.quantoraresearch.com/v1/observations/changes?start_date=2026-06-10T00:00:00Z&order=asc&limit=500" \
  -H "x-api-key: $CONDUIT_API_KEY"

Provenance

Every observation traces back to an official release. Pass an observationId to the provenance endpoint for the named source, source URL, raw payload reference metadata, and the ingestion run.
curl -s "https://data.quantoraresearch.com/v1/provenance/observations/obs_bls_cpi_us_2026_05" \
  -H "x-api-key: $CONDUIT_API_KEY"

Freshness and liveness

Each observation carries a freshnessStatus of fresh, stale, or unknown, set by a per-frequency age gate: a monthly series that has not printed in roughly 2.5 months is flagged stale, quarterly series get a wider budget to account for publication lag, and non-periodic rows return unknown. Pass freshness=fresh to drop anything behind its cadence. For feed-level health rather than per-row freshness, a per-series liveness check at GET /v1/ops/liveness (requires ops:read) flags silently-frozen feeds across connectors.

Errors and rate limits

Non-2xx responses share one envelope with a stable, machine-readable code.
CodeStatusMeaning
bad_request400Malformed query, or an unknown query parameter.
unauthorized401Missing or invalid API key.
forbidden403Key lacks the required scope.
not_found404Resource does not exist.
rate_limited429Rate limit exceeded; see details.
internal_error500Unexpected server error.
Every /v1 response includes x-ratelimit-policy, x-ratelimit-limit, x-ratelimit-remaining, and x-ratelimit-reset (ISO) headers. The default data:read budget is 1000 requests per 60-second window. On exceed you get 429 rate_limited with details carrying required_scope, limit, and window_seconds.

Next steps

Indicators, entities, and countries

Discover the catalog of indicators, resolve entities by ticker or CIK, and list what each country covers.

Macro screener

Filter countries by the latest values of canonical indicators with a compact filter DSL.