This example demonstrates an authentication provider webhook process using Upstash Workflow.
The workflow handles the user creation, trial management, email reminders and notifications.
import { serve } from "@upstash/workflow/nextjs";
import { WorkflowContext } from '@upstash/qstash/workflow'
* This can be the payload of the user created webhook event coming from your
* auth provider (e.g. Firebase, Auth0, Clerk etc.)
*/
type UserCreatedPayload = {
name: string;
email: string;
};
export const { POST } = serve<UserCreatedPayload>(async (context) => {
const { name, email } = context.requestPayload;
const { userid } = await context.run("sync user", async () => {
return await createUserInDatabase({ name, email });
});
await context.run("create new user in stripe", async () => {
await createNewUserInStripe(email);
});
await context.run("start trial in Stripe", async () => {
await startTrialInStripe(email);
});
await context.run("send welcome email", async () => {
await sendEmail(
email,
"Welcome to our platform!, You have 14 days of free trial."
);
});
await context.sleep("wait", 7 * 24 * 60 * 60);
const stats = await context.run("get user stats", async () => {
return await getUserStats(userid);
});
await sendProblemSolvedEmail({context, email, stats});
await context.sleep("wait for trial warning", 5 * 24 * 60 * 60);
const isUpgraded = await context.run("check upgraded plan", async () => {
return await checkUpgradedPlan(email);
});
if (isUpgraded) return;
await context.run("send trial warning email", async () => {
await sendEmail(
email,
"Your trial is about to end in 2 days. Please upgrade your plan to keep using our platform."
);
});
await context.sleep("wait for trial end", 2 * 24 * 60 * 60);
await context.run("send trial end email", async () => {
await sendEmail(
email,
"Your trial has ended. Please upgrade your plan to keep using our platform."
);
});
});
async function sendProblemSolvedEmail({
context: WorkflowContext<UserCreatedPayload>
email: string,
stats: { totalProblemsSolved: number }
}) {
if (stats.totalProblemsSolved === 0) {
await context.run("send no answers email", async () => {
await sendEmail(
email,
"Hey, you haven't solved any questions in the last 7 days..."
);
});
} else {
await context.run("send stats email", async () => {
await sendEmail(
email,
`You have solved ${stats.totalProblemsSolved} problems in the last 7 days. Keep it up!`
);
});
}
}
async function createUserInDatabase({
name,
email,
}: {
name: string;
email: string;
}) {
console.log("Creating a user in the database:", name, email);
return { userid: "12345" };
}
async function createNewUserInStripe(email: string) {
console.log("Creating a user in Stripe for", email);
}
async function startTrialInStripe(email: string) {
console.log("Starting a trial of 14 days in Stripe for", email);
}
async function getUserStats(userid: string) {
console.log("Getting user stats for", userid);
return {
totalProblemsSolved: 10_000,
mostInterestedTopic: "JavaScript",
};
}
async function checkUpgradedPlan(email: string) {
console.log("Checking if the user has upgraded the plan", email);
return false;
}
async function sendEmail(email: string, content: string) {
console.log("Sending email to", email, content);
}
const { userid } = await context.run("sync user", async () => {
return await createUserInDatabase({ name, email });
});
await context.run("create new user in stripe", async () => {
await createNewUserInStripe(email);
});
await context.run("start trial in Stripe", async () => {
await startTrialInStripe(email);
});
await context.run("send welcome email", async () => {
await sendEmail(
email,
"Welcome to our platform!, You have 14 days of free trial."
);
});
After 7 days, we check if the user has solved any questions. If not, we send a reminder email:
await context.sleep("wait", 7 * 24 * 60 * 60);
const stats = await context.run("get user stats", async () => {
return await getUserStats(userid);
});
await sendProblemSolvedEmail({context, email, stats});
async function sendProblemSolvedEmail({
context: WorkflowContext<UserCreatedPayload>
email: string,
stats: { totalProblemsSolved: number }
}) {
if (stats.totalProblemsSolved === 0) {
await context.run("send no answers email", async () => {
await sendEmail(
email,
"Hey, you haven't solved any questions in the last 7 days..."
);
});
} else {
await context.run("send stats email", async () => {
await sendEmail(
email,
`You have solved ${stats.totalProblemsSolved} problems in the last 7 days. Keep it up!`
);
});
}
}
If the user hasn’t upgraded 2 days before the trial ends, we send a trial warning email:
await context.sleep("wait for trial warning", 5 * 24 * 60 * 60);
const isUpgraded = await context.run("check upgraded plan", async () => {
return await checkUpgradedPlan(email);
});
if (isUpgraded) return;
await context.run("send trial warning email", async () => {
await sendEmail(
email,
"Your trial is about to end in 2 days. Please upgrade your plan to keep using our platform."
);
});
If they upgraded, we end the workflow by returning.
await context.sleep("wait for trial end", 2 * 24 * 60 * 60);
await context.run("send trial end email", async () => {
await sendEmail(
email,
"Your trial has ended. Please upgrade your plan to keep using our platform."
);
});