Tutorial/Flutter quickstart

Build a Flutter currency converter with a server-side API key

Build a typed Flutter converter that loads a source-aware FX quote through your own proxy, shows loading and error states, reports cache age, and rounds only at display time.

ERexchangerate.dev·Sep 29, 2026·8 min read

A mobile Flutter app is a public client, so it must not contain an exchangerate.dev bearer key. Put the key in a small server-side /api/fx proxy, have Flutter request {from,to}, and keep the returned rate, source, market session, and observation timestamp together in a typed model.

Key points
The downloadable Dart file calls your proxy, never the exchangerate.dev API key from the app.
The response model validates the rate and data_updated_at before rendering.
Loading, HTTP/format errors, source, market session, and cache age are visible to the user.
The display uses fixed decimals while the unrounded API value remains available to application code.
Indicative rates are for estimates and display; settlement belongs to the responsible payment provider.

Put the credential behind your server

Your server-side route accepts from and to, adds Authorization: Bearer $EXCHANGERATE_API_KEY, calls /v1/latest/{from}?symbols={to}, and returns only the fields the app needs. Keep the key in the server environment. The app passes its proxy URL with --dart-define=FX_PROXY_BASE_URL=…; it never receives the upstream key.

proxy contract · responsecopy
GET /api/fx?from=USD&to=EUR

{"from":"USD","to":"EUR","rate":0.9245,"source":"live","market_session":"open","data_updated_at":"2026-09-29T10:00:00Z"}

Add the HTTP dependency

Create a Flutter app, add the current http package to pubspec.yaml, and save the complete Flutter converter as lib/main.dart. Run it with flutter run --dart-define=FX_PROXY_BASE_URL=https://your-app.example/api/fx. Download the minimal Node proxy, set EXCHANGERATE_API_KEY in the server environment, and run node flutter-currency-converter-proxy.mjs with Node 20 or newer. It listens on loopback port 8787 for local testing. Before connecting a device, expose it through your own authenticated HTTPS backend with request limits; it validates currencies and amount, forwards the key, and returns only the typed quote fields the app needs. The file uses the standard Flutter Material widgets and a typed FxQuote model. Flutter’s official networking recipe covers the package setup and request pattern.

Validate the quote before rendering

The model rejects a missing, non-positive, non-finite, or non-numeric rate and a missing data_updated_at. That keeps an HTML error page, a proxy bug, or an empty JSON response out of the conversion display. The client also bounds the request at ten seconds and surfaces non-2xx status codes.

Dart · typed response shapecopy
class FxQuote {
  final String from;
  final String to;
  final double rate;
  final String source;
  final String marketSession;
  final DateTime dataUpdatedAt;
}

Show loading, errors, and freshness

The screen disables the button while the request is running, displays a progress indicator, and keeps a readable error when the proxy fails. After success it shows the amount, displayed rate, source, market session, observation time, app cache age (time since this device loaded the response), and observation age (time since data_updated_at). A user can see whether the app is showing a live trading-day observation or a daily reference.

Round for display, preserve the value

For the sample’s supported currencies, display JPY with 0 decimals and USD, EUR, GBP, and IDR with 2; display the rate with 6 decimals for readability. That is presentation rounding. Keep the parsed numeric rate and use a decimal or fixed-point strategy in a production accounting boundary; do not use a binary floating-point display value as a settlement record.

Mobile credentials are public
Obfuscation, compile-time constants, and a private Flutter repository do not make an API key secret once it ships in an app. The proxy boundary is part of the design, not an optional hardening step.

Test the customer path

Run the app with a test proxy response, then exercise a timeout, HTTP 401/429, malformed JSON, missing rate, and an old data_updated_at. Flutter’s platform-specific networking, TLS, and proxy deployment still need a real-device or emulator check; this downloadable file is a runnable client example, not a hosted proxy.

Indicative rates only
Use the result for conversion estimates, display, and analytics. A payment provider or regulated system must obtain and retain its own executable quote and settlement record.
ER
exchangerate.dev
Integration guides for developers building with FX data.

Keep reading

TutorialCurrency conversion in JavaScript and Node.jsRead ReferenceExchange rate API quickstartRead TutorialBuild a Python exchange-rate alertRead
More ComparisonsFixer vs exchangerate.devOpen Exchange Rates vs exchangerate.devCurrencylayer vs exchangerate.devWise vs exchangerate.devCurrencylayer vs ExchangeRate-API
LearnReading source and market_session in your pipelineIndicative vs executable FX rates: what a rates API actually gives youECB reference rates, explained
Live RatesEUR/USDGBP/USDUSD/JPY