When the payment from the Stripe checkout session has been successfully completed, we are redirected to the createSubscription
serverless function that verifies the recipient details from the URL query parameter as encircled in the below image:
In the Stripe checkout session API, we define the success URL for the checkout session. In the success URL, we need to verify the recipient details and store the details in the Sanity Server.
To save the recipient subscription record in the Sanity Server, we first need to verify if the subscription actually exists on Stripe. For that, we can create a function at the below location:
src/lib/isSubscribed.js
In the isSubscribed.js
function, we can write the code as below:
import stripeAPI from "stripe"
export const isSubscribed = async (email, priceId) => {
try {
const stripe = new stripeAPI(String(process.env.GATSBY_STRIPE_secret_ID), {
apiVersion: "2020-08-27",
})
const customers = await stripe.customers.list({
email: email,
limit: 1,
})
const subscriptions = await stripe.subscriptions.list({
customer: customers.data[0].id,
price: priceId,
limit: 1,
})
return {
cusid: customers?.data[0]?.id,
subid: subscriptions?.data[0]?.id,
status: subscriptions?.data[0]?.status,
cancel_at_period_end: subscriptions?.data[0]?.cancel_at_period_end,
canceled_at: subscriptions?.data[0]?.canceled_at,
cancel_at: subscriptions?.data[0]?.cancel_at,
start_date: subscriptions?.data[0]?.start_date,
livemode: subscriptions?.data[0]?.livemode,
priceId: priceId,
message: "success",
}
} catch (err) {
return { message: "notFound" }
}
}
Let's explain the isSubscribed.js
function.
The above function accepts two (2) parameters e.g. email
, priceId
. If the subscription for the respective email exists, the function returns the subscription details from the Stripe dashboard.
In the isSubscribed.js
, we use stripe.customers.list
node API to customer details with respect to their email as below
Also, we use stripe.subscriptions.list
to get the customer subscription as below.
We can use isSubscribed
function in createSubscription
serverless function to check if the subscription of email exists. For the createSubscription
serverless function, we can create the file at the below location:
/src/api/createSubscription.js
In the createSubscription.js
, we can write code as below:
import generator from "generate-password"
import { format } from "date-fns"
import { isSubscribed } from "../lib/isSubscribed"
import { sendEmailSG } from "../lib/sendEmailSG"
import { sanityCreate, sanityRequest } from "../lib/sanity/sanityActions"
export default async function handler(req, res) {
const email = req?.body?.email || req?.query?.email
const stripePriceId = req?.body?.stripePriceId || req?.query?.stripePriceId
const name = req?.body?.name || req?.query?.name
const sanityPriceId = req?.body?.sanityPriceId || req?.query?.sanityPriceId
const redirectOrigin = req?.body?.redirectOrigin || req?.query?.redirectOrigin
// Check if the subscription actually exist in Stripe
let isSubscribe = await isSubscribed(email, stripePriceId)
try {
if (
typeof isSubscribe?.cusid == "string" &&
typeof isSubscribe?.subid == "string"
) {
// Query customer from Sanity Server
let cusData = await sanityRequest(`
*[_type =='customer' && email=="${email}"]
`)
// Generate random password
let genPassword = generator.generate({ length: 10, numbers: true })
let cusPassword = cusData[0]?.password
? cusData[0]?.password
: genPassword
let cusRef = cusData[0]?._id ? cusData[0]?._id : isSubscribe.cusid
// Define mutation request for Sanity
let cusSanity = await sanityCreate("createIfNotExists", {
_id: cusRef,
_type: "customer",
email: email,
password: cusPassword,
name: name,
cusid: cusRef,
})
let subSanity = await sanityCreate("createIfNotExists", {
_type: "subscriptions",
_id: isSubscribe.subid,
customer: { _ref: cusRef, _type: "reference" },
price: { _ref: sanityPriceId, _type: "reference" },
status: isSubscribe?.status,
cancel_at_period_end: isSubscribe.cancel_at_period_end,
canceled_at: isSubscribe?.canceled_at
? format(new Date(isSubscribe?.canceled_at * 1000), "yyyy-MM-dd")
: "",
cancel_at: isSubscribe?.cancel_at
? format(new Date(isSubscribe?.cancel_at * 1000), "yyyy-MM-dd")
: "",
start_date: isSubscribe.start_date
? format(new Date(isSubscribe.start_date * 1000), "yyyy-MM-dd")
: "",
livemode: isSubscribe?.livemode,
subID: isSubscribe.subid,
title: `${email}`,
})
if (
typeof cusSanity?._id == "string" &&
typeof subSanity?._id == "string"
) {
try {
// Send email to customer for their login details
await sendEmailSG({
email: email,
subject: "You credential for the course",
html: `
<p>Email: ${email}</p>
<p>Password: ${cusPassword}</p>
`,
})
} catch (error) {}
if (redirectOrigin) {
// Redirect to the success URL
res.redirect(`${redirectOrigin}?state=success`)
} else {
res.status(200).json({
message: "success",
})
}
} else {
if (redirectOrigin) {
res.redirect(`${redirectOrigin}?state=fail`)
} else {
res.status(400).json({
message: null,
})
}
}
return
} else {
throw {
status: 400,
message: "You're not subscribed!!!",
}
}
} catch (error) {
const status = error.response?.status || error.statusCode || 500
const message = error.response?.data?.message || error.message
res.status(status).json({
message: error.expose ? message : `Faulty ${req.baseUrl}: ${message}`,
})
}
}
Let's breakdown createSubscription.js
function to understand it better.
The createSubscription
serverless function accepts the request body parameter as below:
stripePriceId
,name
,sanityPriceId
,redirectOrigin
We need to download two npm packages for the above function by executing the below command in the terminal.
npm i generate-password date-fns
The generate-password
npm package is used to generate passwords by passing certain parameters and date-fns
package is used to format the date.
Next, we can use isSubscribed
function to check if the subscription of the customer actually exists. If so, we can then send the mutation request to the Sanity server.
If the subscription actually exists in Stripe, we can then create the customer and subscription document for the respective user in the Sanity Server. We check if the customer with the same email exists in the Sanity Server. If so, we can use an existing customer as a reference and if not, we can create a new customer. For that, we can write the code as below:
After that, we can create the subscription document in the Sanity by using the below code.
If the mutation request is successful, we can send an email to the recipient for their login details and redirect the success URL. For that, we can write the code as below.
To test the createSubscription
serverless function, we can send the HTTP request using the Postman as below:
In the above request, we get the value for stripePriceId
and sanityPriceId
from the Sanity Studio as shown in the below image.
You might ask the below question?
Why are recipient details stored on the Sanity Server if it is already in the Stripe Dashboard?
With every successful subscription, Stripe stores information about the recipient on their dashboard. But... we also need to store the recipient information on the Sanity Server.
Below are reasons to store recipient information on Sanity Studio:
In the next chapter, we will use the createSubscription
to redirect the user to the success or fail page.