Issue Nº 56 — Nov 11, 2026

The NBP API says 93 days, but only the table calls enforce it

Issue fifty-six covers the National Bank of Poland API in the Currency Exchange category. It gives official zloty exchange rates and gold prices. It needs no key and sends a wildcard CORS header. We queried it live on 10 and 11 November 2026. The docs say one query cannot cover more than 93 days. Only the table calls enforce that. The single-currency and gold calls accept 367 days.

The 93-day limit is real for tables only

The docs say a single enquiry cannot cover more than 93 days. We tested the limit on three paths. GET /api/exchangerates/tables/a/2026-08-09/2026-11-10/ spans 93 days and returned 200. Starting one day earlier returned 400 with the text: Limit of 93 days has been exceeded.

GET /api/exchangerates/rates/a/eur/2025-11-08/2026-11-10/ spans 367 days and returned 200 with 253 rates. Starting one day earlier returned 400 with: Limit of 367 days has been exceeded. The gold path /api/cenyzlota/ has the same 367-day limit and returned 253 rows for the same range.

So a client that splits every range into 93-day parts makes four times more calls than it needs for one currency. Use 93 days for tables. Use 367 days for one currency or for gold.

A second cap: 255 rows

GET /api/exchangerates/rates/a/eur/last/255/ returned 200 with 255 rates. last/256 returned 400 with: Maximum size of 255 data series has been exceeded. We did not find this number in the English docs page.

The 255-row cap matters for the 367-day range. A full year has about 253 business days, so the row cap and the day cap are almost the same limit.

Errors are plain text, not JSON

A date with no table returns 404 with content type text/plain. We sent GET /api/exchangerates/tables/a/2026-11-08/, a Sunday. The body was: 404 NotFound - Not Found - Brak danych. Adding format=json did not change it. An unknown currency code returned the same 404 text.

A future date returned 400 with: Invalid date range. A range over a limit returns 400 with a Polish and English message in one line.

A client that calls response.json() on every reply will throw on these errors. Check the status code first. Treat a 404 on a weekend or a holiday as a normal result.

Formats and field names

With no format parameter and no Accept header, GET /api/exchangerates/rates/a/eur/last/1/ returned JSON. Adding ?format=xml returned XML. Sending Accept: application/xml also returned XML.

Currency names in the tables are in Polish, for example dolar amerykański for USD. The gold response uses Polish field names: GET /api/cenyzlota/last/3/ returned rows like {"data":"2026-11-10","cena":516.29}. The table A reply on 10 November had 32 currencies.

Table C gives a buy and a sell price. GET /api/exchangerates/rates/c/eur/last/2/ returned the fields bid and ask, not mid.

Caching, CORS and rate limits

We sent Origin: https://example.com with each request. Every reply, errors included, had access-control-allow-origin: * and cache-control: no-cache. A browser app can call the API directly, but nothing is cached for you.

GET /api/exchangerates/tables/a/today/ returned 200 at 21:03 Warsaw time on 10 November, with table 219/A/NBP/2026. We did not probe it before the table came out, so we do not know if it returns 404 first.

The docs page states no rate limit and no key. We did not send a burst of requests, so we make no claim about throttling.

National Bank of Poland, by the numbers

Rendered live from the atlas entry
AuthenticationNone required
HTTPSSupported
CORSEnabled
PricingFree
FormatsJSON, XML
governmenthistoricalno-keygold-prices

Sources

Facts checked Nov 2026