Exchange Rates Scraper — ECB & National Bank of Kazakhstan FX avatar

Exchange Rates Scraper — ECB & National Bank of Kazakhstan FX

Pricing

from $0.14 / 1,000 result items

Go to Apify Store
Exchange Rates Scraper — ECB & National Bank of Kazakhstan FX

Exchange Rates Scraper — ECB & National Bank of Kazakhstan FX

Fiat exchange rates for AI agents: ECB reference rates for 30 currencies plus official National Bank of Kazakhstan rates for KZT, RUB, UZS, KGS, AED and 40+ more. Latest, historical date, daily time series since 1999, conversion, 1d/7d/30d/YTD changes, wide/long output. No API key.

Pricing

from $0.14 / 1,000 result items

Rating

0.0

(0)

Developer

Samat Makatov

Samat Makatov

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

10 days ago

Last modified

Share

Clean fiat exchange rates for AI agents, finance bots and back-office automations. Two official sources in one Actor: European Central Bank reference rates (30 currencies, daily since 1999, via Frankfurter) and the National Bank of Kazakhstan official rates (KZT plus RUB, UZS, KGS, AED, SAR, GEL and 40+ more as KZT crosses). Latest rates, one historical date, daily time series, conversion of an amount and 1d/7d/30d/YTD changes — with warnings instead of silent gaps when a currency is not covered. No API key, no proxy, no browser.

Use cases

  • Accounting & invoicing — official ECB / NBK rate for a given invoice date (mode: date) for KZ, EU and US bookkeeping.
  • FX monitoring & alerts — schedule latest with includeChanges and alert when USD/KZT or EUR/USD moves more than X % in a day.
  • Pricing engines — daily refresh of the full rate table (format: wide) for multi-currency price lists.
  • Analytics / backtests — daily history of any ECB pair since 1999 (one pair is ~7,000 rows: set maxItems above that) or NBK pair for up to a year per run.
  • Treasury reporting — convert cash balances (mode: convert, amount) at the official rate of a month-end date.
  • Agent tools — one MCP/API call that answers "what is 2 500 USD in KZT today and how did the rate move this month?".

Input

FieldTypeDefaultAllowed values / notes
modestringlatestlatest, date, history, convert, currencies
basestringUSDISO 4217 code, upper or lower case; must be quoted by the chosen source (see Reference). Ignored when pairs is set
symbolsstring[][] = all of the sourceISO codes; unsupported ones are reported, not dropped
pairsstring[]—USD/KZT, EUR/USD, USDKZT… several bases in one run; overrides base/symbols
sourcestringautoauto (ECB, NBK for what ECB lacks), ecb, nbk
datestringlatestYYYY-MM-DD (a real calendar date), modes date/convert. ECB returns the last business day ≤ date
startDatestringendDate − 30 dYYYY-MM-DD, mode history
endDatestringtodayYYYY-MM-DD, mode history. NBK history: the last 366 days of the range per run, up to tomorrow's rate
amountstring"1"Amount of base to convert (mode convert): "2500", "2 500.75", "1,000,000"; a single decimal comma ("2,5") means 2.5. Anything else stops the run before any request
includeChangesbooleanfalseAdds change1dPct, change7dPct, change30dPct, changeYtdPct (latest/date/convert, format long)
includeInversebooleanfalseAdds inverseRate = 1 / rate (format long)
formatstringlonglong (row per date × currency) or wide (row per date, currencies as columns; rates only)
fieldsstring[]all columnsKeep only these columns, in this order; id is always kept. Columns: see Output. Case, spaces, _ and - do not matter; a name that is not a column of the run is skipped and named in SUMMARY.warnings; if none is a column, the run stops before any request with the list of columns
decimalsintegerraw0–10, rounds rate/inverseRate
maxItemsinteger50001–100 000 dataset rows (format wide: one per date). The cut falls on a whole date, oldest dates first — see Limits
strictbooleanfalseFail the run before any request if any requested currency is unsupported

mode, source and format are fixed lists (values above): Apify refuses any other value before the run starts, with the list of allowed values. Currency codes and pairs are free text: upper or lower case, and pairs as USD/KZT, USD-KZT or USDKZT.

