RateExchanger API
Exchange rates for 170+ currencies against any base currency. Every endpoint is a plain HTTPS GET request that returns JSON, so you can call it from any language without an SDK.
Quickstart
- Get your API token. Every plan, including Free, can call the API.
- Send a request to
/exchangewith your token in theAuthorizationheader. On a paid plan, add?base=EURto price everything against another currency. - Read the rates from the
dataarray. Eachrateis how much of that currency one unit ofbasebuys.
Endpoints
| Endpoint | Returns | Token |
|---|---|---|
GET /exchange | Current rates for every currency against a base currency. | Required |
GET /convert | An amount converted from one currency to another. | Required |
GET /collection | Your saved currency collections with their rates. | Required |
GET /collection/{id} | One of your collections. | Required |
GET /currency | Supported currencies, paginated with page and per_page. | Required |
GET /country | Supported countries, paginated with page and per_page. | Required |
curl "https://rateexchanger.io/api/exchange" \ -H "Authorization: Bearer $RATEX_API_TOKEN"
const response = await fetch("https://rateexchanger.io/api/exchange", {
headers: { Authorization: `Bearer ${process.env.RATEX_API_TOKEN}` },
});
const { base, data } = await response.json();
const euro = data.find((item) => item.currency.code === "EUR");
console.log(euro.rate); // 0.896555
import os
import requests
response = requests.get(
"https://rateexchanger.io/api/exchange",
headers={"Authorization": f"Bearer {os.environ['RATEX_API_TOKEN']}"},
)
rates = {item["currency"]["code"]: item["rate"] for item in response.json()["data"]}
print(rates["EUR"]) # 0.896555
{
"base": "USD",
"data": [
{
"id": "01a131b5-0c2e-7d4f-9b1a-3e8f6a2c4d71",
"currency": {
"id": "01a131b4-9ad1-7a3e-8c55-1f2b3c4d5e6f",
"name": "Euro",
"code": "EUR"
},
"rate": 0.896555,
"updated_at": "2026-10-12T16:01:26.000000Z"
},
{
"id": "01a131b5-0c2f-71b8-a6d2-7c9e0f1a2b3c",
"currency": {
"id": "01a131b4-9ad3-7e10-b2c4-5d6e7f8a9b0c",
"name": "British Pound Sterling",
"code": "GBP"
},
"rate": 0.757241,
"updated_at": "2026-10-12T16:01:26.000000Z"
}
]
}
Getting started
Authentication
Send your API token as a bearer token in the Authorization header. A request with a missing or invalid token gets 401 with the message Unauthenticated.
Your token identifies your account, so every request is checked against your subscription and request allowance. Tokens don't expire; they stay valid until they're revoked.
You don't need to set an Accept header. The API always answers in JSON, including errors.
curl "https://rateexchanger.io/api/exchange" \ -H "Authorization: Bearer $RATEX_API_TOKEN"
const response = await fetch("https://rateexchanger.io/api/exchange", {
headers: { Authorization: `Bearer ${process.env.RATEX_API_TOKEN}` },
});
import os
import requests
response = requests.get(
"https://rateexchanger.io/api/exchange",
headers={"Authorization": f"Bearer {os.environ['RATEX_API_TOKEN']}"},
)
{
"message": "Unauthenticated."
}
Getting started
Rate limits
Each plan includes a set number of requests per month, and every request to any endpoint counts toward it, including requests that fail with an error such as 404 or 422. Requests turned away because your plan is used up or your subscription has lapsed don't count. All plans get the same rates, refreshed every 30 minutes.
| Plan | Requests included | Rate updates |
|---|---|---|
| Free | 500 | Every 30 minutes |
| Basic | 20,000 | Every 30 minutes |
| Pro | 700,000 | Every 30 minutes |
| Elite | 1,800,000 | Every 30 minutes |
When you reach the limit
Once your plan's requests are used up, every endpoint returns 429 until your next monthly allowance starts or you upgrade. If your subscription lapses, every endpoint returns 403 instead.
Each account can also send up to 50 requests per second, shared across all its keys. Going faster returns 429 with a Retry-After header, and those requests don't count toward your plan. Every response includes X-RateLimit-Limit and X-RateLimit-Remaining headers, and your dashboard shows how many requests you've used this month.
{
"success": false,
"error": "You have used up the allowed API requests (500) within your plan!",
"code": 429
}
Getting started
Errors
Failed requests return a standard HTTP status with a JSON body. 401, 422 and 500 errors carry a message; invalid parameters also list what's wrong under errors, keyed by parameter name.
403, 404 and 429 errors use a different shape: success is false, the reason is in error, and code repeats the status. Check the HTTP status first, then read whichever field is present.
| Status | What happened |
|---|---|
| 401 | The token is missing or invalid. |
| 403 | Your email address isn't verified yet, your subscription has expired, your plan doesn't include the feature you asked for (collections, a custom base currency or currency conversion), or you asked for a collection that isn't yours. |
| 404 | The collection or endpoint doesn't exist. |
| 422 | A parameter is invalid, such as an unsupported base currency or a non-numeric page. |
| 429 | You're sending more than 50 requests per second (wait for the Retry-After seconds), or your plan's requests are used up (they reset when your next monthly allowance starts, or you can upgrade). |
| 500 | Something failed on our side. Retry after a short wait. |
curl "https://rateexchanger.io/api/exchange?base=XYZ" \ -H "Authorization: Bearer $RATEX_API_TOKEN"
{
"message": "Invalid base currency.",
"errors": {
"base": [
"Invalid base currency."
]
}
}
Endpoints
Exchange rates
Returns the current rate of every supported currency against a base currency, refreshed every 30 minutes. The base currency itself is left out of data.
Each rate is how much of that currency one unit of base buys, and updated_at is when it was last refreshed. Rates against a custom base are converted from the USD rates and aren't rounded.
Query parameters
-
base string optional
Paid plans only. Three-letter code to price everything against, such as
EUR. Defaults toUSD. On the Free plan, sendingbaseat all, evenUSD, returns403. An unsupported code returns422.
curl "https://rateexchanger.io/api/exchange" \ -H "Authorization: Bearer $RATEX_API_TOKEN"
const response = await fetch("https://rateexchanger.io/api/exchange", {
headers: { Authorization: `Bearer ${process.env.RATEX_API_TOKEN}` },
});
const { data } = await response.json();
import os
import requests
response = requests.get(
"https://rateexchanger.io/api/exchange",
headers={"Authorization": f"Bearer {os.environ['RATEX_API_TOKEN']}"},
)
data = response.json()["data"]
{
"base": "USD",
"data": [
{
"id": "01a131b5-0c2e-7d4f-9b1a-3e8f6a2c4d71",
"currency": {
"id": "01a131b4-9ad1-7a3e-8c55-1f2b3c4d5e6f",
"name": "Euro",
"code": "EUR"
},
"rate": 0.896555,
"updated_at": "2026-10-12T16:01:26.000000Z"
},
{
"id": "01a131b5-0c2f-71b8-a6d2-7c9e0f1a2b3c",
"currency": {
"id": "01a131b4-9ad3-7e10-b2c4-5d6e7f8a9b0c",
"name": "British Pound Sterling",
"code": "GBP"
},
"rate": 0.757241,
"updated_at": "2026-10-12T16:01:26.000000Z"
}
]
}
Endpoints
Convert currency
Converts an amount from one currency to another at the current rate, refreshed every 30 minutes, so you don't have to do the maths yourself.
rate is how much of to one unit of from buys, rounded to 6 decimal places, and result is amount converted, also rounded to 6 decimal places. updated_at is when the older of the two rates was last refreshed, and is null when both sides are USD.
403 with the error Your plan does not include currency conversion!Query parameters
-
from string required
Three-letter code of the currency to convert from, such as
EUR. Any case works. An unsupported code returns422. -
to string required
Three-letter code of the currency to convert to, such as
GBP. -
amount number required
Amount to convert, greater than 0, such as
99or12.50. -
collection string optional
Paid plans only. The
idof one of your collections, to add itsmarkuppercentage to the rate, the same way collection rates are marked up. A collection that isn't yours returns403.
curl "https://rateexchanger.io/api/convert?from=EUR&to=GBP&amount=99" \ -H "Authorization: Bearer $RATEX_API_TOKEN"
const response = await fetch("https://rateexchanger.io/api/convert?from=EUR&to=GBP&amount=99", {
headers: { Authorization: `Bearer ${process.env.RATEX_API_TOKEN}` },
});
const { data } = await response.json();
import os
import requests
response = requests.get(
"https://rateexchanger.io/api/convert",
params={"from": "EUR", "to": "GBP", "amount": 99},
headers={"Authorization": f"Bearer {os.environ['RATEX_API_TOKEN']}"},
)
data = response.json()["data"]
{
"data": {
"from": {
"id": "01a131b4-9ad1-7a3e-8c55-1f2b3c4d5e6f",
"name": "Euro",
"code": "EUR"
},
"to": {
"id": "01a131b4-9ad3-7e10-b2c4-5d6e7f8a9b0c",
"name": "British Pound Sterling",
"code": "GBP"
},
"amount": 99,
"rate": 0.844612,
"markup": 0,
"collection": null,
"result": 83.616576,
"updated_at": "2026-10-12T16:01:26.000000Z"
}
}
Endpoints
List collections
Returns every currency collection saved on your account, each with its name, base currency, markup and the latest rate for the currencies in it. Use collections to fetch just the handful of currencies you care about in one call.
Each item's rate is how much of that currency one unit of the collection's base buys, with the collection's markup percentage added. Rates are rounded to 6 decimal places. An item's updated_at is when its rate was last refreshed, and is null for USD, which every rate is stored against.
403 with the error Your plan does not include API collections!Query parameters
None. All of your collections are returned in one response.
curl "https://rateexchanger.io/api/collection" \ -H "Authorization: Bearer $RATEX_API_TOKEN"
const response = await fetch("https://rateexchanger.io/api/collection", {
headers: { Authorization: `Bearer ${process.env.RATEX_API_TOKEN}` },
});
const { data } = await response.json();
import os
import requests
response = requests.get(
"https://rateexchanger.io/api/collection",
headers={"Authorization": f"Bearer {os.environ['RATEX_API_TOKEN']}"},
)
data = response.json()["data"]
{
"data": [
{
"id": "01a2f7c3-4b5d-7e6f-8a9b-0c1d2e3f4a5b",
"name": "Checkout currencies",
"base": {
"id": "01a131b4-9b52-7c1d-a3e4-6f7a8b9c0d1e",
"name": "United States Dollar",
"code": "USD"
},
"markup": 0,
"items": [
{
"id": "01a2f7c3-5c6d-7e8f-9a0b-1c2d3e4f5a6b",
"currency": {
"id": "01a131b4-9ad1-7a3e-8c55-1f2b3c4d5e6f",
"name": "Euro",
"code": "EUR"
},
"rate": 0.896555,
"updated_at": "2026-10-12T16:01:26.000000Z"
},
{
"id": "01a2f7c3-5c6e-7f90-a1b2-c3d4e5f6a7b8",
"currency": {
"id": "01a131b4-9ad3-7e10-b2c4-5d6e7f8a9b0c",
"name": "British Pound Sterling",
"code": "GBP"
},
"rate": 0.757241,
"updated_at": "2026-10-12T16:01:26.000000Z"
}
],
"created_at": "2026-09-02T14:22:10.000000Z",
"updated_at": "2026-09-02T14:22:10.000000Z"
}
]
}
Endpoints
Get a collection
Returns one of your collections with the latest rate for each currency in it. The response has the same fields as an entry from List collections.
Path parameters
-
id string required
The collection's
id. A collection that belongs to another account returns403; one that doesn't exist returns404.
curl "https://rateexchanger.io/api/collection/01a2f7c3-4b5d-7e6f-8a9b-0c1d2e3f4a5b" \ -H "Authorization: Bearer $RATEX_API_TOKEN"
const response = await fetch("https://rateexchanger.io/api/collection/01a2f7c3-4b5d-7e6f-8a9b-0c1d2e3f4a5b", {
headers: { Authorization: `Bearer ${process.env.RATEX_API_TOKEN}` },
});
const { data } = await response.json();
import os
import requests
response = requests.get(
"https://rateexchanger.io/api/collection/01a2f7c3-4b5d-7e6f-8a9b-0c1d2e3f4a5b",
headers={"Authorization": f"Bearer {os.environ['RATEX_API_TOKEN']}"},
)
data = response.json()["data"]
{
"data": {
"id": "01a2f7c3-4b5d-7e6f-8a9b-0c1d2e3f4a5b",
"name": "Checkout currencies",
"base": {
"id": "01a131b4-9b52-7c1d-a3e4-6f7a8b9c0d1e",
"name": "United States Dollar",
"code": "USD"
},
"markup": 0,
"items": [
{
"id": "01a2f7c3-5c6d-7e8f-9a0b-1c2d3e4f5a6b",
"currency": {
"id": "01a131b4-9ad1-7a3e-8c55-1f2b3c4d5e6f",
"name": "Euro",
"code": "EUR"
},
"rate": 0.896555,
"updated_at": "2026-10-12T16:01:26.000000Z"
},
{
"id": "01a2f7c3-5c6e-7f90-a1b2-c3d4e5f6a7b8",
"currency": {
"id": "01a131b4-9ad3-7e10-b2c4-5d6e7f8a9b0c",
"name": "British Pound Sterling",
"code": "GBP"
},
"rate": 0.757241,
"updated_at": "2026-10-12T16:01:26.000000Z"
}
],
"created_at": "2026-09-02T14:22:10.000000Z",
"updated_at": "2026-09-02T14:22:10.000000Z"
}
}
Endpoints
Currencies
Lists every supported currency with its name and three-letter ISO 4217 code. Use these codes for the base parameter.
Query parameters
-
per_page number optional
Results per page. Defaults to
25. Use-1to get every currency in one response, without pagination. -
page number optional
Page to return. Defaults to
1.
Paginated responses also include links (first, last, previous and next page URLs) and meta (current page, total and so on).
curl "https://rateexchanger.io/api/currency?per_page=2" \ -H "Authorization: Bearer $RATEX_API_TOKEN"
const response = await fetch("https://rateexchanger.io/api/currency?per_page=2", {
headers: { Authorization: `Bearer ${process.env.RATEX_API_TOKEN}` },
});
const { data } = await response.json();
import os
import requests
response = requests.get(
"https://rateexchanger.io/api/currency",
params={"per_page": 2},
headers={"Authorization": f"Bearer {os.environ['RATEX_API_TOKEN']}"},
)
data = response.json()["data"]
{
"data": [
{
"id": "01a131b4-9ac6-70cb-9522-fb389aa55357",
"name": "United Arab Emirates Dirham",
"code": "AED"
},
{
"id": "01a131b4-9ac7-724c-abaf-93bac978e922",
"name": "Afghan Afghani",
"code": "AFN"
}
],
"meta": {
"current_page": 1,
"last_page": 87,
"per_page": 2,
"total": 173
}
}
Endpoints
Countries
Lists every supported country with its name, URL-friendly slug and two-letter ISO 3166 code.
Query parameters
-
per_page number optional
Results per page. Defaults to
25. Use-1to get every country in one response, without pagination. -
page number optional
Page to return. Defaults to
1.
curl "https://rateexchanger.io/api/country?per_page=2" \ -H "Authorization: Bearer $RATEX_API_TOKEN"
const response = await fetch("https://rateexchanger.io/api/country?per_page=2", {
headers: { Authorization: `Bearer ${process.env.RATEX_API_TOKEN}` },
});
const { data } = await response.json();
import os
import requests
response = requests.get(
"https://rateexchanger.io/api/country",
params={"per_page": 2},
headers={"Authorization": f"Bearer {os.environ['RATEX_API_TOKEN']}"},
)
data = response.json()["data"]
{
"data": [
{
"id": "01a131b4-9196-71ca-95ca-22bf8c422cce",
"name": "Afghanistan",
"slug": "afghanistan",
"code": "AF"
},
{
"id": "01a131b4-9197-7036-bcfe-b9a41f75a308",
"name": "Albania",
"slug": "albania",
"code": "AL"
}
],
"meta": {
"current_page": 1,
"last_page": 99,
"per_page": 2,
"total": 198
}
}