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.