diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index a9c7a54..6449705 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -27,3 +27,15 @@ jobs:
- name: Upload coverage to Coveralls
uses: coverallsapp/github-action@v2
+ with:
+ parallel: true
+ flag-name: node-${{ matrix.node-version }}
+
+ finish:
+ needs: build
+ runs-on: ubuntu-latest
+ steps:
+ - name: Close parallel build
+ uses: coverallsapp/github-action@v2
+ with:
+ parallel-finished: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c6bfd34..1e2d24b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,17 @@
All notable changes to this project will be documented in this file.
+## [2.0.0] - 2026-02-19
+
+### Added
+- OHLC (candlestick) endpoint support via `currency.ohlc()`
+- `currency()`, `date()`, `interval()`, `base()` methods on the Ohlc class
+- Intervals supported: `5m`, `15m`, `30m`, `1h`, `4h`, `12h`, `1d` (default: `1d`)
+
+### Changed
+- **Breaking**: Migrated from API v1 to v2 (`/api/v1/` → `/api/v2/`)
+- Bumped package version to 2.0.0
+
## [1.2.0] - 2026-02-13
### Added
diff --git a/Makefile b/Makefile
index 85cf491..8c342d0 100644
--- a/Makefile
+++ b/Makefile
@@ -22,5 +22,8 @@ run: ## Run test file
publish: ## Publish version (use: make publish OTP=123456 if 2FA enabled)
docker run --rm -v ${PWD}:${WORKING_DIR} -v ${HOME}/.npmrc:/home/node/.npmrc:ro -w ${WORKING_DIR} --name ${CONTAINER_NAME} ${LOCAL_DOCKER_IMAGE} npm publish $(if ${OTP},--otp=${OTP})
+deprecate: ## Deprecate all v1.x versions on npm (use: make deprecate OTP=123456 if 2FA enabled)
+ docker run --rm -v ${HOME}/.npmrc:/home/node/.npmrc:ro node:24-slim npm deprecate currencyapi-node@'"<2.0.0"' "The v1 API will redirect to v2 on 31 July 2026. Please upgrade to currencyapi-node@2.0.0 for v2 support and the new OHLC endpoint." $(if ${OTP},--otp=${OTP})
+
help:
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
diff --git a/README.md b/README.md
index aad6b8c..64d5ecf 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,12 @@
-# CurrencyApi NodeJs wrapper
+# CurrencyApi NodeJs wrapper
-[](https://www.npmjs.com/package/currencyapi-node) [](https://coveralls.io/github/houseofapis/currencyapi-node?branch=master)
+[](https://www.npmjs.com/package/currencyapi-node) [](https://coveralls.io/github/houseofapis/currencyapi-node?branch=master)
+> **Note:** API v1 is deprecated and will be retired on **31st July 2026**, at which point all v1 traffic will be redirected to v2. This SDK (v2.0.0+) targets API v2. If you are on an older version of this SDK, please upgrade.
-CurrencyApi.net provides live currency rates via a REST API. A live currency feed for over 152 currencies, including physical (USD, GBP, EUR + more) and cryptos (Bitcoin, Litecoin, Ethereum + more). A JSON and XML currency api updated every 60 seconds.
+
+CurrencyApi.net provides live currency rates via a REST API. A live currency feed for over 152 currencies, including physical (USD, GBP, EUR + more) and cryptos (Bitcoin, Litecoin, Ethereum + more). A JSON and XML currency api updated every 60 seconds.
Features:
@@ -13,6 +15,7 @@ Features:
- Popular cryptocurrencies included; Bitcoin, Litecoin etc.
- Convert currencies on the fly with the convert endpoint.
- Historical currency rates back to year 2000.
+- OHLC (candlestick) data with multiple intervals.
- Easy to follow documentation
Signup for a free or paid account here.
@@ -183,3 +186,38 @@ const result = await currency
| `endDate()` | The historical date you wish to receive the currency conversions until. This should be formatted as YYYY-MM-DD. **Required**. |
| `base()` | The base currency you wish you receive the currency conversions for. This will output all currency conversions for that currency. **Default: USD**. |
| `output()` | Response output in either JSON or XML. **Default: JSON**. |
+
+
+
+### OHLC (candlestick data):
+
+```javascript
+const result = await currency
+ .ohlc()
+ .currency('GBP')
+ .date('2024-01-13')
+ .get()
+```
+
+Example with all available methods:
+
+```javascript
+const result = await currency
+ .ohlc()
+ .currency('GBP')
+ .date('2024-01-13')
+ .interval('1h')
+ .base('USD')
+ .output('JSON')
+ .get()
+```
+
+**Available methods for ohlc endpoint**
+
+| Methods | Description |
+| --- | --- |
+| `currency()` | The quote currency to retrieve OHLC data for. This will be a three letter ISO 4217 currency code. **Required**. |
+| `date()` | The date to retrieve OHLC data for. This should be formatted as YYYY-MM-DD. **Required**. |
+| `interval()` | The time interval for each candle. Allowed values: `5m`, `15m`, `30m`, `1h`, `4h`, `12h`, `1d`. **Default: 1d**. |
+| `base()` | The base currency. **Default: USD**. |
+| `output()` | Response output in either JSON or XML. **Default: JSON**. |
diff --git a/package.json b/package.json
index 00b0d7c..75c5df2 100644
--- a/package.json
+++ b/package.json
@@ -18,7 +18,7 @@
"role": "Developer"
}
],
- "version": "1.2.0",
+ "version": "2.0.0",
"engines": {
"node": ">=16.0.0"
},
diff --git a/src/CurrencyApi.js b/src/CurrencyApi.js
index 934bcc3..28fd552 100644
--- a/src/CurrencyApi.js
+++ b/src/CurrencyApi.js
@@ -3,6 +3,7 @@ const Convert = require('./classes/Convert')
const History = require('./classes/History')
const Timeframe = require('./classes/Timeframe')
const Currencies = require('./classes/Currencies')
+const Ohlc = require('./classes/Ohlc')
/**
* @class CurrencyApi
@@ -64,6 +65,15 @@ class CurrencyApi
return new Currencies(this.key)
}
+ /**
+ * Use the ohlc endpoint
+ *
+ * @returns {Ohlc}
+ */
+ ohlc() {
+ return new Ohlc(this.key)
+ }
+
}
module.exports = CurrencyApi
diff --git a/src/classes/Endpoint.js b/src/classes/Endpoint.js
index 9414143..8266d4f 100644
--- a/src/classes/Endpoint.js
+++ b/src/classes/Endpoint.js
@@ -14,7 +14,7 @@ const BASE_URL = 'https://currencyapi.net/api/';
/**
* Version of the API
*/
-const API_VERSION = 'v1';
+const API_VERSION = 'v2';
/**
* Default base currency
diff --git a/src/classes/Ohlc.js b/src/classes/Ohlc.js
new file mode 100644
index 0000000..467c1f6
--- /dev/null
+++ b/src/classes/Ohlc.js
@@ -0,0 +1,68 @@
+const Endpoint = require('./Endpoint')
+
+/**
+ * Allowed intervals for OHLC data
+ */
+const ALLOWED_INTERVALS = ['5m', '15m', '30m', '1h', '4h', '12h', '1d']
+
+/**
+ * @class Ohlc
+ */
+class Ohlc extends Endpoint {
+
+ /**
+ * Ohlc constructor
+ *
+ * @param {string} key
+ */
+ constructor(key) {
+ super(key, 'ohlc')
+ this.addParam('interval', '1d')
+ }
+
+ /**
+ * Set the quote currency
+ *
+ * @param {string} currency eg. 'GBP'
+ * @returns {Ohlc}
+ */
+ currency(currency) {
+ this.addParam('currency', currency.toUpperCase())
+ return this
+ }
+
+ /**
+ * Set the date
+ *
+ * @param {string} date eg. '2024-01-13'
+ * @returns {Ohlc}
+ */
+ date(date) {
+ this.addParam('date', date)
+ return this
+ }
+
+ /**
+ * Set the interval. Allowed values: 5m, 15m, 30m, 1h, 4h, 12h, 1d
+ *
+ * @param {string} interval eg. '1h'
+ * @returns {Ohlc}
+ */
+ interval(interval) {
+ this.addParam('interval', interval)
+ return this
+ }
+
+ /**
+ * Set the base currency
+ *
+ * @param {string} currency eg. 'USD'
+ * @returns {Ohlc}
+ */
+ base(currency) {
+ this.addParam('base', currency.toUpperCase())
+ return this
+ }
+}
+
+module.exports = Ohlc
diff --git a/tests/convert.test.js b/tests/convert.test.js
index 6bf755a..03e896f 100644
--- a/tests/convert.test.js
+++ b/tests/convert.test.js
@@ -69,7 +69,7 @@ describe("Fetching convert works as expected", () => {
convert.from('GbP')
convert.to('UsD')
const response = await convert.get();
- const expectedUrl = 'https://currencyapi.net/api/v1/convert?key=invalidKey&output=JSON&amount=10&from=GBP&to=USD'
+ const expectedUrl = 'https://currencyapi.net/api/v2/convert?key=invalidKey&output=JSON&amount=10&from=GBP&to=USD'
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
headers: {
@@ -100,7 +100,7 @@ describe("Fetching convert works as expected", () => {
convert.to('UsD')
const response = await convert.get()
- const expectedUrl = 'https://currencyapi.net/api/v1/convert?key=invalidKey&output=XML&amount=10&from=GBP&to=USD'
+ const expectedUrl = 'https://currencyapi.net/api/v2/convert?key=invalidKey&output=XML&amount=10&from=GBP&to=USD'
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
headers: {
"Content-Type": "application/xml",
diff --git a/tests/currencies.test.js b/tests/currencies.test.js
index 20976a8..0c9309d 100644
--- a/tests/currencies.test.js
+++ b/tests/currencies.test.js
@@ -42,7 +42,7 @@ describe("Fetching currencies works as expected", () => {
})
)
const response = await currencies.get();
- const expectedUrl = 'https://currencyapi.net/api/v1/currencies?key=invalidKey&output=JSON'
+ const expectedUrl = 'https://currencyapi.net/api/v2/currencies?key=invalidKey&output=JSON'
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
headers: {
@@ -67,7 +67,7 @@ describe("Fetching currencies works as expected", () => {
currencies.output('XmL')
const response = await currencies.get()
- const expectedUrl = 'https://currencyapi.net/api/v1/currencies?key=invalidKey&output=XML'
+ const expectedUrl = 'https://currencyapi.net/api/v2/currencies?key=invalidKey&output=XML'
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
headers: {
"Content-Type": "application/xml",
diff --git a/tests/currencyapi.test.js b/tests/currencyapi.test.js
index 53b8fe8..571afb6 100644
--- a/tests/currencyapi.test.js
+++ b/tests/currencyapi.test.js
@@ -4,6 +4,7 @@ const History = require('./../src/classes/History')
const Timeframe = require('./../src/classes/Timeframe')
const Convert = require('./../src/classes/Convert')
const Currencies = require('./../src/classes/Currencies')
+const Ohlc = require('./../src/classes/Ohlc')
let currencyApi
let invalidKey = 'invalidKey'
@@ -24,5 +25,6 @@ describe("Setting CurrencyApi", () => {
expect(currencyApi.timeframe()).toBeInstanceOf(Timeframe);
expect(currencyApi.convert()).toBeInstanceOf(Convert);
expect(currencyApi.currencies()).toBeInstanceOf(Currencies);
+ expect(currencyApi.ohlc()).toBeInstanceOf(Ohlc);
})
})
\ No newline at end of file
diff --git a/tests/history.test.js b/tests/history.test.js
index de7a6df..d818bf7 100644
--- a/tests/history.test.js
+++ b/tests/history.test.js
@@ -59,7 +59,7 @@ describe("Fetching history works as expected", () => {
)
history.date('2023-01-02')
const response = await history.get();
- const expectedUrl = 'https://currencyapi.net/api/v1/history?key=invalidKey&output=JSON&base=USD&date=2023-01-02'
+ const expectedUrl = 'https://currencyapi.net/api/v2/history?key=invalidKey&output=JSON&base=USD&date=2023-01-02'
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
headers: {
@@ -85,7 +85,7 @@ describe("Fetching history works as expected", () => {
history.date('2023-01-02')
history.base('GbP')
const response = await history.get();
- const expectedUrl = 'https://currencyapi.net/api/v1/history?key=invalidKey&output=XML&base=GBP&date=2023-01-02'
+ const expectedUrl = 'https://currencyapi.net/api/v2/history?key=invalidKey&output=XML&base=GBP&date=2023-01-02'
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
headers: {
diff --git a/tests/ohlc.test.js b/tests/ohlc.test.js
new file mode 100644
index 0000000..2d2db60
--- /dev/null
+++ b/tests/ohlc.test.js
@@ -0,0 +1,142 @@
+jest.mock("node-fetch")
+const fetch = require("node-fetch")
+const Ohlc = require('./../src/classes/Ohlc')
+
+let ohlc
+let invalidKey = 'invalidKey'
+
+beforeEach(() => {
+ ohlc = new Ohlc(invalidKey)
+})
+
+describe("Setting Ohlc", () => {
+
+ test('Constructor setting params correctly', () => {
+ expect(ohlc.key).toBe(invalidKey)
+ expect(ohlc.endpoint).toBe('ohlc')
+ })
+
+ test('Check default params have been set', () => {
+ let params = ohlc.getParams()
+ expect(params).toHaveProperty('output', 'JSON')
+ expect(params).toHaveProperty('interval', '1d')
+ })
+
+ test('Set currency works and returns object', () => {
+ const setCurrency = ohlc.currency('gBp')
+ let params = ohlc.getParams()
+ expect(params).toHaveProperty('currency', 'GBP')
+ expect(setCurrency).toBeInstanceOf(Ohlc)
+ })
+
+ test('Set date works and returns object', () => {
+ const setDate = ohlc.date('2024-01-13')
+ let params = ohlc.getParams()
+ expect(params).toHaveProperty('date', '2024-01-13')
+ expect(setDate).toBeInstanceOf(Ohlc)
+ })
+
+ test('Set interval works and returns object', () => {
+ const setInterval = ohlc.interval('1h')
+ let params = ohlc.getParams()
+ expect(params).toHaveProperty('interval', '1h')
+ expect(setInterval).toBeInstanceOf(Ohlc)
+ })
+
+ test('Set all allowed intervals', () => {
+ const intervals = ['5m', '15m', '30m', '1h', '4h', '12h', '1d']
+ intervals.forEach(i => {
+ ohlc.interval(i)
+ expect(ohlc.getParams()).toHaveProperty('interval', i)
+ })
+ })
+
+ test('Set base works and returns object', () => {
+ const setBase = ohlc.base('eUr')
+ let params = ohlc.getParams()
+ expect(params).toHaveProperty('base', 'EUR')
+ expect(setBase).toBeInstanceOf(Ohlc)
+ })
+
+ test('Set output works and returns object', () => {
+ const setOutput = ohlc.output('xMl')
+ let params = ohlc.getParams()
+ expect(params).toHaveProperty('output', 'XML')
+ expect(setOutput).toBeInstanceOf(Ohlc)
+ })
+
+ test('Methods can be chained', () => {
+ const result = ohlc.currency('GBP').date('2024-01-13').interval('1h').base('USD')
+ expect(result).toBeInstanceOf(Ohlc)
+ let params = ohlc.getParams()
+ expect(params).toHaveProperty('currency', 'GBP')
+ expect(params).toHaveProperty('date', '2024-01-13')
+ expect(params).toHaveProperty('interval', '1h')
+ expect(params).toHaveProperty('base', 'USD')
+ })
+
+})
+
+describe("Fetching ohlc works as expected", () => {
+
+ test("fetch json working as expected", async () => {
+
+ const mockData = {
+ "valid": true,
+ "base": "USD",
+ "quote": "GBP",
+ "date": "2024-01-13",
+ "interval": "1h",
+ "ohlc": [
+ {
+ "start": "2024-01-13T00:00:00Z",
+ "open": 1.2735,
+ "high": 1.2756,
+ "low": 1.2720,
+ "close": 1.2748
+ }
+ ]
+ }
+ fetch.mockReturnValue(
+ Promise.resolve({
+ json: () =>
+ Promise.resolve(mockData)
+ })
+ )
+ ohlc.currency('GBP').date('2024-01-13').interval('1h')
+ const response = await ohlc.get()
+ const expectedUrl = 'https://currencyapi.net/api/v2/ohlc?key=invalidKey&output=JSON&interval=1h¤cy=GBP&date=2024-01-13'
+
+ expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
+ headers: {
+ "Content-Type": "application/json",
+ "X-Sdk": "node"
+ }
+ })
+ expect(response).toEqual(mockData)
+ })
+
+ test("fetch xml working as expected", async () => {
+
+ const mockData = ''
+
+ fetch.mockReturnValue(
+ Promise.resolve({
+ text: () =>
+ Promise.resolve(mockData)
+ })
+ )
+ ohlc.output('XmL').currency('GBP').date('2024-01-13')
+ const response = await ohlc.get()
+
+ const expectedUrl = 'https://currencyapi.net/api/v2/ohlc?key=invalidKey&output=XML&interval=1d¤cy=GBP&date=2024-01-13'
+ expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
+ headers: {
+ "Content-Type": "application/xml",
+ "X-Sdk": "node"
+ }
+ })
+ expect(response).toEqual(mockData)
+ })
+
+})
diff --git a/tests/rates.test.js b/tests/rates.test.js
index 8211130..7f791f0 100644
--- a/tests/rates.test.js
+++ b/tests/rates.test.js
@@ -62,7 +62,7 @@ describe("Fetching rates works as expected", () => {
})
)
const response = await rates.get();
- expect(fetch).toHaveBeenLastCalledWith("https://currencyapi.net/api/v1/rates?key=invalidKey&output=JSON&base=USD", {
+ expect(fetch).toHaveBeenLastCalledWith("https://currencyapi.net/api/v2/rates?key=invalidKey&output=JSON&base=USD", {
headers: {
"Content-Type": "application/json",
"X-Sdk": "node"
@@ -91,7 +91,7 @@ describe("Fetching rates works as expected", () => {
rates.output('XmL')
const response = await rates.get()
- expect(fetch).toHaveBeenLastCalledWith("https://currencyapi.net/api/v1/rates?key=invalidKey&output=XML&base=USD", {
+ expect(fetch).toHaveBeenLastCalledWith("https://currencyapi.net/api/v2/rates?key=invalidKey&output=XML&base=USD", {
headers: {
"Content-Type": "application/xml",
"X-Sdk": "node"
diff --git a/tests/timeframe.test.js b/tests/timeframe.test.js
index a91a055..6a39640 100644
--- a/tests/timeframe.test.js
+++ b/tests/timeframe.test.js
@@ -69,7 +69,7 @@ describe("Fetching timeframe works as expected", () => {
timeframe.startDate('2023-01-02')
timeframe.endDate('2023-01-03')
const response = await timeframe.get();
- const expectedUrl = 'https://currencyapi.net/api/v1/timeframe?key=invalidKey&output=JSON&base=USD&start_date=2023-01-02&end_date=2023-01-03'
+ const expectedUrl = 'https://currencyapi.net/api/v2/timeframe?key=invalidKey&output=JSON&base=USD&start_date=2023-01-02&end_date=2023-01-03'
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
headers: {
@@ -96,7 +96,7 @@ describe("Fetching timeframe works as expected", () => {
timeframe.startDate('2023-01-02')
timeframe.endDate('2023-01-03')
const response = await timeframe.get();
- const expectedUrl = 'https://currencyapi.net/api/v1/timeframe?key=invalidKey&output=XML&base=USD&start_date=2023-01-02&end_date=2023-01-03'
+ const expectedUrl = 'https://currencyapi.net/api/v2/timeframe?key=invalidKey&output=XML&base=USD&start_date=2023-01-02&end_date=2023-01-03'
expect(fetch).toHaveBeenLastCalledWith(expectedUrl, {
headers: {