<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: viraj geeth</title>
    <description>The latest articles on DEV Community by viraj geeth (@viraj_geeth_e6dc448fe4d43).</description>
    <link>https://dev.to/viraj_geeth_e6dc448fe4d43</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3874173%2F195b59fe-6e41-4083-bac9-db75e702a6a6.png</url>
      <title>DEV Community: viraj geeth</title>
      <link>https://dev.to/viraj_geeth_e6dc448fe4d43</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/viraj_geeth_e6dc448fe4d43"/>
    <language>en</language>
    <item>
      <title>I benchmarked 6 free exchange rate APIs every hour for a week. Here are the numbers.</title>
      <dc:creator>viraj geeth</dc:creator>
      <pubDate>Fri, 25 Sep 2026 12:34:21 +0000</pubDate>
      <link>https://dev.to/viraj_geeth_e6dc448fe4d43/i-benchmarked-6-free-exchange-rate-apis-every-hour-for-a-week-here-are-the-numbers-32od</link>
      <guid>https://dev.to/viraj_geeth_e6dc448fe4d43/i-benchmarked-6-free-exchange-rate-apis-every-hour-for-a-week-here-are-the-numbers-32od</guid>
      <description>&lt;p&gt;Every "best exchange rate API" list I have read ranks providers by their pricing page. Nobody measures them. So I set up a GitHub Action that hits six free, keyless exchange rate endpoints every hour, records latency, HTTP status and the publication date in the body, and publishes the results as JSON and CSV.&lt;/p&gt;

&lt;p&gt;Disclosure up front: I build &lt;a href="https://allratestoday.com/exchange-rate-api/" rel="noopener noreferrer"&gt;AllRatesToday&lt;/a&gt;, which is one of the six. The harness is public, the raw data is public, and the numbers below are copied from it without editing. If you think the method is unfair to anyone, the workflow file is the place to argue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Method
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vantage:&lt;/strong&gt; GitHub Actions hosted runner, &lt;code&gt;ubuntu-latest&lt;/code&gt;, US East.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cadence:&lt;/strong&gt; hourly, since 2026-09-19. The table below covers the first 7 days (31 runs at the time of writing).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per run:&lt;/strong&gt; 3 sequential GETs per provider with a cache-busting query string and a 15 s timeout. The median of the three is recorded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uptime:&lt;/strong&gt; share of runs that returned HTTP 2xx with a parseable body.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freshness:&lt;/strong&gt; the publication date inside the response compared with the run date (UTC).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/AllRates-Today/central-bank-exchange-rates/blob/main/scripts/benchmark.mjs" rel="noopener noreferrer"&gt;benchmark.mjs&lt;/a&gt; and &lt;a href="https://github.com/AllRates-Today/central-bank-exchange-rates/blob/main/.github/workflows/benchmark.yml" rel="noopener noreferrer"&gt;benchmark.yml&lt;/a&gt;. Output: &lt;a href="https://github.com/AllRates-Today/central-bank-exchange-rates/blob/main/benchmark/latest.json" rel="noopener noreferrer"&gt;latest.json&lt;/a&gt; and &lt;a href="https://github.com/AllRates-Today/central-bank-exchange-rates/blob/main/benchmark/history.csv" rel="noopener noreferrer"&gt;history.csv&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results, first 7 days
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Median&lt;/th&gt;
&lt;th&gt;p90&lt;/th&gt;
&lt;th&gt;Uptime&lt;/th&gt;
&lt;th&gt;Currencies&lt;/th&gt;
&lt;th&gt;Data age&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;fawazahmed0/currency-api (jsDelivr)&lt;/td&gt;
&lt;td&gt;market, static file&lt;/td&gt;
&lt;td&gt;11 ms&lt;/td&gt;
&lt;td&gt;23 ms&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;340&lt;/td&gt;
&lt;td&gt;1 day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AllRatesToday open central-bank endpoint&lt;/td&gt;
&lt;td&gt;official (ECB table)&lt;/td&gt;
&lt;td&gt;31 ms&lt;/td&gt;
&lt;td&gt;68 ms&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;29&lt;/td&gt;
&lt;td&gt;1 day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ExchangeRate-API open endpoint&lt;/td&gt;
&lt;td&gt;market&lt;/td&gt;
&lt;td&gt;112 ms&lt;/td&gt;
&lt;td&gt;131 ms&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;166&lt;/td&gt;
&lt;td&gt;0 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FloatRates&lt;/td&gt;
&lt;td&gt;market&lt;/td&gt;
&lt;td&gt;316 ms&lt;/td&gt;
&lt;td&gt;379 ms&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;146&lt;/td&gt;
&lt;td&gt;1 day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frankfurter&lt;/td&gt;
&lt;td&gt;official (ECB)&lt;/td&gt;
&lt;td&gt;373 ms&lt;/td&gt;
&lt;td&gt;580 ms&lt;/td&gt;
&lt;td&gt;96.8%&lt;/td&gt;
&lt;td&gt;29&lt;/td&gt;
&lt;td&gt;1 day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ECB eurofxref-daily.xml&lt;/td&gt;
&lt;td&gt;official, primary source&lt;/td&gt;
&lt;td&gt;401 ms&lt;/td&gt;
&lt;td&gt;558 ms&lt;/td&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;29&lt;/td&gt;
&lt;td&gt;1 day&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;"Data age" is the gap between the publication date in the response and the run date. A 1-day age on an ECB-derived feed is normal: the ECB publishes around 16:00 CET and the date rolls the next day.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the numbers actually say
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Static beats dynamic.&lt;/strong&gt; The fastest endpoint is not an API at all. fawazahmed0's project publishes JSON files to a CDN once a day. If daily market rates are enough and you can live without an SLA, a CDN file will always win on latency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edge-cached official tables are the next tier.&lt;/strong&gt; The AllRatesToday open endpoint serves the ECB table from Cloudflare's edge, which is why it lands at 31 ms from a US runner. It carries the ECB's own publication date, so it is usable for invoices and month-end where the auditor asks which rate you used.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The classic "free API" options are 100 to 400 ms.&lt;/strong&gt; ExchangeRate-API's open endpoint was the most consistent of the dynamic services: 100% uptime and a tight p90. FloatRates and Frankfurter are fine but slower, and Frankfurter dropped one run in the week. One failed run in 31 is not a verdict on Frankfurter, and the 30-day column on the live page will be fairer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Going straight to the ECB is the slowest option.&lt;/strong&gt; The primary source XML is 400 ms and still one day old. There is no freshness advantage to fetching it yourself. Cache it or use a mirror.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which one should you use
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Side project, daily rates, no budget:&lt;/strong&gt; fawazahmed0's CDN files or ExchangeRate-API's open endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anything an accountant will read:&lt;/strong&gt; an official-rate endpoint that returns the publisher and date. AllRatesToday's open endpoint does that for the ECB with no key, and the keyed API covers 116 central banks plus HMRC, US Treasury and Swiss customs tables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time market rates in a checkout:&lt;/strong&gt; none of the free endpoints above. Every one is daily. You need a paid tier from any provider that quotes sub-minute updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try the two fastest yourself
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# static CDN file, daily&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/eur.min.json | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; 200

&lt;span class="c"&gt;# official ECB table with publication date, no key&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"https://allratestoday.com/api/open/central-bank/ecb?source=USD&amp;amp;target=EUR"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The live page at &lt;a href="https://allratestoday.com/benchmarks/exchange-rate-api/" rel="noopener noreferrer"&gt;allratestoday.com/benchmarks/exchange-rate-api&lt;/a&gt; updates hourly and adds a rolling 30-day column once there is enough history. If you want another free endpoint added to the harness, open an issue on the data repo and include a keyless URL.&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>fintech</category>
    </item>
    <item>
      <title>A currency API with no API key: AllRatesToday is now in the public-apis directory</title>
      <dc:creator>viraj geeth</dc:creator>
      <pubDate>Tue, 22 Sep 2026 18:06:45 +0000</pubDate>
      <link>https://dev.to/viraj_geeth_e6dc448fe4d43/a-currency-api-with-no-api-key-allratestoday-is-now-in-the-public-apis-directory-4n5a</link>
      <guid>https://dev.to/viraj_geeth_e6dc448fe4d43/a-currency-api-with-no-api-key-allratestoday-is-now-in-the-public-apis-directory-4n5a</guid>
      <description>&lt;p&gt;&lt;a href="https://allratestoday.com/" rel="noopener noreferrer"&gt;AllRatesToday&lt;/a&gt; is now listed in the&lt;br&gt;
&lt;a href="https://publicapis.dev/resource/allratestoday/obgx1siv" rel="noopener noreferrer"&gt;public-apis&lt;/a&gt; directory under Currency&lt;br&gt;
Exchange. Rather than write a post that just says that, here is the part of the API that earns a&lt;br&gt;
place in a list of public APIs: a set of endpoints that need no key at all.&lt;/p&gt;
&lt;h2&gt;
  
  
  The keyless part
&lt;/h2&gt;

&lt;p&gt;Central banks and tax authorities publish an official exchange rate table, usually once per business&lt;br&gt;
day. That number is not a market rate — it is the figure a VAT return, a customs declaration or a set&lt;br&gt;
of statutory accounts has to use, because the regulation names the institution that published it.&lt;/p&gt;

&lt;p&gt;We collect those tables from 116 central banks and 3 tax authorities and serve the latest one for any&lt;br&gt;
source with no key, no signup and CORS wide open:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://allratestoday.com/api/open/central-bank/ecb"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bank"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ecb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rate_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-09-22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age_days"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stale"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cadence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"daily"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"quote"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"reference"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.1463&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"quote"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GBP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"reference"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.8578&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask for a single pair and you get the pair, plus whether it was published directly or derived:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://allratestoday.com/api/open/central-bank/cbuae?source=AED&amp;amp;target=USD"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap &lt;code&gt;ecb&lt;/code&gt; for &lt;code&gt;fed&lt;/code&gt;, &lt;code&gt;boe&lt;/code&gt;, &lt;code&gt;rbi&lt;/code&gt;, &lt;code&gt;pboc&lt;/code&gt;, &lt;code&gt;snb&lt;/code&gt;, &lt;code&gt;hmrc&lt;/code&gt;, &lt;code&gt;ustreasury&lt;/code&gt;, &lt;code&gt;bazg&lt;/code&gt; or any of the other&lt;br&gt;
codes. The catalogue is keyless too, and tells you how fresh each source is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://allratestoday.com/api/open/central-banks"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every response carries the publication date, the age in days and a &lt;code&gt;stale&lt;/code&gt; flag, which matters more&lt;br&gt;
than it sounds: a table that is one day old on a Saturday is correct behaviour, and a table that is&lt;br&gt;
nine days old is a problem. You should be able to tell those apart without guessing.&lt;/p&gt;

&lt;p&gt;The condition is attribution — a visible credit linking back — which is the same deal the data&lt;br&gt;
repository carries under CC BY 4.0.&lt;/p&gt;
&lt;h2&gt;
  
  
  In JavaScript, with no setup
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://allratestoday.com/api/open/central-bank/ecb?source=EUR&amp;amp;target=USD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rate_date&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`ECB reference rate on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rate_date&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: 1 EUR = &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; USD`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;CORS is open, so this works from the browser. No proxy, no key in your bundle.&lt;/p&gt;
&lt;h2&gt;
  
  
  What does need a key
&lt;/h2&gt;

&lt;p&gt;The free key takes a minute and no card, and unlocks the parts that are a database query rather than&lt;br&gt;
one cached object:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real-time mid-market rates&lt;/strong&gt; for 160+ currencies, refreshed every 60 seconds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A rate on any past date&lt;/strong&gt;, with the publishing institution's own weekend and holiday rule applied
and stated in the response&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full history and time series&lt;/strong&gt;, and CSV, XML or XLSX instead of JSON&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross rates&lt;/strong&gt; computed between two currencies neither of which is the bank's home currency&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Same data, no API at all
&lt;/h2&gt;

&lt;p&gt;If you would rather not call an API, the whole central-bank archive is a git repository, mirrored to&lt;br&gt;
jsDelivr, Hugging Face and Kaggle and refreshed daily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://cdn.jsdelivr.net/gh/AllRates-Today/central-bank-exchange-rates@main/data/ecb/latest.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is also an MCP server, so an AI agent can look up a rate and cite the institution and date&lt;br&gt;
instead of inventing one from training data.&lt;/p&gt;

&lt;h2&gt;
  
  
  One correction to the listing
&lt;/h2&gt;

