End-to-End API Monetization with .NET, Stripe, and Moesif
Many API developers and companies struggle to find ways to easily set up systems to monetize their APIs. Some are simple but not customizable, some are complex and require massive engineering effort to actually get it all running.
To make things easier, Moesif created a feature a few months ago called Billing Meters which gives massive customizability but with a minimal amount of code and engineering effort.
For this example, which could actually be used out of the box, we will use Moesif, a .Net 7 Minimal API, and Stripe to charge users for API usage. For this setup there are a few assumptions:
- A working .NET Core installation
- We will be using .Net Core 7
SDK
version 7.0.302AspNetCore
7.0.5NETCore
7.0.5
- We will be using .Net Core 7
- You have an active Stripe account
- You have an active Moesif account
The setup is pretty simple from the outside. We will create a /register endpoint which:
- Registers a user in Stripe
- Subscribes that user to a product
- Registers the User and Company in Moesif
- Create a JWT to authenticate/authorize calls to our monetized endpoint
1 - Create Your Product and Price in Stripe
The first step we will take is to create a product and price in Stripe. It’s best to do this step first because then when you integrate Stripe into Moesif you’ll already have some pricing plans for Moesif to pull in. A pricing plan can then be associated with specific billing criteria set up within a Billing Meter in Moesif.
To create a product and price, log into Stripe and proceed to the Products page in the Stripe UI. Once there, click on the + Add Product button in the top right corner.
You’ll then be able to add in the details for your product and price(s) for it. The form for your product will have a few fields to fill out.
Product Information
Name
- This is the name of your product. In the example below, we use the name “My API”.
Description
- This field is optional but you could put a brief description of the product here. In the example below, we use a description of “This is a monetized API”.
Image
- Optionally upload an image that can help you easily recognize a item on the Products page. We’ll be using the default placeholder image in this example.
Pricing Information
Pricing model
A few different pricing modals can be set up in Stripe. These pricing models include:
- Standard pricing
- Use this if you want to charge the same price for each API call.
- Package pricing
- Use this if you charge for API usage by the package, or a group of units. For example, you could set it up to charge $10 for every 1000 API calls. Every time the user goes over the 1000 API call threshold, they are charged another $10.
- Graduated pricing
- Use graduated pricing tiers that may result in a different price for some units in an order. For example, you might charge $10.00 per unit for the first 100 units and then $5.00 per unit for the next 50. Today, this is only available for recurring prices.
- Volume pricing
- Use if you charge the same price for each unit based on the total number of units sold. For example, you might charge $10.00 per unit for 50 units, and $7.00 per unit for 100 units.
Price
Depending on the pricing model selected, prices can be set in this field.
Billing period
The billing period can be set as:
- Daily
- Weekly
- Monthly
- Every 3 months
- Every 6 months
- Yearly
- Customer
For your configuration with Moesif, we recommend setting the billing period as Monthly. We also recommend that if you are using Moesif’s Billing Meter feature check the Usage is metered box as well.
Charge for Metered Usage by
Once the Usage is metered checkbox is selected, the option for charge for metered usage by will appear. This field lets you choose how metered usage will be calculated and charged for. Values available for this field are:
- Sum of usage values during period
- Users are charged for their usage recorded throughout the billing cycle
- Most recent usage value during period
- Users are charged based on the last usage recorded before the billing period ended
- Most recent usage value
- Users are charged for the last usage recorded throughout the subscription’s life at the end of each billing cycle
- Maximum usage value during period
- Users are charged for the highest amount recorded during the billing cycle
Optimal setup for a Moesif Billing Meter is to set this value as Sum of usage values during period since usage is reported hourly by Moesif to Stripe
Price description
This is an optional field but recommended. Here you can put a brief description of your price. This will allow you to more easily decipher which price you are selecting in the billing meter in Moesif, especially if you have multiple prices for a single product.
Once you’ve input all of the details for your product and price, you can click Save product in the top right corner of the screen.
As you create products, you will be able to view and edit them on the products screen.
2 - Enable the Moesif-Stripe Integration
Once your products and prices are created, it’s time to begin to integrate Stripe with Moesif. To begin configuring Stripe in Moesif, go to the Billing Meters page and click the Edit Billing Provider dropdown in the top right corner of the screen.
This will bring up the Stripe configuration screen walking you through the integration. From this screen, you can get all of the info needed to plug Stripe into Moesif. Each step for configuration is covered within the modal.
Add the Moesif Webhook to Stripe
The first step in the integration is to add the Moesif webhook into the configuration in Stripe. Adding this allows Stripe to send subscription updates to Moesif.
To add the Moesif webhook to Stripe, from the upper right-hand side click on Developers, and then Webhooks in the left-side menu. This will bring you to the Webhooks page where you can view existing webhooks and add new ones. To add a new webhook we will click the Add an endpoint button at the bottom of the screen.
From here, we will plug in our Moesif API endpoint URL and configure the events to listen to. You’ll want to copy your Moesif Webhook URL into the Endpoint URL field and then click the + Select Events button.
These details can all be found on the Stripe configuration page in Moesif mentioned in the previous section.
You should select the option under Customer for Select all Customer events. After this, click the Add events button at the bottom of the screen.
After this, you’ll be returned back to the original screen where you added the endpoint details. Scroll to the bottom of the screen and click Add endpoint to save the endpoint to Stripe.
Plug the Stripe API Details into Moesif
For Moesif to add usage quantities to subscriptions in Stripe, we need to add the Stripe API details into Moesif. This is done in the Stripe configuration screen in Moesif, the same screen we’ve been working with previously.
Currently, Moesif only supports version 2020-08-27 of the Stripe API so that field defaults for the Stripe API Version field.
For the Stripe API Key field, you’ll need to retrieve the API key from Stripe to plug it in. From the Developers screen, the same one we used in the previous step, you’ll click on API Keys. You’ll then be able to see the private key for your API in either the Secret key or a generated Restricted keys field on the screen. Either key can be used.
After copying the key from Stripe, you’ll paste this key into the Stripe API Key field back in Moesif. After doing this, back in Moesif you can scroll down to the bottom of the screen and click Save to save the configuration.
Optionally, you have the ability to customize the company_id in Moesif as well. The default should work fine for most purposes. However, you can fully customize it to specify how to map Stripe Subscription and Customer objects to Subscription ID and Company ID in Moesif respectively:
- A Stripe Customer maps to Moesif Company.
- A Stripe Subscription maps to a Moesif Subscription.
3 - Create a Billing Meter
Once you have the Stripe integration active in Moesif, you can begin to set up your billing meter. Billing meters created in Moesif do two things: track usage based on specific criteria and report that usage to the billing provider. Moesif allows you to set up very simple and very complex billing meters with relative ease.
To create the Billing Meter, in Moesif you will navigate to the Billing Meter screen. You can do this from the left-side menu. On the Billing Meter’s screen, you’ll then click + Add Billing Meter in the top-right corner of the screen.
The next screen is where you can actually input the criteria for your Billing Meter.
Fields on this screen include:
-
Billing Meter Name
- This is the Moesif internal name of your new Billing Meter
-
Billing Provider
- In this dropdown you can choose the billing provider you want to send your usage metrics to.
-
Product (Stripe only)
- Here you can choose which Product that you’ve set up in Stripe you want your usage metrics to be tied to.
-
Price (Stripe only)
- The last field in the Billing Provider settings for the Billing Meter, here you will choose which Price you want to tie your usage metrics to.
-
Filters
- Under the Filters configuration, you will configure your billing criteria to only include requests that fit a certain criteria.
-
Metrics
- Here you can choose which metric you would like to bill on. Available options include:
-
Event Count
- This will increment usage for every event that fits the criteria outlined in the Filter criteria.
-
Unique Users
- This will increment usage whenever a unique user sends a request that fits the Filter criteria. For every unique user, the count will be incremented by 1 regardless of the event count for that user.
-
Unique Companies
- This will increment usage whenever a unique company sends a request that fits the Filter criteria. For every unique company, the count will be incremented by 1 regardless of the event count for that company.
-
Unique Sessions/API Keys
- This will increment usage whenever a unique session or API key is used to send a request that fits the Filter criteria. For every unique session or API key, the count will be incremented by 1 regardless of the event count for that particular session or API key.
There are other options under Metrics as well but the above 4 tend to be the most applicable to usage-based billing.
As an example, for this guide we will create a Billing Meter that will filter traffic for a single endpoint, named /test-service
, and where requests received a successful HTTP 200 response. We will use the Event Count metric to make sure that every request is added to the tally and sent to the billing provider.
In Moesif, the billing meter will be configured as shown below.
We will then click Create. This will create and activate the Billing Meter. A modal will appear notifying you that the billing meter has been created and presents a walk-through to ensure the meter is correctly configured.
First, we will set up a flow to get users registered, subscribed, and create a JWT so they can use our monetized API. Once that is complete we will come back and proceed with the walk-through.
4 - Creating the API
Instead of using a pre-built onboarding flow, such as through a Developer Portal within an API gateway, we will build our own. We will create an endpoint called /register which we can then use to onboard our users who want to use the API. The result will be that the user receives a JWT that they can use that will track their usage.
Since we are using Moesif, Stripe, and .Net Core as part of our overall solution, we need to make sure each of the components is working together properly.
Here’s what the endpoint will do:
- Create a customer in Stripe
- Subscribe the new customer to the API subscription in Stripe
- Create the CompanyID in Moesif (which will be the Stripe subscription ID)
- Create the UserID in Moesif (which will be the Stripe Customer ID)
- Create a JWT with a
sub
field that contains the Stripe Customer ID
If you already have User and Company identifiers in Moesif and other systems that you want to use, instead of using Stripe’s customer and subscription as your IDs, you can do that in Moesif under the Stripe configuration settings.
In this example, we will create a simple .Net 7 Minimal API to do the above.
Creating the .Net 7 Project
We’ll be using the .NET cli tool to create our initial project. The .NET command line interface provides the ability to develop, build, run, and publish .NET applications.
The .NET cli new
command provides many templates to create your project. You can also add the search
command to find community-developed templates from NuGet or use dotnet new list
to see available templates provided by Microsoft.
We’ll be creating a Minimal API and starting from as clean a slate as possible. We’ll be using the empty ASP.NET Core template. In the directory of your choosing; enter the following in the terminal:
dotnet new web
You’ll notice that the directory structure will look something like this:
We’ll be doing all of our work in the Program.cs
file. Its starting code should look similar to the following:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
We can see how concise and readable our starter code is. Let’s break down the code provided by the template line by line:
- The
WebApplication.CreateBuilder(args)
method creates a new instance of theWebApplicationBuilder
class, which is used to configure and build theWebApplication
instance. The args parameter is an optional array of command-line arguments that can be passed to the application at runtime. - The
builder.Build()
method is called to create a new instance of theWebApplication
class, which represents the running application. This instance configures the application, defines routes, and handles requests. - The third line defines a route for the root path (“/”) of the application using the
app.MapGet()
method. This means that when the root path is requested, the application will respond with the string “Hello World!”. - We start the application by calling the
app.Run()
method.
Using the builder pattern, we can configure and customize the WebApplication
instance. This allows us to define the application’s behavior, including middleware, routes, and other settings, in a structured and extensible way. For example, the WebApplication
instance created by the builder can be thought of as the “entry point” of the application, which handles requests and generates responses.
Overall, this code block creates a simple Minimal API in .NET 7 that responds with a “Hello World!” message when the application’s root path is requested.
Next, we’ll customize our API to provide /register
and /test-service
endpoints.
Adding Project Dependencies
We will install the Moesif Middleware using the NuGet package manager. Enter the following in your terminal while in the correct directory:
dotnet add package Moesif.Middleware Stripe.net System.IdentityModel.Tokens.Jwt
Our <ProjectName>.csproj
will be updated to reflect the newly added NuGet package.
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Moesif.Middleware" Version="1.3.20" />
<PackageReference Include="Stripe.net" Version="41.16.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.30.1" />
</ItemGroup>
</Project>
Run the following command to ensure your project builds correctly.
dotnet build
Your dependencies will be brought into the project and compiled if necessary. The Moesif.Middleware
dependency is what allows us to connect to Moesif.
Adding the Moesif Integration Code
First, we’ll add some configuration details into our appsettings.json
file. It’s here we can define various options like our application ID, whether or not to log the body of a request, or enable local debugging. Enter the following, editing as you see fit:
{
"MoesifOptions": {
"ApplicationId": "YOUR_MOESIF_APPLICATION_ID",
"LocalDebug": false,
"LogBody": true,
"LogBodyOutgoing": true,
"ApiVersion": "1.1.0",
"EnableBatching": true,
"BatchSize": 25
},
...
}
Obtaining Your Moesif Application ID
Your Moesif application ID is found in Moesif by going to the menu link in the bottom-left of the screen (which will show your name) and selecting API Keys.
The key will then be on the page that appears under Collector Application Id.
Creating Moesif Options
Next, we’ll create a file to host all of our Moesif middleware implementations. We’ll create a folder called Settings
and create a file within it called MoesifOptions.cs
.
Don’t be intimidated by the wall of code. This file includes a fair amount of boilerplate. We don’t need to edit this at all right now, but it will be useful to have in the future if you wish to enable more features in Moesif.
// MoesifOptions.cs
namespace ProjectName.Settings
{
public class MoesifOptions
{
private readonly IConfiguration _config;
public MoesifOptions(IConfiguration config)
{
_config = config;
}
public static Func<HttpRequest, HttpResponse, string> IdentifyUser = (HttpRequest req, HttpResponse res) => {
// Implement your custom logic to return user id
return req.HttpContext?.User?.Identity?.Name;
};
public static Func<HttpRequest, HttpResponse, string> IdentifyCompany = (HttpRequest req, HttpResponse res) => {
return req.Headers["X-Organization-Id"];
};
public static Func<HttpRequest, HttpResponse, string> GetSessionToken = (HttpRequest req, HttpResponse res) => {
return req.Headers["Authorization"];
};
public static Func<HttpRequest, HttpResponse, Dictionary<string, object>> GetMetadata = (HttpRequest req, HttpResponse res) => {
Dictionary<string, object> metadata = new Dictionary<string, object>
{
{"string_field", "value_1"},
{"number_field", 0},
{"object_field", new Dictionary<string, string> {
{"field_a", "value_a"},
{"field_b", "value_b"}
}
}
};
return metadata;
};
public static Func<HttpRequestMessage, HttpResponseMessage, Dictionary<string, object>> GetMetadataOutgoing = (HttpRequestMessage req, HttpResponseMessage res) => {
Dictionary<string, object> metadata = new Dictionary<string, object>
{
{"string_field", "value_1"},
{"number_field", 0},
{"object_field", new Dictionary<string, string> {
{"field_a", "value_a"},
{"field_b", "value_b"}
}
}
};
return metadata;
};
public Dictionary<string, object> getMoesifOptions()
{
Dictionary<string, object> moesifOptions = new Dictionary<string, object>
{
{MoesifOptionsParamNames.ApplicationId, getConfigString(MoesifOptionsParamNames.ApplicationId)},
{MoesifOptionsParamNames.LocalDebug, getConfigBool(MoesifOptionsParamNames.LocalDebug)},
{MoesifOptionsParamNames.LogBody, getConfigBool(MoesifOptionsParamNames.LogBody)},
{MoesifOptionsParamNames.LogBodyOutgoing, getConfigBool(MoesifOptionsParamNames.LogBodyOutgoing)},
{MoesifOptionsParamNames.ApiVersion, getConfigString(MoesifOptionsParamNames.ApiVersion)},
{MoesifOptionsParamNames.EnableBatching, getConfigBool(MoesifOptionsParamNames.EnableBatching)},
{MoesifOptionsParamNames.BatchSize, getConfigInt(MoesifOptionsParamNames.BatchSize)},
{MoesifOptionsParamNames.IdentifyUser, IdentifyUser},
{MoesifOptionsParamNames.IdentifyCompany, IdentifyCompany},
{MoesifOptionsParamNames.GetSessionToken, GetSessionToken},
{MoesifOptionsParamNames.GetMetadata, GetMetadata},
{MoesifOptionsParamNames.GetMetadataOutgoing, GetMetadataOutgoing}
};
return moesifOptions;
}
public string getConfigString(string paramName)
{
return _config.GetValue<string>(MoesifOptionsParamNames.asKey(paramName));
}
public bool getConfigBool(string paramName)
{
return _config.GetValue<bool>(MoesifOptionsParamNames.asKey(paramName));
}
public int getConfigInt(string paramName)
{
return _config.GetValue<int>(MoesifOptionsParamNames.asKey(paramName));
}
public bool isConfiguredMoesifApplicationId()
{
string appId = null;
try
{
appId = (string)getMoesifOptions().GetValueOrDefault(MoesifOptionsParamNames.ApplicationId);
}
catch (Exception ex)
{
Console.WriteLine("Error Reading Moesif Application Id in appsettings(.env).json: " + ex.Message);
}
return !string.IsNullOrWhiteSpace(appId) && !appId.StartsWith("<");
}
}
public class MoesifOptionsParamNames
{
// Read from appsettings.json
public static string Key = "MoesifOptions";
// Read from appsettings.json
public static string ApplicationId = "ApplicationId";
// Read from appsettings.json
public static string LocalDebug = "LocalDebug";
// Read from appsettings.json
public static string LogBody = "LogBody";
// Read from appsettings.json
public static string LogBodyOutgoing = "LogBodyOutgoing";
// Read from appsettings.json
public static string ApiVersion = "ApiVersion";
// Read from appsettings.json
public static string EnableBatching = "EnableBatching";
// Read from appsettings.json
public static string BatchSize = "BatchSize";
public static string IdentifyUser = "IdentifyUser";
public static string IdentifyCompany = "IdentifyCompany";
public static string GetSessionToken = "GetSessionToken";
public static string GetMetadata = "GetMetadata";
public static string GetMetadataOutgoing = "GetMetadataOutgoing";
public static string asKey(string suffix)
{
return Key + ":" + suffix;
}
}
}
In this file we define our configuration of the Moesif middleware. We can also define details that can enable user and company tracking, add custom metadata that will be associated with an event, and add the ability to skip certain events entirely.
Configuring the Initial Project
We’ll jump over to our Program.cs
file to enable the Moesif middleware, configure our Stripe and Moesif API clients, and define our /register
and /test-service
endpoints. First, we’ll import a couple namespaces into our project. Next, after our builder
declaration, we will configure ASP.NET’s Kestrel server to allow synchronous operations. We configure our Stripe and Moesif API clients in order to create our products and customers within Stripe as well as our users and subscriptions within Moesif. We also configure our Moesif Middleware which forwards events to Moesif.
using System.Text;
using System.Text.Json;
using System.Security.Claims;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using Moesif.Middleware;
using Moesif.Api;
using Moesif.Api.Models;
using Stripe;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.AllowSynchronousIO = true;
});
StripeConfiguration.ApiKey = "YOUR_STRIPE_API_KEY";
var apiClient = new MoesifApiClient("YOUR_MOESIF_APPLICATION_ID").Api;
var app = builder.Build();
var moesifOptions = new ProjectName.Settings.MoesifOptions(app.Configuration);
app.UseMiddleware<MoesifMiddleware>(moesifOptions.getMoesifOptions());
Obtaining Your Stripe API and Price Key
You will see in the code example above that we need to provide a secret or restricted key for our createCustomer
and createSubscription
methods.
Your Stripe API Key can be found in the same place we grabbed the key for our Stripe and Moesif integration we did earlier for the Billing Meter. You can actually use the same key for both or create a restricted key with just the scope needed for each function.
While we’re at it, lets grab our Stripe product’s price
key. We will need it in the next section. Your Stripe price key is an identifier for the price you created earlier in Stripe. This can be found by going to the product in Stripe and grabbing the value from the API ID column.
Take note of the price key. We will be using it next.
Creating the Test Service and Registration Endpoint
Next, we’ll define our /test-service
and /register
endpoints.
...
app.MapGet("/test-service", () => "Hello World!");
app.MapPost("/register", async context =>
{
var json = await JsonDocument.ParseAsync(context.Request.Body);
var email = json.RootElement.GetProperty("email").GetString();
var firstName = json.RootElement.GetProperty("firstname").GetString();
var lastName = json.RootElement.GetProperty("lastname").GetString();
try
{
// create Stripe customer
var customerId = CreateStripeCustomer(email, firstName, lastName);
var subscriptionId = CreateStripeSubscription(customerId, "YOUR_PRICE_KEY");
// create jwt for user using customerId
var token = GenerateAccessToken(customerId);
var moesifCompanyResponse = CreateMoesifCompany(subscriptionId);
var moesifUserResponse = CreateMoesifUser(customerId, subscriptionId, email, firstName, lastName, token);
context.Response.StatusCode = 200;
await context.Response.WriteAsJsonAsync(new { jwt = token });
}
catch (Exception ex)
{
context.Response.StatusCode = 500;
await context.Response.WriteAsync($"An error occurred: {ex.Message}");
}
});
Our /test-service
endpoint returns a simple string.
The /register
endpoint utilizes several helper functions and where is most of the work happens. We extract our users name and email from the body of the request then creates a customer and subscription within Stripe returning the necessary identifiers as well as passing along a price key that we got in the previous step. A JWT is then created using the customer identifier and finally passes all this data along to CreateMoesifCompany
and CreateMoesifUser
to create a company and user within Moesif. The JWT is passed along in the response we get from the call to the /register
endpoint which we will use as the bearer token in our call to the /test-service
endpoint.
Creating our Helper Functions
Next’ we’ll define all the helper functions that are used in the /register
call.
...
string GenerateAccessToken(string id)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes("RANDOM_256_BIT_STRING");
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim("sub", id)
}),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
try
{
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred while creating the JWT: {ex.Message}");
throw;
}
}
GenerateAccessToken
takes an id parameter, which will be our customerID, and returns a JWT token as a string. The method creates a JwtSecurityTokenHandler
object, generates a key which requires a 256 bit string, creates a SecurityTokenDescriptor
object, and creates a JWT token using the CreateToken
method of the JwtSecurityTokenHandler
class. If an exception is thrown while creating the token, the catch block will catch the exception and log an error message to the console. Finally, the method returns the JWT
token as a string.
...
string CreateStripeCustomer(string email, string firstname, string lastname)
{
try
{
var customerOptions = new CustomerCreateOptions
{
Email = email,
Name = $"{firstname} {lastname}",
Description = "Customer created through /register endpoint"
};
var customerService = new CustomerService();
var customer = customerService.Create(customerOptions);
return customer.Id;
}
catch (Exception ex)
{
return $"An error occurred while creating Stripe customer: {ex.Message}";
}
}
string CreateStripeSubscription(string customerID, string plan) {
try
{
var subscriptionOptions = new SubscriptionCreateOptions
{
Customer = customerID,
Items = new List<SubscriptionItemOptions>
{
new SubscriptionItemOptions
{
Price = plan
}
}
};
var subscriptionService = new SubscriptionService();
var subscription = subscriptionService.Create(subscriptionOptions);
return subscription.Id;
}
catch (Exception ex)
{
return $"An error occurred while creating Stripe subscription: {ex.Message}";
}
}
Next, we define the helper functions that create our Customer and Subscription within Stripe.
The CreateStripeCustomer
method takes three parameters: email
, firstname
, and lastname
. It creates a new Stripe customer using the CustomerCreateOptions
object. It then returns the ID
of the newly created customer. If an exception is thrown while creating the customer, the catch block will catch the exception and return an error message that includes the exception message.
The CreateStripeSubscription
method takes two parameters: customerID
and plan
. It creates a new Stripe subscription using the SubscriptionCreateOptions
object, which contains the customer ID and the ID of the price plan. It then returns the ID of the newly created subscription. Again, if an exception is thrown while creating the subscription, the catch block will catch the exception and return an error message that includes the exception message.
...
string CreateMoesifUser(string customerId, string subscriptionId, string email, string firstname, string lastname, string jwt)
{
try
{
var metadata = new Dictionary<string, object>
{
{"email", $"{email}"},
{"first_name", $"{firstname}"},
{"last_name", $"{lastname}"},
{"metadata", new Dictionary<string, object>
{
{"jwt", $"{jwt}"},
}
}
};
var user = new UserModel()
{
UserId = customerId,
CompanyId = subscriptionId,
Metadata = metadata
};
apiClient.UpdateUser(user);
return "User information updated successfully.";
}
catch (Exception ex)
{
return $"An error occurred while updating user information: {ex.Message}";
}
}
string CreateMoesifCompany(string subscriptionId)
{
try
{
var company = new CompanyModel()
{
CompanyId = subscriptionId,
};
apiClient.UpdateCompany(company);
return "Company information updated successfully.";
}
catch (Exception ex)
{
return $"An error occurred while updating company information: {ex.Message}";
}
}
The CreateMoesifUser
method takes six parameters: customerId
, subscriptionId
, email
, firstname
, lastname
, and jwt
. It creates a new Dictionary object that contains the user’s email, first name, last name, and JWT token. It then creates a new UserModel
object that contains the user’s ID, company ID, and metadata, and updates the user’s information using the UpdateUser
method of the apiClient
object.
The CreateMoesifCompany
method takes one parameter: subscriptionId
. It creates a new CompanyModel
object that contains the company’s ID, and updates the company’s information using the UpdateCompany
method of the apiClient
object.
Finally, we’ll make sure we include the method that actually runs the application:
...
app.Run();
With our code written, run the following command to compile and run our project:
dotnet run
The API is now operational and ready for testing. After running the previous command, you will see which port has been used to host your API in the console. You can define which port you would like to use by editing the Properties > launchSettings.json
file or by adding editing the app.Run()
command in Program.cs
like so, replacing 3000 with your desired port number:
app.Run("http://localhost:3000");
If you are having issues with dependencies building, try:
dotnet clean && dotnet build && dotnet run
5 - Send a Test Request to the /register Endpoint
Once your /register endpoint has been coded and deployed, it’s time to test it. For right now we will simply use Postman to send a request. Our request will contain a JSON request body that will contain a:
- First name
- Last name
Of course, this is the minimal amount of information we would want to configure our system and profiles in Stripe and Moesif, plus, generate the JWT. You can easily add more fields as needed for your specific use case.
In Postman, we will create our request with the following information:
Request Type: POST
Endpoint URL: http://localhost:{port}/register
Request Body:
{
"firstname": "Userfirstname",
"lastname": "Userlastname",
"email": "test@test.com"
}
Replace port in your endpoint URL with the assigned port number.
Once everything is plugged into Postman, it should look like the following:
Once the request is sent, the response should contain an JWT that the newly registered user can use.
We will now check Stripe to ensure that the information we registered the customer with is correctly entered into Stripe.
Logging back into Stripe, you’ll navigate to Customers screen. You should see your newly created user in the list.
Click on the newly added customer in the list. On the next screen, you should see that the customer is also subscribed to your APIs subscription.
With this check completed, we can safely assume that our /register endpoint is correctly setting up our users accounts and subscriptions in Stripe.
6 - Call Your API Using the Generated JWT
Our next step is to actually use our generated JWT. We will then confirm that all the correct information is added into Moesif. The data we are confirming includes:
- The Stripe Customer ID is mapped to the Moesif User ID
- The Stripe Subscription ID is mapped to the Moesif Company ID
- Moesif contains the Stripe metadata in the users profile
Use Postman to Send the Request
Next, let’s use Postman, or another platform, to send a request to the /test-service endpoint. This is the endpoint that we set up the billing meter for in Step 3, above.
In Postman, we will:
- Put the /test-service API endpoint as the request URL
- Select the Authorization tab
- Select the Type as Bearer Token
- Populate the token details
- Set the Token as the JWT received from our /register call
Below is an example of the populated request configuration in Postman. To send the request to our endpoint, click Send.
Once sent, the API call analytics should land in Moesif.
Confirm That Moesif Received the Request Info Using Profile Dashboards
Back in Moesif, you’ll navigate to the Live Event Log screen. You can do this by clicking the New button and selecting Live Event Log.
On this screen, you should see the request you just sent. You should see the entry has both a User ID and Company ID populated with the Stripe user and subscription ID’s. The entries should look like this:
The customer ID will look like “cus_XXXX” and the subscription ID will look like “sub_XXXX”.
If you click on the User ID shown in the entries on the Live Event Log screen, you will come to the users profile page. On this page, we will confirm that the Stripe metadata is present. We will need to add a new column to our profile to display the Stripe data. To do this, from the profile page, click on the … More Actions button and click Customize Profiles’ Layout.
We will then add a new column for the Stripe metadata. You will click the + button on the far right of the screen to create a new column where we will add the Stripe metadata.
You may need to scroll to the right to see it depending on your resolution and screen size to see the + button.
You will then drill down to Metadata > stripe > customer > created and use this field in the new row. I’ve also changed the column image to one more fitting. You can customize this by clicking on the image and selecting whichever one fits best.
You can also add other fields, but for right now just this single field is enough to tell us that Moesif is correctly receiving data from Stripe.
If you don’t see the Stripe metadata entry as an available field, wait a few minutes. If after a few minutes the Stripe metadata isn’t present, ensure that your Stripe configuration is correct in Moesif. After confirming or editing it, try creating a new user and sending a request again to confirm that the integration is working.
At this point, we now have confirmed that our API call is working and is stamped with the correct user and company details in Moesif. We also confirmed that Stripe is sending data back to Moesif which is correctly being mapped to the corresponding user profile, confirmed through the Stripe metadata in Moesif.
7 - Send a Request to Your Monetized API
We will once again want to make sure that everything is working with our UI, through to our backend systems. For this, simply repeat the steps from Step 6 to confirm that the user and company IDs are populated correctly and that the Stripe metadata is returned for this user and the new JWT. We should see these calls populated within our Live Event Log as well.
8 - Confirm All the Pieces are Working Correctly
Although this is optional, this step may help with troubleshooting any issues that may have came from our previous steps. Here are a few things to check to make sure that all is working as it should. After creating a new user through the UI and using the generated JWT to place a call to your API, confirm the following:
In Stripe
- Confirm that a customer has been created in Stripe with the details you entered into the UI
- Confirm that the customer has been subscribed to the correct product and price
In Moesif
- Your API call was recorded in Moesif in the Live Event Log
- Your API call has the Stripe Customer ID and Subscription ID in the User and Company fields in Moesif, respectively.
- Confirm that the Stripe metadata is populated in Moesif
- All Billing Meter test conditions have passed
9 - Check Stripe for Usage
Lastly, After a few hours, it’s best to go into Stripe to confirm that usage is being added to a users subscription. Be sure that you’ve sent a few requests through in order to make sure you have some data that should be sent to Stripe.
It may take a few hours for usage to make its way from Moesif to Stripe. If data still isn’t in Moesif after a few hours, ensure you’ve followed all the steps outlined within this guide. This includes making sure that your user and company ID’s from Moesif are correctly mapped to the corresponding keys in Stripe.
To check the usage, in Stripe you’ll want to navigate to the Customers screen and select the customer that you made the API call with. Once selected, you should see some active subscriptions for the users that you’ve registered through the /register endpoint. The one we created earlier is called My API. Click on the subscription entry.
On the next screen, click on View Usage beside the price entry.
A modal should now pop up showing you the usage for the API that has been reported to Stripe from Moesif.
Remember, there is a delay in Moesif’s reporting to Stripe. If you data isn’t there yet, check back in a bit later.
10 - Determining If the Billing Meter is Working Correctly
Testing the created Billing Meter is easy with out Test Meter function. Navigate to your created Billing Meter from the left side navigation pane and selecting your Stripe Test billing meter. Select Test Meter on the top right.
We will first confirm the meter that you are attempting to test. Click the Next button at the bottom of the modal.
Moesif will wait for Subscriptions to created within Stripe and those subscriptions to be associated within Moesif itself. This page will update automatically, no need to refresh.
Moesif will then wait for an API call to our any endpoint associated with our billing meter using our the JWT that has been created for us.
Finally, Moesif will sync all usage data to Stripe every 15 minutes. This step may take a few minutes depending on when the API call was initiated but will update on the given interval.
Wrapping up
Monetization has always been a tough hurdle to get past. Many custom solutions offered flexibility but at a very high engineering and support cost. With Moesif, API monetization is possible in an extremely minimal amount of time. As demonstrated in this article, With a little bit of configuration and minimal amount of code we can create a production-ready, post-paid monetization scheme in minimal time.