Overview
Lume Exchange Rates brings exchange-rate comparison, conversion and historical charts into one place. Choose the currencies that matter to you, whether you are planning a trip, comparing an international price or building a product.
We use External exchange-rate provider as the configured source. Each latest-rate response identifies its source and publication time. Available currency symbols are updated from the latest provider data.
Quick start
Production external JSON APIs are currently disabled. Examples below require an enabled environment and a valid paid API key. Browser login alone does not authorize API calls. The website calculator remains available.
export LUME_API_URL='https://lumeexchangerates.com'
export LUME_API_KEY='YOUR_API_KEY'
curl --fail-with-body -H "Authorization: Bearer $LUME_API_KEY" "$LUME_API_URL/v1/quotes?anchor=USD&targets=EUR,JPY"const response = await fetch(process.env.LUME_API_URL + '/v1/quotes?anchor=USD&targets=EUR,JPY', {
headers: { Authorization: 'Bearer ' + process.env.LUME_API_KEY }
});
const body = await response.json();
if (!response.ok) throw new Error(body.error?.code || 'HTTP_' + response.status);
console.log(body.anchor, body.meta.timestamp, body.data);Access & authentication
Manage customer keys in /account. Key issuance and rate access require an active paid subscription and server-confirmed payment. Unsubscribed accounts have no free API allowance. Provider credentials remain server-side.
Authorization: Bearer lume_…| Permission | Access |
|---|---|
| rates:read | /v1/currencies, /v1/quotes, /v1/exchange, /v1/history, /v1/series, /v1/candles, /v1/capabilities |
| usage:read | /v1/usage?range=today|7d|30d |
| Owner session | /api/usage, account and support management |
Keep secret keys on servers. Configured IP/domain restrictions must all match. CORS is opt-in for explicitly allowed HTTPS origins and never replaces authentication.
Endpoints
| GET endpoint | Parameters |
|---|---|
| /v1/currencies | — |
| /v1/quotes | anchor, targets |
| /v1/exchange | from, to, quantity |
| /v1/history | date, anchor, targets |
| /v1/series | start, end, anchor, targets |
| /v1/candles | start, period, anchor, targets, source |
| /v1/capabilities | — |
| /v1/usage | range=today|7d|30d |
GET /v1/currencies
All symbols with current rates, with provider names. Includes available alternatives and metals.
Parameter: —
curl --request GET 'https://staging.lumeexchangerates.com/v1/currencies' --header 'Authorization: Bearer YOUR_API_KEY'The values and dates below illustrate response structure; they are not live rates. Arrays may show only a subset. Use the API explorer for current data.
{
"meta": {
"mode": "provider",
"source": "External exchange-rate provider",
"source_url": "https://openexchangerates.org/",
"as_of": "2026-01-01T00:00:00.000Z",
"fetched_at": "2026-01-01T00:00:05.000Z",
"currency_count": 3,
"includes_alternative": true,
"refresh_interval_seconds": 300,
"provider_plan": "Unlimited",
"notice": "Illustrative response; not live rates."
},
"data": [
{
"code": "USD",
"name": "United States Dollar"
},
{
"code": "EUR",
"name": "Euro"
},
{
"code": "JPY",
"name": "Japanese Yen"
}
]
}| Parameter | Type | Description |
|---|---|---|
| data[].code | string | Uppercase symbol. Alternative assets can exceed three characters or include underscores. |
| data[].name | string | Provider name, or the code itself when no name is available. |
GET /v1/quotes
Base symbol; defaults to USD. Any current provider symbol is accepted.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| anchor | string | Optional | USD | Base symbol; defaults to USD. Any current provider symbol is accepted. |
| targets | string | Optional | all | Comma-separated target symbols. Omit to return all available symbols. |
curl --request GET 'https://staging.lumeexchangerates.com/v1/quotes?anchor=USD&targets=EUR,JPY' --header 'Authorization: Bearer YOUR_API_KEY'The values and dates below illustrate response structure; they are not live rates. Arrays may show only a subset. Use the API explorer for current data.
{
"meta": {
"mode": "provider",
"source": "External exchange-rate provider",
"source_url": "https://openexchangerates.org/",
"as_of": "2026-01-01T00:00:00.000Z",
"fetched_at": "2026-01-01T00:00:05.000Z",
"currency_count": 3,
"includes_alternative": true,
"refresh_interval_seconds": 300,
"provider_plan": "Unlimited",
"notice": "Illustrative response; not live rates."
},
"anchor": "USD",
"data": [
{
"currency": "EUR",
"value": 0.9
},
{
"currency": "JPY",
"value": 150
}
]
}Example: /v1/quotes?anchor=EUR&targets=USD,JPY. value is target units per one anchor unit. Duplicate targets are removed. Empty, lowercase or unavailable symbols return 400.
| Parameter | Type | Description |
|---|---|---|
| anchor | string | Base symbol; defaults to USD. Any current provider symbol is accepted. |
| data[].currency | string | To |
| data[].value | number | rates[currency] / rates[anchor] |
GET /v1/exchange
Non-negative numeric amount to convert.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| from | string | Optional | USD | Source currency symbol; defaults to USD. |
| to | string | Optional | EUR | Target currency symbol; defaults to EUR. |
| quantity | number | Optional | 1 | Non-negative numeric amount to convert. |
curl --request GET 'https://staging.lumeexchangerates.com/v1/exchange?from=USD&to=EUR&quantity=100' --header 'Authorization: Bearer YOUR_API_KEY'The values and dates below illustrate response structure; they are not live rates. Arrays may show only a subset. Use the API explorer for current data.
{
"meta": {
"mode": "provider",
"source": "External exchange-rate provider",
"source_url": "https://openexchangerates.org/",
"as_of": "2026-01-01T00:00:00.000Z",
"fetched_at": "2026-01-01T00:00:05.000Z",
"currency_count": 3,
"includes_alternative": true,
"refresh_interval_seconds": 300,
"provider_plan": "Unlimited",
"notice": "Illustrative response; not live rates."
},
"data": {
"from": "USD",
"to": "EUR",
"quantity": 100,
"rate": 0.9,
"result": 90
}
}Example: /v1/exchange?from=USD&to=EUR&quantity=100. Always specify from and to in global integrations. This legacy GET route defaults to EUR. Empty values, negatives, NaN, infinity and result overflow return 400.
| Parameter | Type | Description |
|---|---|---|
| data.rate | number | rates[to] / rates[from] |
| data.result | number | quantity × rate |
GET /api/rates/latest
Latest published rate
Parameter: —
curl --request GET 'https://staging.lumeexchangerates.com/api/rates/latest' --header 'Authorization: Bearer YOUR_API_KEY'The values and dates below illustrate response structure; they are not live rates. Arrays may show only a subset. Use the API explorer for current data.
{
"meta": {
"provider": "External exchange-rate provider",
"kind": "latest_published",
"provider_timestamp": 1767225600,
"published_at": "2026-01-01T00:00:00.000Z",
"expected_interval_seconds": 300,
"lag_seconds": 5,
"stale": false,
"timezone": "Asia/Seoul",
"fetched_at": "2026-01-01T00:00:05.000Z",
"persistent_storage": true
},
"data": {
"base": "USD",
"rates": {
"USD": 1,
"EUR": 0.9,
"JPY": 150
}
}
}| Parameter | Type | Description |
|---|---|---|
| data.base | string | USD |
| data.rates | object | All available USD-relative rates; validate availability against the latest response. |
| meta.provider_timestamp | integer | UTC · UNIX seconds |
| meta.published_at | string | ISO 8601 · UTC |
| meta.fetched_at | string | Server retrieval time, distinct from provider publication time. |
| meta.expected_interval_seconds | integer | seconds |
| meta.stale | boolean | True when age exceeds max(3 × expected interval, 900 seconds). |
| meta.lag_seconds | integer | Seconds since provider publication. |
| meta.persistent_storage | boolean | Whether the persistent collection service is connected. |
| meta.kind | string | latest_published | utc_daily |
GET /api/currencies
Currency
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| lang | string | Optional | en | en / ko / ja / zh / es / hi / bn / de / fr / nl / pt / it / ru / vi / th / ar / id / ur |
curl --request GET 'https://staging.lumeexchangerates.com/api/currencies?lang=en' --header 'Authorization: Bearer YOUR_API_KEY'The values and dates below illustrate response structure; they are not live rates. Arrays may show only a subset. Use the API explorer for current data.
{
"meta": {
"provider": "External exchange-rate provider",
"kind": "latest_published",
"provider_timestamp": 1767225600,
"published_at": "2026-01-01T00:00:00.000Z",
"expected_interval_seconds": 300,
"lag_seconds": 5,
"stale": false,
"timezone": "Asia/Seoul",
"fetched_at": "2026-01-01T00:00:05.000Z",
"persistent_storage": true
},
"data": [
{
"code": "USD",
"name": "US Dollar"
},
{
"code": "EUR",
"name": "Euro"
}
]
}Currency names use Intl.DisplayNames. Unrecognized assets retain their codes. Only symbols present in the latest data are returned.
GET /api/rates/history
Website-internal chart route. Accepts from/to currencies and period=1D|1W|1M|3M|1Y. 1D returns collected minute observations from the last 24 hours; other periods return UTC daily rates through yesterday. Missing minutes are not fabricated. No observations returns 503 HISTORY_NOT_COLLECTED.
Data is persisted in S3 and meta.persistent_storage is true. Historical symbol availability and provider permissions may restrict results.
GET /api/rates/previous
Previous UTC day
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| from | string | Optional | USD | From |
| to | string | Optional | EUR | To |
curl --request GET 'https://staging.lumeexchangerates.com/api/rates/previous?from=USD&to=EUR' --header 'Authorization: Bearer YOUR_API_KEY'The values and dates below illustrate response structure; they are not live rates. Arrays may show only a subset. Use the API explorer for current data.
{
"meta": {
"kind": "utc_daily",
"reference_date": "2026-01-01",
"reference_timestamp": "2026-01-01T23:59:59Z"
},
"data": {
"from": "USD",
"to": "EUR",
"rate": 0.9,
"rates": {
"USD": 1,
"EUR": 0.9
}
}
}The comparison uses the previous UTC day’s provider reference. reference_timestamp is the logical day-end boundary, not a quote’s actual publication time. Percentage change is (current − reference) / reference × 100.
POST /api/convert
Converter
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| Content-Type | header | Required | application/json | application/json |
| amount | number | Required | — | 0 ≤ amount ≤ 1e15; finite |
| from | string | Required | — | From |
| to | string | Required | — | To |
curl --request POST 'https://staging.lumeexchangerates.com/api/convert' --header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{"amount":100,"from":"USD","to":"EUR"}'The values and dates below illustrate response structure; they are not live rates. Arrays may show only a subset. Use the API explorer for current data.
{
"meta": {
"provider": "External exchange-rate provider",
"kind": "latest_published",
"provider_timestamp": 1767225600,
"published_at": "2026-01-01T00:00:00.000Z",
"expected_interval_seconds": 300,
"lag_seconds": 5,
"stale": false,
"timezone": "Asia/Seoul",
"fetched_at": "2026-01-01T00:00:05.000Z",
"persistent_storage": true
},
"data": {
"amount": 100,
"from": "USD",
"to": "EUR",
"rate": 0.9,
"result": 90
}
}Send amount as a JSON number: "100" as a string returns 400. Symbols must exist in the latest snapshot. This endpoint calculates a value; it does not execute a transfer or trade.
GET /v1/history
Daily history and date-range series are available through /v1/history and /v1/series.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| date | YYYY-MM-DD | Required | — | 1999-01-01 ≤ date < UTC today |
| anchor | string | Optional | USD | From |
| targets | CSV | Optional | all | To |
curl --request GET 'https://staging.lumeexchangerates.com/v1/history?date=2026-01-01&anchor=EUR&targets=USD,JPY' --header 'Authorization: Bearer YOUR_API_KEY'The values and dates below illustrate response structure; they are not live rates. Arrays may show only a subset. Use the API explorer for current data.
{
"meta": {
"date": "2026-01-01",
"published_at": "2026-01-01T23:00:00Z",
"partial_day": false
},
"anchor": "EUR",
"data": [
{
"currency": "USD",
"value": 1.1
}
]
}| Parameter | Type | Description |
|---|---|---|
| meta.partial_day | boolean | UTC daily reference |
| meta.published_at | ISO 8601 UTC | Latest published rate |
GET /v1/series
start/end are inclusive UTC YYYY-MM-DD dates. Require start ≤ end < today UTC, with at most 366 days. anchor/targets match /v1/quotes. data[].time is the date and data[].rates maps target codes to rates. Values below illustrate the response shape.
{
"request_id": "server-generated-uuid",
"meta": {
"source": "Open Exchange Rates",
"kind": "utc_daily",
"start": "2026-01-01",
"end": "2026-01-02",
"day_count": 2
},
"anchor": "USD",
"data": [
{
"time": "2026-01-01",
"rates": {
"EUR": 0.9
}
},
{
"time": "2026-01-02",
"rates": {
"EUR": 0.91
}
}
]
}GET /v1/candles
GET /v1/candles accepts start (a completed UTC minute), period, anchor, targets and source. Default source=observations returns collected-minute OHLC and arithmetic mean; inspect meta.samples, expected_samples and complete for gaps. Repeated publications and missing minutes are not provider tick data. source=provider requires upstream OHLC permission; otherwise 422 OHLC_NOT_IN_PLAN. Cross-currency extrema are requested from the provider, never formed by dividing independent highs/lows.
/v1/candles?start=2026-11-09T06:00:00Z&period=1h&anchor=EUR&targets=JPY&source=observations| Source | Periods |
|---|---|
| observations | 1m, 5m, 15m, 30m, 1h, 12h, 1d |
| provider | 1m, 5m, 15m, 30m, 1h, 12h, 1d, 1w, 1mo; provider history/alignment limits apply |
GET /v1/capabilities
GET /v1/capabilities distinguishes implemented features from upstream availability. It describes daily-series limits, intraday observations and source-specific candle periods. It never changes the external API gate; normal key authentication and scope checks still apply.
/v1/capabilitiesData & precision
An exchange rate is useful only when its meaning is clear. Our rates are indicative references, not a bank offer or a guaranteed transaction price. Currency conversion uses a shared rate snapshot; rounding belongs at the display or settlement stage.
rate = rates[to] / rates[from]
result = amount * rateRates preserve floating-point precision without fixed decimal truncation. Round only for display or your accounting policy.
All rates use one source unit, including JPY. Multiply by 100 only at the display layer if needed. Account for JavaScript binary floating-point error and apply an explicit decimal and rounding policy for settlement.
Timestamps
UNIX timestamps are UTC seconds and ISO timestamps use Z. Daily UTC dates may differ from local calendar dates. The website displays latest publication time in the browser’s timezone. meta.timezone is a server display hint; it does not alter timestamp semantics.
| Parameter | Type | Description |
|---|---|---|
| /v1 meta.as_of | ISO 8601 | YYYY-MM-DD | Provider timestamp |
| /v1 meta.refresh_interval_seconds | integer | Cache |
| /v1 meta.currency_count | integer | … currencies available |
| /v1 meta.mode | provider | daily | Data source |
| /api meta.published_at | ISO 8601 UTC | Latest published rate |
| history data[].time | YYYY-MM-DD UTC | UNIX seconds | UTC daily reference |
Errors
| HTTP | error.code |
|---|---|
| 400 | INVALID_PARAMETER / INVALID_CURRENCY / INVALID_CONVERSION / INVALID_JSON / INVALID_DATE / INVALID_DATE_RANGE |
| 401 | INVALID_API_KEY / AUTH_REQUIRED |
| 403 | SUBSCRIPTION_REQUIRED / SCOPE_NOT_ALLOWED / IP_NOT_ALLOWED / DOMAIN_NOT_ALLOWED |
| 404 | NOT_FOUND / OBSERVATIONS_NOT_COLLECTED |
| 422 | OHLC_NOT_IN_PLAN / CANDLE_HISTORY_UNAVAILABLE / FEATURE_UNAVAILABLE |
| 405 | METHOD_NOT_ALLOWED |
| 429 | RATE_LIMIT_EXCEEDED / MONTHLY_LIMIT_EXCEEDED |
| 503 | API_NOT_AVAILABLE / PROVIDER_UNAVAILABLE / SERVICE_UNAVAILABLE |
Branch on HTTP status and error.code. Include X-Request-Id/request_id when contacting support, never keys or passwords. For 429, honor Retry-After in seconds with bounded backoff and jitter.
Limits & caching
| Plan | Monthly UTC | Per second | Per minute |
|---|---|---|---|
| Launch | 10000 | 5 | 60 |
| Scale | 100000 | 20 | 300 |
| Unlimited | Unlimited | 50 | 1200 |
All keys share account quotas. Second/minute windows are fixed UTC windows; monthly quota resets at 00:00 UTC on the first. Admitted requests count once, including cache hits, input errors and provider errors. Authentication/quota/preflight rejections do not count. /v1/usage reads consume no API quota.
Responses are private, no-store. Provider caching defaults to 300 seconds; publication values may repeat according to the upstream interval. X-RateLimit-*, X-Monthly-* and RateLimit headers expose limits and remaining counts. timestamp/source/stale describe the data; response_timestamp is response creation time.
Availability
Production external JSON APIs are currently disabled. Examples below require an enabled environment and a valid paid API key. Browser login alone does not authorize API calls. The website calculator remains available.
/v1/currencies, /v1/quotes, /v1/exchange, /v1/history, /v1/series, /v1/candles, /v1/capabilities, /v1/usage
API explorer
Call the API on this site. Your provider key stays on the server.
Run the request to view the real JSON response.