com.atlassian.confluence.content.render.xhtml.migration.exceptions.UnknownMacroMigrationException: The macro 'next_previous_links' is unknown.

Enabling Monetization of APIs

WSO2 API Manager allows you to manage, govern and monetize APIs. You can specify throttling tiers and list the APIs that are available in the Gateway using the API Store. Subscribers who subscribe to the listed APIs and invoke them are billed based on the throttling tiers. To define a billing plan you need to define a new throttling tier in WSO2 API Manager.

Subscription workflow

To activate the subscription using throttling tiers, you need to use the WSO2 API Manager Subscription workflow. In the default workflow, subscriptions are automatically active. But when integrating with the billing engine, subscriptions are active if and only if the billing engine accepts the user. This behavior can be achieved by extending the default subscription workflow. When a subscriber tries to subscribe to an API after the subscription workflow is configured, they will be redirected to the billing engine for authentication with the API manager workflow details. Then the billing engine accepts the user or signs them up as a new user to the system. After the user enrollment is done by the billing engine it will redirect them back to the WSO2 API manager and activate the subscription. 

To configure the default subscription workflow, follow the instructions given in Implementing Workflow Extensions.

Configuring billing developer subscriptions

A developer can subscribe to an API, invoke it and get invoiced for it but avoid the bill payment. To stop this from happening there needs to be a mechanism that address this issue. With WSO2 API Manager subscriptions can be enabled and disabled at the publisher’s will. If the user doesn’t pay, the publisher can disable the subscription and re-enable it once the payment is made. This can be achieved in two ways.

  • To enable/disable subscriptions through the UI, login to the API Publisher and click the Manage Subscriptions tab

Controlling over exposure

Throttling tiers contain a Quota Reach Option, which might result in the gateway getting flooded with requests. You can use the Hard Level Throttling option to define the maximum number of requests per minute. For more information, see Setting Maximum Backend Throughput Limits

Configuring API Manager Analytics

You have to configure WSO2 API Manager Analytics in order to the billing engine to retrieve data. The API invocation related events are published to WSO2 APIM Analytics, which then persists all the events and makes them available in internal tables. You may also want summarized data sets based on the raw event data to help the billing engine work efficiently.

For details on how to configure WSO2 API Manager Analytics, see Configuring APIM Analytics.

Data retrieving model for monetization

Following are the events that are sent to WSO2 DAS:

  • org.wso2.apimgt.statistics.request

  • org.wso2.apimgt.statistics.response

  • org.wso2.apimgt.statistics.fault

  • org.wso2.apimgt.statistics.throttle

  • org_wso2_apimgt_statistics_destination

  • org.wso2.apimgt.statistics.workflow

For more information about the event details please refer Introducing the WSO2 API Manager Statistics Model.


Implement workflow extensions 

To configure the default subscription workflow, start a new maven project and create a new class named SubscriptionBillingWorkflow. Download the source code from here

 Expand to view the sample code...
/*
 *   Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *   WSO2 Inc. licenses this file to you under the Apache License,
 *   Version 2.0 (the "License"); you may not use this file except
 *   in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 *
 */
package org.wso2.sample.apimgt.workflow;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.apimgt.api.APIManagementException;
import org.wso2.carbon.apimgt.api.WorkflowResponse;
import org.wso2.carbon.apimgt.impl.APIConstants;
import org.wso2.carbon.apimgt.impl.APIManagerConfiguration;
import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO;
import org.wso2.carbon.apimgt.impl.dto.SubscriptionWorkflowDTO;
import org.wso2.carbon.apimgt.impl.dto.WorkflowDTO;
import org.wso2.carbon.apimgt.impl.workflow.*;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.sample.apimgt.dao.BillingDao;

import java.io.File;
import java.util.List;

public class SubscriptionBillingWorkflow extends WorkflowExecutor {

    private static final Log log = LogFactory.getLog(SubscriptionBillingWorkflow.class);

    private String billingEngineUrl;
    private String APIMStoreUrl;

    @Override
    public String getWorkflowType() {
        return "SubscriptionBillingWorkflow";
    }

    @Override
    public List getWorkflowDetails(String status) throws WorkflowException {
        return null;
    }

