Skip to content

Macro series and latest values

Three endpoints cover the time-series store: a catalogue (/v1/series), the observations of one series (/v1/series/{series_id}) and the newest value of many series at once (/v1/latest). The catalogue currently lists 693 series: Türkiye, Russia, EU, one China and one US series, with daily, weekly, monthly, quarterly and annual frequencies. For what each id means and its unit, see Series ids and units.

GET /v1/series

Searches the catalogue. Use it to find the id you need, then fetch the data with the other two endpoints.

curl -s -H "Authorization: Bearer $TRRU_KEY" -G "https://trru.atapinar.com/v1/series" \
  --data-urlencode "search=policy rate" --data-urlencode "country=RU"
Parameter Type Default Meaning
search string empty Case-insensitive substring match on the series id, the Turkish name (name_tr) or the English name (name_en). % and _ are matched literally.
country string empty Country code, exact match after upper-casing: TR, RU, EU, CN, US.
category string empty Category, exact match after lower-casing. Values in use include rates, fx, prices, expectations, reserves, markets, macro, fiscal, trade, energy, tourism, transport, aviation, payments, real_estate, consumption, business, companies, logistics, construction, labour, activity, external.

All three filters combine with AND. With no filters you get the whole catalogue (693 rows at the time of writing), ordered by country, category, series id. The list is not paginated and is cut at 2000 rows, which the catalogue is far below.

Example response

Request: GET /v1/series?search=policy%20rate&country=RU

{
  "data": {
    "rows": [
      {
        "series_id": "ru.policy_rate_bis",
        "name_tr": "Rusya MB politika faizi (BIS, aylık)",
        "name_en": "Bank of Russia policy rate (BIS, monthly)",
        "unit": "%",
        "frequency": "monthly",
        "country": "RU",
        "category": "rates",
        "first_obs": "2015-01-01",
        "last_obs": "2026-09-01",
        "source_id": "evds"
      }
    ],
    "row_count": 1,
    "truncated": false
  },
  "meta": {
    "sources": [
      { "source_id": "evds", "fetched_at": "2026-11-13T17:30:29.379365+00:00", "as_of": "2026-09-01" }
    ],
    "request_id": "469f72f2464243f7856b5e1a4edb6828",
    "truncated": false
  }
}

Field notes

Field Meaning
series_id Stable id used in the other endpoints, for example ru.key_rate, tr.exports_to.ru.usd.
name_tr, name_en Turkish and English names. Both are filled for every series today.
unit Unit string such as %, USD, RUB. Read it before comparing series.
frequency daily, weekly, monthly, quarterly or annual.
first_obs, last_obs First and last observation date held. For monthly data the date is the first day of the month.
source_id Where the series comes from. Match it against /v1/sources.

Similar ids

ru.policy_rate_bis is the BIS monthly series. The Bank of Russia's own daily key rate is ru.key_rate. When two series look alike, compare source_id, frequency and last_obs.

GET /v1/series/{series_id}

Returns observations of one series in long format, oldest first.

curl -s -H "Authorization: Bearer $TRRU_KEY" \
  "https://trru.atapinar.com/v1/series/ru.key_rate?start=2026-10-01"
Parameter Type Default Meaning
series_id (path) string required One series id. Only one id per call; for several series call /v1/latest or repeat the request.
start date empty First observation date to include (YYYY-MM-DD, inclusive).
end date empty Last observation date to include (inclusive).
resample string empty Empty for raw observations, or week, month, quarter, year. Any other value returns 400 resample must be '', week, month, quarter or year.

Row cap and truncation

A response holds at most 2000 rows. Rows are ordered by date ascending, so when a series is longer than the cap you get its oldest 2000 observations and truncated is true (both in data and in meta). Example: ru.key_rate without any parameters is a daily series with more than 2000 rows, so the call returns data starting in 2015 and ending long before today.

To read the recent part of a long series, set start, or resample:

# last 30 days of a daily series
curl -s -H "Authorization: Bearer $TRRU_KEY" \
  "https://trru.atapinar.com/v1/series/ru.key_rate?start=2026-10-15"

# one value per month
curl -s -H "Authorization: Bearer $TRRU_KEY" \
  "https://trru.atapinar.com/v1/series/ru.key_rate?resample=month&start=2026-01-01&end=2026-03-31"
body = get("/v1/series/ru.key_rate", resample="month", start="2026-01-01", end="2026-03-31")
for row in body["data"]["rows"]:
    print(row["period"], row["obs_date"], row["value"])
if body["meta"]["truncated"]:
    print("result was cut at 2000 rows: narrow start/end")
const body = await get("/v1/series/ru.key_rate", { resample: "month", start: "2026-01-01", end: "2026-03-31" });
for (const row of body.data.rows) console.log(row.period, row.obs_date, row.value);
if (body.meta.truncated) console.log("result was cut at 2000 rows: narrow start/end");

Raw example

Request: GET /v1/series/ru.key_rate?start=2026-10-01. The real response has row_count 31; the rows list is trimmed here to the first three.