&lt;p&gt;The directory's generated description says our rates come from Reuters and Refinitiv. They do not,&lt;br&gt;
and we do not license either. The real-time feed is aggregated institutional interbank market data;&lt;br&gt;
the official tables come from each institution's own publication. We had a sentence on our blog that&lt;br&gt;
placed the word "Reuters" next to our own sourcing, which is almost certainly what a crawler merged.&lt;br&gt;
That sentence is now fixed, and I have asked the directory to update the entry. If you are picking a&lt;br&gt;
data provider, "sourced from Reuters" is a claim worth making a vendor prove.&lt;/p&gt;




&lt;p&gt;Docs: &lt;a href="https://allratestoday.com/docs/" rel="noopener noreferrer"&gt;allratestoday.com/docs&lt;/a&gt; ·&lt;br&gt;
&lt;a href="https://allratestoday.com/openapi.json" rel="noopener noreferrer"&gt;OpenAPI&lt;/a&gt; ·&lt;br&gt;
&lt;a href="https://allratestoday.com/llms.txt" rel="noopener noreferrer"&gt;llms.txt&lt;/a&gt; for agents ·&lt;br&gt;
&lt;a href="https://allratestoday.com/register/" rel="noopener noreferrer"&gt;free key&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>currency</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Auto-localize prices in React with react-currency-localizer-realtime</title>
      <dc:creator>viraj geeth</dc:creator>
      <pubDate>Sat, 19 Sep 2026 19:50:47 +0000</pubDate>
      <link>https://dev.to/viraj_geeth_e6dc448fe4d43/auto-localize-prices-in-react-with-react-currency-localizer-realtime-mg2</link>
      <guid>https://dev.to/viraj_geeth_e6dc448fe4d43/auto-localize-prices-in-react-with-react-currency-localizer-realtime-mg2</guid>
      <description>&lt;p&gt;If you sell to international customers, showing prices in the visitor's local currency isn't a nice-to-have — it's a conversion-rate lever. But wiring it up usually turns into a small project: IP geolocation, exchange-rate fetching, caching, fallbacks, race conditions when the rate call is slower than render.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/react-currency-localizer-realtime" rel="noopener noreferrer"&gt;&lt;code&gt;react-currency-localizer-realtime&lt;/code&gt;&lt;/a&gt; compresses all of that into a React hook and a component. Drop it in, pass a price, done.&lt;/p&gt;

&lt;p&gt;Under the hood it uses real-time mid-market rates from the &lt;a href="https://allratestoday.com" rel="noopener noreferrer"&gt;AllRatesToday API&lt;/a&gt; — 160+ currencies, updated every 60 seconds, sourced from institutional interbank market data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;⚡ &lt;strong&gt;Real-time mid-market rates&lt;/strong&gt; — no retail markup, no hidden spread&lt;/li&gt;
&lt;li&gt;🌍 &lt;strong&gt;Auto-detect&lt;/strong&gt; the user's currency via IP geolocation (no API key needed for geolocation)&lt;/li&gt;
&lt;li&gt;💱 &lt;strong&gt;160+ currencies&lt;/strong&gt; — major, minor, exotic, and precious metals&lt;/li&gt;
&lt;li&gt;🧠 &lt;strong&gt;Smart caching&lt;/strong&gt; — 24h localStorage for geolocation, 1h memory cache for rates&lt;/li&gt;
&lt;li&gt;🔀 &lt;strong&gt;Three usage patterns&lt;/strong&gt; — hook, component, or batch&lt;/li&gt;
&lt;li&gt;🎯 &lt;strong&gt;Manual override&lt;/strong&gt; — skip geolocation with an explicit currency&lt;/li&gt;
&lt;li&gt;🔷 &lt;strong&gt;TypeScript-first&lt;/strong&gt; — full type definitions&lt;/li&gt;
&lt;li&gt;📦 &lt;strong&gt;Zero runtime deps&lt;/strong&gt; besides React itself&lt;/li&gt;
&lt;li&gt;🪶 &lt;strong&gt;~4KB gzipped&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;🛡️ &lt;strong&gt;Graceful fallbacks&lt;/strong&gt; — shows the original price if anything fails&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;react-currency-localizer-realtime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React 17+ is the only peer dependency.&lt;/p&gt;

&lt;p&gt;Get a free API key at &lt;a href="https://allratestoday.com/register" rel="noopener noreferrer"&gt;allratestoday.com/register&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The component — the simplest way
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LocalizedPrice&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-currency-localizer-realtime&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductCard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Premium Plan&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LocalizedPrice&lt;/span&gt;
        &lt;span class="na"&gt;basePrice&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;99.99&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;baseCurrency&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"USD"&lt;/span&gt;
        &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"YOUR_API_KEY"&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A visitor from Germany sees &lt;code&gt;92.34 €&lt;/code&gt;. A visitor from India sees &lt;code&gt;₹8,321&lt;/code&gt;. A visitor from the US just sees &lt;code&gt;$99.99&lt;/code&gt;. No per-country routing, no SSR detection, no currency-switcher UI to build.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The hook — full control
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;useCurrencyConverter&lt;/code&gt; when you need loading/error states or custom formatting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCurrencyConverter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-currency-localizer-realtime&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ProductPrice&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;convertedPrice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;localCurrency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCurrencyConverter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;basePrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;baseCurrency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading price...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;$&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt; &lt;span class="c1"&gt;// graceful fallback&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;convertedPrice&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;localCurrency&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Manual override
&lt;/h2&gt;

&lt;p&gt;Want to honor a user-picked currency? Pass it explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LocalizedPrice&lt;/span&gt;
  &lt;span class="na"&gt;basePrice&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mf"&gt;99.99&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;baseCurrency&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"USD"&lt;/span&gt;
  &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"JPY"&lt;/span&gt;           &lt;span class="c1"&gt;// override geolocation&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"YOUR_API_KEY"&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful when you have a currency switcher in the header.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just use &lt;code&gt;Intl.NumberFormat&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Intl.NumberFormat&lt;/code&gt; handles &lt;em&gt;formatting&lt;/em&gt;, not &lt;em&gt;conversion&lt;/em&gt;. If you pass it &lt;code&gt;99.99&lt;/code&gt; and tell it to format as JPY, it'll print &lt;code&gt;¥100&lt;/code&gt; — wrong. You still need an actual exchange rate.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;react-currency-localizer-realtime&lt;/code&gt; handles both: detect the currency, fetch the rate, apply it, format the output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance notes
&lt;/h2&gt;

&lt;p&gt;Two things usually hurt currency localizers on page load:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Geolocation calls on every render.&lt;/strong&gt; Fixed here with a 24h localStorage cache.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate fetches on every price.&lt;/strong&gt; Fixed here with a 1h in-memory cache shared across component instances.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Net effect: first visit triggers two network calls; every subsequent price on the page (and every return visit within 24h) is instant.&lt;/p&gt;

&lt;p&gt;If a request fails, the component falls back to showing the original price rather than blanking — your customers never see a broken UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-world use case
&lt;/h2&gt;

&lt;p&gt;This is the package I reach for whenever a WooCommerce/Shopify/custom storefront needs per-visitor pricing &lt;em&gt;without&lt;/em&gt; forking the catalog by region. It's the missing middle between "one-currency site" and "separate regional installs."&lt;/p&gt;

&lt;p&gt;Combine it with &lt;code&gt;LocalizedPrice&lt;/code&gt; on product cards and a currency switcher in the header, and you've covered 95% of international-storefront UX in an afternoon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;npm: &lt;a href="https://www.npmjs.com/package/react-currency-localizer-realtime" rel="noopener noreferrer"&gt;&lt;code&gt;react-currency-localizer-realtime&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Free API key: &lt;a href="https://allratestoday.com/register" rel="noopener noreferrer"&gt;allratestoday.com/register&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://allratestoday.com" rel="noopener noreferrer"&gt;allratestoday.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you ship it on a live store, I'd love to see the before/after conversion numbers — drop them in the comments.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written by the team behind &lt;a href="https://allratestoday.com" rel="noopener noreferrer"&gt;AllRatesToday&lt;/a&gt; — an exchange rate API with real-time mid-market rates for 150+ currencies and the official published rates of 116 central banks and tax authorities, with keyless open endpoints for the central-bank data. Browse the &lt;a href="https://allratestoday.com/docs" rel="noopener noreferrer"&gt;API docs&lt;/a&gt; or &lt;a href="https://allratestoday.com/register/" rel="noopener noreferrer"&gt;grab a free key&lt;/a&gt; to start building.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Open source: official SDKs for &lt;a href="https://github.com/AllRates-Today" rel="noopener noreferrer"&gt;JavaScript, Python, PHP, Go and Rust&lt;/a&gt;,&lt;br&gt;
plus an MCP server (&lt;code&gt;@allratestoday/mcp-server&lt;/code&gt;) for AI agents.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow along: &lt;a href="https://github.com/AllRates-Today" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>ecommerce</category>
      <category>currency</category>
    </item>
    <item>
      <title>Where Does Exchange Rate Data Come From? Sources, Accuracy, and Compliance</title>
      <dc:creator>viraj geeth</dc:creator>
      <pubDate>Sat, 19 Sep 2026 19:50:43 +0000</pubDate>
      <link>https://dev.to/viraj_geeth_e6dc448fe4d43/where-does-exchange-rate-data-come-from-sources-accuracy-and-compliance-n4b</link>
      <guid>https://dev.to/viraj_geeth_e6dc448fe4d43/where-does-exchange-rate-data-come-from-sources-accuracy-and-compliance-n4b</guid>
      <description>&lt;p&gt;When a developer asks "where does the data come from?", they are usually not asking out of curiosity. They are asking because an auditor, compliance officer, or product manager wants to know if the rates in their application are &lt;strong&gt;legally defensible&lt;/strong&gt;. The data source determines everything: accuracy, update frequency, auditability, and whether you can use it in regulated financial applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Four Tiers of Exchange Rate Data
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Tier 1: Central Banks (Most Authoritative)
&lt;/h3&gt;

&lt;p&gt;The ECB, Federal Reserve, Bank of England, and other central banks publish official reference rates. These are the gold standard for regulatory and tax reporting.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ECB:&lt;/strong&gt; ~30 currencies, updated daily at 16:00 CET&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Federal Reserve:&lt;/strong&gt; ~25 currencies, updated daily at 12:00 ET&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limitations:&lt;/strong&gt; Very few currencies, once-daily updates, published with delays&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Accounting, tax filings, regulatory compliance&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tier 2: Licensed Financial Data Providers (Production-Grade)
&lt;/h3&gt;

&lt;p&gt;Refinitiv, Bloomberg, and ICE provide real-time interbank rates sourced directly from Tier 1 banks and market makers. These feeds cost thousands per month when accessed directly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coverage:&lt;/strong&gt; 150–200+ currencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update frequency:&lt;/strong&gt; Seconds to minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data type:&lt;/strong&gt; Mid-market (interbank) rates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Trading, payments, e-commerce, any production app&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tier 3: Aggregated / Derived Data (Varies Widely)
&lt;/h3&gt;

&lt;p&gt;Some APIs aggregate rates from multiple unnamed sources, apply their own averaging, or derive rates from commercial services. Quality varies dramatically.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transparency:&lt;/strong&gt; Often unclear which sources are used&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risk:&lt;/strong&gt; May include retail spreads or outdated data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Non-critical displays, hobby projects&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tier 4: Scraped / Unverified Data (Not Recommended)
&lt;/h3&gt;

&lt;p&gt;Some free APIs scrape exchange rates from public websites or other APIs. No provenance, no audit trail, may violate terms of service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reliability:&lt;/strong&gt; Can break without notice&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legal risk:&lt;/strong&gt; May violate ToS of scraped sources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best for:&lt;/strong&gt; Personal projects only&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Major APIs Actually Use
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;API&lt;/th&gt;
&lt;th&gt;Primary Source&lt;/th&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Disclosed?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AllRatesToday&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;institutional interbank market data / Interbank feeds&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Tier 2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frankfurter&lt;/td&gt;
&lt;td&gt;European Central Bank (ECB)&lt;/td&gt;
&lt;td&gt;Tier 1&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open Exchange Rates&lt;/td&gt;
&lt;td&gt;"Multiple commercial sources"&lt;/td&gt;
&lt;td&gt;Tier 2–3&lt;/td&gt;
&lt;td&gt;Partially&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ExchangeRate-API&lt;/td&gt;
&lt;td&gt;"Central Banks and financial institutions"&lt;/td&gt;
&lt;td&gt;Tier 1–3&lt;/td&gt;
&lt;td&gt;Partially&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixer.io&lt;/td&gt;
&lt;td&gt;"ECB and commercial feeds"&lt;/td&gt;
&lt;td&gt;Tier 1–3&lt;/td&gt;
&lt;td&gt;Partially&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CurrencyAPI&lt;/td&gt;
&lt;td&gt;Not specified&lt;/td&gt;
&lt;td&gt;Unknown&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key insight:&lt;/strong&gt; Many APIs use vague language like "multiple commercial sources" without naming them. If you need data that will withstand an audit, look for APIs that explicitly name their sources.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Data Source Matters for Compliance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Financial Reporting (IFRS / GAAP)
&lt;/h3&gt;

