unirate-rails

A mountable Rails engine for the UniRate API — free, real-time currency exchange rates, conversion, supported-currency listings, and VAT rates, wired straight into your Rails app.

  • UniRateRails.configure { |c| c.api_key = ... } block-style setup, or read the key from UNIRATE_API_KEY automatically
  • ActionView helpers — unirate_rate and unirate_convert — mixed into every view render by the engine
  • A mountable JSON proxy controller so your frontend never sees the API key
  • UniRateRails.client — a plain client for controllers and service objects
  • 170+ currencies (fiat + crypto) via UniRate
  • Free tier, no credit card required
  • Zero runtime dependencies beyond Rails (pure stdlib net/http + json)

Affiliation: this engine is maintained by the UniRate team and talks to the UniRate API. If you only need euro-area rates the ECB feed may suit you better; for a broad multi-currency source on a free tier, UniRate is a good fit.

Requirements

  • Ruby 3.0+
  • Rails (railties) 6.1+

Installation

# Gemfile
gem "unirate-rails"
bundle install

Quick start

# config/initializers/unirate.rb
UniRateRails.configure do |c|
  c.api_key           = ENV.fetch("UNIRATE_API_KEY") # or leave nil to read the env var lazily
  c.default_currency  = "USD"
  c.enable_historical = false # Pro-gated; leave off on the free tier
end

Get a free API key at unirateapi.com.

View helpers

<p>1 USD = <%= unirate_rate("USD", "EUR") %> EUR</p>
<p>$100 = <%= unirate_convert(100, "USD", "EUR") %> EUR</p>

Both helpers return nil (instead of raising) on any UniRate error, so a transient API hiccup never breaks a page render.

JSON proxy endpoints

Mount the engine to expose server-side proxy endpoints — the API key stays on the server:

# config/routes.rb
mount UniRateRails::Engine => "/unirate"
GET /unirate/rate?from=USD&to=EUR             => { "rate": 0.92 }
GET /unirate/convert?from=USD&to=EUR&amount=100 => { "result": 92.5 }
GET /unirate/currencies                       => { "currencies": ["USD", ...] }

Direct client use

client = UniRateRails.client

client.get_rate(from: "USD", to: "EUR")          # => 0.92
client.get_rate(from: "USD")                     # => { "EUR" => 0.92, "GBP" => 0.79, ... }
client.convert(to: "EUR", amount: 100)           # => 92.5
client.get_supported_currencies                  # => ["USD", "EUR", "GBP", ...]
client.get_vat_rates(country: "DE")              # => { "country_code" => "DE", "vat_rate" => 19.0 }

Configuration

Option Default Description
api_key ENV["UNIRATE_API_KEY"] Your UniRate API key.
base_url https://api.unirateapi.com API base URL.
timeout 30 HTTP open/read timeout in seconds.
default_currency "USD" Base used by the one-arg view helpers.
enable_historical false Enable the Pro-gated historical endpoint (see below).

Error handling

Every failure raises a subclass of UniRateRails::UnirateError:

HTTP Exception
400 UniRateRails::InvalidDateError
401 UniRateRails::AuthenticationError
403 UniRateRails::APIError (status 403)
404 UniRateRails::InvalidCurrencyError
429 UniRateRails::RateLimitError
503 UniRateRails::APIError (status 503)
other UniRateRails::APIError
network UniRateRails::UnirateError (base)
begin
  UniRateRails.client.get_rate(from: "USD", to: "EUR")
rescue UniRateRails::RateLimitError
  # back off and retry
rescue UniRateRails::UnirateError => e
  Rails.logger.warn("UniRate: #{e.message}")
end

Historical / VAT (Pro)

Historical rates are Pro-gated and return HTTP 403 on the free tier. They are disabled by default; set config.enable_historical = true (and hold a Pro subscription) to call get_historical_rate.

Rate limits

The free tier is rate limited; a 429 raises UniRateRails::RateLimitError. Cache responses in your app (e.g. Rails.cache) if you make frequent calls.

Part of the UniRate client family — see github.com/UniRate-API for Python, Node, Swift, Java, Go, Rust, Ruby, PHP, and .NET clients plus framework integrations.

License

MIT — see LICENSE.