NBP & ECB Exchange Rates - Historical Currency Converter avatar

NBP & ECB Exchange Rates - Historical Currency Converter

Pricing

from $2.00 / 1,000 amount converteds

Go to Apify Store
NBP & ECB Exchange Rates - Historical Currency Converter

NBP & ECB Exchange Rates - Historical Currency Converter

Get NBP and ECB reference exchange rates, look up historical dates and convert currency amounts. Each result includes the rate date for traceable reporting. Uses public central-bank APIs, not scraped prices. Not a live trading feed or accounting advice.

Pricing

from $2.00 / 1,000 amount converteds

Rating

0.0

(0)

Developer

Daniel Michałek

Daniel Michałek

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Categories

Share

Official FX Rates (NBP + ECB)

Get official exchange rates straight from the public APIs of Narodowy Bank Polski (NBP) and the European Central Bank (ECB), and convert amounts with the correct rate date - including weekend/holiday look-back and the Polish tax rule "NBP mid rate from the last business day before the transaction" (D-1).

Typical uses: invoice and expense conversion for Polish bookkeeping (VAT, CIT/PIT), EUR reference rates for contracts and reports, historical rate series for analysis.

Source: European Central Bank, ECB Data Portal API. ECB source data is available free of charge. Actor charges pay for the normalization, conversion and delivery service, not for access to ECB data. See the ECB copyright and reuse notice. Converted amounts and cross rates are calculated by this Actor; published source observations are unchanged. Every ECB dataset row and run summary includes this disclosure in sourceNotice. NBP values come from the official NBP Web API.

What it does

  1. Validates your input and plans the minimum number of API calls (NBP ranges are split into 93-day chunks, the NBP limit; ECB into 366-day chunks).
  2. Calls only these official endpoints:
    • NBP: https://api.nbp.pl/api/exchangerates/... (JSON)
    • ECB: https://data-api.ecb.europa.eu/service/data/EXR/... (SDMX CSV)
  3. Writes one dataset item per published rate (rate list) and one per requested conversion.

Rate semantics of every rate item: 1 baseCurrency = rate quoteCurrency.

  • NBP (tables A/B, mid rates): base = foreign currency, quote = PLN.
  • ECB (daily euro reference rates): base = EUR, quote = foreign currency.
  • Conversions between two non-base currencies are computed as cross rates via PLN (NBP) or EUR (ECB), using rates of the same publication date.

Input

FieldTypeDefaultDescription
sourceNBP or ECBNBPWhich central bank to use.
nbpTableA, B or CANBP only. A = major currencies (daily), B = other currencies (weekly), C = bid/ask (rate list only, not for conversions).
currenciesarray of ISO codes-Currencies to list rates for. The base currency (PLN / EUR) is ignored.
startDateYYYY-MM-DD-Start of the rate list. Required if currencies is set.
endDateYYYY-MM-DDstartDateEnd of the rate list (inclusive, max 3660 days).
conversionsarray-{ "amount": 100, "from": "USD", "to": "PLN", "date": "2024-01-02", "id": "optional" }, max 10000 per run.
rateDateModeexact, onOrBefore, beforeonOrBeforeonOrBefore: rate of that day or the last one published before it. before: last rate strictly before the date (Polish D-1 tax rule). exact: only a rate published on that day.
maxLookbackDaysinteger 0-3110How far back a conversion may look for the last published rate.
decimalsinteger 0-82Rounding of converted amounts (half away from zero).

You need at least currencies + startDate, or conversions (or both).

Example - invoice conversion with the Polish D-1 rule:

{
"source": "NBP",
"rateDateMode": "before",
"conversions": [
{ "id": "FV/2024/001", "amount": 1200, "from": "EUR", "to": "PLN", "date": "2024-01-03" },
{ "id": "FV/2024/002", "amount": 99.99, "from": "USD", "to": "EUR", "date": "2024-01-08" }
]
}

Example - ECB reference rates for January 2024:

{
"source": "ECB",
"currencies": ["USD", "PLN", "CHF"],
"startDate": "2024-01-01",
"endDate": "2024-01-31"
}

Output

Numbers in the examples below are illustrative. Rate item:

{
"recordType": "rate",
"source": "NBP",
"date": "2024-01-02",
"currency": "EUR",
"baseCurrency": "EUR",
"quoteCurrency": "PLN",
"rate": 4.3434,
"table": "A",
"tableNo": "001/A/NBP/2024"
}

