> ## Documentation Index
> Fetch the complete documentation index at: https://forest-chore-open-api.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Create an API-based Chart

### Creating an API-based Chart

Sometimes, charts data are complicated and closely tied to your business. Forest allows you to code how the chart is computed. Choose **API** as the data source when configuring your chart.

<img src="https://mintcdn.com/forest-chore-open-api/l9oWVTFSA2iV8NAX/images/legacy/javascript-agents/image%20(466).png?fit=max&auto=format&n=l9oWVTFSA2iV8NAX&q=85&s=b67c1ae108e6c090d8f3999c4ca7ec65" alt="" width="645" height="69" data-path="images/legacy/javascript-agents/image (466).png" />

Forest will make the HTTP call to Smart Chart URL when retrieving the chart values for the rendering.

### Value API-based Chart

On our Live Demo, we have a `MRR` value chart which computes our Monthly Recurring Revenue. This chart queries the Stripe API to get all charges made in the current month (in March for this example).

<Tabs>
  <Tab title="SQL">
    When serializing the data, we use the `Liana.StatSerializer()` serializer. Check the `value` syntax below.

    ```
    { value: <number> }
    ```

    ```javascript theme={null}
    const P = require('bluebird');
    const express = require('express');
    const router = express.Router();
    const Liana = require('forest-express-sequelize');
    const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
    const moment = require('moment');

    ...

    router.post('/stats/mrr', (req, res) => {
      let mrr = 0;

      let from = moment.utc('2018-03-01').unix();
      let to = moment.utc('2018-03-31').unix();

      return stripe.charges
        .list({
          created: { gte: from, lte: to }
        })
        .then((response) => {
          return P.each(response.data, (charge) => {
            mrr += charge.amount;
          });
        })
        .then(() => {
          let json = new Liana.StatSerializer({
            value: mrr
          }).perform();

          res.send(json);
        });
    });

    ...

    module.exports = router;
    ```
  </Tab>

  <Tab title="Mongoose">
    When serializing the data, we use the `Liana.StatSerializer()` serializer. Check the `value` syntax below.

    ```
    { value: <number> }
    ```

    ```javascript theme={null}
    const P = require('bluebird');
    const express = require('express');
    const router = express.Router();
    const Liana = require('forest-express-mongoose');
    const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
    const moment = require('moment');

    ...

    router.post('/stats/mrr', (req, res) => {
      let mrr = 0;

      let from = moment.utc('2018-03-01').unix();
      let to = moment.utc('2018-03-31').unix();

      return stripe.charges
        .list({
          created: { gte: from, lte: to }
        })
        .then((response) => {
          return P.each(response.data, (charge) => {
            mrr += charge.amount;
          });
        })
        .then(() => {
          let json = new Liana.StatSerializer({
            value: mrr
          }).perform();

          res.send(json);
        });
    });

    ...

    module.exports = router;
    ```
  </Tab>

  <Tab title="Rails">
    When serializing the data, we use the `serialize_model()` method. Check the `value` syntax below.

    ```
    { value: <number> }
    ```

    ```ruby theme={null}
    Rails.application.routes.draw do
      # MUST be declared before the mount ForestLiana::Engine.
      namespace :forest do
        post '/stats/mrr' => 'charts#mrr'
      end

      mount ForestLiana::Engine => '/forest'
    end
    ```

    ```ruby theme={null}
    class Forest::ChartsController < ForestLiana::ApplicationController
      def mrr
        mrr = 0

        from = Date.parse('2018-03-01').to_time(:utc).to_i
        to = Date.parse('2018-03-31').to_time(:utc).to_i

        Stripe::Charge.list({
          created: { gte: from, lte: to },
          limit: 100
        }).each do |charge|
          mrr += charge.amount / 100
        end

        stat = ForestLiana::Model::Stat.new({ value: mrr })
        render json: serialize_model(stat)
      end
    end
    ```
  </Tab>
</Tabs>