&lt;p&gt;IFRS and GAAP require that exchange rates used in financial statements be traceable to a recognized source. Central Bank rates (Tier 1) are always accepted. Rates from a named provider like Reuters (Tier 2) are typically accepted. Rates from unnamed sources may be challenged by auditors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Payment Services (PSD2)
&lt;/h3&gt;

&lt;p&gt;In the EU, PSD2 requires transparency in currency conversion. If you process cross-border payments, you must disclose the exchange rate and its source. Using an API that doesn't disclose its source makes this impossible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tax Reporting
&lt;/h3&gt;

&lt;p&gt;Tax authorities accept Central Bank rates or recognized market rates. Using rates from an undisclosed source could result in rejected filings.&lt;/p&gt;

&lt;h2&gt;
  
  
  How AllRatesToday Sources Its Data
&lt;/h2&gt;

&lt;p&gt;AllRatesToday publishes two kinds of rates. Real-time mid-market rates are aggregated from institutional interbank market data; official rates are collected from the publication of each of 116 central banks and tax authorities (Tier 1). For the real-time feed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt; Tier 2 — aggregated institutional interbank market data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate type:&lt;/strong&gt; Mid-market (interbank) — no spread or markup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coverage:&lt;/strong&gt; 160+ currencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update frequency:&lt;/strong&gt; Every 60 seconds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comparable to:&lt;/strong&gt; the mid-market rate shown by Google Finance and XE&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API response includes timestamps for every rate, giving you a verifiable audit trail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.9234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-04-09T14:30:00Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;For audit trails:&lt;/strong&gt; Store the rate, timestamp, and source currency pair for every conversion your application performs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Choosing the Right Source for Your Use Case
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Recommended Source&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Financial statements&lt;/td&gt;
&lt;td&gt;Central Bank (Tier 1)&lt;/td&gt;
&lt;td&gt;Required by IFRS/GAAP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tax reporting&lt;/td&gt;
&lt;td&gt;Central Bank (Tier 1)&lt;/td&gt;
&lt;td&gt;Accepted by all tax authorities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payment processing&lt;/td&gt;
&lt;td&gt;Reuters/Refinitiv (Tier 2)&lt;/td&gt;
&lt;td&gt;Real-time accuracy, named source for PSD2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E-commerce pricing&lt;/td&gt;
&lt;td&gt;Reuters/Refinitiv (Tier 2)&lt;/td&gt;
&lt;td&gt;Live rates prevent margin erosion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dashboard / display&lt;/td&gt;
&lt;td&gt;Tier 1 or Tier 2&lt;/td&gt;
&lt;td&gt;Either works&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Questions to Ask Your API Provider
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What is the primary data source?&lt;/strong&gt; Accept named sources (ECB, Reuters, Bloomberg). Be wary of "multiple sources" without specifics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Are the rates mid-market or retail?&lt;/strong&gt; Mid-market = no spread. Retail = hidden markup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How often is the data refreshed from the source?&lt;/strong&gt; Not how fast the API responds — how fresh the underlying data is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can I get a data provenance statement?&lt;/strong&gt; For regulated industries, you may need written confirmation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What happens if the source goes down?&lt;/strong&gt; Stale data, errors, or failover?&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;AllRatesToday&lt;/strong&gt; sources mid-market rates from institutional interbank market data. Named source, timestamped responses, audit-ready data. Free tier available.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://allratestoday.com/register" rel="noopener noreferrer"&gt;Get your free API key&lt;/a&gt; | &lt;a href="https://allratestoday.com/developers" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt; | &lt;a href="https://github.com/allratestoday/exchange-rates-api" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written by the team behind &lt;a href="https://allratestoday.com" rel="noopener noreferrer"&gt;AllRatesToday&lt;/a&gt; — an exchange rate API with real-time mid-market rates for 150+ currencies and the official published rates of 116 central banks and tax authorities, with keyless open endpoints for the central-bank data. Browse the &lt;a href="https://allratestoday.com/docs" rel="noopener noreferrer"&gt;API docs&lt;/a&gt; or &lt;a href="https://allratestoday.com/register/" rel="noopener noreferrer"&gt;grab a free key&lt;/a&gt; to start building.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Open source: official SDKs for &lt;a href="https://github.com/AllRates-Today" rel="noopener noreferrer"&gt;JavaScript, Python, PHP, Go and Rust&lt;/a&gt;,&lt;br&gt;
plus an MCP server (&lt;code&gt;@allratestoday/mcp-server&lt;/code&gt;) for AI agents.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow along: &lt;a href="https://github.com/AllRates-Today" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>fintech</category>
      <category>currency</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Mid-Market vs Retail Exchange Rates: What Developers Need to Know</title>
      <dc:creator>viraj geeth</dc:creator>
      <pubDate>Sat, 19 Sep 2026 19:50:40 +0000</pubDate>
      <link>https://dev.to/viraj_geeth_e6dc448fe4d43/mid-market-vs-retail-exchange-rates-what-developers-need-to-know-10kl</link>
      <guid>https://dev.to/viraj_geeth_e6dc448fe4d43/mid-market-vs-retail-exchange-rates-what-developers-need-to-know-10kl</guid>
      <description>&lt;p&gt;When you integrate an exchange rate API into your application, one of the most important questions to ask is: &lt;strong&gt;"Is this the mid-market rate or a retail rate?"&lt;/strong&gt; The difference can mean a 1–5% hidden markup on every conversion your users see — and most API documentation doesn't make this clear.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is the Mid-Market Rate?
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;mid-market rate&lt;/strong&gt; (also called the &lt;strong&gt;interbank rate&lt;/strong&gt;) is the midpoint between the buy price and the sell price of a currency pair on the global foreign exchange market. It is the "true" exchange rate — the rate at which banks trade with each other in large volumes.&lt;/p&gt;

&lt;p&gt;When you see an exchange rate on Google, XE, or Bloomberg, you are seeing the mid-market rate.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; If banks are buying EUR at 1.0820 USD and selling EUR at 1.0830 USD, the mid-market rate is &lt;strong&gt;1.0825&lt;/strong&gt; — the midpoint between the two.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What Is a Retail Rate?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;retail rate&lt;/strong&gt; is the mid-market rate plus a &lt;strong&gt;spread&lt;/strong&gt; (markup). This spread is how banks, exchange services, and money transfer companies make money.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider Type&lt;/th&gt;
&lt;th&gt;Typical Spread&lt;/th&gt;
&lt;th&gt;Impact on $10,000&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mid-market (interbank)&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Online transfer (e.g. Wise)&lt;/td&gt;
&lt;td&gt;0.3–0.7%&lt;/td&gt;
&lt;td&gt;$30–$70&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bank wire transfer&lt;/td&gt;
&lt;td&gt;1–3%&lt;/td&gt;
&lt;td&gt;$100–$300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Credit card foreign transaction&lt;/td&gt;
&lt;td&gt;1–3%&lt;/td&gt;
&lt;td&gt;$100–$300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Airport currency exchange&lt;/td&gt;
&lt;td&gt;3–8%&lt;/td&gt;
&lt;td&gt;$300–$800&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why This Matters for Your Application
&lt;/h2&gt;

&lt;p&gt;If your API returns retail rates instead of mid-market rates, you have a transparency problem. Your users might think they are getting the "real" exchange rate, but there is already a hidden markup baked into the data.&lt;/p&gt;

&lt;h3&gt;
  
  
  E-Commerce Price Display
&lt;/h3&gt;

&lt;p&gt;If your online store shows "1 USD = 0.92 EUR" but the real mid-market rate is 0.9350, your international customers are seeing prices that are 1.6% higher than they should be. On a $500 purchase, that is $8 in invisible overcharge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-Currency SaaS Billing
&lt;/h3&gt;

&lt;p&gt;If you bill customers in their local currency using retail rates, you are effectively applying a markup your customers didn't agree to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Financial Reporting
&lt;/h3&gt;

&lt;p&gt;Auditors and compliance teams expect rates traceable to a recognized source. Mid-market rates from Reuters, Bloomberg, or Central Banks are accepted. Retail rates from unnamed sources are not.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Tell What Your API Returns
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Compare against Google:&lt;/strong&gt; Search "1 USD to EUR" on Google (mid-market rate). If your API's rate differs by more than 0.05%, it may include a spread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the documentation:&lt;/strong&gt; Look for "interbank," "mid-market," or "wholesale." If the docs say "indicative rates" or don't specify, be cautious.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask about the source:&lt;/strong&gt; Reuters, Refinitiv, or Bloomberg = mid-market. Unnamed "multiple sources" = potentially includes retail spreads.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Red flag:&lt;/strong&gt; If an exchange rate API is completely free with unlimited requests and doesn't disclose its data source, the data may be low-quality or include a hidden spread.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Adding Your Own Transparent Markup
&lt;/h2&gt;

&lt;p&gt;If your business model requires a spread, start with the mid-market rate and apply your own transparent margin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AllRatesToday&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@allratestoday/sdk&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AllRatesToday&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MARKUP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.005&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 0.5% spread&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getCustomerRate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;midMarketRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customerRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;midMarketRate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;MARKUP&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;midMarket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;midMarketRate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;customerRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;customerRate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;spread&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MARKUP&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getCustomerRate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EUR&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Mid-market: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;midMarket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Customer rate: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;customerRate&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (includes &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spread&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;% fee)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach gives you full control over your pricing while being transparent with your users about the markup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Mid-Market Rate&lt;/th&gt;
&lt;th&gt;Retail Rate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Definition&lt;/td&gt;
&lt;td&gt;Midpoint between buy/sell&lt;/td&gt;
&lt;td&gt;Mid-market + provider's spread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Markup&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;0.3% to 8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Used by&lt;/td&gt;
&lt;td&gt;Google, XE, Bloomberg&lt;/td&gt;
&lt;td&gt;Banks, exchange bureaus&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for apps&lt;/td&gt;
&lt;td&gt;Price display, invoicing, comparison&lt;/td&gt;
&lt;td&gt;Simulating actual transfer cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit-friendly&lt;/td&gt;
&lt;td&gt;Yes (traceable source)&lt;/td&gt;
&lt;td&gt;Depends on provider&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;strong&gt;AllRatesToday&lt;/strong&gt; provides mid-market rates from institutional interbank market data for 160+ currencies. No hidden spreads, no markup. Free tier available.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://allratestoday.com/register" rel="noopener noreferrer"&gt;Get your free API key&lt;/a&gt; | &lt;a href="https://allratestoday.com/developers" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt; | &lt;a href="https://github.com/allratestoday/exchange-rates-api" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written by the team behind &lt;a href="https://allratestoday.com" rel="noopener noreferrer"&gt;AllRatesToday&lt;/a&gt; — an exchange rate API with real-time mid-market rates for 150+ currencies and the official published rates of 116 central banks and tax authorities, with keyless open endpoints for the central-bank data. Browse the &lt;a href="https://allratestoday.com/docs" rel="noopener noreferrer"&gt;API docs&lt;/a&gt; or &lt;a href="https://allratestoday.com/register/" rel="noopener noreferrer"&gt;grab a free key&lt;/a&gt; to start building.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Open source: official SDKs for &lt;a href="https://github.com/AllRates-Today" rel="noopener noreferrer"&gt;JavaScript, Python, PHP, Go and Rust&lt;/a&gt;,&lt;br&gt;
plus an MCP server (&lt;code&gt;@allratestoday/mcp-server&lt;/code&gt;) for AI agents.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow along: &lt;a href="https://github.com/AllRates-Today" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>currency</category>
      <category>fintech</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Is Oanda API Free? (And What to Use Instead in 2026)</title>
      <dc:creator>viraj geeth</dc:creator>
      <pubDate>Mon, 14 Sep 2026 11:15:16 +0000</pubDate>
      <link>https://dev.to/viraj_geeth_e6dc448fe4d43/is-oanda-api-free-and-what-to-use-instead-in-2026-1445</link>
      <guid>https://dev.to/viraj_geeth_e6dc448fe4d43/is-oanda-api-free-and-what-to-use-instead-in-2026-1445</guid>
      <description>&lt;p&gt;&lt;strong&gt;Short answer: no.&lt;/strong&gt; Oanda does not offer a free, general-purpose currency API for developers. The widely-cited &lt;strong&gt;v20 REST API&lt;/strong&gt; requires a registered Oanda fxTrade brokerage account, and the separate &lt;strong&gt;Exchange Rates Data API&lt;/strong&gt; is paid-only with no permanent free tier.&lt;/p&gt;