    @Override
    public WorkflowResponse execute(WorkflowDTO workflowDTO) throws WorkflowException {
        super.execute(workflowDTO);

        SubscriptionWorkflowDTO subsWorkflowDTO = null;
        boolean userExists = false;

        if (workflowDTO instanceof SubscriptionWorkflowDTO) {
            subsWorkflowDTO = (SubscriptionWorkflowDTO) workflowDTO;

            try {
                BillingDao billingDao = BillingDao.getInstance();
                userExists = billingDao.userExists(subsWorkflowDTO.getSubscriber());
            } catch (APIManagementException e) {
                log.error("Error occurred while accessing Database: " + e.getMessage(), e);
                throw new WorkflowException("Error occurred while accessing Database: " + e.getMessage(), e);
            }
        }

        if (!userExists) {
            loadDefaultConfig();
            HttpWorkflowResponse httpworkflowResponse = new HttpWorkflowResponse();
            httpworkflowResponse.setRedirectUrl(billingEngineUrl);
            httpworkflowResponse.setAdditionalParameters("CallbackUrl",
                    APIMStoreUrl + "/site/blocks/workflow/workflow-listener/ajax/workflow-listener.jag");
            httpworkflowResponse.setAdditionalParameters("workflowRefId", workflowDTO.getExternalWorkflowReference());
            httpworkflowResponse.setAdditionalParameters("reDirectUrl", APIMStoreUrl);
            httpworkflowResponse.setRedirectConfirmationMsg(
                    "You will be redirected to a page to setup your billing " + "account Information");
            return httpworkflowResponse;
        } else {
            ApiMgtDAO apiMgtDAO = ApiMgtDAO.getInstance();
            try {
                apiMgtDAO.updateSubscriptionStatus(Integer.parseInt(workflowDTO.getWorkflowReference()),
                        APIConstants.SubscriptionStatus.UNBLOCKED);
            } catch (APIManagementException e) {
                log.error("Could not complete subscription creation workflow", e);
                throw new WorkflowException("Could not complete subscription creation workflow", e);
            }
        }

        return new GeneralWorkflowResponse();
    }

    @Override
    public WorkflowResponse complete(WorkflowDTO workflowDTO) throws WorkflowException {
        workflowDTO.setUpdatedTime(System.currentTimeMillis());
        super.complete(workflowDTO);
        log.info("Subscription Creation [Complete] Workflow Invoked. Workflow ID : " + workflowDTO
                .getExternalWorkflowReference() + "Workflow State : " + workflowDTO.getStatus());

        ApiMgtDAO apiMgtDAO = ApiMgtDAO.getInstance();

        if (WorkflowStatus.APPROVED.equals(workflowDTO.getStatus())) {
            try {
                apiMgtDAO.updateSubscriptionStatus(Integer.parseInt(workflowDTO.getWorkflowReference()),
                        APIConstants.SubscriptionStatus.UNBLOCKED);
            } catch (APIManagementException e) {
                log.error("Could not complete subscription creation workflow", e);
                throw new WorkflowException("Could not complete subscription creation workflow", e);
            }
        } else if (WorkflowStatus.REJECTED.equals(workflowDTO.getStatus())) {
            try {
                apiMgtDAO.updateSubscriptionStatus(Integer.parseInt(workflowDTO.getWorkflowReference()),
                        APIConstants.SubscriptionStatus.REJECTED);
            } catch (APIManagementException e) {
                log.error("Could not complete subscription creation workflow", e);
                throw new WorkflowException("Could not complete subscription creation workflow", e);
            }
        }
        return new GeneralWorkflowResponse();
    }

    public void loadDefaultConfig() {
        APIManagerConfiguration configuration = new APIManagerConfiguration();
        String filePath = CarbonUtils.getCarbonHome() + File.separator + "repository" +
                File.separator + "conf" + File.separator + "api-manager.xml";
        try {
            configuration.load(filePath);
        } catch (APIManagementException e) {
            log.error("cannot find the congifuration file at: " + filePath, e);
        }

        billingEngineUrl = configuration.getFirstProperty("billingEngineUrl");
        APIMStoreUrl = configuration.getFirstProperty("APIStore.URL");

    }
}

Deploying the extended workflow

  1. Build the maven project (subs-billing-workflow in the source).

  2. Copy and paste the built jar into the <API-M home>/repository/component/lib folder.

  3. Log in to the WSO2 API Manager web console and browse the resources.

  4. Open the /_system/governance/apimgt/applicationdata/workflow-extensions.xml file. Replace the “SubscriptionCreation” tag with the value given in the example below

    <SubscriptionCreation executor="org.wso2.sample.apimgt.workflow.SubscriptionBillingWorkflow"/>

