Subscription management#
Skalio ID integrates with payment gateways to allow persons to purchase and manage subscriptions for an organization. The responsibilities are clearly separated:
- The payment gateway service handles the complete purchasing and payment process. It manages subscriptions and informs Skalio ID of updates. Such updates may be triggered by direct actions of a person (e.g. upgrade) or resulting from a subscription timeout (e.g. after cancellation).
- Skalio ID manages the organization with its members and privileges. Skalio ID records subscription updates in its database and informs registered Skalio services, such as TeamBeam Transfer, of subscription updates.
- Registered Skalio services receive subscription updates and implement changes relevant to their data model.
- Skalio ID also notifies persons of subscription updates via the event stream and via email.
Data model considerations#
See the entity relationship diagram for a detailed mapping of the entities.
- The database holds a list of products, grouped into product domains. A product is defined by human-readable values for
domain
andproductId
, and may hold additionalname
anddescription
. A frontend can rely on stable values fordomain
andproductId
. - Subscriptions are owned by an organization. A subscription can have multiple subscription items, which are applied cumulatively.
- A subscription item defines limitations, such as number of organization members.
- An organization matches a customer.
- A person can manage the subscriptions of their organization, provided he has the necessary privileges.
Payment gateway integrations#
The following payment gateways are supported:
- Stripe, https://stripe.com
Subscription state diagram#
The following states exist:
- No subscription: the customer does not have any active subscriptions and is not member of an organization.
- Active subscription: a subscription exists. The state is
active
. The subscription has no expiration date. The customer can use the purchased tier. - Cancelled subscription: a subscription exists. The state is
active
, but an expiration date exists. The customer can still use the purchased tier until the subscription expires.
The following actions alter the state of a subscription:
- initial purchase: Completing a checkout creates an active subscription where there was none before.
- product change: The customer may upgrade or downgrade the product attached to the subscription using the customer portal. The subscription remains active.
- cancellation: The customer cancels the subscription at Stripe. It remains active, but has an expiration date.
- reactivation: A cancelled subscription is reactivated at Stripe. The expiration date is removed.
- expiration: The expiration date of the cancelled subscription has passed. The subscription is deleted.
Stripe integration#
Importing products#
Products must be defined in the Stripe Products dashboard first, before they can be imported into Skalio ID.
Note: when defining a product, ensure you add metadata:
domain
(string, required) - The domain this product belongs to. Example:skp
productId
(string, required) - The name of product. Example:pro
Use the stripe product sync
command to import them into the local database. This needs to be done only once, but can be repeated at any time. Contents of the local database are overwritten.
skalio-id> stripe product sync
Import and sync products as defined by Stripe
During sync, the products require a local product ID. These IDs are stable Strings,
which are understood by frontend developers and their apps.
Fetching list of products from Stripe ... OK
Found 3 products.
Stripe product: prod_LxZQhVx9tZ2pg6
Product domain: spaces
Product ID : enterprise
Display name : Novospace Enterprise
Description : 5 TB Speicherplatz, beliebig viele Spaces, AV-Vertrag.
-> found entry, syncing it now ...
-> Updating entry in DB ... OK
Stripe product: prod_LxZOgoNVjxKyZw
Product domain: spaces
Product ID : business
Display name : Novospace Business
Description : 1 TB Speicherplatz, beliebig viele Spaces, AV-Vertrag.
-> found entry, syncing it now ...
-> Updating entry in DB ... OK
Stripe product: prod_LtO1MZHXU5jZAZ
Product domain: spaces
Product ID : premium
Display name : Novospace Premium
Description : 50 GB Speicherplatz, beliebig viele Spaces, AV-Vertrag.
-> found entry, syncing it now ...
-> Updating entry in DB ... OK
Webhook endpoint registration#
To receive events, the local API endpoint must be registered with Stripe once. The stripe webhook register
command can be used for this. It returns the webhook signature signing secret, which must be added to the configuration setting stripe.webhookSigningSecret
.
skalio-id> stripe webhook register
Registration of a new webhook with Stripe
In order to register a new webhook, you need to provide the name of this environment, such as
'databeam' or 'production', etc. You also need to provide the external URL where the webhook
is reachable.
After successful registration, the command returns a `secret` that is used to verify the signature
of incoming events. This value must be entered into the configuration.
Suggested Webhook endpoint: https://id.databeam.de/id/v1/subscriptions/stripe/webhook
Environment name > databeam
Webhook endpoint URL > https://id.databeam.de/id/v1/subscriptions/stripe/webhook
Confirm (y/N)? y
Making request towards stripe ... Success!
New webhook signing secret: whsec_3KMYzDacmL0g79M54yyw513uGUoOo5FD
Please update the configuration parameter stripe.webhookSigningSecret with this value!
Checkout#
The Stripe Checkout flow is used to purchase a product and create the initial subscription. In this flow, the customer registers himself within Stripe and provides payment information. It is only available if the person is not member of a paid organization.
Skalio ID sends a PURCHASE_PENDING
event to indicate that a purchase process is taking place when a checkout.session.completed
event is received from Stripe . Services using Skalio ID can use this event to show a loading state until they receive a SUBSCRIPTION_UPDATED
event.
Customer portal#
Once a subscription exists, a person must request a Stripe Customer Portal session to manage his subscription as well as access billing information. This routes the person to a Stripe-managed website.
Events#
Stripe communicates updates and changes by posting webhook events to Skalio ID. These events are received and parsed by Skalio ID. Only events that pass signature verification will be accepted for processing. Event processing occurs in a deferred fashion and may change the order in which they are being processed.
If this results in changes to a subscription, a SignalingEvent
is sent to each person who has admin
privileges in the affected organization. Subscription updates are also published to registered Skalio services. See the event stream for details.
Events remain in the database until they are expired automatically. Already processed events are not processed again.
Example events sent from Stripe to the Skalio ID webhook endpoint#
customer.created
customer.updated
customer.deleted
checkout.session.completed
customer.subscription.created
customer.subscription.updated
customer.subscription.deleted
Organization removal#
When a person removes the organization from Skalio ID, this has wide-ranging consequences. All related entities and data are being removed, and the delete operation is cascaded to other Skalio services.
The Stripe entities customer
and subscription
are both mapped to a Skalio ID subscription
. When the organization is removed, all Stripe subscriptions are cancelled and the Stripe customers are deleted.
Stripe sends webhook events as a result of this operation, but typically the database has removed the related entities already.
Skalio service integration#
Subscription changes are propagated from Skalio ID to other Skalio services by publishing a message on the broker in the {brokerPrefix}.updatedEntity
queue. The message is of type SubscriptionUpdateJson
, carrying an ISubscriptionUpdate
payload.
The consequences of the subscription change are to be handled by each Skalio service individually. This may include increasing limits on resources or granting or revoking access to features.
ISubscriptionUpdate payload#
orgUid
(string, required): The unique ID of the organization.createdAt
(string, required): The timestamp when the subscription was initially created.updatedAt
(string, required): The timestamp when the update became effective.expiresAt
(string, optional): The timestamp when the subscription is being cancelled;null
otherwise.domain
(string, optional): The product domain. Values:spaces
: Novospaceskp
: TeamBeamnull
: Subscription does not yet reference a product.
productId
(string, optional): The ID of the product,null
if the subscription does not yet reference a product.displayName
(string, optional): A user-presentable name for the product,null
if the subscription does not yet reference a product.status
(string, optional): The subscription status. Values:active
trialing
canceled
unpaid
past_due
incomplete
incomplete_expired
null
: no product yet
Example:
{
"orgUid" : "pep6umv2hzzhhj64",
"updatedAt" : "2022-07-13T11:50:52.085287Z",
"expiresAt" : null,
"domain" : "spaces",
"productId" : "business",
"status" : "active"
}