Vraag vijf verschillende diensten op dit moment naar de EUR/USD-koers en je krijgt vijf licht verschillende getallen. Niet wild verschillend — maar anders op de vierde decimaal, soms op de derde. Als je finance-team ooit een ticket heeft geopend omdat de checkout 1,0847 toonde terwijl het bankafschrift 1,0821 zegt, weet je al dat dit geen academische kwestie is.
Dus: waar halen wisselkoers-API's hun data vandaan? Het eerlijke antwoord is dat geen enkele API de wisselkoers "kent", omdat er geen enkele wisselkoers is om te kennen. De valutamarkt is een over-the-counter markt zonder centrale beurs en zonder slotbel — alleen duizenden instellingen die elkaar wereldwijd prijzen quoteren. Elke API die je kunt aanroepen is een pipeline die die markt bemonstert, opschoont en jou één getal geeft. Deze gids doorloopt die pipeline laag voor laag, legt precies uit waarom twee aanbieders van elkaar afwijken, en laat zien hoe je een feed controleert voordat je er facturatielogica op bouwt.
Het korte antwoord: drie lagen tussen de markt en jouw JSON
Elke wisselkoers-API — gratis of betaald, de onze inbegrepen — bestaat uit dezelfde drie lagen:
- Acquisitie. Ruwe prijzen worden opgehaald uit upstream-bronnen: institutionele FX-feeds, publicaties van centrale banken en broker- of retailquotes.
- Normalisatie. Die ruwe prijzen worden gevalideerd, uitschieters weggegooid, meerdere bronnen gemengd, en er wordt één referentiekoers per paar afgeleid.
- Levering. De afgeleide koers wordt volgens een vaste cadans vastgelegd, gecachet en via HTTP geserveerd met een tijdstempel.
Verschillen in elk van die drie lagen leveren een ander getal op in je response body. De meeste ontwikkelaars gaan ervan uit dat de afwijking uit laag 1 komt. In de praktijk veroorzaken laag 2 en 3 er net zoveel van.
Laag 1 — Waar de ruwe prijzen echt vandaan komen
Interbancaire en institutionele feeds
Het dichtst bij een "echte" wisselkoers komt de interbancaire markt: de prijzen waartegen grote banken en liquidity providers onderling handelen. Die prijzen komen binnen als continue stromen van bid- en ask-quotes vanuit handelsplatformen, prime brokers en marktdataleveranciers.
Zulke feeds zijn de bron met de hoogste betrouwbaarheid. Ze zijn ook de duurste, en dat is de belangrijkste reden waarom gratis API's ze zelden als primaire bron gebruiken. Als een aanbieder "realtime" of "sub-minuut" koersen belooft, komt dat vrijwel altijd doordat institutionele feeds bovenaan zijn pipeline staan.
Let op: een interbancaire feed geeft je twee prijzen, geen één — een bid en een ask. De enkele koers die je in een API-antwoord ziet is meestal het middelpunt daartussen. Als dat onderscheid nieuw voor je is, behandelt onze gids over de bid-ask spread bij valutawissel dat in detail.
Referentiekoersen van centrale banken
De tweede grote bron zijn officiële publicaties van centrale banken. Het bekendste voorbeeld is de Europese Centrale Bank, die op elke TARGET-werkdag rond 16:00 CET euro-referentiekoersen publiceert, op basis van een concertatieprocedure tussen Europese centrale banken. Tientallen andere centrale banken publiceren gelijkwaardige dagkoersen voor hun eigen valuta.
Centralebankkoersen hebben twee enorme voordelen: ze zijn gratis en ze zijn gezaghebbend. Veel belastingdiensten en verslaggevingsstandaarden accepteren ze expliciet voor rapportage. Daarom is een groot deel van het gratis API-ecosysteem erop gebouwd. Frankfurter, een breed gebruikt opensourceproject in dit veld, volgt dagkoersen van 84 centrale banken voor 201 valuta, met historie tot 1948 — allemaal publieke data, geherdistribueerd.
Ze hebben ook twee serieuze beperkingen:
- Het zijn dagelijkse momentopnames, geen live prijzen. Een referentiekoers van 16:00 CET zegt niets over wat er om 09:00 of 22:00 gebeurde.
- Ze stoppen in het weekend en op feestdagen. Als je API geen data teruggeeft voor een zaterdag, of het vrijdaggetal herhaalt, is een ECB-afgeleide bron meestal de verklaring.
Retail- en brokerquotes
De derde bron is prijsstelling richting de eindklant: wat een bank, kaartnetwerk, betaalprovider of overboekingsdienst een klant daadwerkelijk geeft. Die koersen bevatten al een opslag — een marge die bovenop de marktkoers in de prijs zit.
Daarom komt een koers op een consumentenvergelijkingssite niet overeen met de koers op je bankafschrift. Het is op geen van beide plekken een fout; ze meten verschillende dingen. Consumentensites tonen doorgaans de mid-market koers, terwijl je bank je de mid-market koers plus zijn spread quoteert. Voor de meeste softwaretoepassingen wil je het mid-market getal en wil je je eigen opslag expliciet toepassen, waar je hem kunt zien en controleren.
Laag 2 — Hoe aanbieders feeds omzetten in één koers
Zodra de ruwe prijzen binnenkomen, moet de aanbieder beslissen welk getal hij publiceert. Hier vallen vier beslissingen, en elk daarvan is een plek waar aanbieders uiteenlopen.
Blending. De meeste commerciële API's leunen niet op één upstream-bron. Open Exchange Rates omschrijft zijn data bijvoorbeeld als verzameld bij meerdere aanbieders en algoritmisch gemengd. Blending vlakt één slechte tick af, maar de weegfactoren zijn propriëtair — en juist daarom komen twee gemengde feeds nooit exact overeen.
Uitschieters verwerpen. Een foute quote van één handelsplatform kan een orde van grootte afwijken. Aanbieders passen filters toe die prijzen buiten een tolerantieband rond de consensus weggooien. Agressief filteren betekent stabiele koersen maar tragere reactie op echte bewegingen. Losjes filteren betekent snelle reactie maar af en toe ruis.
Mid-afleiding. Als de upstream-feed bid/ask is, publiceert de aanbieder een mid. Het eenvoudige middelpunt (bid + ask) / 2 is standaard, maar volumegewogen benaderingen geven een licht ander resultaat.
Cross-rate triangulatie. Geen enkele aanbieder haalt alle 30.000+ mogelijke valutaparen direct binnen. In plaats daarvan worden de meeste paren berekend via een pivotvaluta — meestal USD of EUR:
GBP/JPY = (USD/JPY) / (USD/GBP)Dat betekent dat de koers die je voor een exotisch paar krijgt afronding en timing erft van twee andere paren. Aanbieders die op USD pivoteren en aanbieders die op EUR pivoteren komen bij hetzelfde cross op verschillende getallen uit. De mechaniek behandelen we in kruiskoersen uitgelegd.
Laag 3 — Hoe de koers in jouw code belandt
De laatste laag is die welke ontwikkelaars het meest bepalen en waar ze het minst over nadenken.
De verversingsfrequentie is de grootste onderscheidende factor tussen aanbieders en tussen prijsniveaus. Gratis plannen verversen vaak een- of tweemaal per dag. Betaalde niveaus verversen elk uur, elke tien minuten of elke 60 seconden. Twee API's met identieke data lopen uiteen simpelweg omdat de één om 14:00 en de ander om 14:47 een momentopname maakte.
Caching versterkt dat. De meeste API's zitten achter een CDN, en de meeste goed gebouwde clients cachen daar lokaal bovenop. Tel een edge-cache van 15 minuten op bij een verversing van 10 minuten en je applicatie werkt mogelijk met een koers van 25 minuten oud. Dat is prima om prijzen te tonen en onacceptabel om een transactie af te wikkelen — de praktische vraag is altijd hoe oud is te oud voor precies deze handeling. Onze gids over caching en foutafhandeling bij valuta-API's legt uit hoe je die vensters dimensioneert.
Tijdstempels zijn je verdediging. Elke serieuze API geeft het moment terug waarop de koers is vastgelegd. Lees dat veld. Ga er niet van uit dat het moment waarop je de respons ontving het moment is waarop de koers klopte:
const MAX_AGE_SECONDS = 900; // 15 minutes
async function getRate(base, symbol) {
const res = await fetch(
`https://api.finexly.com/v1/latest?base=${base}&symbols=${symbol}`,
{ headers: { Authorization: `Bearer ${process.env.FINEXLY_API_KEY}` } }
);
const data = await res.json();
const ageSeconds = Math.floor(Date.now() / 1000) - data.timestamp;
if (ageSeconds > MAX_AGE_SECONDS) {
throw new Error(`Rate is ${ageSeconds}s old — refusing to price on stale data`);
}
return { rate: data.rates[symbol], ageSeconds };
}Dit is het onderliggende verzoek en een representatieve responsvorm:
curl "https://api.finexly.com/v1/latest?base=USD&symbols=EUR,GBP,JPY" \
-H "Authorization: Bearer YOUR_API_KEY"{
"success": true,
"base": "USD",
"timestamp": 1755244800,
"rates": {
"EUR": 0.9241,
"GBP": 0.7863,
"JPY": 147.2150
}
}Alle parameter- en endpointdetails staan in de Finexly API-documentatie.
Waarom twee API's verschillende getallen geven voor hetzelfde paar
Als je de drie lagen samenneemt, zijn dit de zes oorzaken van afwijking, ruwweg op volgorde van hoeveel schade ze aanrichten:
- Verschillende momentopnametijden. Verreweg de meest voorkomende oorzaak. Er is niets mis met beide feeds; ze keken simpelweg op andere momenten.
- Verschillende bronmixen. Een centralebank-afgeleide koers en een interbancair afgeleide koers meten per definitie twee verschillende dingen.
- Mid-market versus koers met opslag. De ene aanbieder geeft je het marktmiddelpunt, de andere een klantprijs met de spread er al in.
- Verschillende pivotvaluta voor crosses. USD-gepivoteerde en EUR-gepivoteerde triangulatie leveren verschillende resultaten voor hetzelfde niet-USD-paar.
- Precisie en afronding. Zes decimalen afgekapt naar vier, of koersen die als inverse paren zijn gepubliceerd en teruggedraaid, veroorzaken allebei drift.
- Cachinglagen die je vergat. Je CDN, de HTTP-cache van je framework en je eigen Redis-laag stapelen allemaal ouderdom op.
Een bruikbare vuistregel: bij hoofdparen is een verschil van enkele basispunten (0,01% = 1 bp) tussen twee gerenommeerde mid-market bronnen normaal en te verwachten. Een verschil van 50 bp of meer betekent dat een van beide verouderd, met opslag belast of kapot is — en dat wil je uitzoeken voordat je live gaat.
Hoe je een wisselkoers-API controleert voordat je erop vertrouwt
Neem de nauwkeurigheidsclaims van een aanbieder niet op goed geloof aan. Draai deze controle een week lang tegen de bron die je finance-team als gezaghebbend beschouwt:
import os
import requests
from datetime import datetime, timezone
FINEXLY_URL = "https://api.finexly.com/v1/latest"
HEADERS = {"Authorization": f"Bearer {os.environ['FINEXLY_API_KEY']}"}
def get_rate(base: str, symbol: str) -> dict:
r = requests.get(
FINEXLY_URL,
headers=HEADERS,
params={"base": base, "symbols": symbol},
timeout=5,
)
r.raise_for_status()
data = r.json()
return {
"rate": data["rates"][symbol],
"captured_at": datetime.fromtimestamp(data["timestamp"], tz=timezone.utc),
}
def basis_points(a: float, b: float) -> float:
"""Difference between two rates, in basis points."""
return abs(a - b) / ((a + b) / 2) * 10_000
primary = get_rate("EUR", "USD")
reference = 1.0839 # whatever your accounting source published
diff = basis_points(primary["rate"], reference)
print(f"Finexly: {primary['rate']} captured {primary['captured_at']:%H:%M UTC}")
print(f"Reference: {reference}")
print(f"Delta: {diff:.1f} bp -> {'OK' if diff < 25 else 'INVESTIGATE'}")Drie dingen om in de resultaten op te letten:
- Is het verschil stabiel of drift het? Een constante afwijking wijst op een systematische opslag. Een willekeurige wijst op timing.
- Piekt het verschil op bepaalde uren? Dat wijst op het moment van vastleggen, meestal rond een publicatievenster van een centrale bank.
- Wat gebeurt er in het weekend? Als je bron vrijdagmiddag bevriest en maandag weer aanslaat, is hij centralebank-afgeleid — plan je maandagse reconciliatie daaromheen.
Je kunt de triangulatie ook toetsen door een cross direct op te halen en hem via USD te berekenen; beide zouden binnen één à twee basispunten moeten overeenkomen.
Een databron kiezen voor jouw toepassing
Er is geen universeel "beste" bron — alleen de juiste bron voor wat je bouwt.
| Toepassing | Wat je nodig hebt | Acceptabele ouderdom |
|---|---|---|
| Prijzen tonen aan kopers | Mid-market koers, je eigen opslag erbovenop | Uren |
| SaaS-abonnementsfacturatie | Mid-market, één momentopname per facturatierun, opgeslagen bij de factuur | Uren, maar moet vastgelegd zijn |
| Boekhouding en fiscale rapportage | Referentiekoers van de centrale bank voor de specifieke datum | Dagelijks, per definitie |
| Analytics en dashboards | Consistente historische tijdreeks uit één bron | Dagelijks |
| Uitbetalingen en overboekingen | Verse mid-market met een expliciete tolerantieband | Minuten |
| Handel en hedging | Echte bid/ask uit een institutionele feed | Seconden |
Als je nog opties afweegt: onze vergelijking van gratis versus betaalde valuta-API's legt uit wat er verandert als je een niveau hoger gaat, en de pagina prijsplannen laat zien waar verversingsfrequentie en verzoekslimieten liggen. Voor een snelle handmatige check op een paar gebruikt de valutaomrekenaar dezelfde onderliggende feed als de API.
Veelgestelde vragen
Waar halen gratis valuta-API's hun data vandaan?
Bijna altijd uit publicaties van centrale banken, meestal de dagelijkse euro-referentiekoersen van de Europese Centrale Bank, soms gemengd met een handvol andere publieke bronnen. Daarom verversen gratis niveaus doorgaans eenmaal per dag, slaan ze weekends over en dekken ze minder exotische valuta dan betaalde niveaus.
Waarom wijkt de koers van mijn API af van die van Google?
Google toont een mid-market referentiekoers, die een momentopname is en geen continue live prijs, en die niet noodzakelijk op hetzelfde moment als jouw API-aanroep wordt bemonsterd. Een klein verschil is normaal. Een groot verschil betekent meestal dat een van beide een retailkoers met opslag is in plaats van een mid-market koers.
Welke wisselkoers moet ik gebruiken voor boekhouding en belastingaangifte?
Gebruik de officiële referentiekoers die de betreffende centrale bank voor de transactiedatum publiceert — dat verwachten de meeste belastingdiensten. Haal hem op via een historisch endpoint met een expliciete datum in plaats van een live koers te hergebruiken, en sla hem op bij het transactierecord.
Is een realtime wisselkoers-API echt realtime?
Zelden in letterlijke zin. "Realtime" betekent meestal dat de aanbieder met korte tussenpozen ververst — 60 seconden is gebruikelijk op het hoogste niveau — niet dat hij tick voor tick streamt. Controleer het tijdstempel in de respons en het gedocumenteerde verversingsinterval, niet de marketingtekst.
Kan ik wisselkoersen niet gewoon scrapen in plaats van een API te gebruiken?
Dat kan, maar je erft elke faalmodus van de pagina die je scrapet: layoutwijzigingen, rate limiting, geen tijdstempels, geen historische backfill en vaak een schending van de gebruiksvoorwaarden. De volledige afweging behandelden we in valuta-API versus web scraping.
Bouw op een feed die je kunt controleren
Weten waar je wisselkoersdata vandaan komt is het verschil tussen een valutabug die je in één zin uitlegt en een die een week engineering opslokt. Stel elke aanbieder drie vragen voordat je integreert: wat zijn de bronnen, hoe vaak wordt er ververst, en draagt elke respons een vastlegtijdstempel?
Klaar om wisselkoersen te integreren die je echt kunt controleren? Haal je gratis Finexly API-sleutel — geen creditcard nodig. Begin met 1.000 gratis verzoeken per maand over 170+ valuta, met getijdstempelde responses en historische data vanaf dag één.
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 →