Reference

Sources

sourcePublisherCurrenciesFrequencyHistoryNotes
ecbEuropean Central Bank euro reference rates, served by Frankfurter30business days, ~16:00 CETsince 1999-01-04cross rates via EUR; no KZT/RUB
nbkNational Bank of Kazakhstan official rates48 vs KZT (+KZT)daily, published the day before1990s onwardsnon-KZT pairs are KZT cross rates; one request per day of history

ECB set (30)

AUD, BRL, CAD, CHF, CNY, CZK, DKK, EUR, GBP, HKD, HUF, IDR, ILS, INR, ISK, JPY, KRW, MXN, MYR, NOK, NZD, PHP, PLN, RON, SEK, SGD, THB, TRY, USD, ZAR

NBK set (48 + KZT)

AED, AMD, AUD, AZN, BRL, BYN, CAD, CHF, CNY, CZK, DKK, EGP, EUR, GBP, GEL, HKD, HUF, IDR, ILS, INR, IRR, JPY, KGS, KRW, KWD, MDL, MNT, MXN, MYR, NOK, OMR, PKR, PLN, QAR, RON, RUB, SAR, SEK, SGD, THB, TJS, TRY, UAH, USD, UZS, VND, XDR, ZAR — and KZT as base or quote.

Run {"mode":"currencies"} to get this dictionary as a dataset (code, name, ecb, nbk).

Routing in source: auto

PairSource used
both codes in ECB set (EUR/USD, USD/JPY, GBP/CHF…)ECB
any side is KZT or an NBK-only code (USD/KZT, KZT/RUB, EUR/UZS, USD/AED…)NBK
code in neither setwarning Not available…, listed in SUMMARY.warnings; strict: true fails the run

Examples

Daily FX table for a price list (all ECB currencies, one row per day)

{ "base": "EUR", "mode": "history", "startDate": "2026-08-01", "endDate": "2026-08-31", "format": "wide" }

USD/KZT alert feed with momentum

{ "pairs": ["USD/KZT", "EUR/KZT", "RUB/KZT"], "includeChanges": true, "includeInverse": true, "decimals": 4 }

Official rate for an invoice dated 20 March 2020 (EU and KZ books)

{ "mode": "date", "date": "2020-03-20", "pairs": ["EUR/USD", "USD/KZT"] }

Convert a treasury balance

{ "mode": "convert", "base": "USD", "symbols": ["KZT", "EUR", "GBP"], "amount": "250000" }

Tenge history for a backtest (NBK, one request per day)

{ "source": "nbk", "base": "KZT", "symbols": ["USD", "EUR", "RUB", "CNY"], "mode": "history", "startDate": "2026-01-01", "endDate": "2026-06-30" }

Output

One item per date × base × currency (format: long):

{
"id": "NBK:2026-09-13:USD:KZT",
"date": "2026-09-13",
"base": "USD",
"currency": "KZT",
"currencyName": "Kazakhstani Tenge",
"rate": 450.91,
"inverseRate": 0.002218,
"change1dPct": 0, "change7dPct": -1.24, "change30dPct": -3.05, "changeYtdPct": -10.28,
"source": "NBK",
"sourceUrl": "https://nationalbank.kz/rss/get_rates.cfm?fdate=13.09.2026",
"fetchedAt": "2026-09-12T23:42:49.083Z"
}
FieldTypeDescription
idstring<source>:<date>:<base>:<currency> — stable across runs
datestringRate date (ECB: business day the rate was fixed; NBK: official date)
base, currencystring1 base = rate × currency
currencyNamestringEnglish name
ratenumberRaw source precision unless decimals set
inverseRatenumberOnly with includeInverse
amount, convertednumberOnly in mode convert
change1dPct … changeYtdPctnumberOnly with includeChanges; % vs 1/7/30 days earlier and vs last rate of previous year
sourcestringECB or NBK
sourceUrlstringExact request URL
fetchedAtstringISO timestamp of the run

format: wide emits { id, date, base, source, sourceUrl, fetchedAt, EUR: 0.86, GBP: 0.74, … } — one row per source × date × base with the rates only (inverseRate, amount/converted and the change columns exist in format long). Mode currencies emits { id, code, name, ecb, nbk, sources, fetchedAt }.

