Official Dart client for the UniRate API — free, real-time and historical currency exchange rates plus VAT rates. Works in Dart and Flutter (mobile, web, desktop).
- 🔄 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
- ⚡ Modern Dart:
async/await, typed models, injectablehttp.Client - 📦 One dependency —
package:http
- Dart SDK 3.0+ (or Flutter 3.10+)
dart pub add unirate_apiOr add it to your pubspec.yaml:
dependencies:
unirate_api: ^0.1.0import 'package:unirate_api/unirate_api.dart';
Future<void> main() async {
final client = UniRateClient('your-api-key');
// Current rate
final rate = await client.getRate(from: 'USD', to: 'EUR');
print('USD -> EUR: $rate');
// Convert
final euros = await client.convert(amount: 100, from: 'USD', to: 'EUR');
print('100 USD = $euros EUR');
// All supported currencies
final currencies = await client.getSupportedCurrencies();
print('${currencies.length} currencies supported');
client.close();
}Get a free API key at https://unirateapi.com.
// Single pair
final double rate = await client.getRate(from: 'USD', to: 'EUR');
// All rates for a base
final Map<String, double> rates = await client.getAllRates(from: 'USD');
// Convert an amount
final double result = await client.convert(amount: 100, from: 'USD', to: 'EUR');
// Supported currency list
final List<String> codes = await client.getSupportedCurrencies();// Rate on a specific date
final rate = await client.getHistoricalRate(date: '2024-01-01', from: 'USD', to: 'EUR');
// All rates on a date
final rates = await client.getHistoricalRates(date: '2024-01-01', from: 'USD');
// Convert using a historical rate
final amount = await client.convertHistorical(
amount: 100,
from: 'USD',
to: 'EUR',
date: '2024-01-01',
);
// Time series
final series = await client.getTimeSeries(
startDate: '2024-01-01',
endDate: '2024-01-07',
base: 'USD',
currencies: ['EUR', 'GBP'],
);
// Available historical coverage per currency
final limits = await client.getHistoricalLimits();Historical endpoints require a Pro subscription and return
ApiException(status 403) on the free tier.
// All countries
final vatRates = await client.getVatRates();
// Single country (ISO-3166 alpha-2 code)
final germany = await client.getVatRate(country: 'DE');
print('Germany VAT: ${germany.vatData.vatRate}%');Every method throws a subclass of UniRateException:
try {
final rate = await client.getRate(from: 'USD', to: 'ZZZ');
} on AuthenticationException {
// invalid API key
} on InvalidCurrencyException {
// unknown currency code
} on RateLimitException {
// back off and retry
} on InvalidDateException {
// bad request parameters / date format
} on ApiException catch (e) {
// other HTTP error — e.statusCode / e.response
} on UniRateException catch (e) {
// network or decoding failure
}The constructor accepts any http.Client, so mocking is trivial with
package:http's MockClient:
import 'package:http/testing.dart';
import 'package:http/http.dart' as http;
import 'package:unirate_api/unirate_api.dart';
final mock = MockClient((request) async => http.Response('{"rate": "0.92"}', 200));
final client = UniRateClient('test-key', httpClient: mock);
final rate = await client.getRate(from: 'USD', to: 'EUR'); // 0.92When you supply your own client you own its lifecycle; close() only disposes
a client the constructor created.
- Currency endpoints: standard rate limits apply
- Historical endpoints: 50 requests/hour on the free tier
- VAT endpoints: 1800 requests/hour on the free tier
- unirate-api-python — Python (PyPI:
unirate-api) - unirate-api-nodejs — Node.js / TypeScript (npm:
unirate-api) - unirate-api-swift — Swift (SPM)
- unirate-api-java — Java (Maven)
- unirate-api-go — Go
- unirate-api-rust — Rust (crates.io:
unirate-api) - unirate-api-ruby — Ruby (gem:
unirate-api) - unirate-api-php — PHP (Composer:
unirate-api/unirate-api) - unirate-api-dotnet — .NET / C# (NuGet:
UniRateApi)
MIT — see LICENSE.