UniRate Elixir Client

Official Elixir client for the UniRate API — free currency exchange rates, historical data, and VAT rates.

Built on the Erlang/OTP standard library only (:httpc for HTTP and the OTP 27 :json module for parsing): zero third-party dependencies.

Requirements

Installation

Add unirate_api to your deps in mix.exs:

def deps do
[
{:unirate_api, "~> 0.1.0"}
]
end

Then run mix deps.get.

Quick start

client = UniRate.Client.new("your-api-key")
# A single exchange rate.
UniRate.Client.get_rate(client, "USD", "EUR")
#=> 0.92
# All rates for a base currency.
UniRate.Client.get_rate(client, "USD")
#=> %{"EUR" => 0.92, "GBP" => 0.79, ...}
# Convert an amount.
UniRate.Client.convert(client, "EUR", from: "USD", amount: 100)
#=> 92.5
# Supported currencies.
UniRate.Client.get_supported_currencies(client)
#=> ["USD", "EUR", "GBP", ...]
# VAT rate for a country.
UniRate.Client.get_vat_rate(client, "DE")
#=> %{"country_code" => "DE", "country_name" => "Germany", "vat_rate" => 19.0}

Currency and country codes are upper-cased automatically before being sent.

Configuration

UniRate.Client.new("your-api-key",
timeout: 30_000, # request timeout in milliseconds
base_url: "https://api.unirateapi.com"
)

API

Current data (free tier)

Method Returns
get_rate(client, from \\ "USD", to \\ nil, opts \\ []) a number when to is set, else a %{code => rate} map
convert(client, to, opts \\ []) the converted amount (options: :amount, :from)
get_supported_currencies(client, opts \\ []) a list of currency-code strings
get_vat_rates(client, opts \\ []) the full VAT response (option: :country)
get_vat_rate(client, country, opts \\ []) the vat_data object for one ISO-3166 alpha-2 country

Historical data (Pro plan)

These endpoints require a Pro subscription and return 403 on the free tier (surfaced as a UniRate.Error with reason: :api and status: 403).

Method
get_historical_rate(client, date, opts \\ []) — options :amount, :from, :to
get_historical_rates(client, date, opts \\ []) — options :amount, :base
convert_historical(client, amount, from, to, date, opts \\ [])
get_time_series(client, start_date, end_date, opts \\ []) — options :amount, :base, :currencies
get_historical_limits(client, opts \\ [])

Every method also accepts :format ("json" default, or "xml" / "csv" / "tsv") and :callback. When :format is not "json", the raw response body string is returned instead of a parsed value.

Error handling

Every failure is a UniRate.Error — rescue the whole family with one clause and narrow on :reason:

try do
UniRate.Client.get_rate(client, "USD", "ZZZ")
rescue
e in UniRate.Error ->
case e.reason do
:invalid_currency -> IO.puts("unknown currency")
:authentication -> IO.puts("bad API key")
:rate_limit -> IO.puts("slow down")
:api -> IO.puts("API error #{e.status}: #{e.message}")
:transport -> IO.puts("network error: #{e.message}")
_ -> reraise(e, __STACKTRACE__)
end
end
Reason HTTP Meaning
:invalid_date 400 Invalid request parameters
:authentication 401 Missing or invalid API key
:api 403 Endpoint requires a Pro subscription
:invalid_currency 404 Currency not found or no data available
:rate_limit 429 Rate limit exceeded
:api 503 / other Service unavailable / generic (carries status + body)
:transport — Network/transport failure or unparseable response

Rate limits

The free tier is rate-limited. On HTTP 429 the client raises a UniRate.Error with reason: :rate_limit; back off and retry.

Testing

mix test # mock tests only (default)
UNIRATE_API_KEY=... mix test --include live # + live free-tier tests

Mock tests inject a transport function via the :http option, so they never hit the network.

UniRate ships official clients for many languages — Python, Node/TypeScript, Go, Rust, Ruby, PHP, Java, Swift, and more. See github.com/UniRate-API.

License

MIT © 2026 Unirate Team. See LICENSE.