With fields, a row keeps id plus the listed columns in your order, e.g. "fields": ["date", "rate"] → { "id": …, "date": …, "rate": … }.

The key-value store record SUMMARY holds items (rows saved), warnings[] (unsupported codes, skipped fields, switches that do not apply), unsupported[], maxItemsReached (where the maxItems cut fell), notRead[] (work a spending-limit or timeout stop left unread), failures[] (a source request that failed while the others were saved), status and the run counts (delivered, stoppedBy). Every mode, currencies included, ends with a status message that sums this up.

Use it from code / agents

curl -X POST "https://api.apify.com/v2/acts/yadroo~fx-rates/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H 'content-type: application/json' -d '{"pairs":["USD/KZT","EUR/USD"],"includeChanges":true}'
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/fx-rates').call({ base: 'EUR', mode: 'history', startDate: '2026-01-01', format: 'wide' });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yadroo/fx-rates").call(run_input={"mode": "convert", "base": "USD", "symbols": ["KZT"], "amount": "2500"})
items = client.dataset(run["defaultDatasetId"]).list_items().items

MCP: add https://mcp.apify.com to your agent and call the tool yadroo/fx-rates with the same JSON input.

Pricing

Pay per event: $0.001 per run start + $0.0002 per dataset row. Typical runs: latest rates for 5 currencies ≈ $0.002; a month of history for 30 currencies (~650 rows) ≈ $0.13; a year of EUR history in wide format (~255 rows, one per date) ≈ $0.05.

Store discounts: Bronze −10 %, Silver −20 %, Gold and above −30 % on the row price; the start event is the same on every plan; platform usage is included. Warnings, unsupported codes and failed requests are never rows, so they cost nothing.

Your Maximum cost per run is respected: the run stops reading at it and ends with "Stopped at your spending limit: N rows delivered" (what was left unread is named in the status and SUMMARY.notRead).

Limits & FAQ

  • Freshness — ECB rates are fixed once per business day around 16:00 CET (no weekends/TARGET holidays; latest returns the last fixing). NBK publishes the official rate for the next day in the afternoon (Astana time), every calendar day.
  • Why is my currency missing? — It is not in the chosen source. The run logs Not available from … and stores the list in SUMMARY.warnings; set source: auto, or strict: true to fail instead.
  • Are NBK cross rates official? — USD/KZT, EUR/KZT etc. are the official NBK quotes. Pairs like EUR/USD from NBK are computed as KZT-per-EUR / KZT-per-USD and are tagged source: NBK; prefer ECB for non-KZT pairs (auto does).
  • maxItems — counts dataset rows, what you are billed for (format wide: one row per date). History comes oldest date first, and the cut falls on a whole date, so the last date is never delivered with only some of its currencies; when even the first date (or a single latest snapshot) is larger than maxItems, its first maxItems rates are kept. Nothing is read ahead of the cut: an NBK history stops requesting days once maxItems rows are saved. The status and SUMMARY.maxItemsReached say where the cut fell.
  • Rate limits — ECB history is one request per run; NBK history is one request per day with a 120 ms pause and a 366-day cap (a full year takes about 3 minutes). Up to 3 attempts with back-off on 429/5xx/timeouts. Rows are saved as they arrive (per source request, every ~50 rows of an NBK history).
  • Run timeout — a run near its timeout stops starting new requests, saves what it has read and ends SUCCEEDED with "Stopped before the run timeout: N rows saved".
  • Errors — invalid or impossible dates (2026-02-30), a range that ends before it starts, an amount that is not a number, an unsupported base, no valid pair at all, strict with an unsupported code, or fields naming no column stop the run before any request with an explanation; nothing is charged beyond the start event. A malformed pair next to valid ones is skipped with a warning. When one source request fails and others work, their rows are saved and the failure is named in the status and SUMMARY.failures; the run fails only when nothing could be fetched.
  • Roadmap — more national-bank sources (CBR, NBU, CBU) on request; percent-change thresholds as a filter.

Made by Yadroo — see also us-treasury-yields, world-bank-indicators, sec-company-financials, sec-edgar-filings, coingecko-markets.