#jvheaney
1 messages ยท Page 1 of 1 (latest)
Hello! Can you share your request ID making the update with me?
Sure, can I get that from the stripe dashboard?
This should be the subscription ID: sub_1NHX1qIMivMon7GPUVdFTe1d
and were you trying to create a new subscription? or were you trying to update an existing one?
Should be updating an existing one
I can send you a pastebin of the endpoint code, if you'd like. It's pretty much identical to the documentation (as far as I can tell)
Can you clarify really quick - what were you trying to update about this subscription? I do see that you're making the update request successfully, but you passed in the same price ID that it already had, so nothing on the subscriptoin actually changed (see https://dashboard.stripe.com/test/logs/req_ryQ3sbg8l9RTBY)
Sign in to the Stripe Dashboard to manage business payments and operations in your account. Manage payments and refunds, respond to disputes and more.
I was trying to update to another price ID, but it's entirely possible that it's actually incorrect data being passed on the frontend... do you mind if I take a quick peak and get back to you in a few minutes?
Yeah go ahead, but let me also explain the larger issue here
You never actually successfully paid this subscription when it was created because you created it with payment_behavior: default_incomplete . You need to actually confirm the PaymentIntent generated during subscription creation to complete payment
(you're missing everything described in this section - https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=elements#collect-payment)
Is this for updating a subscription as well? We have the integrated for subscription creation (when the user isn't already subscribed)
Yes, you can use a similar flow with updating, but it'd be slightly different because you'd use the PaymentMethod that you already created earlier during Subscription creation
Really, I'd recommend backing up a step and getting Subscriptoin creation to work end-to-end and then layering up updating
Subscription creation should be working as far as I can tell, here's another subscription I just tested:
sub_1NIFWKIMivMon7GP32eXTXaL
That subscription isn't active either - it also has a status of incomplete
The initial plan with Price ID price_1NBN2uIMivMon7GPidotrPbA is active
Which was the one I created the subscription with, it's the update one that is incomplete. Is that what you're seeing as well?
Or am I confused?
Let me clarify - a Price being active has nothing to do with the Subscription being active or not. An active price just means that you can use it to create new Subscriptions.
What you really need to be looking at is the status of the Subscription itself (https://stripe.com/docs/api/subscriptions/object#subscription_object-status), which in this case is incomplete
You can see in that subscription creation request as well - https://dashboard.stripe.com/test/logs/req_zFaOqPvRO3E5Sk the status is incomplete
Sure, I see that, that was the one we updated with. The one we initially created it with seems to be successful (again, unless I am sorely confused):
https://dashboard.stripe.com/test/subscriptions/sub_1NIFVaIMivMon7GPNc10YHu7
Sign in to the Stripe Dashboard to manage business payments and operations in your account. Manage payments and refunds, respond to disputes and more.
"Premium test plan" is active. Is that not an active subscription then?
Apologies if I am missing something, I really am all new to this
That subscription's active because afer it was created the underlying PaymetnIntent was confirmed and paid for (https://dashboard.stripe.com/test/logs/req_WZI4zWSKf1jjsJ), which transitioned the Subscription to active
Which is exactly what we recommend in our docs here (https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=elements#collect-payment)
Perfect, okay. So then when we try to update our subscription, we call an endpoint as described in your docs here:
https://stripe.com/docs/billing/subscriptions/upgrade-downgrade
We get a 200 from the endpoint, but the invoice remains unpaid and subscription updated webhook never called.
Is there an additional payment intent or something that needs to be completed for updating the plan? I don't see that anywhere in the documentation unless I missed something
You're likely not getting the subscription update webhook because of what I described earlier - the request I looked at passed in the same price, so there was no actual change to the subscription
Here's the example I was looking at -
I have a new request for you to look at that did different prices and still failed:
req_Uwcb6pzNvkgqps
I am going from $20/mo to $8/mo and it still fails
๐ I'm stepping in as Karbi needs to step away. Give me a moment to catch up
Sure thing, thank you for your help so far Karbi. I really do appreciate it!
^^ I'll let bismarck take over, but just want to quickly flag - that request has the same issue. The subscription originally has price_1NBjnGIMivMon7GPiDDOGO78 and the update request is just passing in the same price
That is very confusing because the payment intent of the subscription creation is this:
https://dashboard.stripe.com/test/payments/pi_3NIFVbIMivMon7GP1kgCDBgU
which was for our $20/mo price ID (as it says the card was charged for $20). Then we try to update to $8/mo with this request ID:
req_Uwcb6pzNvkgqps (price ID in this request is price_1NBjnGIMivMon7GPiDDOGO78 which is $8)
Sign in to the Stripe Dashboard to manage business payments and operations in your account. Manage payments and refunds, respond to disputes and more.
I think you are mixing up objects and Subscriptions here.
pi_3NIFVbIMivMon7GP1kgCDBgU is associated with in_1NIFVaIMivMon7GPBFCC4jXR which is associated with sub_1NIFVaIMivMon7GPNc10YHu7
The request you provided for the update (req_Uwcb6pzNvkgqps) is for updating sub_1NIFWKIMivMon7GP32eXTXaL which is a different Subsription than the above.
Let me confirm my flow then here, maybe the issue is in my initial subscription creation:
- User calls payment intent endpoint, I create a payment intent and return that ID to the frontend along with needed details
- User completes request with the payment intent on the frontend
- My webhook gets called with "customer.subscription.created", and I save the subscription ID from there into my database
- My webhook gets called with "invoice.paid" and I update that user's information for my app accordingly in the database
then when a user wants to update:
- The user makes a call to my update endpoint with their new price ID
- I get their subscription ID from the database according to their userid
- I update the subscription with that subscription ID and set the price ID with Stripe's API library
- Return a 200 to the frontend
-- Beyond this I don't get any other info
Is that all correct?
Why are you creating a PaymentIntent initially prior to creating the Subscription?
Let's say a user buys plan 1 of our app, do we not create a payment intent initially to start the subscription? Like this (https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=elements&element=payment#create-subscription)
I am following that guide step by step and it seems like all is well until updating
Okay then you likely mispoke. You are creating a Subscription which then creates an Invoice and you are grabbing the PaymentIntent associated with that Invoice and passing its client_secret to the frontend to handle the initial payment, correct?
You aren't actually creating a PaymentIntent directly.
Okay just making sure ๐
No worries
Okay can you show me your code for how you are updating the Subscription?
Sure, is pastebin okay?
Yeah or just pasting the relevant parts here between 3 backticks works: like this
Sure:
@RequestMapping(value = "/gw/billing/update", method = RequestMethod.POST)
public ResponseEntity< String > updatePlan(@RequestParam("priceId") String priceId, HttpServletRequest request) throws StripeException {
String authToken = jtp.resolveToken(request);
String userid = jtp.getUseridFromJWT(authToken);
String subscriptionId = upr.getSubscriptionId(userid);
try {
Subscription subscription = Subscription.retrieve(subscriptionId);
SubscriptionUpdateParams params = SubscriptionUpdateParams
.builder()
.addItem(
SubscriptionUpdateParams
.Item.builder()
.setId(subscription.getItems().getData().get(0).getId())
.setPrice(priceId)
.build()
)
.setCancelAtPeriodEnd(false)
.setProrationBehavior(SubscriptionUpdateParams.ProrationBehavior.ALWAYS_INVOICE)
.build();
subscription.update(params);
return new ResponseEntity<String>(new ResponseData(true, "Upgraded.").toResponse(), HttpStatus.OK);
}
catch(Exception e) {
e.printStackTrace();
return new ResponseEntity<String>(new ResponseData(false, "Server error.").toResponse(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Okay all that looks fine to me. So my guess is, based on the above object misalignment, that you aren't getting the right Subscription ID via String subscriptionId = upr.getSubscriptionId(userid);
So what does upr.getSubscriptionId(userid); do exactly?
I assume it calls your database?
Yup, just calls for the subscription ID for that user
The other thing you could do real quick to verify that is to hardcode in the Subscription ID
So let's do that first
Using your above example, let's hardcode that with sub_1NIFVaIMivMon7GPNc10YHu7
Sure
Then that should update it from price_1NBN2uIMivMon7GPidotrPbA to price_1NBjnGIMivMon7GPiDDOGO78
Let me build and deploy that on the test machine, just need 2 minutes here
Sure no rush
I've just tried it again and it hasn't seemed to work: req_97CXfdlIfcdizl
Here is the customer page with that status as incomplete: cus_O4OITH2A4bq4Fu
Think you are looking at the wrong Sub. It did work. You updated: https://dashboard.stripe.com/test/subscriptions/sub_1NIFVaIMivMon7GPNc10YHu7
You can see an Invoice was generated and paid via the proration adjustment
And the Sub is now on the $8/month Price
Those are three different Subscriptions you are looking at
As you have created 3 different Subscriptions for that Customer
We do not de-duplicate Subscription creation for Customers. A Customer can have multiple Subscriptions and multiple for the same Price. This is all under your control
For which part specifically?
Once the subscription is updated accordingly
If you click on the Subscription and scroll to the bottom of that Dashboard page then you can see all the Events (Webhooks) generated for that Subscription
So for instance a customer.subscription.updated Event is created whenever you do one of these updates. For example: https://dashboard.stripe.com/test/events/evt_1NIGArIMivMon7GPqecMAjlW
I see
and does that subscription event contain the price ID of the plan the user subscribed to?
I usually got that from invoice.paid previously
Yep it does. It will contain the entire Subscription object.
Okay, I am going to dig into what parts may be misconfigured on my end here. One other question, if someone purchases a 30 days subscription and cancels after 17 days, let's say, I get a subscription cancelled event on the webhook and remove the subscription ID from their user record. Will I get a webhook call on the 30th day to remove their subscription level? Or am I to keep track of those days?
Are you using cancel_at_period_end?
Is that a configuration I make in the subscription object? I don't currently use that anywhere
How do you cancel the Subscription?
Are you just calling the cancel endpoint: https://stripe.com/docs/api/subscriptions/cancel ?
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
Subscription subscription = Subscription.retrieve(subscriptionId);
Subscription deletedSubscription = subscription.cancel();
That's basically the applicable code
Yep okay then that cancels immediately.
So do you still want to provision access to your product until the end of the period though?
If that's possible, yes
Yep then you want to update the Subscription instead and set cancel_at_period_end: true. See: https://stripe.com/docs/billing/subscriptions/cancel?dashboard-or-api=api#cancel-at-the-end-of-the-current-billing-cycle
Got it. And at that point (the end of the period) would it call customer.subscription.cancel?
Yes it will cancel automatically and a customer.subscription.deleted webhook will be emitted
at the end of the period?
Yep
Awesome, okay
I am going to tackle this then. Thank you for all your help today, and thank Karbi for me if you speak to him! ๐
We are happy to help! And will do ๐