And you can already use/apply discount codes directly in Stripe, if you want to create special offers. It’s manual, but it works fine - I have quite a few setup myself
Hi John - I’m hoping to do this as well as I have a few thousand members on a different site I’d like to bring over and I have to offer them a discount. It’s a bit tedious to do it manually but if you had a solution for something broader, that would really be cool.
Thanks @jsh4 - that was kind of what I was thinking. However… I’ve been playing around a bit with how coupons might work and am happy to do a PR but for the life of me I can’t see where the checkout session is created. I’m doing a full scale search within the project and I’m utterly stumped.
I then got to thinking “why don’t I just create my own checkout” using Stripe Elements. I was thinking that I could apply a coupon there (which I can) but there’s no way, that I can see, to add the member_id to subscription.
Finally - I see how the membership API is being used to create the session then redirect off to Stripe. I can intercept all of it and make my own thing easily - I just want to pass in a coupon ID through the session which the docs say is possible:
It would seem a simple thing to add to the API call… Happy to PR this if I could just get a pointer to where the Stripe Session is created.
OK I think I figured this out. @John weigh in and let me know if I’m crazy :).
I dove into the members-api package and noticed that a metadata key was being passed in and, as far as I can tell, it’s not being used for anything currently. It seems like it’s there for theming reasons? Not sure - anyway I worked up a Vue/axios call to the API endpoint that looks like this:
const sessionRes = await axios.get("/members/api/session");
const payload ={
plan: "Monthly",
identity: sessionRes.data,
successUrl: location.href,
cancelUrl: location.href,
metadata: {coupon: 'asdasdasd'}
}
try{
const stripeCheckoutSession = await axios.post("/members/api/create-stripe-checkout-session/", payload);
Stripe(stripeCheckoutSession.data.publicKey).redirectToCheckout({
sessionId: stripeCheckoutSession.data.sessionId
});
}catch(err){
//if we're here we have a bad coupon code
}
I made two small tweaks to the createCheckoutSession method, which were to pull the payload into a variable and then check for the presence of a coupon passed in through the metadata:
As you can see, it works great when there’s a valid coupon code :).
The one thing I’m not a super huge fan of is trapping the 400 here - ideally the API would return a wrapper for the checkout with a success/fail flag or the like and an error message the dev could do something with.
I’m happy to PR both things if you find this useful.
Hi friends me again - this is interesting… I got this to work by sidestepping the Ghost checkout process entirely, which is fun and interesting. I created a Firebase function (serverless) that accepts a plan name (“Monthly” or “Yearly”) along with a customer email. It pings Stripe to see if the customer exists and uses that customer information (which is another thing I wanted). It then sets up the checkout session, passing in the discount code if one was provided.
I didn’t expect it to work - but it did. The webhook coming from Stripe is reconciled by Ghost on the user’s email thankfully. The one thing that’s not present is the discount code on the user’s screen but… oh well. I suppose I can tweak that later with another serverless call.
If you’re interested in the code let me know - it’s pretty straightforward stuff.
Stripe just announced coupon support for Checkout, shown in this tweet:
Maybe this fixes this issue?
edit: looks like it’s done with a allow_promotion_codes bool passed into the stripe checkout session call. i get that it might not be as clear cut as that (should it always default to true?) but looks like this is a good first step to this stuff landing. @robconery maybe if you’ve been looking at the source you know where this could fit in?
Yep, I mentioned above 10 days ago that this was in progress and coming shortly — we’ve been beta testing it for several months.
The implementation suggested by @signalnerve is correct, and the question on the PR is the right one: Does it make sense for this to be on by default for everyone? At the moment: probably not.
We would consider adding it behind a config flag, to start.
Yep - adding this to the session code triggered the coupon at Stripe. Works great! I’m able to create the session using my serverless function so all’s well.
I think most people are content just sending people off to Stripe to setup a quick paywall to get off the ground. If they’re successful, however, not having promos/discounts is a bit of a blocker. Discount codes are extremely common in online checkouts and people ask for them constantly. This is going to be even more the case as people turn to online resources rather than in-person.
I would urge you to consider adding a checkbox to the labs page next to the Stripe signup.
Oh - if anyone is curious about the Stripe solution that I got working I made a gist here. If you’re not familiar with Firebase this might look weird but you should be able to use the same code with Cloudflare workers or AWS Lambda.
So far it’s working well in testing so… fingers crossed.