End-to-End API Monetization with Django, 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 called Billing Meters which gives massive customizability but with a minimal amount of code and engineering effort.
For this blog post, which could actually be used out of the box, we will use Moesif, Django, and Stripe to charge users for API usage. To complete this Stripe Django monetization example, there are a few detail assumptions:
- You have a working Python environment installed on your machine
- We are using Python 3.10.5, the latest version available at the time of writing
- We are also using pipenv to manage our project within a virtual environment
- You have an active Stripe account with access to the Stripe Dashboard
- You have an active Moesif account
The setup is pretty simple from the outside. We will create a /register endpoint which:
- Registers a new user in Stripe
- Subscribes that user to a product
- Registers the User and Company in Moesif
- Creates a JWT to authenticate/authorize calls to our monetized endpoint
I’ve also created a frontend using Django Forms that is houses a simple form that registers a user by calling the /register endpoint and then displays the generated JWT for the newly registered user.
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.
At this point, your Stripe integration is complete in Moesif and you can begin to use it.
Optionally, you have the ability to customize the Customer ID Source in Moesif as well. The default will work for this guide, no changes are required. If you do need to customize it, these settings allow you to specify how to map the Stripe subscription and customer objects to the company ID and user ID in Moesif.
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 - Create The /register Endpoint
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 Python 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 an
id
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, I will create a simple Django API with the Django REST framework to do the above.
Install the necessary python dependencies
As previously mentioned, we’ll be utilizing pipenv
to safely manage our dependencies in a virtual environment. Pipenv offers developers an easy way to setup a working environment. Using pipenv grants us some more advanced features but most importantly includes built in support for environment variables.
I’ve created a folder called moesif-monetization-django
which I’ll be working in but feel free to call yours whatever you would like. Open this directory in your favorite IDE or text editor. I will be using Visual Studio Code for the remainder of this tutorial for all coding. Open Code’s integrated terminal and use pipenv
to install the following dependencies for use in your virtual environment.
pipenv install django djangorestframework moesifdjango stripe pyjwt
You will see that both Pipfile
and Pipfile.lock
files have been created.
These dependencies will help us to make calls to REST endpoints, connect to Stripe and Moesif, generate and validate JWTs, and various other capabilities we will build into our app.
Using pip and installing your dependencies globally is a perfectly fine alternative, if you prefer. If you are using pip you will need to install the django-environ package to manage environment variables. The command you will use will look like this:
pip install django moesifdjango stripe django-environ
.
Launch the pipenv shell
Let’s hop into our virtual environment’s shell and start setting up our project.
pipenv shell
Create the Django project
Next, we’ll use the django-admin startproject
command create a folder called moesif_monetization and prepare our project. This is where we will add our API code. Run the following command:
django-admin startproject moesif_monetization .
You’ll see a moesif_monetization folder in your current working directory along with a manage.py
file.
Finally, we’ll apply the necessary migrations by running the following:
python manage.py migrate
Confirm project dependencies
You can double check your Pipfile file includes the correct dependencies:
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
django = "*"
moesifdjango = "*"
stripe = "*"
djangorestframework = "*"
pyjwt = "*"
moesifapi = "*"
[dev-packages]
[requires]
python_version = "3.10"
Your dependencies will be brought into the project and installed to our virtual environment. These dependencies will help us to make calls to REST endpoints, connect to Stripe and Moesif, generate and validate JWTs, and various other capabilities we will build into our app.
Create the .env file
Instead of hard-coding the Stripe keys and other static values into our app, we will abstract them into a .env file. Again, we’ll be utilizing pipenv
’s built in support for environment variables.
In the root directory, create a file named .env. Within this file, we will add a few entries that will contain the keys and values used in our code.
STRIPE_API_KEY="sk_test_XXX"
STRIPE_PRICE_KEY="price_XXX"
MOESIF_APPLICATION_ID="YOUR_MOESIF_APPLICATION_ID"
TOKEN_SECRET_KEY="YOUR_TOKEN_SECRET_KEY”
The values that are here can be found in the following places:
Obtaining Your Stripe API and Price Key
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.
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 Your Token Secret
This will be the secret that is used as part of generating and validating your JWTs. This could be any 256-bit string you’d like, however, for production purposes you are best off using some sort of generation and obviously keeping this key stored elsewhere.
Once you’ve populated the file with the four key-value pairs, save the file. We won’t need to touch this file again for the remainder of the tutorial.
Set up the settings.py file
We will need to make a few changes to the default settings file that Django has generated for us. We’ll add a few applications, which is a term that encompasses python packages, models, views, templates, template tags, static files, URLs, and middleware for use in our project.
First, add the following imports to the file.
import os, jwt
Next, we’ll add the rest_framework
to our INSTALLED_APPS
definitions.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
]
Comment out the CsrfViewMiddleware
and add moesif_middleware
to the MIDDLEWARE
definitions.
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'moesifdjango.middleware.moesif_middleware'
]
Next, we’ll define our identifyUser
function which enables us to track users within Moesif and configure our Moesif Middleware.
def identifyUser(req, res):
customerID = ""
try:
jwt_token = req.headers['Authorization']
tokenArray = jwt_token.split(" ");
decodedJWT = jwt.decode(tokenArray[1], os.environ['TOKEN_SECRET_KEY'], algorithms=["HS256"])
customerID = decodedJWT.get("id")
except Exception as exception:
print(exception)
customerID = ""
if customerID != "":
# Sending customerID to Moesif...
return customerID
else:
# CustomerID not found - possibly not included in request authorization header
return None
MOESIF_MIDDLEWARE = {
'APPLICATION_ID': os.environ['MOESIF_APPLICATION_ID'],
'CAPTURE_OUTGOING_REQUESTS': False, # Set to True to also capture outgoing calls to 3rd parties.
'IDENTIFY_USER': identifyUser, # Optional hook to link API calls to users
}
We are a bit ahead of the game here with our identifyUser
function. When our Django server receives an API call, it’s contents are then forwarded to Moesif. Within this function we’ll extract the JWT from the request’s Authorization Header
. We’ll parse it and check it against our token secret key allowing us to extract the customerID
to enable user tracking within Moesif.
We also define and configure the Moesif middleware with our application ID. We’ll need to revisit this file later but for now lets move on to standing up our API.
Edit the urls.py file
In the root directory of our app, we will edit the generated urls.py file. In this file we will add the following code that simply defines our endpoints:
from django.contrib import admin
from django.urls import path
from moesif_monetization import views
urlpatterns = [
path('admin/', admin.site.urls),
path('test-service/', views.test_service),
path('register/', views.register),
]
We’ll also come back to this later in order to configure the endpoints for our frontend.
Create the views.py file
Our next step is to implement the logic for our /register and /test-service endpoints.
The /register endpoint will essentially create the binding between our generated JWT, Stripe, and Moesif. The outcome will be a generated JWT which will associate usage with a user in Moesif, which will then be reported to Stripe.
First, lets define our imports and configure our api clients.
import os, stripe, jwt, json
from moesifapi.moesif_api_client import *
from moesifapi.models import *
from django.http.response import JsonResponse
from rest_framework import status
stripe.api_key = os.environ['STRIPE_API_KEY']
api_client = MoesifAPIClient(os.environ['MOESIF_APPLICATION_ID']).api
Now we will define our register
function. Our first step in the flow is to create the customer in Stripe. We will use Stripe python package to do just that. We will use the parameters from the request body (email, first name, last name) to create the customer in Stripe using the stripe.Customer.create function. We will then store the created customer in a custom variable so we can access the customer ID generate in Stripe.
def register(request):
request_body = json.loads(request.body.decode('utf-8'))
# Create Stripe Customer
customer = stripe.Customer.create(
email = request_body['email'],
name = request_body['firstname'] + ' ' + request_body['lastname'],
description = 'Customer created through /register endpoint'
)
print("Creating Stripe Customer Complete. Returned ID: " + customer.id)
In the same function body, we will subscribe this new user to our API subscription we created in Stripe earlier. We will use the stripe.Subscriptions.create function and use the generated customer ID from the previous function call to subscribe them. This will return back a subscription object containing an ID we will use later.
# Create Stripe Subscription
subscription = stripe.Subscription.create(
customer = customer.id,
items = [{'price': os.environ['STRIPE_PRICE_KEY']}]
)
print("Creating Stripe Subscription Complete. Returned ID: " + subscription.id)
After our customer and subscription are created in Stripe, we will then use the Moesif middleware to create the user and add their relevant details into Moesif. First we will call the Moesif middleware’s update_company function to map the Stripe subscription.id to the companyId in Moesif.
# Create Company in Moesif
company = {'company_id': customer.id}
update_company = api_client.update_company(company)
Our next step is to generate a JWT with the Stripe Customer ID attached. This line will create a JWT for us to use with our endpoints.
token = jwt.encode({'id': customer.id}, os.environ['TOKEN_SECRET_KEY'])
We will then do a similar step with the update_user function and use it to map the Stripe customer.id to the userId and companyId, and some other metadata we collected on the user into Moesif.
Optionally we will add our JWT to our Moesif user metadata for ease of use. This isn’t recommended for production environments but can help when testing your setup instead of generating a new JWT if you lose the previously generated one.
# Create User in Moesif
user = {
'user_id': customer.id,
'company_id': customer.id,
'metadata': {
'email': request_body['email'],
'first_name': request_body['firstname'],
'last_name': request_body['lastname'],
'metadata': {
'jwt': token
}
}
}
update_user = api_client.update_user(user)
Next, we will add the subscription data into Moesif too. To do this, we will take our Stripe subscription ID and map it into Moesif using the api_client
’s update_subscription method that is exposed through the SDK.
# Create the subscription in Moesif
subscription = {
'subscription_id': subscription.id,
'company_id': customer.id,
'status': 'Active'
}
update_subscription = api_client.update_subscription(subscription)
Lastly, we will return a 200 OK JsonResponse back to the caller with the JWT in the response body.
return JsonResponse(data=token, status=status.HTTP_200_OK, safe=False, encoder=json.JSONEncoder)
The completed function will look like this:
def register(request):
request_body = json.loads(request.body.decode('utf-8'))
# Create Stripe Customer
print("Creating Stripe Customer")
customer = stripe.Customer.create(
email = request_body['email'],
name = request_body['firstname'] + ' ' + request_body['lastname'],
description = 'Customer created through /register endpoint'
)
print("Creating Stripe Customer Complete. Returned ID: " + customer.id)
# Create Stripe Subscription
print("Creating Stripe Subscription")
subscription = stripe.Subscription.create(
customer = customer.id,
items = [{'price': os.environ['STRIPE_PRICE_KEY']}]
)
print("Creating Stripe Subscription Complete. Returned ID: " + subscription.id)
# Create User and Company in Moesif
print("Creating Company in Moesif")
company = {'company_id': customer.id}
update_company = api_client.update_company(company)
print("Creating Company in Moesif Complete.")
print("Creating JWT")
token = jwt.encode({'id': customer.id}, os.environ['TOKEN_SECRET_KEY'])
print("JWT Created")
print("Creating User in Moesif")
user = {
'user_id': customer.id,
'company_id': customer.id,
'metadata': {
'email': request_body['email'],
'first_name': request_body['firstname'],
'last_name': request_body['lastname'],
'metadata': {
'jwt': token
}
}
}
update_user = api_client.update_user(user)
subscription = {
'subscription_id': subscription.id,
'company_id': customer.id,
'status': 'Active'
}
update_subscription = api_client.update_subscription(subscription)
print('Creating User in Moesif Complete.')
# Having issues with these two responses below
# return HttpResponse(data=token)
# return render(request, 'index.html', token)
return JsonResponse(data=token, status=status.HTTP_200_OK, safe=False, encoder=json.JSONEncoder)
Next we’ll implement the logic for our /test-service endpoint.
def test_service(request):
try:
# Parse request headers and jwt token array
jwt_token = request.headers['Authorization']
token_array = jwt_token.split(" ")
# Attempt to decode JWT
print("JWT tokenized: " + token_array[1]);
decoded = jwt.decode(token_array[1], os.environ['TOKEN_SECRET_KEY'], algorithms=["HS256"])
print("Decoded: " + decoded.get("id"))
except Exception:
return JsonResponse(data="Bad Auth Token", status=status.HTTP_401_UNAUTHORIZED, safe=False)
return JsonResponse(data={token_array[0]: token_array[1]}, status=status.HTTP_200_OK, safe=False)
We’ll attempt to parse the Authorization Header for the JWT that we have passed along. We’ll then try and decode the JWT using our TOKEN_SECRET_KEY
from our .env
file. Depending on the outcome we’ll return the proper JsonResponse
object, successfully including our JWT token for auditing purposes.
With that, we can now actually try out our endpoints to make sure that each piece is working as expected. The outcome should be a registered user with an associated JWT which will record and report usage data to Stripe. Let’s move onto testing it. Fire up your server by running the following command:
python manage.py runserver
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 - Create the frontend
Next, we want to add a simple little frontend so we don’t need to call for our JWT through Postman. We will make a quick little registration form that will then return a JWT for our newly registered user to use.
First, we’ll create a few template files and then edit our settings.py file to add our moesif_monetization project as an application itself and to let Django find our template files. We will then update our urls.py file to introduce some new endpoints. Next, we’ll implement the markup for our html pages. Additionally we’ll create Django form used to coordinate passing data between our views. Finally we’ll update our views.py file and make some changes to our functions to accommodate receiving data from our frontend.
Adding frontend files
In the moesif_monetization directory of the application, we will create a folder called templates
. We will then add a base.html, an index.html, and a registered.html file into that folder.
In addition, create a forms.py file within the moesif_monetization directory.
Edit the settings.py file
Add moesif_monetization
, or whatever your project name may be, to the INSTALLED_APPS
array. This allows Django to see our project as an application itself and present our frontend.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'moesif_monetization'
]
Additionally, add the following to the DIRS
section of the TEMPLATES
section. This allows Django to locate our template files.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
Edit the url.py file
In the urls.py file, we will add in routes to serve the static HTML files. Replace what we entered earlier with the following the following code:
urlpatterns = [
path('', views.index, name='index'),
path('admin/', admin.site.urls),
path('test-service/', views.test_service),
path('register/', views.register),
path('registered/', views.registered, name='registered'),
]
This code will now load the website (once we have the code plugged in) when you navigate to http://127.0.0.1:8000/.
Code the frontend form
Finally, let’s add the code for our frontend HTML and Django form functionality. In the base.html file, we will add markup that looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Moesif Monetization Demo</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script src="https://unpkg.com/htmx.org@1.6.1"></script>
</head>
<body>
<div class="container mt-4">
{% block content %}
{% endblock %}
</div>
</body>
</html>
Additionally, in the index.html file.
{% extends 'base.html' %}
{% block content %}
<form method="post">
{{ form.as_p }}
<input type="submit" value="Register">
</form>
{% endblock %}
Finally, the registered.html file.
{% extends 'base.html' %}
{% block content %}
<p>
{{ jwt }}
</p>
<a href="../">Go Back</a>
{% endblock %}
Create the Registration Form
In our forms.py file, let’s define our Registration Form.
from django import forms
class RegistrationForm(forms.Form):
first_name = forms.CharField(label='First Name', max_length=100)
last_name = forms.CharField(label='Last Name', max_length=100)
email = forms.EmailField(label='Email', max_length=100)
This markup in combination with our forms.py file will display a form which allows users to input an email, first name, and last name. It also has a Register button that will call the new register_frontend python function we’ll implement. That function will be in our views.py file.
Edit the views.py file
We’ll add the following three functions and imports to complete our views.py file.
...
from django.shortcuts import render
from .forms import RegistrationForm
...
def index(request):
context = {'form': RegistrationForm()}
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = RegistrationForm(request.POST)
# check whether it's valid:
if form.is_valid():
response = register_frontend(form.cleaned_data['email'], form.cleaned_data['first_name'], form.cleaned_data['last_name'])
print("get_registration_info - Valid")
jwt = (response.content.decode("utf-8").strip('"'))
request_context = {'jwt': jwt}
return render(request, 'registered.html', request_context)
else:
print("get_registration_info - not valid")
else:
print("get_registration_info - Not Post")
return render(request, 'index.html', context)
def registered(request):
return render(request, 'registered.html')
def register_frontend(email, firstname, lastname):
# Create Stripe Customer
customer = stripe.Customer.create(
email = email,
name = firstname + ' ' + lastname,
description = 'Customer created through /register endpoint'
)
print("Creating Stripe Customer Complete. Returned ID: " + customer.id)
# Create Stripe Subscription
subscription = stripe.Subscription.create(
customer = customer.id,
items = [{'price': os.environ['STRIPE_PRICE_KEY']}]
)
print("Creating Stripe Subscription Complete. Returned ID: " + subscription.id)
# Create Company in Moesif
company = {'company_id': subscription.id}
update_company = api_client.update_company(company)
token = jwt.encode({'id': customer.id}, os.environ['TOKEN_SECRET_KEY'])
# Create User in Moesif
user = {
'user_id': customer.id,
'company_id': subscription.id,
'metadata': {
'email': email,
'first_name': firstname,
'last_name': lastname,
'metadata': {
'jwt': token
}
}
}
update_user = api_client.update_user(user)
return JsonResponse(data=token, status=status.HTTP_200_OK, safe=False, encoder=json.JSONEncoder)
The register_frontend function is essentially the same as the register function we implemented earlier with some minor changes to accommodate how the frontend passes data to our backend.
8 - Test the frontend
To test the frontend, save your code changes and restart the server. Then, in a browser, navigate to http://127.0.0.1:8000/. You will then see the form show up.
Fill out the form fields and submit
Now that the form is loaded on the screen, fill in the fields and click the Register button. This will take the info, post it to our /register_frontend endpoint, and give us the generated JWT.
It is suggested that you use a different email than you used earlier when you created a JWT directly through the /register endpoint.
Confirm the JWT is returned
Once the submit button is clicked, after a few seconds, the JWT should be returned back to the UI.
9 - 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.
10 - 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
11 - 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.
12 - 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, monetization of your digital product 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.