Configuring the billing engine

  1. Create a mysql database ‘billing’

  2. Get the sample billing engine provide for WSO2 API Manager from here

  3. Build the project and locate the war file.

  4. Deploy the war in the Tomcat container.

  5. Locate the deploy webapp and edit the <apim-billing-engine-home>/WEB-INF/classes/datasource.properties file as shown below

  6. Define the new billing plan
    You can define the following two different types of billing plans based on the WSO2 API Manager billing model
    • Subscription-based Usage Plan : Charges based on the subscription fee and fee per additional request.
      standard.png

    • Request-based Usage Plan : Charge a fixed fee per request
      usageplan.png

Install additional cApp

You can use this additional cApp to generate additional summary data used to feed the billing engine. The WSO2 DAS REST API was used to retrieve the data.

  1. Locate cApp from apim-billing-engine/src/main/resources/DAS-cApp/dist/APIM_Billing_2.0.0.car
  2. Login to WSO2 APIM Analytics web console
  3. Go to carbon-application section and deploy the downloaded cApp

Configuring WSO2 API Manager

  1. Define the data source for the billing engine. Since the workflow extension is used, define the billing engine user details data source configuration in the <API-M home>/repository/conf/datasources/master-datasources.xml file as given in the example below.

    <datasource>
      <name>BILLING_DB</name>
      <description>The datasource used for registry and user manager</description>
      <jndiConfig>
          <name>jdbc/BILLING_DB</name>
      </jndiConfig>
      <definition type="RDBMS">
          <configuration>
              <url>jdbc:mysql://localhost:3306/billing?autoReconnect=true&amp;</url>
              <username>root</username>
              <password>pass</password>
              <driverClassName>com.mysql.jdbc.Driver</driverClassName>
              <maxActive>50</maxActive>
              <maxWait>60000</maxWait>
              <testOnBorrow>true</testOnBorrow>
              <validationQuery>SELECT 1</validationQuery>
              <validationInterval>30000</validationInterval>
              <defaultAutoCommit>false</defaultAutoCommit>
          </configuration>
      </definition>
    </datasource>
    
    
    
  2. To configure the billing engine URL open the <API-M home>/repository/conf/api-manager.xml file and replace the value as given below

    <billingEngineUrl>http://localhost:8080/apim-billing-engine-1.0.0/app/main</billingEngineUrl>
  3. Since WSO2 API Manager is configured for monetization we can enable the API status as free or premium. To enable this flag edit the registry location <API-M home>/_system/config/apimgt/applicationdata/tenant-conf.json as shown below:
    1. To enable monetization set the “EnableMonetization” property to true.

    2. To define if the unlimited tier is paid, set the IsUnlimitedTierPaid property to true.

  4. Copy and paste the mysql jar to /repository/component/lib since the extension workflow uses the mysql connector.
  5. Enable Analytics by setting <Analytics> in api-manager.xml file

Deploy the extended workflow

  1. Build the maven project (subs-billing-workflow in the source).

  2. Copy and paste the built jar file into the <API-M_HOME>/repository/component/lib folder.

  3. Log in to the WSO2 API Manager web console and browse the resources.

  4. Edit the /_system/governance/apimgt/applicationdata/workflow-extensions.xml file.

  5. Find the SubscriptionCreation tag and replace it as shown below

    <SubscriptionCreation executor="org.wso2.sample.apimgt.workflow.SubscriptionBillingWorkflow"/>

Test the system

  1. Create a subscription tier in the Admin Portal. For instructions on creating a tier, see Adding a new subscription-level throttling tier.

    tier.png
  2. Deploy the sample API in the API Publisher
  3. Edit the sample API. Go to the Manage tab and select the new tier you have created in the previous step. Click Publish
  4. Go to the API Store and subscribe to the sample API. You will be re-directed to the billing engine. 

  5. Sign up using the billing engine. You will be re-directed to the Store with a successful subscription. 
  6. Log in to the billing engine once more, using your credentials.
  7. Create a new billing plan according to your subscription tier as shown below.
    standard.png
  8. Invoke the sample API from the API Publisher.
  9. Go to the billing engine and generate an invoice as shown below 

    You have to select the correct plan and the month in order to generate the invoice.

  10. Your invoice will be generated based on usage.
com.atlassian.confluence.content.render.xhtml.migration.exceptions.UnknownMacroMigrationException: The macro 'next_previous_links2' is unknown.