@allratestoday/sdk 1.4.5 โ 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/README.md +277 -412
- package/dist/index.d.mts +118 -33
- package/dist/index.d.ts +118 -33
- package/dist/index.js +204 -98
- package/dist/index.mjs +204 -98
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -5,546 +5,411 @@
|
|
|
5
5
|
[](https://github.com/AllRates-Today/exchange-rates-api/blob/main/LICENSE)
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
7
|
[](https://www.npmjs.com/package/@allratestoday/sdk)
|
|
8
|
-
[](https://snyk.io/test/github/allratestoday/exchange-rates-api)
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
## ๐ Why Choose This Client?
|
|
13
|
-
|
|
14
|
-
- โก **Lightning Fast** โ Zero runtime dependencies, pure TypeScript performance
|
|
15
|
-
- ๐ก **Real-Time Data** โ Rates updated every 60 seconds
|
|
16
|
-
- ๐น **Mid-Market Rates** โ No retail spread or markup baked in
|
|
17
|
-
- ๐ **160+ Currencies** โ Major, minor, and exotic currency pairs
|
|
18
|
-
- ๐๏ธ **Official Rates Too** โ latest tables from 121 central banks + 3 tax authorities via `officialRates()`, no key needed
|
|
19
|
-
- ๐ท **Type-Safe** โ Full TypeScript support with intelligent autocomplete
|
|
20
|
-
- ๐ **Universal** โ Works seamlessly in Node.js 18+ and modern browsers
|
|
21
|
-
- ๐งโ๐ป **Developer-Friendly** โ Simple API, extensive documentation, and great DX
|
|
22
|
-
|
|
23
|
-
## ๐ Get Your API Key
|
|
24
|
-
|
|
25
|
-
Ready to start? Get your free API key from [allratestoday.com/register](https://allratestoday.com/register).
|
|
26
|
-
|
|
27
|
-
## ๐ฆ Installation
|
|
9
|
+
Official JavaScript/TypeScript client for [AllRatesToday](https://allratestoday.com): live mid-market exchange rates for 160+ currencies, and the official rates published by 121 central banks and 3 tax authorities. Zero dependencies, ESM and CommonJS, full TypeScript types.
|
|
28
10
|
|
|
29
11
|
```bash
|
|
30
12
|
npm install @allratestoday/sdk
|
|
31
13
|
```
|
|
32
14
|
|
|
33
|
-
|
|
34
|
-
yarn add @allratestoday/sdk
|
|
35
|
-
```
|
|
15
|
+
## Contents
|
|
36
16
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
17
|
+
- [Two kinds of rates](#two-kinds-of-rates)
|
|
18
|
+
- [Quick start](#quick-start)
|
|
19
|
+
- [API key and configuration](#api-key-and-configuration)
|
|
20
|
+
- [Browser and frontend apps](#browser-and-frontend-apps)
|
|
21
|
+
- [What a rate means](#what-a-rate-means)
|
|
22
|
+
- [Methods](#methods)
|
|
23
|
+
- [Errors, retries and troubleshooting](#errors-retries-and-troubleshooting)
|
|
24
|
+
- [Quotas and billing](#quotas-and-billing)
|
|
25
|
+
- [Compatibility](#compatibility)
|
|
26
|
+
- [TypeScript](#typescript)
|
|
27
|
+
- [Use it from an AI agent](#use-it-from-an-ai-agent)
|
|
28
|
+
- [Testing, contributing and support](#testing-contributing-and-support)
|
|
40
29
|
|
|
41
|
-
##
|
|
30
|
+
## Two kinds of rates
|
|
42
31
|
|
|
43
|
-
|
|
32
|
+
| | Mid-market rates | Official rates |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| Use for | Pricing, checkout, conversion widgets, dashboards | Invoices, VAT/GST, customs, accounting, audits |
|
|
35
|
+
| What it is | Live mid-market rate, no retail spread | The figure a central bank or tax authority published |
|
|
36
|
+
| Updates | About every minute | Once per publication (usually each business day) |
|
|
37
|
+
| History | Last 365 days (`forDate`, `timeSeries`, `getHistoricalRates`) | Each bank's full archive (`officialRatesOn`), e.g. ECB from 1999 |
|
|
38
|
+
| API key | Required | Latest table: **no key** (`officialRates`). Past dates and cross pairs: key (`officialRatesOn`) |
|
|
39
|
+
| Methods | `latest`, `getRate`, `getRates`, `convert`, `forDate`, `timeSeries`, `getHistoricalRates` | `officialRates`, `officialRatesOn`, `officialSources` |
|
|
44
40
|
|
|
45
|
-
|
|
41
|
+
## Quick start
|
|
42
|
+
|
|
43
|
+
```ts
|
|
46
44
|
import AllRatesToday from '@allratestoday/sdk';
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
const client = new AllRatesToday({ apiKey: 'YOUR_API_KEY' });
|
|
46
|
+
const client = new AllRatesToday({ apiKey: process.env.ALLRATESTODAY_API_KEY });
|
|
50
47
|
|
|
51
|
-
// Get latest exchange rates
|
|
52
48
|
const { rates } = await client.latest({ base: 'USD', symbols: ['EUR', 'GBP', 'JPY'] });
|
|
53
|
-
console.log(rates);
|
|
49
|
+
console.log(rates); // { EUR: 0.889521, GBP: 0.750666, JPY: 157.95 }
|
|
54
50
|
```
|
|
55
51
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
- [Latest Rates](#-latest-exchange-rates) โ Get current exchange rates
|
|
59
|
-
- [Historical Data](#-historical-exchange-rates) โ Fetch rates for specific dates
|
|
60
|
-
- [Currency Conversion](#-currency-conversion) โ Convert between currencies
|
|
61
|
-
- [Time Series](#-time-series-data) โ Get rates over date ranges
|
|
62
|
-
- [Available Currencies](#-available-currencies) โ List all supported currencies
|
|
63
|
-
- [Single Rate](#-single-rate) โ Get one currency pair
|
|
64
|
-
- [Historical by Period](#-historical-rates-by-period) โ Preset period lookups
|
|
52
|
+
No key yet? Official rates work without one:
|
|
65
53
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
```ts
|
|
55
|
+
const usdInr = await new AllRatesToday().officialRates('rbi', { source: 'USD', target: 'INR' });
|
|
56
|
+
console.log(usdInr.rate_date, usdInr.rate); // 2026-10-15 95.0691
|
|
57
|
+
```
|
|
69
58
|
|
|
70
|
-
Get
|
|
59
|
+
Get a free key (300 requests, no card) at [allratestoday.com/register](https://allratestoday.com/register).
|
|
71
60
|
|
|
72
|
-
|
|
73
|
-
// Get all rates from USD
|
|
74
|
-
const data = await client.latest();
|
|
75
|
-
console.log(data);
|
|
61
|
+
## API key and configuration
|
|
76
62
|
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
63
|
+
```ts
|
|
64
|
+
const client = new AllRatesToday({
|
|
65
|
+
apiKey: process.env.ALLRATESTODAY_API_KEY, // needed for market rates and dated official rates
|
|
66
|
+
baseUrl: 'https://allratestoday.com', // optional
|
|
67
|
+
timeout: 10000, // optional, ms
|
|
68
|
+
});
|
|
80
69
|
```
|
|
81
70
|
|
|
82
|
-
|
|
71
|
+
| Option | Type | Default | Description |
|
|
72
|
+
| --- | --- | --- | --- |
|
|
73
|
+
| `apiKey` | `string` | โ | Sent as `Authorization: Bearer <key>`. Not needed for `officialRates`, `officialSources`, `symbols`. |
|
|
74
|
+
| `baseUrl` | `string` | `https://allratestoday.com` | Origin only. The SDK adds paths such as `/api/v1/rates`, so a proxy at another origin must serve the same paths. |
|
|
75
|
+
| `timeout` | `number` | `10000` | Per HTTP request, in ms. Applies to every method. On expiry the SDK throws `AllRatesTodayError` with `code: 'timeout'`. |
|
|
83
76
|
|
|
84
|
-
|
|
85
|
-
{
|
|
86
|
-
base: 'USD',
|
|
87
|
-
date: '2026-04-09T14:30:00Z',
|
|
88
|
-
rates: {
|
|
89
|
-
CHF: 0.8821,
|
|
90
|
-
GBP: 0.7891,
|
|
91
|
-
JPY: 151.42
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
```
|
|
77
|
+
**Keep the key out of your code and your repo.** Load it from the environment (`.env` with your framework's loader, or your host's secret settings) and add `.env` to `.gitignore`:
|
|
95
78
|
|
|
96
|
-
|
|
79
|
+
```bash
|
|
80
|
+
# .env (never commit this file)
|
|
81
|
+
ALLRATESTODAY_API_KEY=art_live_...
|
|
82
|
+
```
|
|
97
83
|
|
|
98
|
-
|
|
84
|
+
**Retries are not automatic.** Every method makes its requests once; see [retrying](#retrying-transient-failures) for a pattern.
|
|
99
85
|
|
|
100
|
-
|
|
101
|
-
// Using a string date
|
|
102
|
-
const data = await client.forDate('2026-01-15', { base: 'USD', symbols: ['EUR'] });
|
|
103
|
-
console.log(data);
|
|
86
|
+
**Per-request key override**, for multi-tenant apps: every method accepts `{ apiKey }` in its options.
|
|
104
87
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
88
|
+
```ts
|
|
89
|
+
await client.latest({ symbols: ['EUR'], apiKey: tenant.key });
|
|
90
|
+
await client.convert('USD', 'EUR', 100, { apiKey: tenant.key });
|
|
108
91
|
```
|
|
109
92
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
```javascript
|
|
113
|
-
{
|
|
114
|
-
base: 'USD',
|
|
115
|
-
date: '2026-01-15',
|
|
116
|
-
rates: {
|
|
117
|
-
EUR: 0.9187
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
```
|
|
93
|
+
## Browser and frontend apps
|
|
121
94
|
|
|
122
|
-
|
|
95
|
+
> [!WARNING]
|
|
96
|
+
> Never put your API key in browser, mobile or desktop app code. Anyone can read it from the bundle or the network tab and spend your quota.
|
|
123
97
|
|
|
124
|
-
|
|
98
|
+
- **Keyless methods work in the browser.** `officialRates()`, `officialSources()` and `symbols()` call endpoints that send `Access-Control-Allow-Origin: *`.
|
|
99
|
+
- **Keyed methods are server-side only.** The keyed endpoints do not send CORS headers, so browsers block them anyway. Call them from your backend, an API route or a serverless function, and expose only what your frontend needs:
|
|
125
100
|
|
|
126
|
-
```
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
console.log(result);
|
|
130
|
-
```
|
|
101
|
+
```ts
|
|
102
|
+
// app/api/rates/route.ts (Next.js route handler โ runs on the server)
|
|
103
|
+
import AllRatesToday from '@allratestoday/sdk';
|
|
131
104
|
|
|
132
|
-
|
|
105
|
+
const client = new AllRatesToday({ apiKey: process.env.ALLRATESTODAY_API_KEY });
|
|
133
106
|
|
|
134
|
-
|
|
135
|
-
{
|
|
136
|
-
|
|
137
|
-
to: 'EUR',
|
|
138
|
-
amount: 1000,
|
|
139
|
-
result: 923.4,
|
|
140
|
-
rate: 0.9234
|
|
107
|
+
export async function GET() {
|
|
108
|
+
const { rates, date } = await client.latest({ base: 'USD', symbols: ['EUR', 'GBP'] });
|
|
109
|
+
return Response.json({ rates, date }, { headers: { 'Cache-Control': 'public, max-age=60' } });
|
|
141
110
|
}
|
|
142
111
|
```
|
|
143
112
|
|
|
144
|
-
```
|
|
145
|
-
//
|
|
146
|
-
const
|
|
147
|
-
console.log(result);
|
|
113
|
+
```ts
|
|
114
|
+
// In the browser: call your own endpoint, not AllRatesToday
|
|
115
|
+
const { rates } = await fetch('/api/rates').then((r) => r.json());
|
|
148
116
|
```
|
|
149
117
|
|
|
150
|
-
|
|
118
|
+
In SSR frameworks, create the client only in server code (route handlers, server components, `getServerSideProps`, loaders), never in a component that also runs in the browser.
|
|
151
119
|
|
|
152
|
-
|
|
153
|
-
{
|
|
154
|
-
from: 'USD',
|
|
155
|
-
to: 'EUR',
|
|
156
|
-
amount: 1000,
|
|
157
|
-
result: 918.7,
|
|
158
|
-
rate: 0.9187,
|
|
159
|
-
date: '2026-01-15'
|
|
160
|
-
}
|
|
161
|
-
```
|
|
120
|
+
## What a rate means
|
|
162
121
|
|
|
163
|
-
|
|
122
|
+
- **Direction.** Every rate is *units of the target per 1 unit of the base*. `latest({ base: 'USD', symbols: ['EUR'] })` โ `rates.EUR = 0.8895` means 1 USD = 0.8895 EUR. For the reverse, use `1 / rate` or swap base and target.
|
|
123
|
+
- **Market timestamps** (`date` in `latest`, `time` in `getRate`/`getRates`) are UTC, ISO 8601, e.g. `2026-10-16T08:34:01+0000`.
|
|
124
|
+
- **Market history dates** are UTC calendar days (`YYYY-MM-DD`). `1d` history has hourly timestamps.
|
|
125
|
+
- **Official `rate_date`** is the day the institution published the table, not the time of your request. Cite it on invoices and filings.
|
|
126
|
+
- **Weekends and holidays.** Banks publish nothing on those days. `officialRatesOn()` returns the last earlier table and sets `published_on_requested_date: false`. `forDate()` uses the closest earlier point and reports it in `rateDates`.
|
|
127
|
+
- **Stale sources.** `stale: true` on an official response means the institution is behind its own publication schedule; the table is its latest one. `officialSources()` lists which sources are stale right now.
|
|
128
|
+
- **Derived official pairs.** `method: 'published'` is the bank's own figure; `'inverse'` is 1 / a published rate; `'cross'` is computed through the bank's base currency (only from `officialRatesOn`). `derived: true` for the last two.
|
|
164
129
|
|
|
165
|
-
|
|
130
|
+
## Methods
|
|
166
131
|
|
|
167
|
-
|
|
168
|
-
const data = await client.symbols();
|
|
169
|
-
console.log(data);
|
|
170
|
-
```
|
|
132
|
+
All methods return a Promise. Codes are ISO 4217 and case-insensitive. Dates are `YYYY-MM-DD` strings or `Date` objects (a `Date` is taken as its UTC day). "Calls" is how many requests the method counts against your quota.
|
|
171
133
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
CHF: 'Swiss Franc',
|
|
186
|
-
CNY: 'Chinese Yuan',
|
|
187
|
-
EUR: 'Euro',
|
|
188
|
-
GBP: 'British Pound Sterling',
|
|
189
|
-
INR: 'Indian Rupee',
|
|
190
|
-
JPY: 'Japanese Yen',
|
|
191
|
-
KRW: 'South Korean Won',
|
|
192
|
-
USD: 'United States Dollar',
|
|
193
|
-
// ...160+ currencies
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
```
|
|
134
|
+
| Method | Key | Calls |
|
|
135
|
+
| --- | --- | --- |
|
|
136
|
+
| [`latest(options?)`](#latestoptions) | yes | 1 |
|
|
137
|
+
| [`getRate(from, to, amount?, options?)`](#getratefrom-to-amount-options) | yes | 1 |
|
|
138
|
+
| [`getRates(source, target, options?)`](#getratessource-target-options) | yes | 1 |
|
|
139
|
+
| [`convert(from, to, amount, options?)`](#convertfrom-to-amount-options) | yes | 1 (historical: as `forDate`) |
|
|
140
|
+
| [`forDate(date, options)`](#fordatedate-options) | yes | per symbol: 1, or 12 if over 29 days ago |
|
|
141
|
+
| [`timeSeries(start, end, options)`](#timeseriesstart-end-options) | yes | per symbol: 1, or 12 if start over 29 days ago |
|
|
142
|
+
| [`getHistoricalRates(source, target, period?, options?)`](#gethistoricalratessource-target-period-options) | yes | 1, or 12 for `1y` |
|
|
143
|
+
| [`symbols(options?)`](#symbolsoptions) | no | โ |
|
|
144
|
+
| [`officialRates(bank, options?)`](#officialratesbank-options) | no | โ |
|
|
145
|
+
| [`officialRatesOn(bank, date, options?)`](#officialratesonbank-date-options) | yes | 1 |
|
|
146
|
+
| [`officialSources(options?)`](#officialsourcesoptions) | no | โ |
|
|
197
147
|
|
|
198
|
-
###
|
|
148
|
+
### `latest(options?)`
|
|
199
149
|
|
|
200
|
-
|
|
150
|
+
Live mid-market rates from one base.
|
|
201
151
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
});
|
|
207
|
-
console.log(data);
|
|
208
|
-
```
|
|
152
|
+
| Option | Type | Default | |
|
|
153
|
+
| --- | --- | --- | --- |
|
|
154
|
+
| `base` | `string` | `'USD'` | Base currency |
|
|
155
|
+
| `symbols` | `string[]` | all (~160) | Target currencies; still one call |
|
|
209
156
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
{
|
|
214
|
-
base: 'USD',
|
|
215
|
-
startDate: '2026-01-01',
|
|
216
|
-
endDate: '2026-03-31',
|
|
217
|
-
rates: {
|
|
218
|
-
'2026-01-01': {
|
|
219
|
-
EUR: 0.9187,
|
|
220
|
-
GBP: 0.7834
|
|
221
|
-
},
|
|
222
|
-
'2026-01-02': {
|
|
223
|
-
EUR: 0.9195,
|
|
224
|
-
GBP: 0.7841
|
|
225
|
-
},
|
|
226
|
-
'2026-01-03': {
|
|
227
|
-
EUR: 0.9201,
|
|
228
|
-
GBP: 0.7856
|
|
229
|
-
},
|
|
230
|
-
// ...
|
|
231
|
-
}
|
|
232
|
-
}
|
|
157
|
+
```ts
|
|
158
|
+
const data = await client.latest({ base: 'USD', symbols: ['EUR', 'GBP', 'JPY'] });
|
|
159
|
+
// { base: 'USD', date: '2026-10-16T08:37:01+0000', rates: { EUR: 0.889521, GBP: 0.750666, JPY: 157.95 } }
|
|
233
160
|
```
|
|
234
161
|
|
|
235
|
-
###
|
|
162
|
+
### `getRate(from, to, amount?, options?)`
|
|
236
163
|
|
|
237
|
-
|
|
164
|
+
One pair, optionally converted.
|
|
238
165
|
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
**Response:**
|
|
166
|
+
```ts
|
|
167
|
+
await client.getRate('USD', 'EUR');
|
|
168
|
+
// { from: { currency: 'USD', amount: 1 }, to: { currency: 'EUR', amount: 0.889521 },
|
|
169
|
+
// rate: 0.889521, source: 'interbank', time: '2026-10-16T08:38:01+0000' }
|
|
245
170
|
|
|
246
|
-
|
|
247
|
-
{
|
|
248
|
-
from: { currency: 'USD', amount: 1 },
|
|
249
|
-
to: { currency: 'EUR', amount: 0.9234 },
|
|
250
|
-
rate: 0.9234,
|
|
251
|
-
source: 'wise'
|
|
252
|
-
}
|
|
171
|
+
await client.getRate('USD', 'EUR', 500);
|
|
172
|
+
// { from: { currency: 'USD', amount: 500 }, to: { currency: 'EUR', amount: 444.7605 }, rate: 0.889521, source: 'interbank' }
|
|
253
173
|
```
|
|
254
174
|
|
|
255
|
-
|
|
256
|
-
// With amount
|
|
257
|
-
const rate = await client.getRate('USD', 'EUR', 500);
|
|
258
|
-
console.log(`$500 = โฌ${rate.to.amount}`);
|
|
259
|
-
```
|
|
175
|
+
`source` is the rate type label (`interbank` = mid-market), not a data vendor.
|
|
260
176
|
|
|
261
|
-
###
|
|
177
|
+
### `getRates(source, target, options?)`
|
|
262
178
|
|
|
263
|
-
|
|
264
|
-
institution published** โ what invoices, VAT returns, customs declarations and
|
|
265
|
-
audits require โ use `officialRates()`. It covers 121 central banks plus HMRC,
|
|
266
|
-
the US Treasury and Swiss BAZG, and the latest table needs **no API key**:
|
|
179
|
+
Raw rate rows. `target` may be comma-separated (`'EUR,GBP'`) for several rows in one call.
|
|
267
180
|
|
|
268
|
-
```
|
|
269
|
-
|
|
181
|
+
```ts
|
|
182
|
+
await client.getRates('USD', 'EUR,GBP');
|
|
183
|
+
// [ { rate: 0.889403, source: 'USD', target: 'EUR', time: '2026-10-16T08:34:01+0000' },
|
|
184
|
+
// { rate: 0.750723, source: 'USD', target: 'GBP', time: '2026-10-16T08:34:01+0000' } ]
|
|
185
|
+
```
|
|
270
186
|
|
|
271
|
-
|
|
272
|
-
const table = await client.officialRates('ecb');
|
|
273
|
-
console.log(table.rate_date, table.rates); // [{ base: 'EUR', quote: 'USD', type: 'reference', value: 1.17 }, โฆ]
|
|
187
|
+
### `convert(from, to, amount, options?)`
|
|
274
188
|
|
|
275
|
-
|
|
276
|
-
const usd = await client.officialRates('ecb', { source: 'EUR', target: 'USD' });
|
|
277
|
-
console.log(`ECB ${usd.rate_date}: 1 EUR = ${usd.rate} USD`);
|
|
189
|
+
Convert at the live rate, or at a past date's rate with `{ date }` (last 365 days).
|
|
278
190
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
191
|
+
```ts
|
|
192
|
+
await client.convert('USD', 'EUR', 1000);
|
|
193
|
+
// { from: 'USD', to: 'EUR', amount: 1000, result: 889.403, rate: 0.889403 }
|
|
194
|
+
|
|
195
|
+
await client.convert('USD', 'EUR', 1000, { date: '2026-10-01' });
|
|
196
|
+
// { from: 'USD', to: 'EUR', amount: 1000, result: 882.768, rate: 0.882768, date: '2026-10-01', rateDate: '2026-10-01' }
|
|
282
197
|
```
|
|
283
198
|
|
|
284
|
-
|
|
285
|
-
not the time of your call. Dated tables, history and publication calendars sit
|
|
286
|
-
behind the free key on `/api/v1/central-bank/{bank}/{date}`; see the
|
|
287
|
-
[central bank rates API](https://allratestoday.com/central-bank-rates-api/).
|
|
199
|
+
For money, round once at the end in the currency's minor unit. `result` is not rounded to cents.
|
|
288
200
|
|
|
289
|
-
###
|
|
201
|
+
### `forDate(date, options)`
|
|
290
202
|
|
|
291
|
-
|
|
203
|
+
Mid-market rates for a past date in the last 365 days.
|
|
292
204
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
205
|
+
| Option | Type | Default | |
|
|
206
|
+
| --- | --- | --- | --- |
|
|
207
|
+
| `symbols` | `string[]` | **required** | One request per symbol |
|
|
208
|
+
| `base` | `string` | `'USD'` | |
|
|
297
209
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
{
|
|
302
|
-
source: 'USD',
|
|
303
|
-
target: 'EUR',
|
|
304
|
-
period: '30d',
|
|
305
|
-
current: { rate: 0.9234, time: '2026-04-09T14:30:00Z' },
|
|
306
|
-
rates: [
|
|
307
|
-
{ rate: 0.9198, time: '2026-03-10T00:00:00Z' },
|
|
308
|
-
{ rate: 0.9210, time: '2026-03-11T00:00:00Z' },
|
|
309
|
-
// ...
|
|
310
|
-
]
|
|
311
|
-
}
|
|
210
|
+
```ts
|
|
211
|
+
await client.forDate('2026-10-01', { base: 'EUR', symbols: ['USD', 'GBP'] });
|
|
212
|
+
// { base: 'EUR', date: '2026-10-01', rates: { USD: 1.1328, GBP: 0.85395 },
|
|
213
|
+
// rateDates: { USD: '2026-10-01', GBP: '2026-10-01' } }
|
|
312
214
|
```
|
|
313
215
|
|
|
314
|
-
**
|
|
216
|
+
Dates up to 29 days ago use daily data. Older dates use the 1-year series, which has **weekly** points, so `rateDates` may be a few days earlier than `date`, and each symbol costs 12 calls. Dates over a year old throw `invalid_argument`; use [`officialRatesOn()`](#officialratesonbank-date-options) for those.
|
|
315
217
|
|
|
316
|
-
|
|
218
|
+
### `timeSeries(start, end, options)`
|
|
317
219
|
|
|
318
|
-
|
|
220
|
+
Rates for every available day between two dates (inclusive), in the last 365 days. Same options, data density and costs as `forDate`.
|
|
319
221
|
|
|
320
|
-
```
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
222
|
+
```ts
|
|
223
|
+
const ts = await client.timeSeries('2026-10-05', '2026-10-08', { symbols: ['EUR', 'GBP'] });
|
|
224
|
+
// { base: 'USD', startDate: '2026-10-05', endDate: '2026-10-08', rates: {
|
|
225
|
+
// '2026-10-05': { EUR: 0.888573, GBP: 0.755116 },
|
|
226
|
+
// '2026-10-06': { EUR: 0.891504, GBP: 0.756544 }, ... } }
|
|
227
|
+
|
|
228
|
+
// For a chart
|
|
229
|
+
const labels = Object.keys(ts.rates).sort();
|
|
230
|
+
const values = labels.map((d) => ts.rates[d].EUR);
|
|
326
231
|
```
|
|
327
232
|
|
|
328
|
-
|
|
329
|
-
| --------- | -------- | --------------------------- | -------------------------------- |
|
|
330
|
-
| `apiKey` | `string` | โ | Your API key |
|
|
331
|
-
| `baseUrl` | `string` | `https://allratestoday.com` | API base URL |
|
|
332
|
-
| `timeout` | `number` | `10000` | Request timeout in milliseconds |
|
|
233
|
+
### `getHistoricalRates(source, target, period?, options?)`
|
|
333
234
|
|
|
334
|
-
|
|
235
|
+
A preset window ending today: `'1d'` (hourly), `'7d'` (default) and `'30d'` (daily), `'1y'` (weekly, 12 calls).
|
|
335
236
|
|
|
336
|
-
|
|
237
|
+
```ts
|
|
238
|
+
const h = await client.getHistoricalRates('USD', 'EUR', '7d');
|
|
239
|
+
// { source: 'USD', target: 'EUR', period: '7d',
|
|
240
|
+
// current: { rate: 0.889521, time: '2026-10-16' },
|
|
241
|
+
// rates: [ { rate: 0.892738, time: '2026-10-10' }, ... ], // oldest first
|
|
242
|
+
// data: [ { date: '2026-10-10', rate: 0.892738, timestamp: 1791590400000 }, ... ] }
|
|
243
|
+
```
|
|
337
244
|
|
|
338
|
-
|
|
245
|
+
### `symbols(options?)`
|
|
339
246
|
|
|
340
|
-
|
|
341
|
-
const client = new AllRatesToday({ apiKey: 'default_key' });
|
|
247
|
+
Every supported currency. No key needed.
|
|
342
248
|
|
|
343
|
-
|
|
344
|
-
const
|
|
345
|
-
|
|
346
|
-
|
|
249
|
+
```ts
|
|
250
|
+
const { symbols, currencies, count } = await client.symbols();
|
|
251
|
+
// symbols: { USD: 'US Dollar', EUR: 'Euro', GBP: 'British Pound', ... }
|
|
252
|
+
// currencies: [ { code: 'USD', name: 'US Dollar', symbol: '$' }, ... ]
|
|
253
|
+
// count: 163
|
|
347
254
|
```
|
|
348
255
|
|
|
349
|
-
|
|
256
|
+
### `officialRates(bank, options?)`
|
|
350
257
|
|
|
351
|
-
|
|
258
|
+
The latest table an institution published. No key needed. `bank` is a source code from `officialSources()`, e.g. `ecb`, `fed`, `boe`, `rbi`, `cbuae`, `hmrc`.
|
|
352
259
|
|
|
353
|
-
|
|
260
|
+
| Option | Type | |
|
|
261
|
+
| --- | --- | --- |
|
|
262
|
+
| `source`, `target` | `string` | Give both to get one pair. It must be published, or the inverse of a published rate. |
|
|
354
263
|
|
|
355
|
-
```
|
|
356
|
-
|
|
264
|
+
```ts
|
|
265
|
+
const table = await client.officialRates('ecb');
|
|
266
|
+
// { bank: 'ecb', rate_date: '2026-10-15', stale: false, cadence: 'daily',
|
|
267
|
+
// rates: [ { base: 'EUR', quote: 'AUD', type: 'reference', value: 1.6218 }, ... ],
|
|
268
|
+
// attribution: { source: 'Official rates published by ECB, served by AllRatesToday', url: '...', terms: '...' } }
|
|
357
269
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
if (err instanceof AllRatesTodayError) {
|
|
362
|
-
console.log(err.message); // "Currency not found"
|
|
363
|
-
console.log(err.status); // 404
|
|
364
|
-
}
|
|
365
|
-
}
|
|
270
|
+
const pair = await client.officialRates('ecb', { source: 'EUR', target: 'USD' });
|
|
271
|
+
// { bank: 'ecb', rate_date: '2026-10-15', source: 'EUR', target: 'USD', rate: 1.1208,
|
|
272
|
+
// rate_type: 'reference', derived: false, method: 'published', stale: false, ... }
|
|
366
273
|
```
|
|
367
274
|
|
|
368
|
-
|
|
369
|
-
| ------ | ------------------------------------ |
|
|
370
|
-
| โ | Missing API key (thrown before request) |
|
|
371
|
-
| `401` | Invalid API key |
|
|
372
|
-
| `404` | Currency code not found |
|
|
373
|
-
| `429` | Rate limit exceeded |
|
|
374
|
-
| `500` | Server error |
|
|
375
|
-
|
|
376
|
-
---
|
|
377
|
-
|
|
378
|
-
## ๐ท TypeScript
|
|
379
|
-
|
|
380
|
-
The SDK is written in TypeScript and ships full type definitions. All interfaces are exported:
|
|
381
|
-
|
|
382
|
-
```typescript
|
|
383
|
-
import AllRatesToday, {
|
|
384
|
-
AllRatesTodayError,
|
|
385
|
-
AllRatesTodayOptions,
|
|
386
|
-
RequestOptions,
|
|
387
|
-
RateResponse,
|
|
388
|
-
AuthRateResponse,
|
|
389
|
-
LatestOptions,
|
|
390
|
-
LatestResponse,
|
|
391
|
-
ForDateOptions,
|
|
392
|
-
ForDateResponse,
|
|
393
|
-
ConvertOptions,
|
|
394
|
-
ConvertResponse,
|
|
395
|
-
TimeSeriesOptions,
|
|
396
|
-
TimeSeriesResponse,
|
|
397
|
-
HistoricalRateResponse,
|
|
398
|
-
SymbolsResponse,
|
|
399
|
-
} from '@allratestoday/sdk';
|
|
400
|
-
```
|
|
275
|
+
A pair the bank does not cover (e.g. USD/GBP from the ECB) throws a 404; use `officialRatesOn()` for cross pairs. Keyless use requires the visible attribution in `attribution.terms`.
|
|
401
276
|
|
|
402
|
-
|
|
277
|
+
### `officialRatesOn(bank, date, options?)`
|
|
403
278
|
|
|
404
|
-
|
|
279
|
+
The table, or one pair, as published on a date. Needs a key. Covers each bank's archive, and any pair inside the table.
|
|
405
280
|
|
|
406
|
-
```
|
|
407
|
-
|
|
281
|
+
```ts
|
|
282
|
+
await client.officialRatesOn('rbi', '2026-09-30', { source: 'USD', target: 'INR' });
|
|
283
|
+
// { bank: 'rbi', name: 'Reserve Bank of India', requested_date: '2026-09-30', rate_date: '2026-09-30',
|
|
284
|
+
// published_on_requested_date: true, source: 'USD', target: 'INR', rate: 95.9832,
|
|
285
|
+
// rate_type: 'reference', derived: false, method: 'published', disclaimer: '...' }
|
|
408
286
|
|
|
409
|
-
|
|
410
|
-
|
|
287
|
+
await client.officialRatesOn('ecb', '2019-03-15', { source: 'USD', target: 'GBP' });
|
|
288
|
+
// { ..., rate_date: '2019-03-15', rate: 0.7553501946, derived: true, method: 'cross' }
|
|
411
289
|
```
|
|
412
290
|
|
|
413
|
-
|
|
291
|
+
### `officialSources(options?)`
|
|
414
292
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
### Currency Dropdown (React)
|
|
418
|
-
|
|
419
|
-
```tsx
|
|
420
|
-
import { useEffect, useState } from 'react';
|
|
421
|
-
import AllRatesToday from '@allratestoday/sdk';
|
|
293
|
+
Every official source with its latest publication date. No key needed.
|
|
422
294
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
const [currencies, setCurrencies] = useState([]);
|
|
427
|
-
|
|
428
|
-
useEffect(() => {
|
|
429
|
-
client.symbols().then(({ symbols }) => {
|
|
430
|
-
setCurrencies(
|
|
431
|
-
Object.entries(symbols).map(([code, name]) => ({ code, name }))
|
|
432
|
-
);
|
|
433
|
-
});
|
|
434
|
-
}, []);
|
|
435
|
-
|
|
436
|
-
return (
|
|
437
|
-
<select value={value} onChange={e => onChange(e.target.value)}>
|
|
438
|
-
{currencies.map(c => (
|
|
439
|
-
<option key={c.code} value={c.code}>{c.code} โ {c.name}</option>
|
|
440
|
-
))}
|
|
441
|
-
</select>
|
|
442
|
-
);
|
|
443
|
-
}
|
|
295
|
+
```ts
|
|
296
|
+
const { sources, stale_count } = await client.officialSources();
|
|
297
|
+
// sources: [ { code: 'amcm', name: 'Monetary Authority of Macao', latest: '2026-10-16', stale: false, cadence: 'daily' }, ... ]
|
|
444
298
|
```
|
|
445
299
|
|
|
446
|
-
|
|
300
|
+
## Errors, retries and troubleshooting
|
|
447
301
|
|
|
448
|
-
|
|
449
|
-
import AllRatesToday from '@allratestoday/sdk';
|
|
302
|
+
Every failure is an `AllRatesTodayError` with a `code`, and for HTTP errors a `status` and the parsed response body in `details`.
|
|
450
303
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
const TTL = 5 * 60 * 1000; // 5 minutes
|
|
304
|
+
```ts
|
|
305
|
+
import AllRatesToday, { AllRatesTodayError } from '@allratestoday/sdk';
|
|
454
306
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
307
|
+
try {
|
|
308
|
+
await client.latest({ symbols: ['EUR'] });
|
|
309
|
+
} catch (err) {
|
|
310
|
+
if (err instanceof AllRatesTodayError) {
|
|
311
|
+
console.log(err.code, err.status, err.message, err.details);
|
|
459
312
|
}
|
|
460
|
-
const converted = (amountUSD * cache.rates[currency]).toFixed(2);
|
|
461
|
-
return `${converted} ${currency}`;
|
|
462
313
|
}
|
|
463
|
-
|
|
464
|
-
console.log(await getPrice(99.99, 'EUR')); // "92.32 EUR"
|
|
465
|
-
console.log(await getPrice(99.99, 'GBP')); // "78.90 GBP"
|
|
466
314
|
```
|
|
467
315
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
316
|
+
| `code` | `status` | Cause | What to do |
|
|
317
|
+
| --- | --- | --- | --- |
|
|
318
|
+
| `missing_key` | โ | Keyed method called without `apiKey` (no request sent) | Pass `apiKey` |
|
|
319
|
+
| `invalid_argument` | โ | Bad date format, future date, market date over a year old, missing `symbols`, bad bank code, lone `source`/`target` | Fix the call; the message says which |
|
|
320
|
+
| `http` | `400` | Unknown currency code or bad parameter | Check codes against `symbols()` |
|
|
321
|
+
| `http` | `401` | Missing or invalid key | Check the key in your [dashboard](https://allratestoday.com/profile) |
|
|
322
|
+
| `http` | `403` | Your plan does not include this data (e.g. market rates on an official-rates-only plan) | See `details.error`; change plan |
|
|
323
|
+
| `http` | `404` | The bank does not publish that pair / no table | Try `officialRatesOn()` or another source |
|
|
324
|
+
| `http` | `429` | Request quota used up | `details` has `used`, `limit`, `plan`, `resets_at`, `upgrade_url` |
|
|
325
|
+
| `http` | `5xx` | Temporary server or upstream error | Retry with backoff |
|
|
326
|
+
| `timeout` | โ | No response within `timeout` ms | Retry; raise `timeout` if it keeps happening |
|
|
327
|
+
| `network` | โ | DNS, TLS or connection failure (`err.cause` has the original error) | Retry; check connectivity |
|
|
328
|
+
|
|
329
|
+
### Retrying transient failures
|
|
330
|
+
|
|
331
|
+
Retry only `timeout`, `network` and `5xx`. Retrying `4xx` (including `429` quota errors) just fails again.
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
async function withRetry<T>(fn: () => Promise<T>, attempts = 3): Promise<T> {
|
|
335
|
+
for (let i = 1; ; i++) {
|
|
336
|
+
try {
|
|
337
|
+
return await fn();
|
|
338
|
+
} catch (err) {
|
|
339
|
+
const retryable =
|
|
340
|
+
err instanceof AllRatesTodayError &&
|
|
341
|
+
(err.code === 'timeout' || err.code === 'network' || (err.status ?? 0) >= 500);
|
|
342
|
+
if (!retryable || i >= attempts) throw err;
|
|
343
|
+
await new Promise((r) => setTimeout(r, 500 * 2 ** (i - 1))); // 0.5s, 1s, ...
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
483
347
|
|
|
484
|
-
|
|
485
|
-
// { labels: ['2026-01-01', '2026-01-02', ...], values: [0.92, 0.921, ...] }
|
|
348
|
+
const data = await withRetry(() => client.latest({ symbols: ['EUR'] }));
|
|
486
349
|
```
|
|
487
350
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
## ๐ Methods Reference
|
|
351
|
+
**Cache instead of polling.** Market rates move about once a minute and official rates once a day, so cache `latest()` for at least 60 seconds and official tables until the next publication.
|
|
491
352
|
|
|
492
|
-
|
|
493
|
-
| ------ | ----------- |
|
|
494
|
-
| `latest(options?)` | Get latest rates for one or more currencies |
|
|
495
|
-
| `forDate(date, options?)` | Get rates for a specific historical date |
|
|
496
|
-
| `convert(from, to, amount, options?)` | Convert amount between currencies (supports historical date) |
|
|
497
|
-
| `timeSeries(start, end, options?)` | Get rates across a custom date range |
|
|
498
|
-
| `symbols(options?)` | List all 160+ supported currency codes and names |
|
|
499
|
-
| `getRate(from, to, amount?, options?)` | Get a single exchange rate |
|
|
500
|
-
| `getRates(source, target, options?)` | Get rates with full metadata |
|
|
501
|
-
| `getHistoricalRates(source, target, period?, options?)` | Historical rates by preset period (1d/7d/30d/1y) |
|
|
502
|
-
| `officialRates(bank, options?)` | Latest official table (or one pair) published by a central bank / tax authority โ **keyless** |
|
|
503
|
-
| `officialSources(options?)` | Every covered official source with latest publication date and freshness โ **keyless** |
|
|
353
|
+
## Quotas and billing
|
|
504
354
|
|
|
505
|
-
|
|
355
|
+
- The free plan includes **300 requests in total** (they do not reset). Paid plans have monthly quotas; see [pricing](https://allratestoday.com/pricing).
|
|
356
|
+
- Keyless methods (`officialRates`, `officialSources`, `symbols`) do not use your quota.
|
|
357
|
+
- History is billed by volume: a `1y` window is 12 calls; `7d`, `30d` and `1d` are 1. `forDate` and `timeSeries` make one history request per symbol.
|
|
358
|
+
- Your current usage is in the [dashboard](https://allratestoday.com/profile). When you run out, calls fail with `429` and `details` says when the quota resets.
|
|
506
359
|
|
|
507
|
-
##
|
|
360
|
+
## Compatibility
|
|
508
361
|
|
|
509
|
-
|
|
362
|
+
- **Node.js 18 or later** (uses the built-in `fetch` and `AbortSignal.timeout`). Other runtimes with those globals (Deno, Bun, edge workers, modern browsers) should work but are not part of the test suite. In browsers, use keyless methods only (see above).
|
|
363
|
+
- **ESM and CommonJS** builds with an `exports` map:
|
|
510
364
|
|
|
511
|
-
```
|
|
512
|
-
|
|
365
|
+
```js
|
|
366
|
+
import AllRatesToday, { AllRatesTodayError } from '@allratestoday/sdk'; // ESM / TypeScript
|
|
367
|
+
const { default: AllRatesToday } = require('@allratestoday/sdk'); // CommonJS
|
|
513
368
|
```
|
|
514
369
|
|
|
515
|
-
|
|
370
|
+
- **TypeScript** types are bundled (`dist/index.d.ts`); no `@types` package needed.
|
|
371
|
+
- **Bundlers**: zero dependencies and `sideEffects: false`, so it tree-shakes.
|
|
516
372
|
|
|
517
|
-
|
|
518
|
-
npm run test:coverage
|
|
519
|
-
```
|
|
373
|
+
## TypeScript
|
|
520
374
|
|
|
521
|
-
|
|
375
|
+
All request and response types are exported:
|
|
522
376
|
|
|
523
|
-
```
|
|
524
|
-
|
|
377
|
+
```ts
|
|
378
|
+
import type {
|
|
379
|
+
AllRatesTodayOptions, RequestOptions, AllRatesTodayErrorCode,
|
|
380
|
+
LatestOptions, LatestResponse, RateResponse, AuthRateResponse,
|
|
381
|
+
ConvertOptions, ConvertResponse, ForDateOptions, ForDateResponse,
|
|
382
|
+
TimeSeriesOptions, TimeSeriesResponse, HistoryPeriod, HistoryPoint, HistoricalRateResponse,
|
|
383
|
+
SymbolsResponse, CurrencyInfo,
|
|
384
|
+
OfficialRateOptions, OfficialRatesResponse, DatedOfficialRatesResponse, OfficialRateEntry,
|
|
385
|
+
OfficialSource, OfficialSourcesResponse,
|
|
386
|
+
} from '@allratestoday/sdk';
|
|
525
387
|
```
|
|
526
388
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
## ๐ค Use it from an AI agent
|
|
389
|
+
## Use it from an AI agent
|
|
530
390
|
|
|
531
391
|
The same rates are available to coding agents and LLM tools without a second integration:
|
|
532
392
|
|
|
533
393
|
- **Claude Code plugin** (no key): `/plugin marketplace add AllRates-Today/claude-code-plugin` then `/plugin install allratestoday@allratestoday`
|
|
534
394
|
- **Hosted MCP endpoint**: `https://allratestoday.com/api/mcp` โ Streamable HTTP, keyless, nothing to install
|
|
535
395
|
- **Local MCP servers**: `npx -y @allratestoday/mcp-server` (live mid-market rates) ยท `npx -y @allratestoday/central-bank-mcp` (official central-bank rates)
|
|
536
|
-
- **Trial key for agents, no signup**: `POST https://allratestoday.com/api/agent/keys` (send `Content-Type: application/json`) returns a 100-call key valid 7 days
|
|
537
|
-
- **Daily Reference Rate
|
|
396
|
+
- **Trial key for agents, no signup**: `POST https://allratestoday.com/api/agent/keys` (send `Content-Type: application/json`) returns a 100-call key valid 7 days; both MCP servers expose it as `request_trial_key`
|
|
397
|
+
- **Daily Reference Rate**: one fixed USD table per business day, the 16:00 London median of minute samples, never revised โ keyless at `https://allratestoday.com/api/open/reference-rate`
|
|
538
398
|
- Machine-readable site guide: [llms.txt](https://allratestoday.com/llms.txt)
|
|
539
399
|
|
|
540
|
-
##
|
|
400
|
+
## Testing, contributing and support
|
|
401
|
+
|
|
402
|
+
```bash
|
|
403
|
+
npm test # unit tests: fetch is mocked, no network or API key needed
|
|
404
|
+
npm run test:coverage
|
|
405
|
+
npm run build
|
|
406
|
+
```
|
|
541
407
|
|
|
542
|
-
- [
|
|
543
|
-
- [
|
|
544
|
-
-
|
|
545
|
-
- [
|
|
546
|
-
- [GitHub](https://github.com/AllRates-Today/exchange-rates-api)
|
|
408
|
+
- **Changelog**: [CHANGELOG.md](https://github.com/AllRates-Today/exchange-rates-api/blob/main/sdks/javascript/CHANGELOG.md)
|
|
409
|
+
- **Bugs and feature requests**: [GitHub issues](https://github.com/AllRates-Today/exchange-rates-api/issues)
|
|
410
|
+
- **Contributing**: pull requests welcome. Add or update tests in `src/index.test.ts` and run `npm test` before opening one.
|
|
411
|
+
- **Support**: [info@allratestoday.com](mailto:info@allratestoday.com) ยท [API docs](https://allratestoday.com/docs/) ยท [status](https://allratestoday.com/status)
|
|
547
412
|
|
|
548
|
-
##
|
|
413
|
+
## License
|
|
549
414
|
|
|
550
415
|
MIT
|