Power BI already has the connector you need. Create a blank query, call exchangerate.dev with Web.Contents, and split the stable host from the RelativePath. That last detail is easy to miss: it gives the Power BI service a fixed data source it can recognize when the semantic model refreshes.
- Use a blank Power Query and paste the M code in Advanced Editor.
- Keep
https://api.exchangerate.devfixed and put the endpoint inRelativePath. - The query returns a
currency/ratetable plus source and update-time columns. - Choose Anonymous for the web data-source credential because the API key travels in the request header.
- Treat a key embedded in a PBIX file as visible to trusted report editors; use a server-side proxy for broad distribution.
Create a key and open a blank query
Create a free key at exchangerate.dev/signup. In Power BI Desktop, choose Get data → Blank query, then open View → Advanced Editor in Power Query Editor. The published report will use this query as its web data source.
Paste the Power Query M script
let ApiKey = "exr_live_replace_with_your_key_here", Base = "USD", Symbols = "EUR,GBP,JPY", Response = Json.Document( Web.Contents( "https://api.exchangerate.dev", [ RelativePath = "v1/latest/" & Base, Query = [symbols = Symbols], Headers = [Authorization = "Bearer " & ApiKey] ] ) ), Rates = Record.ToTable(Response[rates]), Renamed = Table.RenameColumns( Rates, {{"Name", "currency"}, {"Value", "rate"}} ), WithBase = Table.AddColumn(Renamed, "base", each Response[base], type text), WithSource = Table.AddColumn(WithBase, "source", each Response[source], type text), WithUpdatedAt = Table.AddColumn( WithSource, "data_updated_at", each DateTimeZone.FromText(Response[data_updated_at]), type datetimezone )in WithUpdatedAtReplace the placeholder key, select Done, and name the query FxRates. The preview should show one row per requested currency.
Set the data types before loading
Confirm that currency, base, and source are Text; rate is Decimal number; and data_updated_at is Date/Time/Timezone. Then select Close & Apply. One row per currency is easier to relate to a Currency dimension than a record with one column per code.
Publish and configure scheduled refresh
Publish the report, open the semantic model settings in the Power BI service, and edit the credentials for https://api.exchangerate.dev. Choose Anonymous because the M query already sends the key in the Authorization header. Set a refresh schedule that fits the report.
Power BI needs to identify a stable web data source for refresh. Keeping the host fixed in Web.Contents and moving the endpoint into RelativePath avoids the common “dynamic data source” failure after publication.
Do not treat an M parameter as a secret vault
A parameter is convenient, but anyone trusted to edit the PBIX or query may be able to see the key. That is acceptable for a small internal workspace. If the report file is distributed widely, put exchangerate.dev behind your own server-side endpoint and let Power BI call that endpoint instead.
These rates work for reporting, analytics, planning, and display. They are not an executable dealing quote and should not be used to settle a trade.