If you have ever tried to show Wise's exchange rate inside your own product, you have probably discovered that the Wise exchange rate API is not quite the thing you expected. Wise publishes genuinely excellent mid-market rate data, and it exposes that data over a REST endpoint — but it sits behind a partner onboarding process, it lives in a payments API rather than a market-data API, and the rate you get back is deliberately not the price your user will pay.
This guide covers exactly what Wise exposes, how to authenticate against it, what each endpoint actually returns, and the five structural limits that decide whether Wise is the right source for your project. It also covers the honest answer to the question most people are really asking: if you just need reliable mid-market exchange rates in an app, is Wise the tool for that job?
What the Wise exchange rate API actually is
Wise is a money transfer company. Its API — branded Wise Platform — is built to move money: create quotes, register recipients, fund transfers, reconcile balances, issue cards. Exchange rates appear in that API because you cannot price a transfer without them, not because Wise sells market data.
That framing explains almost every surprise developers hit. Rates are one small module inside a payments platform, and they are scoped to the currency routes Wise actually supports.
Three separate surfaces, three different access paths
The single biggest source of confusion is that "the Wise rate API" refers to at least three distinct things:
GET /rates— the Exchange Rates endpoint. Returns Wise's mid-market rate for a currency pair, current or historical. This is what most people mean.POST /quotes— the Quotes endpoint. Returns a priced transfer: rate, fee, estimated delivery time, and a rate expiration timestamp.GET /comparisons— the Comparison endpoint. Returns estimated price and speed data for Wise and competing providers and banks on a given route.
They are documented in the same reference, they use different authentication schemes, and they answer very different questions. Reaching for the wrong one is the usual cause of "why is this rate different from what wise.com shows me?"
How to get access to Wise rate data
There is no self-serve API key. Access falls into two tracks:
Platform partners. You onboard as a Wise Platform partner and authenticate with OAuth 2.0 (client ID and client secret) to obtain a token. The /rates reference notes that the endpoint "only supports Bearer authentication for non-Affiliate partners," using a User Token or Personal Token.
Affiliate partners. You join the Wise affiliate programme, then email partnerwise@wise.com to request credentials. Wise reviews the request and, if approved, issues Basic auth credentials that unlock exactly two endpoints: Exchange Rates List and Get Temporary Quote. Nothing else.
This is the fork in the road. If you are building a comparison site, a travel blog widget, or a fintech marketing page, the affiliate track is designed for you. If you are building a product feature — multi-currency pricing, invoicing, a converter screen, an internal reporting job — you are asking a payments partner team to approve you for market data, which is not what either side wants from the relationship.
Note also that Wise pins the API version into the URL path: production is https://api.wise.com/2026Q3/rates, with sandbox at https://api.wise-sandbox.com/2026Q3/rates. Legacy affiliate documentation still references /v1/rates on api.transferwise.com. Version strings embedded in paths mean your integration quietly ages unless someone owns upgrading it.
Calling the Wise rates endpoint
Once you have a token, the endpoint itself is clean and well designed. Four call shapes are documented:
# Latest rates for every supported currency
curl -X GET 'https://api.wise.com/2026Q3/rates' \
-H 'Authorization: Bearer <YOUR_TOKEN>'
# Latest rate for a single pair
curl -X GET 'https://api.wise.com/2026Q3/rates?source=EUR&target=USD' \
-H 'Authorization: Bearer <YOUR_TOKEN>'
# Rate at a specific historical moment
curl -X GET 'https://api.wise.com/2026Q3/rates?source=EUR&target=USD&time=2019-02-13T14:53:01' \
-H 'Authorization: Bearer <YOUR_TOKEN>'
# A time series, grouped by day, hour or minute
curl -X GET 'https://api.wise.com/2026Q3/rates?source=EUR&target=USD&from=2019-02-13&to=2019-03-13&group=day' \
-H 'Authorization: Bearer <YOUR_TOKEN>'The response is an array, one object per interval:
[
{
"rate": 1.166,
"source": "EUR",
"target": "USD",
"time": "2018-08-31T10:43:31+0000"
}
]Two details worth flagging. First, group accepts day, hour or minute — minute-level history is unusually generous and genuinely useful for backtesting. Second, the response is always an array, even for a single pair, so parse accordingly:
import requests
TOKEN = "<YOUR_TOKEN>"
BASE = "https://api.wise.com/2026Q3"
def wise_rate(source: str, target: str) -> float:
r = requests.get(
f"{BASE}/rates",
params={"source": source, "target": target},
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=10,
)
r.raise_for_status()
payload = r.json()
if not payload:
raise LookupError(f"No rate returned for {source}/{target}")
return payload[0]["rate"] # array, even for one pair
print(wise_rate("EUR", "USD"))One more trap, well documented in the wild: if you send time and from/to in the same request, the range parameters win and time is ignored. This caused a long-standing bug in n8n's Wise node that took an upstream patch to fix. Send one or the other, never both.
The mid-market rate is not the price your user pays
Wise's /rates endpoint returns the mid-market rate — the midpoint between the buy and sell price on the interbank market. It is the "real" rate, and it is what Wise markets itself on. It is also, by definition, a rate nobody transacts at.
If you need what a transfer will actually cost, you need /quotes:
curl -X POST 'https://api.wise.com/2026Q3/quotes' \
-H 'Authorization: Bearer <YOUR_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
"sourceCurrency": "GBP",
"targetCurrency": "USD",
"sourceAmount": 100
}'The quote response carries the fields that pricing logic actually needs: rate, rateType (for example FIXED), rateExpirationTime, a fee breakdown, feePercentage, and a paymentOptions array with estimatedDelivery per pay-in method. It also returns notices — Wise's own documented example warns that a customer may hold a maximum of three open transfers at a guaranteed rate before further transfers fall back to the live rate.
The practical consequence: a quote is a short-lived, stateful object tied to a transfer, not a rate lookup you can poll on a schedule. If your use case is "display today's USD price on a pricing page," quotes are the wrong primitive and rates are the right one. If your use case is "tell the user precisely what they will receive," rates alone will overstate it. Getting this distinction wrong is a common source of the rounding and reconciliation mismatches described in our guide to currency rounding and decimal places.
What the Comparison API really returns
The Comparison endpoint is the most interesting and the most misunderstood part of the platform. It returns provider-by-provider price and speed estimates for banks and money transfer services on a route:
curl -X GET 'https://api.wise.com/2026Q3/comparisons?sourceCurrency=GBP&targetCurrency=EUR&sendAmount=10000&filter=POPULAR'Before you build anything on top of it, read Wise's own methodology note carefully. Wise states that it collects advertised rates and fees from third-party websites, calculates each provider's markup over the mid-market rate at the moment of collection, and then re-applies that stored markup to the current mid-market rate to produce the number you receive. Collection runs roughly once per hour.
In other words, competitor prices from this endpoint are modelled estimates derived from hourly scrapes, not live quotes. Wise says so plainly, which is to its credit — but it means the data is unsuitable for anything where you would need to stand behind the competitor number. Wise further restricts the estimates to bank transfer pay-in and pay-out only, and notes that many providers price card and cash transactions very differently.
Structurally, the response is denormalised: one provider can return several quotes for the same currency pair because pricing and delivery speed vary by destination country. You get a providers array, each with a quotes array, and reducing that to one headline number per provider is your job, not the API's.
Five limits to know before you build on Wise rates
- Access is a business relationship, not a signup. Affiliate approval or Platform onboarding gates every rate call. There is no dashboard where you generate a key in thirty seconds.
- Coverage follows transfer routes. Wise supports the currencies it can move money in. A dedicated data provider covers currencies it can price, which is a broader set — Finexly covers 170+ currencies, including ones no transfer corridor exists for.
- Rates are one module in a payments API. The surrounding surface is quotes, recipients, KYC, cards and webhooks. That is a large, security-sensitive integration to maintain when all you wanted was a number.
- No published quota. The
/ratesreference documents a429response but does not publish a public request allowance, so you are sizing capacity against an unstated limit. Compare that with an explicit, headers-in-every-response model. - Two currencies per call.
/ratestakes a singlesourceandtarget. Pricing a page in eight currencies means eight calls or a full-table fetch and client-side filtering.
None of these are defects. They are what a payments API looks like when you use it as a data API.
When Wise is the right choice — and when it isn't
| Your use case | Best fit | Why |
|---|---|---|
| Comparison site or affiliate content showing "banks vs Wise" | Wise Comparison API | It is the only source for this data, and the affiliate track exists precisely for it |
| Actually sending money through Wise | Wise Quotes + Transfers | You need the priced, expiring quote object |
| Showing Wise's branded rate because your users asked for it | Wise /rates | Brand attribution is the whole point |
| Multi-currency pricing, checkout or a converter screen | Dedicated currency API | You need breadth, a fast key, and a simple contract |
| Invoicing, billing and revenue reporting | Dedicated currency API | You need a stable historical series and an audit trail |
| Backtesting or analytics | Either | Wise's minute-level history is strong; a data API is easier to obtain |
Using a dedicated exchange rate API instead
A data API inverts the trade-off: no onboarding call, broader coverage, an explicit quota, and a response shape with nothing in it but the rate.
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://api.finexly.com/v1/rate?from=EUR&to=USD"{ "pair": "EUR_USD", "rate": 1.0852 }Pricing a page in several currencies is one round trip rather than one call per pair:
const apiKey = process.env.FINEXLY_API_KEY;
async function priceTable(base, quotes) {
const q = quotes.map((c) => `${base}_${c}`).join(',');
const res = await fetch(`https://api.finexly.com/v1/convert?q=${q}`, {
headers: { Authorization: `Bearer ${apiKey}` },
});
if (!res.ok) throw new Error(`Finexly ${res.status}`);
return res.json();
}
const rates = await priceTable('USD', ['EUR', 'GBP', 'JPY', 'CAD', 'AUD']);
// { "USD_EUR": { "rate": 0.9215 }, "USD_GBP": { "rate": 0.7892 }, ... }And when you want the converted figure rather than the multiplier, let the API do the arithmetic so rounding happens in one place:
import requests
def convert(amount, src, dst, api_key):
r = requests.get(
"https://api.finexly.com/v1/convert-amount",
params={"from": src, "to": dst, "amount": amount},
headers={"Authorization": f"Bearer {api_key}"},
timeout=10,
)
r.raise_for_status()
return r.json()["result"]
print(convert(100, "USD", "EUR", "YOUR_API_KEY"))Every response carries X-RateLimit-Limit, X-RateLimit-Used and X-RateLimit-Units, so quota is observable rather than inferred. Rates refresh every minute during market hours. The free tier is 1,000 requests per month at 10 requests per minute, with paid plans from $6.99/month for 3,500 requests up to 100,000 on the Professional plan — the full breakdown is on the pricing page.
A short note on volume: 1,000 requests a month sounds small until you cache. A single scheduled job that refreshes a full rate table every fifteen minutes uses roughly 2,900 calls a month; every sixty minutes uses about 730. Caching turns your call volume into a function of time rather than traffic, which is what makes a small tier viable at any scale. The patterns are covered in caching and error handling for currency APIs.
Migrating from Wise /rates
If you are moving an existing integration, the mapping is close to one-for-one:
| Wise | Equivalent | Note |
|---|---|---|
GET /rates | GET /v1/currencies then /v1/rate | Wise's bare /rates returns everything; fetch the currency list once |
GET /rates?source=X&target=Y | GET /v1/rate?from=X&to=Y | Returns an object, not a single-element array |
| Several pairs, several calls | GET /v1/convert?q=X_Y,X_Z | One request |
Manual amount * rate | GET /v1/convert-amount | Rounding handled server-side |
?time= historical point | Historical endpoint | Requires a paid plan; see the historical rates guide |
| Basic or OAuth token | Authorization: Bearer | Key from the dashboard, no approval step |
Finally: please do not scrape wise.com. Several marketplace listings offer exactly that, and they are fragile, legally murky, and break the first time the page markup changes. If you need the Wise number specifically, take the affiliate track and get it from the API properly. If you need a number, use an API built to serve one. Our comparison of free currency APIs and the Frankfurter alternatives guide both cover the no-key options in more depth.
Frequently Asked Questions
Is the Wise exchange rate API free? There is no published per-request charge for the rates endpoint, but access is not open. You must be an approved Wise Platform partner or an approved affiliate partner, which means an application and a review rather than a signup form. For most projects the cost is time, not money.
Can I use the Wise API without an account?
No. Both documented tracks require credentials — Bearer tokens for Platform partners, Basic auth client ID and secret for affiliate partners. The only endpoint whose documented example omits an authorization header is /comparisons, and building production traffic on that assumption is unwise.
Does the Wise API return the same rate shown on wise.com?
/rates returns the mid-market rate, which is the headline figure Wise advertises. The amount a customer actually receives comes from /quotes and includes Wise's fee. If your numbers do not match the website, you are almost certainly comparing a mid-market rate against a priced quote.
How far back does Wise historical rate data go?
The endpoint accepts arbitrary from/to timestamps with day, hour or minute grouping; Wise does not publish a fixed earliest date in the reference, so test the specific range you need rather than assuming coverage.
What is the best alternative to the Wise exchange rate API? It depends on what you are replacing. For competitor price comparison there is no alternative — Wise's Comparison API is unique. For mid-market rates in a product, a dedicated currency data API gives you broader coverage, instant keys and an explicit quota. Compare the options on our API comparison page.
Can I show Wise's rate to my users legally? If you are an approved affiliate or Platform partner, yes, within the terms of that agreement. Scraping the public site to obtain the same numbers is a different matter and is not something we would recommend building a business on.
Ready to skip the partner onboarding and just get rates? Get your free Finexly API key — no credit card required. Start with 1,000 free requests per month across 170+ currencies, and upgrade only when your traffic does. You can also try the rates in the browser first with our currency converter.
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 →