NBP table C items carry bid and ask instead of rate (rate is null).

Conversion item:

{
"recordType": "conversion",
"id": "FV/2024/001",
"source": "NBP",
"amount": 1200,
"from": "EUR",
"to": "PLN",
"requestedDate": "2024-01-03",
"rateDateMode": "before",
"status": "ok",
"rateDate": "2024-01-02",
"rate": 4.3434,
"converted": 5212.08,
"path": "direct"
}

path is direct, cross via PLN / cross via EUR, or identity (same currency). A conversion that cannot be served has status: "error" and error:

  • RATE_NOT_FOUND - no rate was published within the look-back window (or not on the exact day).
  • UPSTREAM_INCOMPLETE - an API request covering that date failed; the Actor refuses to guess a rate from partial data.

A run summary (source, planned requests, upstream errors, counts, charged events, stoppedByChargeLimit) is stored in the default key-value store under OUTPUT. If the API fails and nothing billable could be produced, the run is marked as failed.

Pricing (pay per event)

EventCharged when
rate-recordonce per rate item written to the dataset
amount-convertedonce per conversion with status: "ok"

Conversions with status: "error" are returned but never charged. Invalid input fails the run before any API call or charge. The price per event is shown on the Actor's Pricing tab in Apify Store. If your maximum charge per run is reached, the Actor stops after the last paid item and sets stoppedByChargeLimit: true in OUTPUT. The existing stop policy is conservative: reaching the limit for one event type stops the whole run, even if a cheaper event type could still fit within the remaining budget.

The Actor checks capacity before each charge and publishes a paid item only after the SDK confirms chargedCount: 1. A zero budget or declined charge publishes no paid item. In a run without pay-per-event pricing, output is still available and chargedEvents remains zero. This Actor expects the two named events above; automatic dataset-item pricing is rejected because it would also charge conversion errors.

Billing and dataset writes are separate operations, with no shared transaction. Actor.charge does not expose a persistent caller idempotency key for replay after a process restart; the underlying client generates a key for retries within a single API call. A failed write can leave a confirmed charge without an output item; a lost charge acknowledgement can leave an unknown billing result. A durable FX-RUN-STATE record therefore blocks automatic replay after interruption and reports RECONCILIATION_REQUIRED. Inspect the saved phase and confirmed counters against run billing and dataset records before recovery; do not delete the guard or start with fresh storage as a retry. Completed runs with the same input return the saved summary without charging or publishing again. This is not an exactly-once guarantee and does not support concurrent processes sharing the same storage.

Limitations

  • No scraping. Data comes only from the official public NBP Web API and ECB Data Portal API listed above; no web pages are parsed and no third-party rate providers are used.
  • Rates are the official published values. NBP mid rates start on 2002-01-02, ECB reference rates on 1999-01-04; earlier dates are rejected.
  • NBP table B is published weekly; use a longer maxLookbackDays if needed. Currencies that are not in the selected table simply return no data.
  • ECB reference rates are published around 16:00 CET on TARGET business days; NBP table A on Polish business days. Same-day requests made before publication fall back according to rateDateMode.
  • Cross rates are derived arithmetically from two official rates of the same day; they are not themselves official quotes.
  • Results depend on the availability of the upstream APIs. Transient errors (HTTP 429/5xx, network errors) are retried up to 3 times with back-off.
  • This is data tooling, not tax or legal advice.

Local recovery candidate

This copy preserves the existing Actor identity and ownership. Source corrections have not been deployed to the live Actor. The local candidate package is version 0.1.1, targeting Node.js 22 or newer. Output links expose the dataset and OUTPUT summary; the dataset view includes the ECB disclosure. Dockerfile and .dockerignore were newly authored on 2026-10-21 because the remote Dockerfile could not be read; they are not recovered originals. The local Node 22 container build and an offline startup smoke test passed with the preserved proxy-CA Dockerfile; see evidence/docker-validation.json. Production packaging uses ordinary TLS-verified npm ci and prints runtime file hashes during the build. The native import package and expected hashes are under evidence/release-import-0.1.1/. Packaging was prepared without repeating those tests; hosted build, billing and deployment remain separate checks. Recovery provenance remains in the parent RECOVERY_MANIFEST.json; combined validation evidence is in evidence/fx-validation.json.