How to sell pay per use SaaS to AWS customers in the AWS Marketplace

Michael Wittig – 04 Sep 2019

AWS Marketplace allows you to sell software to AWS customers. The customer can either run the software on its own (using AMIs and optional CloudFormation), or you can offer the software as a service (SaaS). You can also offer containers and machine learning algorithms in the AWS Marketplace.

Marketplace

Do you prefer listening to a podcast episode over reading a blog post? Here you go!

The following table summaries your options to sell software in the AWS Marketplace.

Software delivery Pricing
AMI free
BYOL
hourly
monthly
annual
pay per use
AMI + CloudFormation free
BYOL
hourly
monthly
annual
pay per use
AMIs + CloudFormation same as above for first AMI only
SaaS pay per use
contract

We started selling our Slack based Incident Management for AWS in the AWS Marketplace in June 2019. So far, we are thrilled with the results. We simplified purchasing marbot, which increased the number of customers. Now, marbot appears on the AWS bill of our customers. If you plan to start a side business in the AWS tooling space, we highly recommend to check out AWS Marketplace!

In this post, you will learn how to sell pay per use SaaS in the AWS Marketplace. I will show you the overall process and finish with code snippets to implement the process.

Requirements

  1. I suggest you create a new AWS account (aka Marketplace Account) to interact with the AWS Marketplace Management Portal
  2. Register as an AWS Marketplace seller
  3. Create your SaaS product in the AWS Marketplace Management Portal. Creating a product is a chicken and egg problem. You need some information from AWS (like a ProductCode and an SNS topic), and AWS needs information from you. The process has several steps and comes with a testing stage.
  4. Create a new AWS account (aka SaaS Account) where you run your software.

Flows

Once you have created your product, you have to implement three different flows:

  1. Deal with subscribes: validate the token you receive from AWS Marketplace via an HTTP POST request
  2. Send metering data to AWS Marketplace
  3. Deal with unsubscribes: received via an SNS topic

The tricky part is to understand how various parties interact with each other.

  1. Customer
  2. AWS
  3. Your Marketplace Account
  4. Your SaaS Account

Let’s go through the flows in detail.

Subscribe flow

The following figure demonstrates the interaction.

  1. An AWS customer clicks on the subscribe button in the AWS Marketplace
  2. AWS Marketplace forwards the new customer to your website (using an HTTP POST request) with a token
  3. Your app assumes an IAM role in the Marketplace Account and calls the ResolveCustomer API to validate the token.
  4. AWS Marketplace publishes a subscribe-success message to the SNS topic

AWS Marketplace SaaS Flow: Subscribe

Once you received the subscribe-success message, you can report usage for the customer.

Report Usage flow

Every hour, you have to report the usage for every customer. For example, marbot is billed per active user. So we are sending the number of active users for every customer every hour.

AWS Marketplace SaaS Flow: Report Usage

To do so, your app assumes an IAM role in the Marketplace Account and calls the BatchMeterUsage API to report usage.

Unsubscribe flow

At any time, a customer can cancel the subscription.

  1. AWS Marketplace publishes an unsubscribe-pending message to the SNS topic.
  2. One hour passes (you can still report usage for the customer to finish the started hour)
  3. AWS Marketplace publishes an unsubscribe-success message to the SNS topic.

AWS Marketplace SaaS Flow: Unsubscribe

You cannot report usage anymore for the customer.

If you are interested in the implementation details, read on.

Your SaaS Account infrastructure

The following CloudFormation template creates the SQS queue in your SaaS account that will receive the unsubscribe notification.

---
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
MarketplaceTopicArn:
Description: 'SNS topic Arn created by AWS Marketplace.'
Type: String
Default: 'arn:aws:sns:us-east-1:287250355862:aws-mp-subscription-notification-xxxxxxxxxxxxxxxxxxxxxxxxx'
Resources:
DeadLetterQueue:
Type: 'AWS::SQS::Queue'
Properties:
MessageRetentionPeriod: 1209600
Queue:
Type: 'AWS::SQS::Queue'
Properties:
MessageRetentionPeriod: 1209600
RedrivePolicy:
deadLetterTargetArn: !GetAtt 'DeadLetterQueue.Arn'
maxReceiveCount: 5
VisibilityTimeout: 90
QueuePolicy:
Type: 'AWS::SQS::QueuePolicy'
Properties:
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal: '*'
Action: 'sqs:SendMessage'
Resource: !GetAtt 'Queue.Arn'
Condition:
ArnEquals:
'aws:SourceArn': !Ref MarketplaceTopicArn
Queues: [!Ref Queue]
Outputs:
QueueArn:
Value: !GetAtt 'Queue.Arn'

You will learn to process the messages later.

Your Marketplace Account infrastructure

The following CloudFormation template creates the SNS subscription to connect the SNS topic created by AWS marketplace with the SQS queue in the SaaS Account. Besides that, an IAM role is created that you can use in the SaaS Account to validate registration tokens and report usage.

