Live wisselkoersen in Power BI ophalen is zo'n klus die er lang af uitziet voordat hij dat werkelijk is. Je plakt een API-URL in Gegevens ophalen → Web, er verschijnt een koerstabel, je omgerekende omzetmeting licht op, en je publiceert. Twee dagen later mislukt het vernieuwen van de semantische model in de Power BI-service met een melding over een dynamische gegevensbron — of het slaagt en rekent stilletjes elke historische transactie om tegen de koers van vandaag.
Deze gids behandelt het hele traject: een Power Query M-query die een nette koerstabel oplevert, het RelativePath-patroon dat hem vernieuwbaar houdt in de service, een functie voor historische koersen om op transactiedatum om te rekenen, een DAX-meting voor een dynamische rapportagevaluta, en de rekensom van het aantal aanvragen die bepaalt of je vernieuwingsschema binnen een API-abonnement past.
Alle onderstaande query's zijn geschreven tegen de gedocumenteerde antwoordstructuren van de Finexly API. Heb je onze gids over live wisselkoersen in Excel al gelezen, dan komt de M hier bekend voor — maar Power BI voegt een vernieuwingslaag aan de servicekant toe die Excel niet heeft, en juist op die laag lopen de meeste van deze projecten stuk.
De drie manieren om koersen in Power BI te krijgen
| Aanpak | Vernieuwt in de service? | API-sleutel veilig? | Historische koersen | Geschikt voor |
|---|---|---|---|---|
| Web-connector, URL in het dialoogvenster geplakt | Vaak niet — de URL wordt meestal een dynamische gegevensbron | ❌ Sleutel staat in de URL | Nee | Een proof of concept van vijf minuten |
Lege query met Web.Contents + RelativePath | ✅ Ja | ✅ Via header | ✅ Ja | Vrijwel elk echt model |
| Dataflow (of Fabric-pipeline) die een koerstabel voedt | ✅ Ja, en losgekoppeld van het rapportvernieuwen | ✅ Via header | ✅ Ja | Meerdere rapporten, veel rijen |
Methode 1: een live koerstabel met Power Query
Open Gegevens transformeren → Nieuwe bron → Lege query → Geavanceerde editor en plak dit. Het levert één rij per valutapaar op, met een UTC-tijdstempel van het ophaalmoment.
let
ApiKey = "YOUR_API_KEY",
Base = "USD",
Symbols = "EUR,GBP,JPY,CHF,AUD,CAD,SEK,NZD",
Source = Json.Document(
Web.Contents(
"https://api.finexly.com",
[
RelativePath = "v1/latest",
Query = [ base = Base, symbols = Symbols ],
Headers = [ #"Authorization" = "Bearer " & ApiKey ]
]
)
),
Rates = Record.ToTable( Source[rates] ),
Renamed = Table.RenameColumns( Rates, {{"Name", "Quote"}, {"Value", "Rate"}} ),
AddBase = Table.AddColumn( Renamed, "Base", each Base, type text ),
AddStamp = Table.AddColumn( AddBase, "RetrievedUTC", each DateTimeZone.UtcNow(), type datetimezone ),
Typed = Table.TransformColumnTypes(
AddStamp,
{{"Quote", type text}, {"Rate", type number}}
)
in
TypedHet endpoint dat wordt aangeroepen ziet er op de commandoregel zo uit — de moeite waard om één keer te draaien, zodat je de structuur ziet die je parseert:
curl "https://api.finexly.com/v1/latest?base=USD&symbols=EUR,GBP,JPY" \
-H "Authorization: Bearer YOUR_API_KEY"{
"success": true,
"base": "USD",
"date": "2026-09-01",
"rates": { "EUR": "…", "GBP": "…", "JPY": "…" }
}Waarom RelativePath en Query niet optioneel zijn
Dit is de belangrijkste zin van het artikel, dus die krijgt een eigen kop.
Bouw je de URL als één samengevoegde tekenreeks — "https://api.finexly.com/v1/latest?base=" & Base — dan kan Power Query de bestemming pas bepalen als de query daadwerkelijk draait. Microsoft classificeert dat als een dynamische gegevensbron, en dynamische gegevensbronnen worden in de Power BI-service niet vernieuwd, om veiligheids- en privacyredenen. Het rapport vernieuwt prima op je laptop en faalt op het moment dat het wordt ingepland.
Het pad in RelativePath en de parameters in Query doorgeven is de gedocumenteerde uitzondering. Power BI kan dan één statische basis-URL — https://api.finexly.com — vaststellen voor de referentie- en privacycontroles, terwijl de variabele delen variabel blijven. Daaruit volgen drie regels:
- De basis-URL moet een letterlijke tekenreeks zijn. Geen parameters, geen samenvoeging, nergens een
&. RelativePathhoort het vaste endpointpad te zijn."v1/latest", niet"v1/latest?base=USD".- Voeg nooit tekst samen binnen
Query. Geef een record met naam/waarde-paren door en laat Power Query de URL-codering doen. Het escapet ook tekens die het verzoek anders zouden breken.
Referenties instellen
De eerste keer dat je de query draait, vraagt Power BI hoe het zich moet aanmelden bij https://api.finexly.com. Kies Anoniem. Dat voelt verkeerd, maar het klopt: de API-sleutel reist mee in de Authorization-header die je in de M-code hebt gezet, niet via de referentieopslag van Power BI. Kies je Web-API of Basis, dan voegt Power BI een eigen header toe en wordt het verzoek geweigerd.
Stel het privacyniveau consistent in op Openbaar of Organisatie voor al je bronnen. Niet-overeenkomende privacyniveaus zijn de op één na meest voorkomende oorzaak van een vernieuwing die in Desktop werkt en in de service faalt — Power BI blokkeert de query liever dan te riskeren dat gegevens van de ene bron in het verzoek van de andere terechtkomen.
Een eerlijke kanttekening: de sleutel staat nu als platte tekst in de query. Iedereen die het .pbix-bestand opent, kan hem lezen. Voor alles wat verder gaat dan je eigen machine: promoveer de sleutel tot een Power Query-parameter en houd de ingevulde versie in een dataflow die eigendom is van een serviceaccount, zodat rapportauteurs de koerstabel gebruiken zonder de referentie ooit te zien.
Methode 2: historische koersen voor omrekening op transactiedatum
Een live koerstabel beantwoordt "wat is EUR/USD nu". Hij beantwoordt niet "wat was onze omzet in januari in USD", en hem daarvoor gebruiken is de duurste fout in dit hele onderwerp — cijfers van vorig kwartaal herzien omdat het model ze tegen een nieuwe koers heeft omgerekend, is precies wat accountants zoeken. Voedt je rapport iets dat je later moet verdedigen, lees dan naast dit hoofdstuk onze gids over wisselkoersen en fiscale rapportage.
Je hebt een op datum gesleutelde koerstabel nodig. Deze M-functie omhult het timeseries-endpoint en geeft één rij per datum per valuta:
let
FxHistory = (base as text, symbols as text, startDate as date, endDate as date) as table =>
let
ApiKey = "YOUR_API_KEY",
Source = Json.Document(
Web.Contents(
"https://api.finexly.com",
[
RelativePath = "v1/timeseries",
Query = [
base = base,
symbols = symbols,
start_date = Date.ToText( startDate, [Format = "yyyy-MM-dd", Culture = "en-US"] ),
end_date = Date.ToText( endDate, [Format = "yyyy-MM-dd", Culture = "en-US"] )
],
Headers = [ #"Authorization" = "Bearer " & ApiKey ]
]
)
),
Days = Table.RenameColumns( Record.ToTable( Source[rates] ), {{"Name", "RateDate"}} ),
Expanded = Table.ExpandRecordColumn( Days, "Value", Record.FieldNames( Days{0}[Value] ) ),
Unpivoted = Table.UnpivotOtherColumns( Expanded, {"RateDate"}, "Quote", "Rate" ),
AsDate = Table.TransformColumns(
Unpivoted,
{{"RateDate", each Date.FromText( _, [Format = "yyyy-MM-dd", Culture = "en-US"] ), type date}}
),
AddBase = Table.AddColumn( AsDate, "Base", each base, type text ),
Typed = Table.TransformColumnTypes( AddBase, {{"Quote", type text}, {"Rate", type number}} )
in
Typed
in
FxHistoryTwee details daarin doen echt werk:
Culture = "en-US"op zowelDate.ToTextalsDate.FromText. Zonder dat stuurt een machine met een Duitse of Franse landinstelling01.09.2026alsstart_dateen weigert de API — of erger: de vernieuwing van een collega levert een anders gevormde tabel op dan de jouwe. De landinstelling is de onzichtbare variabele in elk Power Query-project dat meer dan één land beslaat.Table.UnpivotOtherColumns. De API geeft datums terug als recordsleutels met een geneste record van valuta's. Ontpivotteren naar de lange vormRateDate / Base / Quote / Ratelevert een tabel op die netjes koppelt aan een datumdimensie en die je niet hoeft te herbouwen telkens als je een valuta toevoegt.
Roep hem één keer per laadbeurt aan: FxHistory( "USD", "EUR,GBP,JPY", #date(2026,1,1), Date.From( DateTime.LocalNow() ) ).
Omdat koersen van een datum in het verleden nooit veranderen, is deze tabel het schoolvoorbeeld voor incrementeel vernieuwen: partitioneer op RateDate, vernieuw de laatste 7 dagen, archiveer de rest. Je vernieuwingstijd groeit niet langer mee met je historie — en je aantal aanvragen evenmin.
Roep de API niet één keer per rij aan
Het patroon dat deze modellen om zeep helpt, is een koersfunctie aanroepen als aangepaste kolom op de feitentabel. Tienduizend transacties betekent tienduizend HTTP-aanvragen per vernieuwing, een vernieuwing van veertig minuten, en een quotarekening die vóór de lunch binnenkomt.
Reken het uit voordat je bouwt. Power BI Pro staat 8 geplande vernieuwingen per semantisch model per dag toe; Premium Per User en Fabric-capaciteit staan er 48 toe. Eén /v1/latest-aanroep die al je valuta's dekt, vernieuwd op het Pro-maximum, kost 8 aanvragen per dag — ruwweg 240 per maand, ruim binnen een gratis niveau van 1.000. Hetzelfde schema met een functie per rij is onbegrensd. Zelfs op het PPU-maximum van 48 vernieuwingen komt één geconsolideerde aanroep uit op ongeveer 1.440 aanvragen per maand, wat een klein betaald abonnement is in plaats van een ramp per rij. Onze prijsplannen vermelden de drempels als je dit precies wilt dimensioneren.
Zodra meer dan één rapport de koersen nodig heeft, verplaats je de query naar een dataflow. De dataflow roept de API op zijn eigen schema aan en materialiseert het resultaat; elk stroomafwaarts model leest uit opslag in plaats van opnieuw de API te raken. Vijf rapporten op dezelfde dataflow maken één set aanvragen, geen vijf.
Bedragen omrekenen: samenvoegen in Power Query of een DAX-meting
Er zijn twee legitieme plekken om de omrekening toe te passen, en ze beantwoorden verschillende vragen.
Optie A: samenvoegen in Power Query
Is je rapportagevaluta vast — alles wordt in USD gerapporteerd, punt — doe de koppeling dan bij het laden.
- Laad de feitentabel in Power Query.
- Query's samenvoegen met de koerstabel, gematcht op valutacode en datum. Houd
Ctrlingedrukt en selecteer de kolommen in dezelfde volgorde in beide tabellen. - Vouw alleen de kolom
Rateuit en zet die op Vast decimaal getal. - Selecteer
AmountenRateen kies Kolom toevoegen → Standaard → Vermenigvuldigen. - Schakel het laden van de koerstabel uit als niets anders ernaar verwijst.
Dit is snel, materialiseert één keer, en kan niet door een slicer worden ondermijnd. Dat laatste punt is de afweging.
Optie B: een DAX-meting met selecteerbare rapportagevaluta
Moeten gebruikers het hele rapport kunnen omschakelen tussen USD, EUR en GBP, dan moet de omrekening op querymoment gebeuren. Voeg een niet-gekoppelde tabel Reporting Currency toe met één kolom ISO-codes, zet die in een slicer, en schrijf:
Revenue (Reporting Currency) =
VAR ReportingCurrency = SELECTEDVALUE( 'Reporting Currency'[Code], "USD" )
RETURN
SUMX (
'Sales',
VAR TxCurrency = 'Sales'[CurrencyCode]
VAR TxDate = 'Sales'[OrderDate]
VAR Rate =
CALCULATE (
MAX ( 'FX Rates'[Rate] ),
REMOVEFILTERS ( 'FX Rates' ),
'FX Rates'[Base] = TxCurrency,
'FX Rates'[Quote] = ReportingCurrency,
'FX Rates'[RateDate] = TxDate
)
RETURN 'Sales'[Amount] * Rate
)Drie dingen om op te merken:
- De
VAR-regels zijn dragend.TxCurrencyenTxDatevóórCALCULATEin variabelen vangen, zet ze vast op de huidigeSUMX-rij. De kolommen rechtstreeks in de filterargumenten aanroepen nodigt een contextovergangsfout uit die plausibel ogende maar foute totalen oplevert. REMOVEFILTERS( 'FX Rates' )voorkomt dat een binnenkomend filter op de koerstabel de opzoeking versmalt.- Een ontbrekende koers geeft
BLANK(), enAmount * BLANK()isBLANK(). Dat is precies het gewenste gedrag. Een rij die stilletjes terugvalt op het niet-omgerekende bedrag, is een rij die je totaal opblaast met de omvang van de wisselkoers.
De relatievalkuil
Maak geen fysieke relatie van de feitentabel naar de koerstabel op alleen de valutacode. Valutacode is niet uniek in een op datum gesleutelde koerstabel, dus stelt Power BI een veel-op-veel-relatie voor — en veel-op-veel met bidirectioneel filteren blaast je rijaantal vrolijk op en vermenigvuldigt je omzet. Gebruik de samengestelde samenvoeging in Power Query, of houd de koerstabel losgekoppeld en zoek koersen op in DAX zoals hierboven.
Vijf fouten die verkeerde cijfers opleveren zonder foutmelding
- Samengevoegde URL's. Vernieuwt in Desktop, faalt in de service met "Dit semantische model bevat een dynamische gegevensbron." Op te lossen met
RelativePathenQuery. - Omgekeerde paren.
base=USD&symbols=EURgeeft USD→EUR. Slaat je feitentabel bedragen in EUR op, dan heb je het omgekeerde nodig. Controleer één bekend paar met de hand voordat je ook maar één totaal vertrouwt. Onze ISO 4217-referentie helpt als je twijfelt welke code aan welke kant hoort. - De koers van vandaag op historische rijen. Het getal verandert bij elke vernieuwing en niemand merkt het tot iemand twee exports van hetzelfde rapport vergelijkt.
- Datums en decimalen in landspecifieke notatie. Een decimale komma maakt van
1,0842tekst,Table.TransformColumnTypesgeeft een fout die het model als leeg behandelt, en de betrokken rijen verdwijnen uit je totalen. - Afronden in de verkeerde stap. Rond één keer af, bij de presentatie, ná de vermenigvuldiging. De koers op vier decimalen afronden vóór vermenigvuldiging met een bedrag van zeven cijfers geeft een zichtbaar verschil met het boekhoudsysteem.
Veelgestelde vragen
Kan Power BI wisselkoersen automatisch vernieuwen?
Ja. Een gepubliceerd semantisch model kan worden ingepland voor maximaal 8 vernieuwingen per dag op Power BI Pro en 48 per dag op Premium Per User of Fabric-capaciteit. Het XMLA-eindpunt van Premium laat externe tools vernieuwingen buiten die limieten starten. De koersquery zelf vraagt niets bijzonders, behalve dat hij met Web.Contents + RelativePath is gebouwd zodat de service hem accepteert.
Hoe geef ik een API-sleutel veilig door in Power BI?
Zet hem in de Headers-record van Web.Contents als Authorization = "Bearer " & ApiKey en kies Anonieme verificatie wanneer Power BI ernaar vraagt. Zo blijft de sleutel buiten de URL, buiten proxylogboeken en buiten de browsergeschiedenis. Het versleutelt de sleutel niet binnen het .pbix — houd hem voor gedeelde modellen in een dataflow die eigendom is van een serviceaccount en laat rapporten de gematerialiseerde tabel lezen.
Waarom zegt mijn model "Dit semantische model bevat een dynamische gegevensbron"?
Omdat de URL in code wordt samengesteld, kan Power BI de bestemming niet verifiëren voordat de query draait en weigert het te vernieuwen in de service. Bouw de aanroep opnieuw met een statische basis-URL plus de opties RelativePath en Query, publiceer opnieuw en voer de referentie voor de basis-URL nogmaals in.
Hoe reken ik bedragen om tegen de koers op transactiedatum?
Laad een op datum gesleutelde koerstabel uit een timeseries-endpoint en match op zowel valuta als datum — via een samengestelde samenvoeging in Power Query, of met een CALCULATE-opzoeking binnen SUMX zoals hierboven getoond. Koppel nooit alleen op valuta; je pakt dan stilzwijgend de koersrij die toevallig als eerste sorteert.
Bestaat er een gratis valuta-API die met Power BI werkt?
Ja. Het gratis niveau van Finexly's gratis valuta-API omvat 1.000 aanvragen per maand zonder creditcard, wat ruim voldoende is voor een Pro-gelicentieerd model dat acht keer per dag vernieuwt. Weeg je aanbieders af op vernieuwingslimieten, historische diepte of valutadekking, vergelijk dan valuta-API's voordat je er een vastdraait in een model dat je jarenlang gaat onderhouden.
Aan de slag met Finexly
Klaar om live wisselkoersen in je Power BI-rapporten te zetten? Haal je gratis Finexly API-sleutel — geen creditcard nodig. Begin met 1.000 gratis aanvragen per maand en schaal op naarmate je groeit. Real-time en historische koersen voor meer dan 170 valuta's, uit één REST API die zich hetzelfde gedraagt of je hem nu aanroept vanuit Power Query, Python of een betaaldienst.
Explore More
Vlado Grigirov
Senior Currency Markets Analyst & Financial Strategist
Vlado Grigirov is a senior currency markets analyst and financial strategist with over 14 years of experience in foreign exchange markets, cross-border finance, and currency risk management. He has wo...
View full profile →