<img src="https://mintcdn.com/forest-chore-open-api/TmGmEqoffYUVv4Df/images/legacy/javascript-agents/screenshot%202019-07-02%20at%2015.09.27.png?fit=max&auto=format&n=TmGmEqoffYUVv4Df&q=85&s=e28f4f1ee6a18fbe45f7128ccb598ec9" alt="" width="1920" height="969" data-path="images/legacy/javascript-agents/screenshot 2019-07-02 at 15.09.27.png" />

### Repartition API-based Chart

On our Live Demo, we have a `Charges` repartition chart which shows a repartition chart distributed by credit card country. This chart queries the Stripe API to get all charges made in the current month (in March for this example) and check the credit card country.

<Tabs>
  <Tab title="SQL">
    When serializing the data, we use the `Liana.StatSerializer()` serializer. Check the `value` syntax below.

    ```
    {
      value: [{
        key: <string> ,
        value: <number>
      }, {
        key: <string> ,
        value: <number>
      }, …]
    }
    ```

    ```javascript theme={null}
    const _ = require('lodash');
    const P = require('bluebird');
    const express = require('express');
    const router = express.Router();
    const Liana = require('forest-express-sequelize');
    const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
    const moment = require('moment');

    router.post(
      '/stats/credit-card-country-repartition',
      Liana.ensureAuthenticated,
      (req, res) => {
        let repartition = [];

        let from = moment.utc('2018-03-01').unix();

        let to = moment.utc('2018-03-20').unix();

        return stripe.charges
          .list({
            created: { gte: from, lte: to },
          })
          .then((response) => {
            return P.each(response.data, (charge) => {
              let country = charge.source.country || 'Others';

              let entry = _.find(repartition, { key: country });
              if (!entry) {
                repartition.push({ key: country, value: 1 });
              } else {
                entry.value++;
              }
            });
          })
          .then(() => {
            let json = new Liana.StatSerializer({
              value: repartition,
            }).perform();

            res.send(json);
          });
      }
    );

    module.exports = router;
    ```
  </Tab>

  <Tab title="Mongoose">
    When serializing the data, we use the `Liana.StatSerializer()` serializer. Check the `value` syntax below.

    ```
    {
      value: [{
        key: <string> ,
        value: <number>
      }, {
        key: <string> ,
        value: <number>
      }, …]
    }
    ```

    ```javascript theme={null}
    const _ = require('lodash');
    const P = require('bluebird');
    const express = require('express');
    const router = express.Router();
    const Liana = require('forest-express-mongoose');
    const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
    const moment = require('moment');

    router.post(
      '/stats/credit-card-country-repartition',
      Liana.ensureAuthenticated,
      (req, res) => {
        let repartition = [];

        let from = moment.utc('2018-03-01').unix();

        let to = moment.utc('2018-03-20').unix();

        return stripe.charges
          .list({
            created: { gte: from, lte: to },
          })
          .then((response) => {
            return P.each(response.data, (charge) => {
              console.log(charge.source);
              let country = charge.source.country || 'Others';

              let entry = _.find(repartition, { key: country });
              if (!entry) {
                repartition.push({ key: country, value: 1 });
              } else {
                entry.value++;
              }
            });
          })
          .then(() => {
            let json = new Liana.StatSerializer({
              value: repartition,
            }).perform();

            res.send(json);
          });
      }
    );

    module.exports = router;
    ```
  </Tab>

  <Tab title="Rails">
    When serializing the data, we use the `serialize_model()` method. Check the `value` syntax below.

    ```
    {
      value: [{
        key: <string> ,
        value: <number>
      }, {
        key: <string> ,
        value: <number>
      }, …]
    }
    ```

    ```ruby theme={null}
    Rails.application.routes.draw do
      # MUST be declared before the mount ForestLiana::Engine.
      namespace :forest do
        post '/stats/credit-card-country-repartition' => 'charts#credit_card_country_repartition'
      end

      mount ForestLiana::Engine => '/forest'
    end
    ```

    ```ruby theme={null}
    class Forest::ChartsController < ForestLiana::ApplicationController
      def credit_card_country_repartition
        repartition = []

        from = Date.parse('2018-03-01').to_time(:utc).to_i
        to = Date.parse('2018-03-20').to_time(:utc).to_i

        Stripe::Charge.list({
          created: { gte: from, lte: to },
          limit: 100
        }).each do |charge|
          country = charge.source.country || 'Others'

          entry = repartition.find { |e| e[:key] == country }
          if !entry
            repartition << { key: country, value: 1 }
          else
            ++entry[:value]
          end
        end

        stat = ForestLiana::Model::Stat.new({ value: repartition })
        render json: serialize_model(stat)
      end
    end
    ```
  </Tab>

  <Tab title="Laravel">
    ```
    {
      value: [{
        key: <string> ,
        value: <number>
      }, {
        key: <string> ,
        value: <number>
      }, …]
    }
    ```
  </Tab>
