Official Nim client for the UniRate API — free, real-time and historical currency exchange rates plus VAT rates.
- 🔄 Real-time exchange rates between 170+ currencies (fiat + crypto)
- 📈 Historical rates back to 1999
- ⏰ Time-series ranges up to 5 years
- 💰 Currency conversion (current and historical)
- 🏛️ VAT rates for countries worldwide
- 🆓 Free tier, no credit card required
- 📦 Zero third-party dependencies — pure Nim standard library (
std/httpclient+std/json)
- Nim 1.6+
- HTTPS support: compile with
-d:ssl(uses the system OpenSSL, loaded at runtime)
nimble install unirate_apiOr add to your own .nimble file:
requires "unirate_api >= 0.1.0"import unirate_api
let client = newClient("your-api-key")
# Current rate
echo client.getRate("USD", "EUR")
# Convert
echo client.convert(100, "USD", "EUR")
# All supported currencies
echo client.getSupportedCurrencies().lenCompile with HTTPS enabled:
nim c -d:ssl -r yourapp.nimGet a free API key at https://unirateapi.com.
All methods are procs taking a Client as their first argument (so client.getRate(...) reads naturally). Currency and country codes are uppercased for you.
# Single pair -> float
let rate = client.getRate("USD", "EUR")
# All rates for a base -> Table[string, float]
let rates = client.getAllRates("USD")
# Convert an amount -> float
let euros = client.convert(100, "USD", "EUR")
# Supported currency codes -> seq[string]
let codes = client.getSupportedCurrencies()These endpoints require a Pro subscription and return APIError (status 403) on the free tier.
client.getHistoricalRate("2024-01-01", "USD", "EUR") # float
client.getHistoricalRates("2024-01-01", "USD") # Table[string, float]
client.convertHistorical(100, "USD", "EUR", "2024-01-01") # float
client.getTimeSeries("2024-01-01", "2024-01-07",
currencies = @["EUR", "GBP"]) # TimeSeriesData
client.getHistoricalLimits() # HistoricalLimitslet all = client.getVatRates() # VatRatesResponse
let de = client.getVatRate("DE") # VatCountryResponse
echo de.vatData.vatRate # 19.0Every method accepts an optional opts = CallOptions(format: ..., callback: ...)
for the API's format / callback query parameters. The typed methods always
decode JSON, so request non-JSON formats only when you know what you are doing.
Every error derives from UniRateError, so you can catch that one type or a
specific subclass:
import unirate_api
try:
let rate = client.getRate("USD", "EUR")
echo rate
except AuthenticationError:
echo "check your API key"
except RateLimitError:
echo "slow down"
except APIError as e:
echo "API error ", e.statusCode, ": ", e.responseBody
except UniRateError as e:
echo "unirate error: ", e.msg| HTTP status | Exception | Meaning |
|---|---|---|
| 400 | InvalidDateError |
Invalid request parameters |
| 401 | AuthenticationError |
Missing or invalid API key |
| 403 |
APIError (statusCode 403) |
Endpoint requires a Pro subscription |
| 404 | InvalidCurrencyError |
Currency not found / no data |
| 429 | RateLimitError |
Rate limit exceeded |
| 503 |
APIError (statusCode 503) |
Service unavailable |
| other / network |
APIError / UniRateError
|
Generic / transport error |
The free tier is rate limited. On HTTP 429 the client raises RateLimitError —
back off and retry.
nimble test # mock suite (offline, no key needed)
nimble live # free-tier live tests (needs UNIRATE_API_KEY)The client takes an injectable Transport proc, so the mock suite runs entirely
offline without touching the network.
UniRate ships official clients for Python, Node/TypeScript, Swift, Java, Go, Rust, Ruby, PHP, .NET, Dart, D, and more — see the UniRate-API organization.
MIT — see LICENSE.