unirate-api-crystal
UniRate API — Crystal client
Official Crystal client for the UniRate API — free currency exchange rates, historical data, and VAT rates.
- Zero dependencies. HTTP via
HTTP::Client, JSON viaJSON, URL encoding viaURI— all in the Crystal standard library. No third-party shards are pulled in (there is nodependencies:key inshard.yml). - Injectable transport, so your tests never touch the network.
- Typed error classes you can rescue individually.
Install
Add the shard to your shard.yml:
dependencies:
unirate-api:
github: UniRate-API/unirate-api-crystal
version: ~> 0.1.0
Then shards install and require "unirate" in your code.
Get a free API key at unirateapi.com.
Quick start
require "unirate"
client = UniRate::Client.new("your-api-key")
# Current rate: how many EUR is one USD?
rate = client.get_rate(to: "EUR", from: "USD") # => 0.92
# Convert an amount
eur = client.convert(100.0, to: "EUR", from: "USD") # => 92.5
# All rates for a base currency
all = client.get_all_rates("USD") # => Hash(String, Float64)
# Supported currency codes
codes = client.get_supported_currencies # => ["USD", "EUR", ...]
API
Construct a client with your API key, plus optional named settings (base URL, timeout in seconds, and a custom Transport):
client = UniRate::Client.new("your-api-key", timeout: 10)
Current rates & conversion (free tier)
| Method | Returns |
|---|---|
get_rate(to, from = "USD") |
Float64 — rate from from to to |
get_all_rates(from = "USD") |
Hash(String, Float64) — every rate for a base |
convert(amount, to, from = "USD") |
Float64 — converted amount |
get_supported_currencies |
Array(String) — supported currency codes |
Historical data (Pro tier)
These require a UniRate Pro subscription and raise a UniRate::APIError (status: 403) on the free tier.
| Method | Returns |
|---|---|
get_historical_rate(date, to, from = "USD") |
Float64 |
get_historical_rates(date, base = "USD") |
Hash(String, Float64) |
convert_historical(amount, from, to, date) |
Float64 |
get_time_series(start_date, end_date, base = "USD", currencies = [], amount = 1.0) |
Hash(String, Hash(String, Float64)) |
get_historical_limits |
UniRate::HistoricalLimitsResponse |
VAT (free tier)
| Method | Returns |
|---|---|
get_vat_rates |
UniRate::VatRatesResponse — every supported country |
get_vat_rate(country) |
UniRate::VatCountryResponse — one ISO-3166 alpha-2 country |
Currency and country codes are upper-cased before they are sent, and an empty from/base defaults to USD.
Error handling
Every method raises a UniRate::UniRateError (or a subclass) on failure. Rescue the base class to catch everything, or a subclass to branch:
require "unirate"
client = UniRate::Client.new("your-api-key")
begin
rate = client.get_rate(to: "ZZZ")
rescue ex : UniRate::AuthenticationError
STDERR.puts "check your API key"
rescue ex : UniRate::InvalidCurrencyError
STDERR.puts "unknown currency"
rescue ex : UniRate::RateLimitError
STDERR.puts "slow down"
rescue ex : UniRate::UniRateError
STDERR.puts "API error #{ex.status}: #{ex.message}"
end
| Error class | HTTP | Meaning |
|---|---|---|
InvalidDateError |
400 | Invalid request parameters |
AuthenticationError |
401 | Missing or invalid API key |
APIError |
403 | Endpoint requires a Pro subscription |
InvalidCurrencyError |
404 | Currency/country not found |
RateLimitError |
429 | Rate limit exceeded |
APIError |
503 / other | Service unavailable / generic |
UniRateError |
— | Transport failure or malformed response body |
All subclasses inherit from UniRate::UniRateError, which carries status (the HTTP status, or 0 for a non-HTTP failure) and body (the raw response body when the server returned one).
Rate limits
The free tier is rate-limited; a 429 surfaces as UniRate::RateLimitError. See unirateapi.com for current limits and Pro plans.
Testing
crystal spec spec/unirate_spec.cr # mock suite, no network
UNIRATE_API_KEY=... crystal spec spec/live_spec.cr # live suite (free tier)
The HTTP layer is the UniRate::Transport abstract class, so your own tests can inject a fake and stay offline.
Related clients
UniRate ships official clients for many languages and platforms — Python, Node.js, Go, Rust, Java, Swift, Ruby, PHP, Elixir, Haxe, V, and more. See unirateapi.com.
License
MIT — see LICENSE. Copyright © 2026 Unirate Team.
unirate-api-crystal
- 0
- 0
- 0
- 0
- 0
- about 1 hour ago
- October 28, 2026
MIT License
Wed, 28 Oct 2026 05:21:24 GMT