Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

Best Practice for Monetizing API Based on Service in Request Body (Single Service)

Amr
Bronze 5
Bronze 5

 

Dears, I hope you are doing well,

We are implementing Apigee Monetization (OPDK) and have a requirement where an API receives requests for different services, each with its own price. The requested service is passed in the body of the request, and each request contains only one service.

Here is the service-level pricing:

  • $8 per request for: OpenAccount, CloseAccount, SuspendAccount
  • $5 per request for: Login, Logout
  • $3 per request for: PersonalLoan, VehicleLoan

Example Request Format:

Show More
{
"id": "1",
"service": "OpenAccount"
}

We would like your recommendation on the best practice for implementing this pricing model using Apigee Monetization (OPDK), specifically how to:

  • Dynamically charge based on the service field in the request body
  • Apply the correct price based on the service name
  • Accurately track monetization metrics and usage per service

Note: This is only for POSTPAID developers.

We are open to any recommended architecture or implementation pattern, including usage of custom attributes, API product configurations, or rate plans.

Please advise on how to approach this requirement effectively. Let us know if additional context is needed.

Thank you,

Solved Solved
1 7 222
1 ACCEPTED SOLUTION

Hi @Amr 

I think you an accomplish what you want using a custom attribute in the Transaction Recording Policy of the Product Bundle. For example, I set a flow variable "delivered_count" to represent the count I want to use to multiply the rate from the rate plan in the response.

kurtkanaskie_0-1750689815823.png

My Rate Plan 

kurtkanaskie_1-1750689882719.png

Then in an Assign Message for my response I set the value of the "delivered_count" variable.

<AssignMessage async="false" continueOnError="false" enabled="true" name="AM-create-status-response">
    <DisplayName>AM-create-status-response</DisplayName>
    <AssignVariable>
        <Name>delivered_count</Name>
        <Value>5</Value>
    </AssignVariable>
    <Set>
        <Headers>
            <Header name="Content-Type">application/json</Header>
            <Header name="X-monetization-status">OK</Header>
        </Headers>
        <Payload contentType="application/json">
{
    "developerEmail":"{developer.email}",
    "application": "{verifyapikey.VA-header.developer.app.name}",
    "product": "{verifyapikey.VA-header.apiproduct.name}",
    "apiproxy": "{apiproxy.name}",
    "apiproxyRevision": "{apiproxy.revision}",
    "basepath": "{proxy.basepath}",
    "suffix": "{proxy.pathsuffix}",
    "message":"STATUS",
    "delivered_count":{delivered_count}
}
</Payload>
        <StatusCode>200</StatusCode>
        <ReasonPhrase>OK</ReasonPhrase>
    </Set>
</AssignMessage>

The result is that the developer will be charged 5 X $0.05 = $0.25 for this call.

In your use case, you could create a rate plan with a rate of $1.00 for a limited band and $1.00 for unlimited calls.

kurtkanaskie_2-1750690672651.png

Then set a flow variable (e.g. delivered_count) for each flow cost (e.g. 3, 5 and 8).

Hope that helps.

View solution in original post

7 REPLIES 7

Amr
Bronze 5
Bronze 5

Hi @dchiesa1 and @AlexET  I need your kind help.

Hi @Amr 

I think you an accomplish what you want using a custom attribute in the Transaction Recording Policy of the Product Bundle. For example, I set a flow variable "delivered_count" to represent the count I want to use to multiply the rate from the rate plan in the response.

kurtkanaskie_0-1750689815823.png

My Rate Plan 

kurtkanaskie_1-1750689882719.png

Then in an Assign Message for my response I set the value of the "delivered_count" variable.

<AssignMessage async="false" continueOnError="false" enabled="true" name="AM-create-status-response">
    <DisplayName>AM-create-status-response</DisplayName>
    <AssignVariable>
        <Name>delivered_count</Name>
        <Value>5</Value>
    </AssignVariable>
    <Set>
        <Headers>
            <Header name="Content-Type">application/json</Header>
            <Header name="X-monetization-status">OK</Header>
        </Headers>
        <Payload contentType="application/json">
{
    "developerEmail":"{developer.email}",
    "application": "{verifyapikey.VA-header.developer.app.name}",
    "product": "{verifyapikey.VA-header.apiproduct.name}",
    "apiproxy": "{apiproxy.name}",
    "apiproxyRevision": "{apiproxy.revision}",
    "basepath": "{proxy.basepath}",
    "suffix": "{proxy.pathsuffix}",
    "message":"STATUS",
    "delivered_count":{delivered_count}
}
</Payload>
        <StatusCode>200</StatusCode>
        <ReasonPhrase>OK</ReasonPhrase>
    </Set>