</Tabs>

<img src="https://mintcdn.com/forest-chore-open-api/TmGmEqoffYUVv4Df/images/legacy/javascript-agents/screenshot%202019-07-02%20at%2015.33.41.png?fit=max&auto=format&n=TmGmEqoffYUVv4Df&q=85&s=5615dee8bff51bf1e27d7cbc87d0a577" alt="" width="1920" height="969" data-path="images/legacy/javascript-agents/screenshot 2019-07-02 at 15.33.41.png" />

### Time-based API-based Chart

On our Live Demo, we have a `Charges` time-based chart which shows the number of charges per day. This chart queries the Stripe API to get all charges made in the current month (in March for this example) and group data by day.

<Tabs>
  <Tab title="SQL">
    When serializing the data, we use the `Liana.StatSerializer()` serializer. Check the `value` syntax below.

    ```
    {
      value: [{
        label: <string> ,
        values: { value: <number> }
      }, {
        label: <string> ,
        values: { value: <number> }
      }, …]
    }
    ```

    ```javascript theme={null}
    const _ = require('lodash');
    const P = require('bluebird');
    const express = require('express');
    const router = express.Router();
    const Liana = require('forest-express-sequelize');
    const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
    const moment = require('moment');

    router.post('/stats/charges-per-day', (req, res) => {
      let values = [];

      let from = moment.utc('2018-03-01').unix();
      let to = moment.utc('2018-03-31').unix();

      return stripe.charges
        .list({
          created: { gte: from, lte: to },
        })
        .then((response) => {
          return P.each(response.data, (charge) => {
            let date = moment.unix(charge.created).startOf('day').format('LLL');

            let entry = _.find(values, { label: date });
            if (!entry) {
              values.push({ label: date, values: { value: 1 } });
            } else {
              entry.values.value++;
            }
          });
        })
        .then(() => {
          let json = new Liana.StatSerializer({
            value: values,
          }).perform();

          res.send(json);
        });
    });

    module.exports = router;
    ```
  </Tab>

  <Tab title="Mongoose">
    When serializing the data, we use the `Liana.StatSerializer()` serializer. Check the `value` syntax below.

    ```
    {
      value: [{
        label: <string> ,
        values: { value: <number> }
      }, {
        label: <string> ,
        values: { value: <number> }
      }, …]
    }
    ```

    ```javascript theme={null}
    const _ = require('lodash');
    const P = require('bluebird');
    const express = require('express');
    const router = express.Router();
    const Liana = require('forest-express-mongoose');
    const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
    const moment = require('moment');

    router.post('/stats/charges-per-day', (req, res) => {
      let values = [];

      let from = moment.utc('2018-03-01').unix();
      let to = moment.utc('2018-03-31').unix();

      return stripe.charges
        .list({
          created: { gte: from, lte: to },
        })
        .then((response) => {
          return P.each(response.data, (charge) => {
            let date = moment.unix(charge.created).startOf('day').format('LLL');

            let entry = _.find(values, { label: date });
            if (!entry) {
              values.push({ label: date, values: { value: 1 } });
            } else {
              entry.values.value++;
            }
          });
        })
        .then(() => {
          let json = new Liana.StatSerializer({
            value: values,
          }).perform();

          res.send(json);
        });
    });

    module.exports = router;
    ```
  </Tab>

  <Tab title="Rails">
    When serializing the data, we use the `serialize_model()` method. Check the `value` syntax below.

    ```
    {
      value: [{
        label: <string> ,
        values: { value: <number> }
      }, {
        label: <string> ,
        values: { value: <number> }
      }, …]
    }
    ```

    ```ruby theme={null}
    Rails.application.routes.draw do
      # MUST be declared before the mount ForestLiana::Engine.
      namespace :forest do
        post '/stats/charges-per-day' => 'charts#charges_per_day'
      end

      mount ForestLiana::Engine => '/forest'
    end
    ```

    ```ruby theme={null}
    class Forest::ChartsController < ForestLiana::ApplicationController
      def charges_per_day
        values = []

        from = Date.parse('2018-03-01').to_time(:utc).to_i
        to = Date.parse('2018-03-31').to_time(:utc).to_i

        Stripe::Charge.list({
          created: { gte: from, lte: to },
          limit: 100
        }).each do |charge|
          date = Time.at(charge.created).beginning_of_day.strftime("%d/%m/%Y")
          entry = values.find { |e| e[:label] == date }
          if !entry
            values << { label: date, values: { value: 1 } }
          else
            ++entry[:values][:value]
          end
        end

        stat = ForestLiana::Model::Stat.new({ value: values })
        render json: serialize_model(stat)
      end
    end
    ```
  </Tab>

  <Tab title="Laravel">
    ```
    {
      value: [{
        label: <string> ,
        values: { value: <number> }
      }, {
        label: <string> ,
        values: { value: <number> }
      }, …]
    }
    ```
  </Tab>