---
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
MarketplaceTopicArn:
Description: 'SNS topic Arn created by AWS Marketplace.'
Type: String
Default: 'arn:aws:sns:us-east-1:287250355862:aws-mp-subscription-notification-xxxxxxxxxxxxxxxxxxxxxxxxx'
SaaSAccountId:
Description: 'AWS SaaS Account id using the role.'
Type: String
SaaSAccountQueueArn:
Description: 'SQS queue ARN which should receive the AWS Marketplace notifications in the SaaS Account.'
Type: String
Resources:
Subscription:
Type: 'AWS::SNS::Subscription'
Properties:
Endpoint: !Ref SaaSAccountQueueArn
Protocol: sqs
Region: 'us-east-1'
TopicArn: !Ref MarketplaceTopicArn
Role:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${SaaSAccountId}:root'
Action: 'sts:AssumeRole'
Policies:
- PolicyName: root
PolicyDocument:
Statement:
- Effect: Allow
Action:
- 'aws-marketplace:BatchMeterUsage'
- 'aws-marketplace:ResolveCustomer'
Resource: '*'
Outputs:
RoleArn:
Value: !GetAtt 'Role.Arn'

Let’s look at the software side of things.

Validate token

Once a new customer subscribes to your SaaS product, AWS Marketplace forwards the new customer to your website using an HTTP POST request. The x-amzn-marketplace-token parameter needs to be validated on your side. The code assumes the IAM role in the SaaS Account first before the ResolveCustomer API call is made to validate the token.

const AWS = require('aws-sdk');

const marketplacemetering = new AWS.MarketplaceMetering({
apiVersion: '2016-01-14',
region: 'us-east-1',
credentials: new AWS.TemporaryCredentials({
RoleArn: 'REPLACE_ME' // TODO replace with RoleArn output from CloudFormation stack
})
});

marketplacemetering.resolveCustomer({
RegistrationToken: 'REPLACE_ME' // TODO replace with token from POST request
}, (err, data) => {
if (err) {
if (err.code === 'InvalidTokenException') {
// invalid token
} else {
throw err;
}
} else {
if (data.ProductCode === 'REPLACE_ME') { // TODO replace with your product code from AWS Marketplace
// success, continue with registration in your own system
// attach the data.CustomerIdentifier with your own records for metering!
} else {
// invalid product code
}
}
});

If the token is valid, you likely want to collect additional information from the new customer and add some entries to your database.

Report usage

Every hour, you have to report the usage of every customer. The code assumes the IAM role in the SaaS Account first before the BatchMeterUsage API call is made.

const AWS = require('aws-sdk');

const marketplacemetering = new AWS.MarketplaceMetering({
apiVersion: '2016-01-14',
region: 'us-east-1',
credentials: new AWS.TemporaryCredentials({
RoleArn: 'REPLACE_ME' // TODO replace with RoleArn output from CloudFormation stack
})
});

marketplacemetering.batchMeterUsage({
ProductCode: 'REPLACE_ME', // TODO replace with your product code from AWS Marketplace
UsageRecords: [{
CustomerIdentifier: 'REPLACE_ME', // TODO replace with the value that you received when validating the token
Dimension: 'REPLACE_ME', // TODO replace with the dimension you charge for, e.g. users
Timestamp: new Date(),
Quantity: 0 // TODO replace with the usage
}]
}, (err, data) => {
if (err) {
throw err;
} else {
if (data.Results.length !== 1) {
// expexted one result
} else {
const result = data.Results[0];
if (result.Status === 'Success') {
// success
} else if (result.Status === 'CustomerNotSubscribed') {
// AWS Marketplace responded with CustomerNotSubscribed, the customer is not paying anymore, have you received the SQS message?!
} else if (result.Status === 'DuplicateRecord') {
// not a big deal
} else {
// unexpected status
}
}
}
});

Unsubscribe

Sad, but true! Sometimes a customer leaves us. AWS Marketplace will send a message to the SNS Topic that you connected to your SQS queue.

The message format is only partially documented. We observed the following message schema:

{
"action": "subscribe-success",
"customer-identifier": "xxxxxxxxxxx",
"product-code": "xxxxxxxxxxxxxxxxxxxxxxxxx"
}

The action can be one of the following:

  • subscribe-success: can be ignored for pay per use SaaS (only important if you integrate directly into API Gateway with keys and usage plans).
  • subscribe-fail: never seen this. Not sure how to handle it.
  • unsubscribe-pending: the customer is not paying anymore. You can still send usage data for the current hour.
  • unsubscribe-success: the customer is not paying anymore. Remove or disable in your database.
  • entitlement-updated: can be ignored for pay per use SaaS.

Critique

Besides our overall satisfaction with AWS Marketplace, we also experienced a few issues.

  1. AWS Marketplace operates from the US and is always paid in USD via credit card. This sometimes confuses our clients from Germany which pay their AWS bill in EUR via direct debit.
  2. Sales taxes are a mystery. We are not sure if AWS Marketplace is comparable to Apple’s App Store, where Apple is the seller.
  3. Notification messages are mostly undocumented. Shout out to @hoegertn for sharing his learnings with me!

Summary

AWS Marketplace is an easy way to sell software to AWS customers. You have to implement three flows: new subscribers, report usage, and unsubscribes. It was never easier to monetize your AWS related business!

Michael Wittig

Michael Wittig

I’ve been building on AWS since 2012 together with my brother Andreas. We are sharing our insights into all things AWS on cloudonaut and have written the book AWS in Action. Besides that, we’re currently working on bucketAV, HyperEnv for GitHub Actions, and marbot.

Here are the contact options for feedback and questions.