</AssignMessage>

The result is that the developer will be charged 5 X $0.05 = $0.25 for this call.

In your use case, you could create a rate plan with a rate of $1.00 for a limited band and $1.00 for unlimited calls.

kurtkanaskie_2-1750690672651.png

Then set a flow variable (e.g. delivered_count) for each flow cost (e.g. 3, 5 and 8).

Hope that helps.

Amr
Bronze 5
Bronze 5

Hi @kurtkanaskie ,

Thank you, and I appreciate your response.

I tried your solution as you did, but not work with me, and the transaction is counted as 1 SAR
Please find my configuration and code.

My rate card

rate-plan.png

 

My Product Transaction Recording Policy
TRP.png

My Custom Code 

Note: dataBioArray and bioArray are configured in KVM, which contains service names depending on the price.

 

// Get the service name from flow variable or query parameter
var serviceName = context.getVariable('serviceName');
var responseStatusCode = context.getVariable("response.status.code");
var responseContent = context.getVariable("response.content");
// Parse the JSON response
var jsonResponse = JSON.parse(responseContent);
var backEndCode = jsonResponse.random;

// Get the arrays from flow variables
var dataBioArray = JSON.parse(context.getVariable('dataBioArray') || '[]');
var bioArray = JSON.parse(context.getVariable('bioArray') || '[]');
var price= "1";
var requestStatus;

// Determine where the service exists using switch case
  if(responseStatusCode === 200 && (backEndCode !== null || backEndCode !== "")){
      
    switch (true) {
        case (dataBioArray.indexOf(serviceName) !== -1):
            price = "8";
            requestStatus = "OK";
            break;
            
        case (bioArray.indexOf(serviceName) !== -1):
           price = "3";
           requestStatus = "OK";
            break;
        default:
            break;
    }
}
context.setVariable('status', requestStatus);
context.setVariable('price', price);

 

 

Trace Variables

AX trace 2.pngAX trace 1.pngtrace.png

My report shows that the transaction price is not like what you mentioned above
Custom price * Flat rate price = 1 * 8
It only shows a flat rate price, which is = 1

report.png

Best Regards,

Hi @kurtkanaskie,
After investigation of the above solution,

Issue Identified:
During the configuration of the Transaction Recording Policy, it was discovered that the correct implementation requires the following sequence:

  1. Adding a Custom Attribute – First, a custom attribute must be defined within the Transaction Recording Policy.

  2. Package Creation – Subsequently, a package must be created with both a rate plan and a rate card that includes the custom attribute.

Root Cause:
The initial attempt failed because the rate plan was created before selecting the appropriate rate card containing the custom attribute. As a result, the system did not display the correct rate card in the selection interface, leading to an incomplete configuration.

Corrective Action:
To ensure proper implementation, the following sequence must be followed:

  1. Add a custom attribute in Transaction Recording Policy

  2. Create package

  3. Create Rate Plan

  4. Create/Select Rate Card with custom attribute

Verification:
Refer to the attached screenshot for the correct selection of the rate card with the custom attribute.

RC.png

Best Regards,

Amr

That's good news!
Looks like the new UI in my Edge SaaS org doesn't support selecting that rate card type, so I must have used the Classic UI back then.

kurtkanaskie_0-1750884119377.png

 

If I was you, I'd scrap your current approach and look at exposing those services following a restful API approach instead. This makes it easier for your consumers to consume, will give you better support for out of the box analytics and monitoring. Additionally if for example, you plan to group sets of resources or subresources as API products you'll be able to do that - with your current approach you cannot. This will probably also simplify your monetization management since you seem to already have groups of services with the same rate.

Hi @dknezic ,

Thank you for your response, and I hope you are doing well.

We already have more than 100 clients using this API, and Apigee has come on board after the services are completed in 3 years. Therefore, we can't change the implementation of the API; we only add Apigee for monetization purposes.