Note: when converting 10,000 USD to USD, a loss of $1–1 due to Float rounding appears as a bug to the user—not a feature. Technically, a converter is simple, but errors in arithmetic, caching, or API integration turn it into a source of complaints. In this article, we break down how to build a reliable module from scratch: from selecting a rate provider to handling edge cases with locales and rounding. Our team brings over 10 years of mobile development experience and more than 40 fintech modules to date—we know all the pitfalls and guarantee accuracy across all devices.
How to choose an API for currency rates?
Choosing an API depends on requirements for update frequency and currency coverage. Compare popular options:
| API | Free Plan | Update Frequency | Features |
|---|---|---|---|
| ExchangeRate-API | 1500 requests/month | Daily | Simple REST, 170+ currencies |
| Open Exchange Rates | 1000 requests/month | Hourly | Historical data |
| Fixer.io | 100 requests/month | Hourly | EUR as base currency |
| Central Bank of Russia XML | Free | Daily | Official rates for USD |
| National Bank of Belarus | Free | Daily | Official rates for BYN |
ExchangeRate-API is 3x cheaper than Fixer.io on average request volume. For most apps, daily updates are sufficient—the CBR provides XML at https://www.cbr.ru/scripts/XML_daily.asp, parsed via XMLParser on iOS or XmlPullParser on Android. Note: the CBR uses windows-1251 encoding and may change the response format. We always apply automatic regression tests on sandbox data and provide a fallback to another provider.
Why Decimal, not Float?
Never use Float or Double for financial calculations. The difference in cents becomes noticeable when converting large sums. Compare precision:
| Type | Precision | Example Error |
|---|---|---|
| Float/Double | ~7-15 digits | 0.1 + 0.2 = 0.30000000000000004 |
| Decimal (iOS) / BigDecimal (Android) | 28-38 digits | 0.1 + 0.2 = 0.3 |
For 1,000,000 USD, a 0.01% discrepancy yields a 100 USD error. On iOS we use Decimal, on Android BigDecimal. They guarantee cent‑level precision and correct rounding according to financial math standards. Learn more about the Decimal data type.
Offline caching and background sync
Rates are stored locally: Core Data / Room to enable offline use with the last known values. We display the timestamp of the last update so the user knows how fresh the data is. For the latest rates, we use background sync via WorkManager (Android) or BGTaskScheduler (iOS). On one project we implemented a TTL of 30 minutes and a 7‑day cache. The user always sees data freshness, and when offline—a warning.
Example CBR parsing code in Swift
import Foundation struct CurrencyRate: Decodable { let code: String let nominal: Int let value: Decimal } class CBRParser: NSObject, XMLParserDelegate { private var rates: [CurrencyRate] = [] private var currentElement = "" private var currentCode = "" private var currentNominal = "" private var currentValue = "" func parse(data: Data) -> [CurrencyRate] { let parser = XMLParser(data: data) parser.delegate = self parser.parse() return rates } func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { currentElement = elementName } func parser(_ parser: XMLParser, foundCharacters string: String) { switch currentElement { case "CharCode": currentCode += string case "Nominal": currentNominal += string case "Value": currentValue += string default: break } } func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { if elementName == "Valute" { let rate = CurrencyRate(code: currentCode.trimmingCharacters(in: .whitespacesAndNewlines), nominal: Int(currentNominal.trimmingCharacters(in: .whitespacesAndNewlines)) ?? 1, value: Decimal(string: currentValue.trimmingCharacters(in: .whitespacesAndNewlines).replacingOccurrences(of: ",", with: ".")) ?? 0) rates.append(rate) currentCode = "" currentNominal = "" currentValue = "" } } } Process of developing the converter
- Analysis – gather requirements (currencies, precision, update frequency) and select API.
- Design – architecture: data layer, repository, cache, view model (MVVM + Clean Architecture).
- Implementation – codebase with unit tests (20+ tests for arithmetic and caching).
- Integration – connect chosen API, handle errors (no network, rate limits, format changes).
- Testing – test on 10 real devices with different locales and regions.
- Deployment – release to App Store / Google Play, passing review.
What's included
- Source code in Swift (iOS) or Kotlin (Android) with comments.
- API documentation and instructions for key renewal.
- Configured caching scheme (local DB) with TTL.
- Test report with code coverage >80%.
- Support for 2 weeks after delivery.
Timeline and cost
Implementation timeline: 3 to 7 business days. The price is fixed after the TOR is agreed upon and does not change. Save up to 30% on development time when ordering a comprehensive solution. Contact us for a project estimate—we will find the optimal solution for your budget.
Typical mistakes in converter development
- Ignoring Decimal: 95% of converter bugs are related to rounding.
- Missing locale handling: on a German locale the comma is a thousands separator, breaking parsing.
- Tight coupling to one API: always design for switching providers.
- No cache expiry check: the user sees week‑old rates without warning.
Order a turnkey currency converter development and get a ready solution with source code and support.