&lt;p&gt;If you landed here because you searched "free Oanda API," you almost certainly don't want what Oanda actually sells. This guide explains what each Oanda API really is, who it's for, why most developers end up looking elsewhere, and which alternatives give you real-time FX data without the brokerage account or enterprise contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Two Oanda APIs (They're Not the Same Product)
&lt;/h2&gt;

&lt;p&gt;The first thing to understand is that "the Oanda API" is two completely different products with different audiences and access models.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Oanda v20 REST API (for traders)
&lt;/h3&gt;

&lt;p&gt;The v20 API is the programmatic interface to Oanda's &lt;strong&gt;fxTrade&lt;/strong&gt; brokerage platform. It exposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live bid/ask prices on the instruments your account is permitted to trade&lt;/li&gt;
&lt;li&gt;Order placement, modification, and cancellation&lt;/li&gt;
&lt;li&gt;Position and trade management&lt;/li&gt;
&lt;li&gt;Account history and transaction logs&lt;/li&gt;
&lt;li&gt;Streaming price and event endpoints over HTTP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To call it, you need an &lt;strong&gt;fxTrade account ID and a personal access token&lt;/strong&gt;, both issued by Oanda after you register. There are two flavors of token:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Practice (demo) tokens&lt;/strong&gt; — work against &lt;code&gt;api-fxpractice.oanda.com&lt;/code&gt; with simulated funds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live tokens&lt;/strong&gt; — work against &lt;code&gt;api-fxtrade.oanda.com&lt;/code&gt; with real funds in your funded account.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The v20 API itself doesn't have a per-call price tag, but you cannot use it without an Oanda account, and the live environment requires the same KYC, residency checks, and (in many regions) minimum deposits as opening any brokerage account. It is &lt;em&gt;not&lt;/em&gt; a developer-tier currency data API in the way that ExchangeRate-API or AllRatesToday are.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The Oanda Exchange Rates API (for businesses)
&lt;/h3&gt;

&lt;p&gt;The Exchange Rates Data API is Oanda's standalone &lt;strong&gt;commercial data product&lt;/strong&gt;, sold separately from fxTrade. It targets enterprises that need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Audit-grade historical FX rates (back to 1990 for some pairs)&lt;/li&gt;
&lt;li&gt;Daily, hourly, or minute-level snapshots&lt;/li&gt;
&lt;li&gt;Specific quote types (bid, ask, mid, highlow)&lt;/li&gt;
&lt;li&gt;Multi-currency reporting for ERP systems and tax compliance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This product has &lt;strong&gt;no free tier and no public pricing&lt;/strong&gt;. Access is through an annual sales contract negotiated based on coverage, frequency, and call volume. Public reports and customer disclosures place entry pricing in the hundreds of dollars per month and up — comparable to XE Currency Data API or Refinitiv's lower-tier feeds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Most Developers Can't (or Shouldn't) Use Oanda
&lt;/h2&gt;

&lt;p&gt;If you just want to convert USD to EUR in your app, or display live rates on a SaaS dashboard, Oanda is almost always the wrong tool. Here's why developers keep walking away:&lt;/p&gt;

&lt;h3&gt;
  
  
  You need a brokerage account for the v20 API
&lt;/h3&gt;

&lt;p&gt;To get a v20 access token, you have to &lt;strong&gt;register an Oanda fxTrade account&lt;/strong&gt;, complete KYC, and in some regions deposit funds. Even the demo path requires identity verification. You can't get a token in five minutes the way you can with most public REST APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  The v20 API isn't designed for general-purpose conversion
&lt;/h3&gt;

&lt;p&gt;The v20 endpoints are built around the concept of &lt;em&gt;your account&lt;/em&gt;: prices for instruments you're allowed to trade, in the account currency you opened with. There is no clean "give me USD/EUR mid-market right now" call without first assembling instrument lists and parsing tradeable prices. It works, but it's overkill for a converter widget.&lt;/p&gt;

&lt;h3&gt;
  
  
  Geofencing and regional restrictions
&lt;/h3&gt;

&lt;p&gt;Oanda is regulated in multiple jurisdictions and not every account type is available everywhere. Developers in some countries can't open a live fxTrade account at all, which means no live token, which means no production v20 access. Demo access is broader but still subject to regional availability.&lt;/p&gt;

&lt;h3&gt;
  
  
  2026 free-tier restrictions
&lt;/h3&gt;

&lt;p&gt;Over the past 12–18 months, Oanda has tightened access on multiple surfaces — including stricter KYC for new fxTrade accounts, region-specific fee schedules, and a rebrand of the data API away from the older "fxTrade Data" naming. The pattern is the same one we've seen at XE, CurrencyLayer, and others: legacy free or low-tier endpoints are quietly retired in favor of paid plans.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Exchange Rates API is sold to procurement, not developers
&lt;/h3&gt;

&lt;p&gt;If you have to email sales, sign an NDA, and wait two weeks for a quote, you're not in the developer-API market — you're in the enterprise data market. That's fine if you're a bank. It's the wrong shape for a startup, side project, or open-source library.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "Free Oanda API" Searches Actually Want
&lt;/h2&gt;

&lt;p&gt;When developers Google "is Oanda API free," what they almost always mean is one of three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;"Can I get live FX rates without paying?"&lt;/strong&gt; — Yes, with a permanent free tier from a developer-first API. Oanda is the wrong starting point.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Can I build a currency converter / SaaS pricing localizer / accounting app for free?"&lt;/strong&gt; — Yes, with sub-second to 60-second mid-market rates, full historical data, and no credit card required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Can I do paper trading / strategy backtests for free?"&lt;/strong&gt; — Use the Oanda v20 API in &lt;em&gt;demo mode&lt;/em&gt;. That's its actual free use case, but you'll still need to register a practice account.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're in the first two camps, you don't need Oanda. You need a developer-first FX data API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Oanda Alternatives for Developers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Permanent Free Tier&lt;/th&gt;
&lt;th&gt;Real-Time Updates&lt;/th&gt;
&lt;th&gt;Trading?&lt;/th&gt;
&lt;th&gt;Account Required&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AllRatesToday&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;60-second mid-market&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Email signup, no card&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oanda v20&lt;/td&gt;
&lt;td&gt;Demo only&lt;/td&gt;
&lt;td&gt;Tick-level on tradeable pairs&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;fxTrade account + KYC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Oanda Exchange Rates&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Configurable, paid&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Annual sales contract&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ExchangeRate-API&lt;/td&gt;
&lt;td&gt;Yes (limited)&lt;/td&gt;
&lt;td&gt;Daily on free, hourly on paid&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;API key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CurrencyLayer&lt;/td&gt;
&lt;td&gt;100 req/mo, USD only&lt;/td&gt;
&lt;td&gt;Hourly free, 60s on paid&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;API key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixer.io&lt;/td&gt;
&lt;td&gt;100 req/mo, EUR only&lt;/td&gt;
&lt;td&gt;Hourly free, 60s on paid&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;API key&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For pure currency data — conversions, historical rates, SaaS pricing localization, accounting integrations, dashboards — &lt;strong&gt;AllRatesToday&lt;/strong&gt; is the practical replacement. Same institutional-grade data feed Oanda's data product is built on, exposed as a clean REST API with a permanent free tier, official SDKs for JavaScript / Python / PHP, and an MCP server for AI agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Oanda &lt;em&gt;Is&lt;/em&gt; the Right Choice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You're building an automated &lt;strong&gt;trading bot&lt;/strong&gt; or systematic strategy and need order execution, not just prices.&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;tick-level streaming&lt;/strong&gt; on a specific set of forex / CFD instruments tied to a real funded account.&lt;/li&gt;
&lt;li&gt;You're an enterprise with a procurement budget and need &lt;strong&gt;audit-grade historical data&lt;/strong&gt; that names Oanda as the source.&lt;/li&gt;
&lt;li&gt;You already have an Oanda relationship for retail FX and want a single vendor.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Skip Oanda
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You only need &lt;strong&gt;currency conversions&lt;/strong&gt; in an app, dashboard, invoice, or report.&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;fast onboarding&lt;/strong&gt; — minutes, not weeks.&lt;/li&gt;
&lt;li&gt;You don't want to &lt;strong&gt;open a brokerage account&lt;/strong&gt; to call an API.&lt;/li&gt;
&lt;li&gt;You need a &lt;strong&gt;free tier&lt;/strong&gt; for prototyping, hobby projects, or open-source.&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;predictable monthly pricing&lt;/strong&gt;, not annual enterprise contracts.&lt;/li&gt;
&lt;li&gt;You need &lt;strong&gt;CORS&lt;/strong&gt; for browser-side calls (the v20 API is server-side only).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Drop-in Replacement Example
&lt;/h2&gt;

&lt;p&gt;Here's the same "USD to EUR conversion" call against AllRatesToday — no brokerage account, no contract, no KYC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://api.allratestoday.com/v1/convert?from=USD&amp;amp;to=EUR&amp;amp;amount=100"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"x-api-key: YOUR_API_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.9234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;92.34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-04-30T18:22:11Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replacing the v20 instrument-pricing flow takes about ten minutes. Replacing the Exchange Rates Data API for historical lookups takes the same. The free tier covers most prototypes outright; paid plans start far below Oanda's enterprise floor.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is the Oanda API free?
&lt;/h3&gt;

&lt;p&gt;No. The v20 REST API requires a registered fxTrade brokerage account (live or demo), and the Exchange Rates Data API is a paid product with no permanent free tier. There is no general-purpose free developer plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use the Oanda API without a trading account?
&lt;/h3&gt;

&lt;p&gt;Not the v20 API. It's tied to your fxTrade account credentials and is intended for executing trades or pulling data tied to that account. The Exchange Rates Data API is separate and does not require a trading account, but it is paid-only.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is the Oanda demo account API free?
&lt;/h3&gt;

&lt;p&gt;Yes — demo (practice) accounts can access the v20 API at no cost, but they're meant for testing trading strategies. They have rate limits, are subject to availability, and the rates may differ slightly from production. Demo access is not a substitute for a production data feed.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does the Oanda Exchange Rates API cost?
&lt;/h3&gt;

&lt;p&gt;Oanda does not publish list pricing publicly. The product is sold per-quote with annual contracts, and pricing is negotiated based on volume, currency coverage, and update frequency. Public reports place entry pricing in the hundreds of dollars per month and up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is there a free alternative to the Oanda API?
&lt;/h3&gt;

&lt;p&gt;Yes. &lt;a href="https://allratestoday.com/" rel="noopener noreferrer"&gt;AllRatesToday&lt;/a&gt; offers a permanent free tier with real-time mid-market rates, 160+ currencies, historical data, and no credit card required. It's the closest free equivalent for developers who don't need Oanda's trade execution capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use Oanda data in a commercial product?
&lt;/h3&gt;

&lt;p&gt;Yes, on paid plans of either the v20 or Exchange Rates products, subject to Oanda's licensing terms. The demo / practice environment is generally not licensed for commercial redistribution — read the terms before shipping.&lt;/p&gt;




&lt;p&gt;If you searched for a free Oanda API, you don't actually need Oanda — you need &lt;strong&gt;real-time mid-market FX rates with a developer-friendly free tier&lt;/strong&gt;. &lt;a href="https://allratestoday.com/" rel="noopener noreferrer"&gt;AllRatesToday&lt;/a&gt; ships exactly that, with official SDKs and an MCP server for AI agents. No brokerage account required.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written by the team behind &lt;a href="https://allratestoday.com" rel="noopener noreferrer"&gt;AllRatesToday&lt;/a&gt; — an exchange rate API&lt;br&gt;
with real-time mid-market rates for 160+ currencies and the official published tables of&lt;br&gt;
116 central banks and tax authorities. The official-rate endpoint needs no key. Browse the&lt;br&gt;
&lt;a href="https://allratestoday.com/docs" rel="noopener noreferrer"&gt;API docs&lt;/a&gt; or &lt;a href="https://allratestoday.com/register/" rel="noopener noreferrer"&gt;grab a free key&lt;/a&gt;&lt;br&gt;
to start building.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Open source: official SDKs for &lt;a href="https://github.com/AllRates-Today" rel="noopener noreferrer"&gt;JavaScript, Python, PHP, Go and Rust&lt;/a&gt;,&lt;br&gt;
plus MCP servers and a hosted MCP endpoint at &lt;code&gt;https://allratestoday.com/api/mcp&lt;/code&gt; for AI agents.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>fintech</category>
      <category>currency</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How Often Are Exchange Rates Updated? Real-Time vs Daily Explained</title>
      <dc:creator>viraj geeth</dc:creator>
      <pubDate>Mon, 14 Sep 2026 11:15:15 +0000</pubDate>
      <link>https://dev.to/viraj_geeth_e6dc448fe4d43/how-often-are-exchange-rates-updated-real-time-vs-daily-explained-g6p</link>
      <guid>https://dev.to/viraj_geeth_e6dc448fe4d43/how-often-are-exchange-rates-updated-real-time-vs-daily-explained-g6p</guid>
      <description>&lt;p&gt;"How often are the rates updated?" is the single most asked question about exchange rate APIs. It shows up in every API's FAQ, every developer forum thread, and every Stack Overflow comparison. And for good reason — the answer determines whether an API is suitable for your project or a liability waiting to happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Layers of "Update Frequency"
&lt;/h2&gt;

&lt;p&gt;When an API says "rates updated every X," that statement hides three separate concerns.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Real-Time vs Delayed Data
&lt;/h3&gt;

&lt;p&gt;The forex market trades 24 hours a day, 5 days a week. Currency prices change every second. An API's update frequency tells you how closely it tracks those changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real-time (seconds to minutes):&lt;/strong&gt; Pulls from live interbank market feeds. Essential for trading, payments, and any app where a 1% swing matters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hourly:&lt;/strong&gt; A middle ground. Acceptable for dashboards and reporting, but misses intraday volatility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Daily:&lt;/strong&gt; A single snapshot, usually from the ECB at 16:00 CET. Fine for accounting and invoicing.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; On March 11, 2026, GBP/USD moved from 1.2910 to 1.2745 within 6 hours after an unexpected Bank of England announcement. An app using daily rates would have shown a price that was off by 1.3% for the entire day — a $13 discrepancy on every $1,000 transaction.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  2. The "Free Tier" Trap
&lt;/h3&gt;

&lt;p&gt;Most exchange rate APIs advertise real-time capabilities but lock them behind paid plans. Here is what free tiers actually deliver:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;API&lt;/th&gt;
&lt;th&gt;Free Tier Update&lt;/th&gt;
&lt;th&gt;Paid Tier Update&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AllRatesToday&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Every 60 seconds&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Every 60 seconds&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open Exchange Rates&lt;/td&gt;
&lt;td&gt;Hourly&lt;/td&gt;
&lt;td&gt;Every 5 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixer.io&lt;/td&gt;
&lt;td&gt;Daily&lt;/td&gt;
&lt;td&gt;Every 60 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ExchangeRate-API&lt;/td&gt;
&lt;td&gt;Daily&lt;/td&gt;
&lt;td&gt;Daily&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CurrencyAPI&lt;/td&gt;
&lt;td&gt;Daily&lt;/td&gt;
&lt;td&gt;Hourly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frankfurter&lt;/td&gt;
&lt;td&gt;Daily (ECB)&lt;/td&gt;
&lt;td&gt;N/A (free only)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice the pattern: most free tiers give you &lt;strong&gt;daily rates only&lt;/strong&gt;. You build your app, test it, ship it — and then discover during market volatility that your "exchange rate feature" is showing yesterday's price.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AllRatesToday is different:&lt;/strong&gt; The free tier gets the same 60-second update frequency as paid plans. The only limit is request volume, not data freshness.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Accuracy vs Latency: What Does "Real-Time" Actually Mean?
&lt;/h3&gt;

&lt;p&gt;This is the subtlety most developers miss. "Real-time" can mean two very different things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real-time source:&lt;/strong&gt; The underlying data comes from live institutional interbank feeds. The rate itself is current.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time delivery:&lt;/strong&gt; The API responds quickly, but the data might be a cached snapshot from hours ago. Fast delivery, stale data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Always ask: &lt;strong&gt;"Is the data real-time, or just the API response?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AllRatesToday sources data from &lt;strong&gt;institutional interbank market data&lt;/strong&gt; and interbank market feeds — the same sources used by Google Finance, XE, and Bloomberg.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Update Frequency Do You Actually Need?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Minimum Update&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Trading / Forex&lt;/td&gt;
&lt;td&gt;Real-time (seconds)&lt;/td&gt;
&lt;td&gt;Price slippage directly costs money&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payment processing&lt;/td&gt;
&lt;td&gt;Real-time (minutes)&lt;/td&gt;
&lt;td&gt;Conversion at checkout must reflect current market&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E-commerce price display&lt;/td&gt;
&lt;td&gt;Hourly to real-time&lt;/td&gt;
&lt;td&gt;Stale rates erode margins or overcharge customers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SaaS multi-currency billing&lt;/td&gt;
&lt;td&gt;Daily to hourly&lt;/td&gt;
&lt;td&gt;Invoices are usually generated at intervals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accounting / Tax reporting&lt;/td&gt;
&lt;td&gt;Daily&lt;/td&gt;
&lt;td&gt;Regulatory bodies accept end-of-day rates&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How to Verify an API's Update Frequency
&lt;/h2&gt;

&lt;p&gt;Don't take marketing claims at face value. Here is a simple test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fetch the rate, wait 2 minutes, fetch again&lt;/span&gt;
&lt;span class="c"&gt;# Compare the timestamps and values&lt;/span&gt;

curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"https://allratestoday.com/api/v1/rates?source=USD&amp;amp;target=EUR"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_API_KEY"&lt;/span&gt; | jq &lt;span class="s1"&gt;'.time, .rate'&lt;/span&gt;

&lt;span class="nb"&gt;sleep &lt;/span&gt;120

curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"https://allratestoday.com/api/v1/rates?source=USD&amp;amp;target=EUR"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_API_KEY"&lt;/span&gt; | jq &lt;span class="s1"&gt;'.time, .rate'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the timestamps are different and the rate has changed (even slightly), the API is genuinely updating. If both calls return the exact same timestamp, you are getting cached daily data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Daily rates&lt;/strong&gt; are fine for accounting and reporting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hourly rates&lt;/strong&gt; work for dashboards and non-transactional displays.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time rates&lt;/strong&gt; are essential for payments, e-commerce, and anything where money changes hands.&lt;/li&gt;
&lt;li&gt;Most free APIs give you daily data. Check the fine print before building on top of it.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;AllRatesToday&lt;/strong&gt; updates every 60 seconds from institutional interbank market data — even on the free plan. 160+ currencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://allratestoday.com/register" rel="noopener noreferrer"&gt;Get your free API key&lt;/a&gt; | &lt;a href="https://allratestoday.com/developers" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt; | &lt;a href="https://github.com/allratestoday/exchange-rates-api" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written by the team behind &lt;a href="https://allratestoday.com" rel="noopener noreferrer"&gt;AllRatesToday&lt;/a&gt; — an exchange rate API&lt;br&gt;
with real-time mid-market rates for 160+ currencies and the official published tables of&lt;br&gt;
116 central banks and tax authorities. The official-rate endpoint needs no key. Browse the&lt;br&gt;
&lt;a href="https://allratestoday.com/docs" rel="noopener noreferrer"&gt;API docs&lt;/a&gt; or &lt;a href="https://allratestoday.com/register/" rel="noopener noreferrer"&gt;grab a free key&lt;/a&gt;&lt;br&gt;
to start building.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Open source: official SDKs for &lt;a href="https://github.com/AllRates-Today" rel="noopener noreferrer"&gt;JavaScript, Python, PHP, Go and Rust&lt;/a&gt;,&lt;br&gt;
plus MCP servers and a hosted MCP endpoint at &lt;code&gt;https://allratestoday.com/api/mcp&lt;/code&gt; for AI agents.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>currency</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>14.6 million official exchange rates from 107 central banks and tax authorities, now on Hugging Face</title>
      <dc:creator>viraj geeth</dc:creator>
      <pubDate>Mon, 14 Sep 2026 11:14:41 +0000</pubDate>
      <link>https://dev.to/viraj_geeth_e6dc448fe4d43/146-million-official-exchange-rates-from-107-central-banks-and-tax-authorities-now-on-hugging-face-4nel</link>
      <guid>https://dev.to/viraj_geeth_e6dc448fe4d43/146-million-official-exchange-rates-from-107-central-banks-and-tax-authorities-now-on-hugging-face-4nel</guid>
      <description>&lt;p&gt;If you have ever needed "the ECB rate on the invoice date" for a tax return, a customs form, a transfer-pricing file or an audit, you know the problem. The number exists. It is public. And it is scattered across a hundred central-bank websites, each with its own PDF, XML feed, Excel download or HTML table, each with its own idea of which way round a rate should be quoted.&lt;/p&gt;

&lt;p&gt;We spent most of this year collecting those tables into one pipeline. As of this week the full history is a public dataset on Hugging Face:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://huggingface.co/datasets/AllRates/central-bank-exchange-rates" rel="noopener noreferrer"&gt;https://huggingface.co/datasets/AllRates/central-bank-exchange-rates&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rows&lt;/td&gt;
&lt;td&gt;14,612,276&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Institutions&lt;/td&gt;
&lt;td&gt;103 central banks + 4 tax authorities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Earliest date&lt;/td&gt;
&lt;td&gt;1914 (Swiss National Bank)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Currencies&lt;/td&gt;
&lt;td&gt;215 base, 202 quote&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Refresh&lt;/td&gt;
&lt;td&gt;daily, from the GitHub source repo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;CC BY 4.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Size&lt;/td&gt;
&lt;td&gt;515 MB CSV, auto-converted to Parquet&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why "official" rates and not market rates
&lt;/h2&gt;

&lt;p&gt;Most exchange-rate datasets are market data: a mid-market snapshot from some aggregator at some time of day. That is the right thing for a price display. It is the wrong thing for anything a regulator will look at.&lt;/p&gt;

&lt;p&gt;Tax offices, customs agencies and accounting standards usually name a publisher. HMRC publishes monthly rates for UK VAT and customs. The ECB reference rate is the default for euro-area statutory reporting. The Reserve Bank of India reference rate is the benchmark for statutory rupee conversions. The Reserve Bank of Australia, Bank of Canada, Banco Central do Brasil and dozens of others publish a daily fixing that is &lt;em&gt;the&lt;/em&gt; rate for that jurisdiction, regardless of what the interbank market did five minutes later.&lt;/p&gt;

&lt;p&gt;Those numbers are not derivable from market data. They have to be collected from the source, on the source's schedule, in the source's convention. That is what this dataset is.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is in it
&lt;/h2&gt;

&lt;p&gt;One CSV per institution under &lt;code&gt;rates/&lt;/code&gt;, five columns, identical everywhere:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Column&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;date&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;ISO 8601 publication date. Weekends and the publisher's holidays are simply absent.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;base&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;The currency being priced (ISO 4217).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;quote&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;The currency it is priced in.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;string&lt;/td&gt;
&lt;td&gt;The publisher's own label: &lt;code&gt;reference&lt;/code&gt;, &lt;code&gt;middle&lt;/code&gt;, &lt;code&gt;buy&lt;/code&gt;, &lt;code&gt;sell&lt;/code&gt;, &lt;code&gt;spot&lt;/code&gt;, &lt;code&gt;indicative&lt;/code&gt;, &lt;code&gt;monthly&lt;/code&gt;, &lt;code&gt;monthly_average&lt;/code&gt;, &lt;code&gt;quarterly&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt;, and a few more.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;value&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;float&lt;/td&gt;
&lt;td&gt;How many &lt;code&gt;quote&lt;/code&gt; one &lt;code&gt;base&lt;/code&gt; buys.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A few rows from &lt;code&gt;rates/ecb.csv&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;date,base,quote,type,value
2025-01-02,EUR,AUD,reference,1.6618
2025-01-02,EUR,BGN,reference,1.9558
2025-01-02,EUR,BRL,reference,6.42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alongside the history there is &lt;code&gt;latest/&amp;lt;code&amp;gt;.json&lt;/code&gt; with each institution's most recent table, and &lt;code&gt;sources.json&lt;/code&gt; with the institution's name, country, home currency, kind (central bank or tax authority) and the URL of the page we collect from.&lt;/p&gt;

&lt;p&gt;Coverage by depth, to give you a sense of what "back to 1914" actually means:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Institution&lt;/th&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;First year in dataset&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Swiss National Bank&lt;/td&gt;
&lt;td&gt;&lt;code&gt;snb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1914&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bank of Korea&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bok&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1964&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bank of Israel&lt;/td&gt;
&lt;td&gt;&lt;code&gt;boi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1975&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hong Kong Monetary Authority&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hkma&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1981&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bank of Japan&lt;/td&gt;
&lt;td&gt;&lt;code&gt;boj&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1998&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;European Central Bank&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ecb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1999&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reserve Bank of India&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rbi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2003&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;People's Bank of China&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pboc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2006&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most institutions only publish a few years of history on their own sites. Where a bank offered more, we took all of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loading it
&lt;/h2&gt;

&lt;p&gt;With the &lt;code&gt;datasets&lt;/code&gt; library, the whole thing as one table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datasets&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dataset&lt;/span&gt;

&lt;span class="n"&gt;ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AllRates/central-bank-exchange-rates&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rates&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With pandas, one institution at a time. This is usually what you want, because 14.6 million rows is a lot of memory for a question about one bank:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;ecb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hf://datasets/AllRates/central-bank-exchange-rates/rates/ecb.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;parse_dates&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;usd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ecb&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;ecb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EUR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ecb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;USD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nf"&gt;set_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;usd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Polars, lazily, if you want to scan several banks without loading all of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;polars&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pl&lt;/span&gt;

&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;pl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scan_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hf://datasets/AllRates/central-bank-exchange-rates/rates/*.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;pl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;USD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;col&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quote&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With DuckDB, straight off the Hub, no download step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;INSTALL&lt;/span&gt; &lt;span class="n"&gt;httpfs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;LOAD&lt;/span&gt; &lt;span class="n"&gt;httpfs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="s1"&gt;'hf://datasets/AllRates/central-bank-exchange-rates/rates/rbi.csv'&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'USD'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;quote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'INR'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'reference'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Three things you can do with it that you could not do before
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Compare what different central banks say the same pair is worth.&lt;/strong&gt; The ECB publishes EUR→USD. The Fed publishes USD→EUR. The Bank of Canada publishes both against CAD. On any given day these disagree by a few basis points because they fix at different times. That spread is itself interesting, and until now you had to scrape three sites to see it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reconstruct a filing exactly.&lt;/strong&gt; Pick the publisher your jurisdiction names, filter to &lt;code&gt;type == "reference"&lt;/code&gt; (or whatever that publisher calls its headline rate), take the row for the invoice date. If the date is missing, the publisher did not publish that day, and your local rule will say whether to use the previous or next business day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Train on a century of official fixings.&lt;/strong&gt; The SNB series runs from 1914. The Bank of Korea from 1964. If you are building anything that needs long, clean, non-market FX series, this is a larger and more consistent corpus than we could find anywhere else in the open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conventions and caveats
&lt;/h2&gt;

&lt;p&gt;We made a few decisions that you should know about before relying on the data.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Direction follows the publisher.&lt;/strong&gt; If the ECB says 1 EUR = 1.0850 USD, that is the row: &lt;code&gt;EUR,USD,reference,1.0850&lt;/code&gt;. We do not flip rates, and we do not compute crosses. If a bank does not publish GBP against JPY, there is no GBP/JPY row for that bank.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;type&lt;/code&gt; is the publisher's label, normalised only in spelling.&lt;/strong&gt; A &lt;code&gt;buy&lt;/code&gt; rate from one bank and a &lt;code&gt;buy&lt;/code&gt; rate from another are not guaranteed to mean the same thing. Read the source page linked in &lt;code&gt;sources.json&lt;/code&gt; if it matters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gaps are real.&lt;/strong&gt; A missing date means the institution did not publish, or published something our collector could not parse and our validation rejected. We would rather have a hole than a wrong number.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every row went through a cross-source plausibility check&lt;/strong&gt; before it was committed. Values that disagree with the rest of the world by more than a threshold are quarantined and reviewed by hand. That caught a handful of unit errors during the backfill, which is why we trust the rest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify before you file.&lt;/strong&gt; The figures are public information republished under CC BY 4.0. For anything legal or tax-related, the original publisher's page is the authority, and it is linked from &lt;code&gt;sources.json&lt;/code&gt; for every institution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How it stays current
&lt;/h2&gt;

&lt;p&gt;The dataset is a mirror of a GitHub repository, &lt;a href="https://github.com/AllRates-Today/central-bank-exchange-rates" rel="noopener noreferrer"&gt;AllRates-Today/central-bank-exchange-rates&lt;/a&gt;, which is itself fed by the collection pipeline behind &lt;a href="https://allratestoday.com" rel="noopener noreferrer"&gt;AllRatesToday&lt;/a&gt;. A scheduled Action runs four times a day, pulls each institution's latest table from a keyless open endpoint, commits only when something changed, and then pushes the consolidated per-institution CSVs to Hugging Face. So the Hub copy is never more than a few hours behind the source sites.&lt;/p&gt;

&lt;p&gt;If you want the same data as small JSON files on a CDN instead of a 500 MB dataset, the GitHub repo serves &lt;code&gt;data/latest.json&lt;/code&gt; and per-bank &lt;code&gt;latest.json&lt;/code&gt; over jsDelivr with no key. If you want it as an API with a query language, the same rates are behind &lt;code&gt;https://allratestoday.com/api/open/central-bank/&amp;lt;code&amp;gt;&lt;/code&gt;, also keyless.&lt;/p&gt;

&lt;h2&gt;
  
  
  License
&lt;/h2&gt;

&lt;p&gt;CC BY 4.0. Use it commercially, redistribute it, train on it. The one condition is visible credit to AllRatesToday with a link to &lt;a href="https://allratestoday.com" rel="noopener noreferrer"&gt;https://allratestoday.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you build something with it, open an issue on the GitHub repo or leave a note in the dataset's Community tab. Missing an institution you need? The repo README lists how new sources get added, and we are actively expanding coverage.&lt;/p&gt;

</description>
      <category>dataset</category>
      <category>finance</category>
      <category>python</category>
      <category>opendata</category>
    </item>
    <item>
      <title>Your coding agent is quoting exchange rates from its training data</title>
      <dc:creator>viraj geeth</dc:creator>
      <pubDate>Mon, 14 Sep 2026 11:12:32 +0000</pubDate>
      <link>https://dev.to/viraj_geeth_e6dc448fe4d43/your-coding-agent-is-quoting-exchange-rates-from-its-training-data-2mgj</link>
      <guid>https://dev.to/viraj_geeth_e6dc448fe4d43/your-coding-agent-is-quoting-exchange-rates-from-its-training-data-2mgj</guid>
      <description>&lt;p&gt;Try this in any AI coding tool:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Write a function that converts USD to EUR.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is a good chance you get something like this back:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;USD_TO_EUR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.92&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;usdToEur&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;USD_TO_EUR&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It compiles. It passes review. It is wrong, and it will stay wrong, silently, for as long as the code lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is worse than a normal hallucination
&lt;/h2&gt;

&lt;p&gt;Most model mistakes are &lt;em&gt;visibly&lt;/em&gt; wrong. You run the code, it throws, you fix it. A stale exchange rate is different in three ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It looks right.&lt;/strong&gt; &lt;code&gt;0.92&lt;/code&gt; is a plausible USD/EUR rate. It was probably even correct at some point during pretraining. Nothing in the diff says "this number has an expiry date."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It has no failure mode.&lt;/strong&gt; The function returns a number forever. There is no exception to catch, no log line, no alert.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It is money.&lt;/strong&gt; If that function prices a checkout, every transaction is off by whatever the market has done since the training cutoff. A percent or two, compounding across every order, in the direction you didn't choose.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And the same reflex shows up in the conversational case. Ask an agent "what's the USD to EUR rate?" and it will often just answer — no fetch, no date, no caveat — because producing a fluent number is what it does.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix isn't a better prompt
&lt;/h2&gt;

&lt;p&gt;You can tell the model "always fetch live rates" in your CLAUDE.md and it will comply, in that repo, until the instruction falls out of context. What actually fixes it is making the correct behaviour the path of least resistance: give the agent a tool that returns a real rate, and a skill that fires on the &lt;em&gt;intent&lt;/em&gt; rather than waiting to be asked.&lt;/p&gt;

&lt;p&gt;That is what this plugin is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace add AllRates-Today/claude-code-plugin
/plugin &lt;span class="nb"&gt;install &lt;/span&gt;allratestoday@allratestoday
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;No API key needed.&lt;/strong&gt; That part matters more than it sounds — read on.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it installs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Two skills.&lt;/strong&gt; Skills load themselves when a task matches their description, which is the difference between a tool you have to remember and one that shows up on its own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;exchange-rates&lt;/code&gt; — fires on currency conversion, FX, localized pricing, historical series. Leads with "never quote a rate from memory", then covers which rate the task needs, caching by pair, money in minor units, and what happens when the fetch fails.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;official-rates&lt;/code&gt; — fires on invoices, VAT, customs, statutory accounting. More on why that is a separate skill below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Someone typing &lt;em&gt;"show prices in the visitor's currency"&lt;/em&gt; gets the first one loaded without ever having heard of us. That is the whole point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Five slash commands:&lt;/strong&gt; &lt;code&gt;/rate USD EUR&lt;/code&gt;, &lt;code&gt;/convert 1500 USD to EUR&lt;/code&gt;, &lt;code&gt;/official-rate ecb USD EUR 2026-01-15&lt;/code&gt;, &lt;code&gt;/fx-history USD EUR 30d&lt;/code&gt;, and &lt;code&gt;/add-currency-support&lt;/code&gt;, which reads your project — its language, HTTP conventions, secrets pattern, existing cache layer — and wires rates in the way that project already does things. It also greps for hardcoded rates while it's in there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two MCP servers&lt;/strong&gt;, so the model can fetch rates directly rather than shelling out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/@allratestoday/mcp-server" rel="noopener noreferrer"&gt;&lt;code&gt;@allratestoday/mcp-server&lt;/code&gt;&lt;/a&gt; — live mid-market rates, 160+ currencies&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/@allratestoday/central-bank-mcp" rel="noopener noreferrer"&gt;&lt;code&gt;@allratestoday/central-bank-mcp&lt;/code&gt;&lt;/a&gt; — official published tables from 100+ central banks and tax authorities&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The mistake that costs more than a stale rate
&lt;/h2&gt;

&lt;p&gt;There are two different numbers people call "the exchange rate", and using the wrong one is the expensive bug.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;mid-market rate&lt;/strong&gt; is the live interbank midpoint. It moves continuously. It is the right number for a checkout, a price display, a converter.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;official rate&lt;/strong&gt; is what a named institution published — the ECB reference rate for a given day, the HMRC monthly rate, the Bank of Japan rate in force. It is fixed once published, carries the publisher's own date, and is what an auditor checks against.&lt;/p&gt;

&lt;p&gt;Compliance rules essentially never say "use the current market rate". They name a publisher and a date. And the two routinely differ by a percent or more, so a VAT return computed from a market rate produces numbers nobody can reconcile.&lt;/p&gt;

&lt;p&gt;An LLM will not make this distinction unprompted — both are "the exchange rate" as far as the language goes. So it's built into the plugin: the &lt;code&gt;official-rates&lt;/code&gt; skill fires on tax and invoicing intent, and &lt;code&gt;/convert&lt;/code&gt; stops and redirects you if you mention an invoice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why keyless mattered more than we expected
&lt;/h2&gt;

&lt;p&gt;The first version of both MCP servers did the responsible-looking thing: no API key, refuse to start, print instructions.&lt;/p&gt;

&lt;p&gt;Then I installed the plugin as a new user would, and ran &lt;code&gt;claude mcp list&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plugin:allratestoday:allratestoday: ✘ Failed to connect — CONNECTION_CLOSED
plugin:allratestoday:allratestoday-central-bank: ✘ Failed to connect — CONNECTION_CLOSED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An MCP server that exits doesn't degrade — it takes the host client's whole config down with it, at exactly the moment someone is deciding whether this is worth the trouble. "Fail fast with a clear message" is good advice for a CLI and terrible advice for a subprocess whose stderr nobody reads.&lt;/p&gt;

&lt;p&gt;Both servers now degrade instead. With no key:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;get_exchange_rate&lt;/code&gt; answers from the official ECB daily reference table — about 30 major currencies, labelled with its publication date so the model never passes a daily fixing off as a live quote&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;list_currencies&lt;/code&gt; returns all 160+ codes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_official_rates&lt;/code&gt; returns the latest published table for any of the 100+ sources&lt;/li&gt;
&lt;li&gt;the metered tools return one sentence explaining the free tier, instead of a dead process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That path reads endpoints that are already open and edge-cached, so it costs nothing to give away:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://allratestoday.com/api/open/central-bank/ecb?source=USD&amp;amp;target=EUR"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bank"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ecb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rate_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-08-28"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.8588851671&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rate_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"reference"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"derived"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"inverse"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;a href="https://allratestoday.com/register" rel="noopener noreferrer"&gt;free API key&lt;/a&gt; adds real-time mid-market rates across 160+ currencies, historical series, rates on past dates, and publication calendars. But nothing is gated behind a signup form before you can tell whether the thing works.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you'd rather not install anything
&lt;/h2&gt;

&lt;p&gt;The general lesson stands on its own: &lt;strong&gt;an agent should never produce a rate it did not fetch.&lt;/strong&gt; Put this in your CLAUDE.md and you get most of the value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Never state or hardcode an exchange rate from memory — fetch it.
For tax, invoices or customs, use the rate the relevant authority
published on the relevant date, not the current market rate.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you want the endpoint without any of the rest, that &lt;code&gt;curl&lt;/code&gt; above needs no key and no account.&lt;/p&gt;




&lt;p&gt;Plugin source: &lt;a href="https://github.com/AllRates-Today/claude-code-plugin" rel="noopener noreferrer"&gt;github.com/AllRates-Today/claude-code-plugin&lt;/a&gt; · API docs: &lt;a href="https://allratestoday.com/docs" rel="noopener noreferrer"&gt;allratestoday.com/docs&lt;/a&gt; · for agents: &lt;a href="https://allratestoday.com/llms.txt" rel="noopener noreferrer"&gt;llms.txt&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
      <category>mcp</category>
      <category>currency</category>
    </item>
    <item>
      <title>Building a Simple Exchange Rate MCP Server using FastMCP and AllRatesToday</title>
      <dc:creator>viraj geeth</dc:creator>
      <pubDate>Sun, 26 Apr 2026 09:38:19 +0000</pubDate>
      <link>https://dev.to/viraj_geeth_e6dc448fe4d43/building-a-simple-exchange-rate-mcp-server-using-fastmcp-and-allratestoday-28bj</link>
      <guid>https://dev.to/viraj_geeth_e6dc448fe4d43/building-a-simple-exchange-rate-mcp-server-using-fastmcp-and-allratestoday-28bj</guid>
      <description>&lt;p&gt;MCP, or Model Context Protocol, is a protocol created by Anthropic (the creators of Claude) to streamline and standardise LLM (large language model) access to external tools and resources.&lt;/p&gt;

&lt;p&gt;FastMCP is a Python framework that allows you to implement MCP in your Python applications.&lt;/p&gt;

&lt;p&gt;In this article, I'll walk you through creating an Exchange Rate MCP server that you can use in your coding agent, Claude Desktop, or any other MCP-compatible environment to get current exchange rates.&lt;/p&gt;




&lt;h2&gt;
  
  
  What really is the point of MCP?
&lt;/h2&gt;

&lt;p&gt;LLMs, such as ChatGPT, Gemini, and Claude models, are trained on vast datasets up to a specific date, known as the knowledge cut-off date.&lt;/p&gt;

&lt;p&gt;This is fine when you ask them about anything historical, but the moment you ask for something current — &lt;em&gt;"what's the USD to EUR rate right now?"&lt;/em&gt; — they'll either guess based on stale training data or, worse, hallucinate a number that looks plausible but is completely wrong. For an LLM, "0.92" and "1.07" are equally valid-looking strings; the model has no built-in mechanism to know which one is true today.&lt;/p&gt;

&lt;p&gt;Also, by default, LLMs cannot inherently take action in the real world. They are just next-token predictors and cannot perform tasks such as searching, fetching live data, or making API calls on the internet independently.&lt;/p&gt;

&lt;p&gt;MCP solves these problems by enabling access to up-to-date information while allowing them to carry out external tasks that they would otherwise be unable to.&lt;/p&gt;

&lt;p&gt;So let's build one and serve our agents some sweet, real-time exchange rates.&lt;/p&gt;




&lt;h2&gt;
  
  
  Let's build our Exchange Rate MCP Server!
&lt;/h2&gt;

&lt;p&gt;To get current exchange rates, we'll be using the &lt;strong&gt;AllRatesToday API&lt;/strong&gt;. At the time of writing, AllRatesToday supports more than 150 currencies, gives you live mid-market rates, and has a generous free tier (300 requests per month) that's more than enough for development.&lt;/p&gt;

&lt;p&gt;The plan: create an AllRatesToday account for an API key, set up a Python virtual environment, write the MCP server code, and run it on Claude Desktop.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 — Get your API key
&lt;/h3&gt;

&lt;p&gt;Head over to &lt;a href="https://allratestoday.com/register" rel="noopener noreferrer"&gt;allratestoday.com/register&lt;/a&gt;, sign up (it takes about thirty seconds), and copy the API key from your dashboard. Keep it somewhere safe — we'll add it to a &lt;code&gt;.env&lt;/code&gt; file in a moment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Create the project folder and virtual environment
&lt;/h3&gt;

&lt;p&gt;We'll use &lt;a href="https://docs.astral.sh/uv/" rel="noopener noreferrer"&gt;uv&lt;/a&gt; — it's faster than pip and handles environments cleanly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; /path/to/your/allrates-mcp
&lt;span class="nb"&gt;cd &lt;/span&gt;allrates-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv init
&lt;span class="c"&gt;# This command creates the following:&lt;/span&gt;
&lt;span class="c"&gt;# ├── .git/&lt;/span&gt;
&lt;span class="c"&gt;# ├── .gitignore&lt;/span&gt;
&lt;span class="c"&gt;# ├── .python-version&lt;/span&gt;
&lt;span class="c"&gt;# ├── README.md&lt;/span&gt;
&lt;span class="c"&gt;# ├── main.py&lt;/span&gt;
&lt;span class="c"&gt;# └── pyproject.toml&lt;/span&gt;

uv venv  &lt;span class="c"&gt;# This creates the virtual environment&lt;/span&gt;

&lt;span class="c"&gt;# To activate the virtual environment in UNIX-based OSes:&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate

&lt;span class="c"&gt;# For Windows:&lt;/span&gt;
.&lt;span class="se"&gt;\.&lt;/span&gt;venv&lt;span class="se"&gt;\S&lt;/span&gt;cripts&lt;span class="se"&gt;\a&lt;/span&gt;ctivate.bat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;code &lt;span class="nb"&gt;.&lt;/span&gt;  &lt;span class="c"&gt;# This opens our project folder in VSCode&lt;/span&gt;

&lt;span class="c"&gt;# If you use Cursor:&lt;/span&gt;
cursor &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# For those of you who live on the edge:&lt;/span&gt;
vim &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv add fastmcp dotenv httpx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's &lt;code&gt;fastmcp&lt;/code&gt; for the MCP framework, &lt;code&gt;dotenv&lt;/code&gt; for reading the API key from a &lt;code&gt;.env&lt;/code&gt; file, and &lt;code&gt;httpx&lt;/code&gt; for the async HTTP client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 — Write the MCP server
&lt;/h3&gt;

&lt;p&gt;Open &lt;code&gt;main.py&lt;/code&gt; and paste the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastmcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastMCP&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastMCP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AllRatesToday Exchange Rate MCP Server&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ALLRATES_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ALLRATES_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;ALLRATES_API_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;EnvironmentError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ALLRATES_API_KEY is not set in environment variables.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;API_BASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://allratestoday.com/api&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="nd"&gt;@mcp.tool&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;convert_currency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base_curr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_curr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Convert an amount from one currency to another using current exchange rates.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;API_BASE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/rate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;base_curr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;target_curr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ALLRATES_API_KEY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unexpected response from AllRatesToday: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;converted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;base_curr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;converted&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;target_curr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(Rate: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTPStatusError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid AllRatesToday API key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AllRatesToday API quota exceeded&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bad request — possibly an unknown currency code: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;base_curr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; or &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;target_curr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HTTP error occurred: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; - &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Request error occurred: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unexpected error occurred: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;mcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A quick walkthrough of what the code does:&lt;/p&gt;

&lt;p&gt;We load the API key from &lt;code&gt;.env&lt;/code&gt; at startup. If it's missing, we crash early — better than failing silently in the middle of a tool call.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@mcp.tool&lt;/code&gt; decorator turns &lt;code&gt;convert_currency&lt;/code&gt; into a tool that the LLM can invoke. FastMCP introspects the type hints (&lt;code&gt;float&lt;/code&gt;, &lt;code&gt;str&lt;/code&gt;, &lt;code&gt;str&lt;/code&gt;) and the docstring to build the tool schema automatically — that's what the LLM uses to decide &lt;em&gt;when&lt;/em&gt; to call this function.&lt;/p&gt;

&lt;p&gt;The function calls the AllRatesToday &lt;code&gt;/api/rate&lt;/code&gt; endpoint with the base and target currencies as query parameters, and the API key as a Bearer token in the &lt;code&gt;Authorization&lt;/code&gt; header. AllRatesToday returns a JSON object containing a &lt;code&gt;rate&lt;/code&gt; field. We multiply that rate by the amount, round to two decimal places, and return a clean human-readable string.&lt;/p&gt;

&lt;p&gt;Error handling is the part most tutorials skip and you shouldn't. We map the common failure modes — invalid key (401), quota exceeded (429), unknown currency code (400) — to readable messages so Claude can surface them sensibly when something goes wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 — Set up your environment variable
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file in your project folder with your API key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ALLRATES_API_KEY=your_api_key"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /path/to/your/allrates-mcp/.env
&lt;span class="c"&gt;# Make sure to replace 'your_api_key' with your actual key from allratestoday.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;dotenv&lt;/code&gt; package picks this up automatically when the server starts. Don't commit this file to git — &lt;code&gt;uv init&lt;/code&gt; already added it to &lt;code&gt;.gitignore&lt;/code&gt;, but it's worth double-checking before your first push.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5 — Wire it into Claude Desktop
&lt;/h3&gt;

&lt;p&gt;Open the Claude Desktop config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# On MacOS:&lt;/span&gt;
code ~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/Claude/claude_desktop_config.json

&lt;span class="c"&gt;# On Windows:&lt;/span&gt;
code %APPDATA%&lt;span class="se"&gt;\C&lt;/span&gt;laude&lt;span class="se"&gt;\c&lt;/span&gt;laude_desktop_config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the server under &lt;code&gt;mcpServers&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allrates-mcp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uv"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"--directory"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"/path/to/your/allrates-mcp/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"main.py"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;/path/to/your/allrates-mcp/&lt;/code&gt; with the &lt;strong&gt;absolute path&lt;/strong&gt; to your project folder. Relative paths look like they should work but don't, because Claude Desktop launches the subprocess from a different working directory than your shell.&lt;/p&gt;

&lt;p&gt;Save the file, then &lt;strong&gt;fully quit and reopen Claude Desktop&lt;/strong&gt; (Cmd+Q on Mac, not just close the window — closing the window leaves it running in the background and the new config won't load).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6 — Try it out
&lt;/h3&gt;

&lt;p&gt;Open a new conversation in Claude Desktop and ask something like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"What's 250 USD in JPY today?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude will recognise that &lt;code&gt;convert_currency&lt;/code&gt; is the right tool, fill in the arguments, and call your MCP server. The tool call appears inline in the conversation, and the answer comes back grounded in real-time data — no hallucinated numbers.&lt;/p&gt;

&lt;p&gt;Try a more open-ended one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"If I had 1000 EUR and converted half to GBP and half to JPY, what would I have in total in USD?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude will chain the tool calls itself — no orchestration logic on your side. That's the magic of MCP. You wrote one function; the agent figured out how to compose it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You now have a working Exchange Rate MCP server in roughly sixty lines of Python. The same pattern — &lt;code&gt;@mcp.tool&lt;/code&gt; plus type hints plus a docstring plus an HTTP call — generalises to any API in the world. Replace the AllRatesToday URL with a weather API and you have a weather server. Replace it with your internal CRM and your AI agent suddenly knows about your customers.&lt;/p&gt;

&lt;p&gt;The bigger point is this: not very long ago, hooking an LLM up to a live data source was a research-grade undertaking with custom plumbing on every side. With FastMCP it's a thirty-minute coding session. The friction is gone, and that changes what's worth building.&lt;/p&gt;

&lt;p&gt;If you want to extend this further, here are some natural next steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a &lt;code&gt;get_historical_rate(base, target, date)&lt;/code&gt; tool using the AllRatesToday &lt;code&gt;/v1/rates?time=&lt;/code&gt; endpoint&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;get_rates_multi(base, [targets])&lt;/code&gt; tool that fetches several rates in one call&lt;/li&gt;
&lt;li&gt;Cache responses in memory to avoid burning your free-tier quota when the agent re-checks the same rate twice in a conversation&lt;/li&gt;
&lt;li&gt;Wrap it with a FastAPI layer and deploy it as an HTTP MCP server so multiple agents can share one instance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full AllRatesToday API documentation is at &lt;a href="https://allratestoday.com/docs" rel="noopener noreferrer"&gt;allratestoday.com/docs&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;If this was useful, leave some claps 👏 — it helps the article reach more developers building agent applications.&lt;/p&gt;

&lt;p&gt;Connect with me on LinkedIn or X, and let me know what you build with it.&lt;/p&gt;

&lt;p&gt;Until next time, happy hacking. 🚀&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tags: MCP Server, FastMCP, Python, AI, LLM, Claude, Currency API, Forex&lt;/em&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>mcp</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What Is the Best Website for Exchange Rates? (2026 Guide)</title>
      <dc:creator>viraj geeth</dc:creator>
      <pubDate>Tue, 14 Apr 2026 17:23:09 +0000</pubDate>
      <link>https://dev.to/viraj_geeth_e6dc448fe4d43/what-is-the-best-website-for-exchange-rates-2026-guide-pij</link>
      <guid>https://dev.to/viraj_geeth_e6dc448fe4d43/what-is-the-best-website-for-exchange-rates-2026-guide-pij</guid>
      <description>&lt;p&gt;If you search "best website for exchange rates," you get a dozen contradictory answers — Google Finance, XE, Wise, Reuters, your bank's app. They all show a number next to a currency pair, and they're all a little different. Which one is right?&lt;/p&gt;

&lt;p&gt;The honest answer: &lt;strong&gt;"best" depends on what you're doing&lt;/strong&gt;. A tourist checking a holiday budget has different needs from a developer building a checkout flow, an accountant reconciling invoices, or a trader sizing a position.&lt;/p&gt;

&lt;p&gt;This guide ranks the best exchange rate websites of 2026 by use case, explains why the numbers differ between them, and helps you pick the right source for your specific situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR — Best Exchange Rate Website by Use Case
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Best Website&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Developers / APIs&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;AllRatesToday&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Real-time, Reuters-sourced, free historical, REST API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quick tourist lookup&lt;/td&gt;
&lt;td&gt;Google Finance&lt;/td&gt;
&lt;td&gt;Already in search results, good enough&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sending money abroad&lt;/td&gt;
&lt;td&gt;Wise&lt;/td&gt;
&lt;td&gt;Shows the rate you'll actually get after fees&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accounting / reporting&lt;/td&gt;
&lt;td&gt;ECB reference rates&lt;/td&gt;
&lt;td&gt;Regulator-accepted daily snapshot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forex trading&lt;/td&gt;
&lt;td&gt;Reuters / Bloomberg / XE&lt;/td&gt;
&lt;td&gt;Live interbank, deep history, charts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-currency dashboard&lt;/td&gt;
&lt;td&gt;AllRatesToday&lt;/td&gt;
&lt;td&gt;API + SDKs + 160+ currencies&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why Exchange Rates Differ Between Websites
&lt;/h2&gt;

&lt;p&gt;Before picking a "best" site, it helps to understand why every site shows a slightly different number for the same pair.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Mid-market vs Retail Rate
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;mid-market rate&lt;/strong&gt; is the midpoint between what banks buy and sell a currency for on the interbank market. It's the "true" rate — and it's not the rate you actually get when you exchange money.&lt;/p&gt;

&lt;p&gt;Most websites (Google, XE, Reuters) display the mid-market rate. Your bank, airport kiosk, or card issuer adds a margin on top — often 2–5% — and that's the rate applied to your transaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Data Source
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interbank feeds&lt;/strong&gt; (Reuters/Refinitiv, Bloomberg) — live, tight, what banks actually quote.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Central banks&lt;/strong&gt; (ECB, Fed) — one snapshot per day, published in the afternoon.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aggregators&lt;/strong&gt; — blend multiple sources into a composite rate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crypto exchanges&lt;/strong&gt; — their own order books, which can drift from broader markets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two sites using different sources will always show slightly different numbers.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Update Frequency
&lt;/h3&gt;

&lt;p&gt;FX markets move every second during trading hours. A site updating once a day will lag a site updating every 60 seconds by however much the market has moved since the snapshot.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Best Exchange Rate Websites in 2026
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. AllRatesToday — Best for Developers and Apps
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://allratestoday.com" rel="noopener noreferrer"&gt;AllRatesToday&lt;/a&gt; is the best choice when you need exchange rates &lt;strong&gt;inside an application&lt;/strong&gt; rather than just on a screen. It's an API-first service that delivers real-time mid-market rates from Reuters/Refinitiv and interbank feeds, with a clean REST endpoint and official SDKs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;160+ currencies&lt;/strong&gt; plus precious metals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;60-second updates&lt;/strong&gt; on paid tiers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free historical rates&lt;/strong&gt; — rare among API providers&lt;/li&gt;
&lt;li&gt;Any base currency, HTTPS, CORS&lt;/li&gt;
&lt;li&gt;Official SDKs for JavaScript, Python, PHP&lt;/li&gt;
&lt;li&gt;Free tier with no credit card&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for: developers, SaaS apps, e-commerce checkouts, multi-currency billing, dashboards, and analytics tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Google Finance — Best for Quick Lookups
&lt;/h3&gt;

&lt;p&gt;Google Finance (accessible via a simple &lt;code&gt;USD to EUR&lt;/code&gt; search) is the fastest way to check a rate when you just need a number. It pulls mid-market data, updates frequently during market hours, and is already in your search bar.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero friction — no tab switch needed&lt;/li&gt;
&lt;li&gt;Mid-market rates&lt;/li&gt;
&lt;li&gt;Includes mini chart and day's high/low&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for: casual lookups, travel budgeting, settling arguments about where the pound is today.&lt;/p&gt;

&lt;p&gt;Limitation: no API, no history beyond what the chart shows, no programmatic access.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. XE.com — Best Consumer Brand
&lt;/h3&gt;

&lt;p&gt;XE has been synonymous with currency conversion since the 1990s. The website's "Currency Converter" is a go-to for travelers and occasional users, and XE publishes mid-market rates updated through the trading day.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;170+ currencies and metals&lt;/li&gt;
&lt;li&gt;Clean currency converter UI&lt;/li&gt;
&lt;li&gt;Money transfer service layered on top&lt;/li&gt;
&lt;li&gt;Charts and historical data on the site&lt;/li&gt;
&lt;li&gt;Paid API tier for businesses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for: travelers, casual conversions, and users who trust the XE brand.&lt;/p&gt;

&lt;p&gt;Limitation: the API is enterprise-priced (annual plans starting in the high hundreds), and there's no meaningful free tier for developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Wise (formerly TransferWise) — Best for Sending Money
&lt;/h3&gt;

&lt;p&gt;If you're actually moving money across borders, Wise is the most useful site in the list. Wise displays mid-market rates and then shows you the &lt;strong&gt;exact rate and fee&lt;/strong&gt; you'll get if you send money — no hidden margin.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mid-market rates with transparent fees&lt;/li&gt;
&lt;li&gt;The rate shown is the rate you get&lt;/li&gt;
&lt;li&gt;Supports 40+ currencies for transfers&lt;/li&gt;
&lt;li&gt;Live rate alerts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for: international transfers, remote work payments, and anyone who wants to know the true cost of a conversion.&lt;/p&gt;

&lt;p&gt;Limitation: it's a transfer service, not a reference data source. You can't build an app on top of the displayed rates.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. European Central Bank (ECB) Reference Rates
&lt;/h3&gt;

&lt;p&gt;The ECB publishes a daily reference rate at 16:00 CET, covering around 30 currencies against EUR. It's free, public, and widely used for &lt;strong&gt;accounting and regulatory reporting&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Completely free, no API key&lt;/li&gt;
&lt;li&gt;Trusted by tax authorities across the EU&lt;/li&gt;
&lt;li&gt;Daily snapshot (not real-time)&lt;/li&gt;
&lt;li&gt;Only covers around 30 currencies, EUR-based&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for: accounting, tax reporting, month-end FX conversions, and any use case where "end-of-day ECB rate" is a regulatory-acceptable answer.&lt;/p&gt;

&lt;p&gt;Limitation: one update per day, EUR-centric, no intraday data, no crypto.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Reuters / Refinitiv — Best for Institutional Trading
&lt;/h3&gt;

&lt;p&gt;Reuters/Refinitiv terminals are the gold standard for institutional FX data. The rates you see on most other sites — including AllRatesToday — ultimately trace back to Reuters or Bloomberg feeds.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;True real-time interbank pricing&lt;/li&gt;
&lt;li&gt;Deep historical data and analytics&lt;/li&gt;
&lt;li&gt;Used by banks, hedge funds, and corporates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Best for: banks, trading desks, and institutional users with enterprise budgets.&lt;/p&gt;

&lt;p&gt;Limitation: priced for enterprise. Not accessible for individual developers or small businesses.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Bloomberg — Institutional Alternative to Reuters
&lt;/h3&gt;

&lt;p&gt;Same category as Reuters, same audience. Bloomberg Terminal is the other dominant institutional data source, with its own FX feeds and analytics. If you have access to a Bloomberg Terminal, you already know how to use it.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Your Bank's Online Portal
&lt;/h3&gt;

&lt;p&gt;Last but worth mentioning: your bank's website shows the exchange rate &lt;strong&gt;they will apply to your transactions&lt;/strong&gt;. That rate includes their margin and often a spread. It's the most honest answer to "what rate will I get?" even if it's far from the mid-market number.&lt;/p&gt;

&lt;p&gt;Best for: understanding your actual conversion cost before initiating a wire or card transaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Choose the Right Exchange Rate Website
&lt;/h2&gt;

&lt;p&gt;Match the tool to the job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"I need a rate for a trip / quick conversion"&lt;/strong&gt; — Google Finance or XE.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"I'm sending money abroad"&lt;/strong&gt; — Wise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"I'm building an app or website"&lt;/strong&gt; — AllRatesToday.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"I need to file taxes / close the month"&lt;/strong&gt; — ECB reference rates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"I'm trading FX professionally"&lt;/strong&gt; — Reuters, Bloomberg, or your broker's terminal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"I want to know what my bank will charge"&lt;/strong&gt; — your bank's portal, not a reference site.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you need more than one of these in one place, an API is the only scalable answer — and that's where AllRatesToday sits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the most accurate exchange rate website?
&lt;/h3&gt;

&lt;p&gt;The most accurate rates come from interbank feeds (Reuters, Bloomberg). Sites that source from those feeds — AllRatesToday, XE, Google Finance — deliver the closest-to-real mid-market numbers. Sites using daily central bank snapshots (Fixer, some free APIs) are accurate only for that one moment of the day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does Google show a different rate than my bank?
&lt;/h3&gt;

&lt;p&gt;Google shows the &lt;strong&gt;mid-market rate&lt;/strong&gt;. Your bank adds a margin to buy and sell, so the rate they apply to your transaction is usually 1–4% worse than Google's number. This is normal and legal — just factor it in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is there a website that shows real-time exchange rates for free?
&lt;/h3&gt;

&lt;p&gt;Yes. Google Finance shows frequently-updated mid-market rates for free. For programmatic access, AllRatesToday offers real-time rates through its API on a free tier (300 requests/month, no credit card).&lt;/p&gt;

&lt;h3&gt;
  
  
  Which website is best for historical exchange rates?
&lt;/h3&gt;

&lt;p&gt;For casual use: XE or the ECB (free, around 30 currencies, 20+ years of history). For developers: AllRatesToday offers historical rates on its free tier, which almost no other API does.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I trust a free exchange rate website?
&lt;/h3&gt;

&lt;p&gt;For reference data — yes. Free doesn't mean inaccurate. Just check the data source. A free site pulling from Reuters is more trustworthy than a paid site that scrapes another website. Always look for a "data source" or "methodology" section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom Line
&lt;/h2&gt;

&lt;p&gt;There is no single "best" exchange rate website — but there is a best one &lt;strong&gt;for you&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;For lookups&lt;/strong&gt;: Google Finance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For transfers&lt;/strong&gt;: Wise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For reporting&lt;/strong&gt;: ECB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For trading&lt;/strong&gt;: Reuters / Bloomberg / XE.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For developers and apps&lt;/strong&gt;: &lt;a href="https://allratestoday.com" rel="noopener noreferrer"&gt;AllRatesToday&lt;/a&gt; — the only option on this list that combines real-time interbank-sourced rates, free historical data, and a developer-friendly API with SDKs in three languages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building anything that needs exchange rates programmatically, &lt;a href="https://allratestoday.com/register" rel="noopener noreferrer"&gt;get a free AllRatesToday API key&lt;/a&gt; and stop screen-scraping Google.&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>apigateway</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
