Pricing models
Per-period pricing
This is the simplest form of subscription pricing. The subscriber pays a fixed
amount every single period (ex: $29/month). Setting up a per-period pricing
consists of creating a Plan with a period (HOURLY, DAILY,
WEEKLY, MONTHLY, YEARLY) and a positive period_amount.
Example fixtures for a $29/month:
{
"fields": {
"slug": "indie",
"created_at": "2019-01-01T00:00:00-00:00",
"title": "Indie",
"organization": 2,
"is_active": 1.
"period_amount": 2900,
"period_type": 4
},
"model": "saas.Plan", "pk": 1
}
The organization field is set to reference the plan provider; here
Organization with pk == 2. The plan is also marked to be available
on the pricing page (is_active == 1) such that user can subscribe
to the plan.
The period_amount is to set as an integer amount of cents, 2900 in this
case, while the period_type is set to 4 which is the enum value for
Plan.MONTHLY.
On the initial payment, when a user subscribes to the plan through the checkout
workflow, Organization.checkout will be called to create the initial charge
and the Subscription record.
Later on whenever the subscription is about to expire, the renewals management
command will call extend_subscriptions to extend the subscription by one
period, then call create_charges_for_balance to charge the period amount
to the card on file.
Per-period pricing with setup fee
It is sometimes necessary to charge a one-time setup fee, maybe because a human needs to be involved to setup a physical space (in case of a co-working office) or send a device (in case of an IoT service).
Example fixtures for a $29/month + a one-time $10 setup fee:
{
"fields": {
"slug": "indie",
"created_at": "2019-01-01T00:00:00-00:00",
"title": "Indie",
"organization": 2,
"is_active": 1,
"period_amount": 2900,
"period_type": 4,
**"setup_amount": 1000**
},
"model": "saas.Plan", "pk": 1
}
The setup_amount (in cents) is automatically added as a one-time charge
on the initial payment.
Per-period pricing with custom periods
You might be selling online Continuous Education Units (CEUs) that are valid for a period of 2 years. Either it is a 2-year period, or a quarter (3-month period), there are pricing models that align naturally with business cycles that fall outside the monthly/yearly dichotomy.
For these cases, it makes sense to define a period_length which a value
grater than 1.
Example fixtures for a $29 per 2-year plan:
{
"fields": {
"slug": "indie",
"created_at": "2019-01-01T00:00:00-00:00",
"title": "Indie",
"organization": 2,
"is_active": 1,
"period_amount": 2900,
**"period_length": 2,**
"period_type": 5
},
"model": "saas.Plan", "pk": 1
}
Per-period pricing with discount for advance payments
Software-as-a-Service (SaaS) is a relationship business. It makes sense to incentivize subscribers to pay in advance by offering discounts.
You can specify advance_discounts on a plan. When you do so, the checkout
workflow will automatically present the option to pay for a multiple periods
in advance to the customer.
Example fixtures for a $29/month and a 20% discount if paid yearly:
{
"fields": {
"slug": "indie",
"created_at": "2019-01-01T00:00:00-00:00",
"title": "Indie",
"organization": 2,
"is_active": 1,
"period_amount": 2900,
"period_type": 4,
**"advance_discounts": [{
"discount_type": "percentage",
"amount": 2000,
"length": 12
}]**
},
"model": "saas.Plan", "pk": 1
}
Usage-based pricing
In some cases, the business model requires to charge base on usage (HTTP
requests, Gigabytes, messages, telephony minutes).
To implement a 3 Part Tariff (3PT) - fixed base, included quota, additional
charges for over quota - we associate a UseCharge instance to a Plan.
Example fixtures for a $29/month, includes 100 “free” messages, $0.15 per message afterwards:
{
"fields": {
"slug": "indie",
"created_at": "2019-01-01T00:00:00-00:00",
"title": "Indie",
"organization": 2,
"is_active": 1,
"period_amount": 2900,
"period_type": 4
},
"model": "saas.Plan", "pk": 1
}
{
"fields": {
"slug": "messages",
"created_at": "2019-01-01T00:00:00-00:00",
"title": "Per message",
"plan": 1,
"use_amount": 15,
"quota": 100
},
"model": "saas.UseCharge", "pk": 1
}
The functions new_use_charge and record_use_charge are the backbone
to implement quota pricing. Each time an UseCharge event occurs, call
record_use_charge passing a subscription object and a use_charge object.
record_use_charge will take care of recording the event into the transaction
ledger, applying the “free” quota limit as required.
Later on the renewals command will recognize the revenue
for the over-quota usage and generate the appropriate invoices.
Marketplace transaction fee
If you are using a Stripe processor backend, it is possible to setup a marketplace with a broker and multiple providers, collecting a broker fee on transaction between subscribers and providers.
To setup a 10% broker fee, update your settings.py as such:
SAAS = {
'BROKER': {
'FEE_PERCENTAGE': 1000,
}
}
This will set the broker_fee_amount field on each Plan created.
When a Charge is created for an initial or renewed subscription,
the broker_fee_amount is applied.
Group buy
The payer is not always the subscriber for a SaaS product. It often happens in enterprise software, but with an increasingly mobile workforce, it often the case that a contractor will bring his account while the employer will fit the bill. In our previous professional certification e-learning example (Per-period pricing with custom periods), a clinic pays for its staff to take the online class, the account and completion certificate belongs to the nurse (i.e. subscriber). This is implemented through a "Group buy" feature.
To turn on the "Group buy" feature, set is_bulk_buyer to True
in an Organization object:
{
"fields": {
"slug": "xia",
"created_at": "2019-01-01T00:00:00-00:00",
"full_name": "Xia Lee",
"processor": 1,
"is_active": 1,
**"is_bulk_buyer": true**
},
"model": "saas.Organization", "pk": 3
}
When a profile with is_bulk_buyer == True goes through the checkout
workflow, steps are added to allow the user to pay
a subscription on behalf of someone else.
When payment occurs, instead of creating a Subscription object
for the payer, a one-time Coupon is mechanically created. The final
subscriber can use that coupon at checkout to zero-out the balance due.