I am working on a platform able to analyse data of the users. I would like to use Stripe payments however I have some problems. At first I would like to describe how I would like my pricing look like in order to make it clearer to understand for you what I want to achieve. During account creation the user can select an amount for example from 1$ to 1000$ that will be available for all services. This amount will be charged every month so this will be working as a subscription plan. The difference is that the amount is not used proportionally each day of the month, as is the case of subscriptions. For example, the user starts one month pricing period 5th of the month with amount equals to 10$. During first 10 days of this period he does not execute any actions so he still has 10$. On the 11th day, he starts the service and uses 4$ within 5 hours. From this time he does not use any tools until the end of the current period and he has 6$ left. I decided at the moment that unused funds will probably not be transferred to the next billing period, so from 5th day of the next month he will have available 10$ again. Of course, his invoice will be charged 10$ in advance each month. It seems to me that up to that point I found a solution. My application is based on Angular frontend and Django backend. So in the frontend I do something like shown below during initial subscription creation with setting up and account:
pay(amount) {
var self = this;
var handler = (<any>window).StripeCheckout.configure({
key: ‘key’,
locale: 'auto',
token: (token: any) => {
this.UserService.sendAccountPricing(token.id, amount).subscribe((data: any) => {
// some code
},
(err: HttpErrorResponse) => {
console.log(err.error)
alert(err.error)
});
}
});
handler.open({
closed: function () {
self.UploaderService.displayNewPaymentButton = true;
},
name: 'Demo Site',
description: '2 widgets',
amount: amount * 100,
email: this.UploaderService.email
});
}
And in the backend:
def post(self, request):
serializer = AccountSerializer(data=request.data)
if serializer.is_valid():
key = request.META.get('HTTP_AUTHORIZATION').split()[1]
user_id = Token.objects.get(key=key).user_id
user = User.objects.get(id=user_id)
customer = stripe.Customer.create(
email=user.email,
source=request.data['token']
)
subscription = stripe.Subscription.create(
customer=customer.id,
items=[
{
'plan': 'plan_H8Kg0c8l8WmaQM',
'quantity': request.data['amount'],
},
],
expand=['latest_invoice.payment_intent'],
)
Account.objects.filter(user=user).update(subscription=subscription['id'])
Account.objects.filter(user=user).update(plan_selected=True)
return Response(status=status.HTTP_200_OK)
I have configured in subscription settings that each 1 quantity is equal to 1$. So when the user selects monthly pricing plan equals to 13$ I send to the backend information with the amount equal to 13 and then Django backend send request to Stripe to create subscription with 13 quantities what is equal to 13$. The source code above is responsible for this part. Can you take a look and check whether it is done properly? Maybe there is a better way to do this? This is just the only solution that came to my mind but it seems to be working. The problems start when I want to downgrade or upgrade my plan. Here is how I would like it to look. When the user downgrade or upgrade his pricing plan I just calculate how much money he spent during current billing period and I give him back all the amount that he got left. Then I charge his invoice with the amount he chose in the new plan and I start from this moment a new billing period. Example:
The user create an account with monthly subscription equals to 20$ on May 3. On May 10, he realizes that it is not enough budget because he has already used 17$ and he decides to upgrade his plan to 50$. The system returns him 3$ that he has got left and charges his account the amount equals to 50$. Now his billing period starts from May 10 and the next invoice equals to 50$ will be on June 10. And here is the problem. I could not find a functionality in Stripe to allow me to do this. I tried to do something like shown below but of course it does not work. Subscription modification is not enough because it does not work as I would like to and as I have described it above. Does anyone have an idea how can I do this? I will be very grateful for help. In addition, advice and tips on what I could do even better are very much appreciated.
Frontend:
newPlan(amount) {
var handler = (<any>window).StripeCheckout.configure({
key: ‘key’,
locale: 'auto',
token: (token: any) => {
alert('Your pricing plan has been changed.');
this.UserService.sendChangeAccountPricing(token.id, amount).subscribe((data: any) => {
// some code
},
(err: HttpErrorResponse) => {
console.log(err.error)
alert(err.error)
});
}
});
handler.open({
name: 'Demo Site',
description: '2 widgets',
amount: amount * 100
});
}
Backend:
def put(self, request):
serializer = AccountSerializer(data=request.data)
if serializer.is_valid():
key = request.META.get('HTTP_AUTHORIZATION').split()[1]
user_id = Token.objects.get(key=key).user_id
user = User.objects.get(id=user_id)
account = Account.objects.filter(user=user)
account = Account.objects.get(user=user)
subscription = stripe.Subscription.retrieve(account.subscription)
subscription = stripe.Subscription.modify(
subscription.id,
items=[{
'id': subscription['items']['data'][0].id,
'plan': ‘myplan',
'quantity': request.data['amount']
}],
billing_cycle_anchor='now',
proration_behavior='none',
)
return Response(status=status.HTTP_200_OK)
Breaking this down to address the key pieces:
If you want to change the billing cycle when updating the subscription, you can use the billing_cycle_anchor
parameter. This will affected future invoices.
Second, while you can prorate the plan/quantity changes, Stripe proration logic is always based on linear time consumption (and only applies to licensed per-seat plans, not metered). If you want to credit for a different amount, you'll need to do so manually, and disable Stripe's proration. You can either: