> For the complete documentation index, see [llms.txt](https://docs.catfee.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.catfee.io/en/getting-started/buy-energy-via-api-on-catfee/nodejs.md).

# Node.js Example for Calling API

Node.js Example for Calling the CatFee.IO REST API

#### Prerequisites

* [You need a valid **API Key** and **API Secret**](/en/getting-started/buy-energy-via-api-on-catfee/api-overview.md#apply-api-info).
* Use Node.js 18 or later and install the `axios` library:

```bash
npm install axios
```

***

#### Example Code

```js
const axios = require('axios');
const crypto = require('crypto');

const API_KEY = 'your_api_key'; // Replace with your actual API Key
const API_SECRET = 'your_api_secret'; // Replace with your actual API Secret
const BASE_URL = 'https://api.catfee.io';
const TIMEOUT_MS = 15000;

// Generate the current timestamp in ISO 8601 format
function generateTimestamp() {
    return new Date().toISOString();
}

// Build request path including query parameters
function buildRequestPath(path, queryParams = []) {
    if (queryParams.length === 0) {
        return path;
    }
    const queryString = new URLSearchParams(queryParams).toString();
    return `${path}?${queryString}`;
}

// Generate signature using HMAC-SHA256
function generateSignature(timestamp, method, requestPath) {
    const signString = timestamp + method.toUpperCase() + requestPath;
    return crypto.createHmac('sha256', API_SECRET)
                 .update(signString)
                 .digest('base64');
}

// Sign and send an HTTP request
async function sendRequest(method, path, queryParams = []) {
    method = method.toUpperCase();
    const requestPath = buildRequestPath(path, queryParams);
    const timestamp = generateTimestamp();
    const signature = generateSignature(timestamp, method, requestPath);
    const headers = {
        'Content-Type': 'application/json',
        'CF-ACCESS-KEY': API_KEY,
        'CF-ACCESS-SIGN': signature,
        'CF-ACCESS-TIMESTAMP': timestamp
    };

    return axios.request({
        url: BASE_URL + requestPath,
        method,
        headers,
        timeout: TIMEOUT_MS,
        validateStatus: () => true,
    });
}

async function main() {
    // Example: Create an order
    const clientOrderId = crypto.randomUUID();
    const queryParams = [
        ['quantity', '65000'],
        ['receiver', 'TRON_ADDRESS'],
        ['duration', '1h'],
        ['client_order_id', clientOrderId],
        ['activate', 'true'],
    ];

    console.log('Client Order ID:', clientOrderId);
    try {
        const response = await sendRequest('POST', '/v1/order', queryParams);
        console.log('HTTP Status:', response.status);
        console.log('Response Body:', response.data);

        if (response.status < 200 || response.status >= 300) {
            throw new Error(`HTTP request failed with status ${response.status}`);
        }

        const result = response.data;
        if (!result || typeof result !== 'object') {
            throw new Error('Response is not valid JSON');
        }
        if (result.code !== 0) {
            const message = result.msg || result.sub_msg || 'Unknown error';
            throw new Error(`API request failed: code=${result.code}, message=${message}`);
        }

        console.log('Order ID:', result.data?.id || '');
    } catch (error) {
        console.error(
            error.code === 'ECONNABORTED' ? 'Request timed out.' : `Request failed: ${error.message}`
        );
        console.error('Retry with the same Client Order ID:', clientOrderId);
    }
}

// Run the main function
main();
```

***

#### Code Explanation

* **generateTimestamp()**\
  Returns the current UTC timestamp in ISO 8601 format using JavaScript's `toISOString()` method.
* **buildRequestPath()**\
  Constructs the full URL path by appending URL-encoded query parameters. `URLSearchParams` is used to format the query string.
* **generateSignature()**\
  Signs the string composed of `timestamp + method + requestPath` using the HMAC-SHA256 algorithm with your `API_SECRET`, then encodes the result in Base64.
* **sendRequest()**\
  Builds the exact signed URL, sets the three authentication headers, and sends the request with a 15-second timeout.
* **main()**\
  Defines the HTTP method and request path, prepares query parameters, generates the necessary headers, and sends the request.

***

#### Notes

* **API Key and Secret**\
  Make sure to replace `API_KEY` and `API_SECRET` with the actual values you obtained from CatFee.IO.
* **Signed request path**\
  The encoded query string and parameter order must be identical in the signature and actual URL. Do not rebuild it with Axios `params` after signing.
* **Idempotent retries**\
  Use a unique `client_order_id` of no more than 64 characters for each new order, and reuse it after a timeout or connection failure.
* **Response handling**\
  HTTP `200` does not necessarily mean business success. Always verify that the response body's `code` is `0`.

***

#### Summary

This example demonstrates how to securely call the CatFee.IO REST API in a Node.js environment. It includes HMAC-SHA256 signature generation for request verification and supports multiple HTTP methods. You can modify and expand the code based on your specific API use cases.