</Tabs>

<img src="https://mintcdn.com/forest-chore-open-api/TmGmEqoffYUVv4Df/images/legacy/javascript-agents/screenshot%202019-07-02%20at%2015.38.29.png?fit=max&auto=format&n=TmGmEqoffYUVv4Df&q=85&s=9d8cd3b10200a27d9f77309ee8f3c039" alt="" width="1920" height="969" data-path="images/legacy/javascript-agents/screenshot 2019-07-02 at 15.38.29.png" />

### Objective API-based Chart

Creating an Objective Smart Chart means you'll be fetching your data from an external API endpoint:

<img src="https://mintcdn.com/forest-chore-open-api/l9oWVTFSA2iV8NAX/images/legacy/javascript-agents/image%20(361).png?fit=max&auto=format&n=l9oWVTFSA2iV8NAX&q=85&s=172d4ad13a07e6de8d812959dfdc2dcd" alt="" width="3345" height="1875" data-path="images/legacy/javascript-agents/image (361).png" />

This endpoint must return data with the following format:

```
{
  value: {
    value: xxxx,
    objective: yyyy
  }
}
```

Here's how you could implement it:

<Tabs>
  <Tab title="SQL">
    ```javascript theme={null}
    ​// [...]
    const Liana = require('forest-express-sequelize');
    ​
    // [...]
    ​
    router.post('/stats/some-objective', (req, res) => {
      // fetch your data here (a promise must be returned)
      .then(() => {
        let json = new Liana.StatSerializer({
          value: {
            value: fetchedValue,
            objective: fetchedObjective
          }
        }).perform();

        res.send(json);
      }
    }
    ```
  </Tab>

  <Tab title="Mongoose">
    ```javascript theme={null}
    ​// [...]
    const Liana = require('forest-express-mongoose');
    ​
    // [...]
    ​
    router.post('/stats/some-objective', (req, res) => {
      // fetch your data here (a promise must be returned)
      .then(() => {
        let json = new Liana.StatSerializer({
          value: {
            value: fetchedValue,
            objective: fetchedObjective
          }
        }).perform();

        res.send(json);
      }
    }
    ```
  </Tab>

  <Tab title="Rails">
    ```ruby theme={null}
    ...

    namespace :forest do
      post '/stats/some-objective' => 'customers#some_objective'
    end

    ...
    ```

    ```ruby theme={null}
    ...

    def some_objective
      # fetch your data here
      stat = ForestLiana::Model::Stat.new({
        value: {
          value: 10, # the fetched value
          objective: 678 # the fetched objective
        }
      })
      render json: serialize_model(stat)
    end

    ...
    ```
  </Tab>

  <Tab title="Laravel">
    ```
    {
      value: {
        value: xxxx,
        objective: yyyy
      }
    }
    ```
  </Tab>
</Tabs>