{
  "data": {
    "rows": [
      { "series_id": "ru.key_rate", "obs_date": "2026-10-01", "value": 14.0 },
      { "series_id": "ru.key_rate", "obs_date": "2026-10-02", "value": 14.0 },
      { "series_id": "ru.key_rate", "obs_date": "2026-10-05", "value": 14.0 }
    ],
    "row_count": 31,
    "truncated": false
  },
  "meta": {
    "sources": [
      { "source_id": "cbr", "fetched_at": "2026-11-13T17:30:30.332163+00:00", "as_of": "2026-11-13" }
    ],
    "request_id": "d6ad2bac8fbe490497fee29ce822951b",
    "truncated": false
  }
}

Resampled example

Request: GET /v1/series/ru.key_rate?resample=month&start=2026-01-01&end=2026-03-31 (live response, meta omitted).

{
  "data": {
    "rows": [
      { "series_id": "ru.key_rate", "period": "2026-01-01", "obs_date": "2026-01-30", "value": 16.0 },
      { "series_id": "ru.key_rate", "period": "2026-02-01", "obs_date": "2026-02-27", "value": 15.5 },
      { "series_id": "ru.key_rate", "period": "2026-03-01", "obs_date": "2026-03-31", "value": 15.0 }
    ],
    "row_count": 3,
    "truncated": false
  }
}

Field notes

Field Meaning
series_id Echo of the id.
obs_date Date of the observation. For monthly data, the first of the month. In a resampled response it is the date of the last observation inside the period.
period Only with resample: the first day of the week, month, quarter or year the row represents.
value Number in the unit given by the catalogue.

Resampling takes the last value in each period; it does not average or sum. That suits rates and index levels, not flows such as monthly trade totals (for flows, use the raw monthly series). meta.sources[].as_of is the newest obs_date returned.

Edge cases

  • An unknown id is not an error: the response is 200 with "rows": [], "row_count": 0 and an empty meta.sources. Check the id against /v1/series.
  • start or end in another format (2026/01/01, 01.01.2026) returns 400 start/end must be YYYY-MM-DD.
  • start later than end returns an empty list.

GET /v1/latest

Newest observation per series, with the series name, unit and frequency. One call replaces many /v1/series/{id} requests for a dashboard.

curl -s -H "Authorization: Bearer $TRRU_KEY" \
  "https://trru.atapinar.com/v1/latest?ids=ru.key_rate,tr.exports_to.ru.usd"
Parameter Type Default Meaning
ids comma-separated string empty Series ids. Spaces and empty items are ignored. Empty (or only blanks and commas) returns all series, currently 693 rows; use it deliberately.

Rows are ordered by series_id.

Example response

Request: GET /v1/latest?ids=ru.key_rate,tr.exports_to.ru.usd,no.such.series

{
  "data": {
    "rows": [
      {
        "series_id": "ru.key_rate",
        "name_tr": "Rusya MB politika faizi (key rate)",
        "unit": "%",
        "frequency": "daily",
        "as_of": "2026-11-13",
        "value": 14.0,
        "source_id": "cbr"
      },
      {
        "series_id": "tr.exports_to.ru.usd",
        "name_tr": "Türkiye'nin Rusya'a ihracatı (TİM konsolide)",
        "unit": "USD",
        "frequency": "monthly",
        "as_of": "2026-10-01",
        "value": 457415414.52000004,
        "source_id": "tim"
      }
    ],
    "row_count": 2,
    "truncated": false,
    "missing": ["no.such.series"]
  },
  "meta": {
    "sources": [
      { "source_id": "cbr", "fetched_at": "2026-11-13T17:30:30.332163+00:00", "as_of": "2026-11-13" },
      { "source_id": "tim", "fetched_at": "2026-11-13T09:45:38.503380+00:00", "as_of": "2026-10-01" }
    ],
    "request_id": "c0fe592822fd47a58478944330f7cb42",
    "truncated": false
  }
}

Unknown ids

no.such.series was in the request and is absent from rows; the response is still 200. When you pass ids, data.missing lists the requested ids that are not registered series (an empty list when all exist). missing is left out when ids is empty (all series are returned).

Check data.missing

A row that is absent from rows is not "no change". Ids listed in data.missing do not exist as series (typo, renamed id). An id that exists but has no observation is in neither list.

wanted = ["ru.key_rate", "tr.exports_to.ru.usd", "no.such.series"]
body = get("/v1/latest", ids=",".join(wanted))
missing = body["data"].get("missing", [])  # ["no.such.series"]

Field notes

Field Meaning
as_of Date of the latest observation of that series (monthly series: first of the month). Different series have different as_of; this is the data date, not the fetch time.
value Latest value, in unit.
name_tr Turkish series name. English names are in /v1/series.
meta.sources[].fetched_at When that source was last refreshed successfully. Compare with as_of to tell "no new data yet" from "the refresh failed": see /v1/sources/freshness.

Tips

  • Cache the catalogue. It changes rarely; the values change daily.
  • For a bulletin, call /v1/latest?ids=... once, then /v1/series/{id}?start=... only for the series you chart.
  • Never hardcode an old as_of: print it next to every number you publish.