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.)*/typeUserCreatedPayload={ name:string; email:string;};exportconst{POST}=serve<UserCreatedPayload>(async(context)=>{const{ name, email }= context.requestPayload;const{ userid }=await context.run("sync user",async()=>{returnawaitcreateUserInDatabase({ name, email });});await context.run("create new user in stripe",async()=>{awaitcreateNewUserInStripe(email);});await context.run("start trial in Stripe",async()=>{awaitstartTrialInStripe(email);});await context.run("send welcome email",async()=>{awaitsendEmail( email,"Welcome to our platform!, You have 14 days of free trial.");});await context.sleep("wait",7*24*60*60);// get user stats and send email with themconst stats =await context.run("get user stats",async()=>{returnawaitgetUserStats(userid);});awaitsendProblemSolvedEmail({context, email, stats});// wait until there are two days to the end of trial period// and check upgrade statusawait context.sleep("wait for trial warning",5*24*60*60);const isUpgraded =await context.run("check upgraded plan",async()=>{returnawaitcheckUpgradedPlan(email);});// end the workflow if upgradedif(isUpgraded)return;await context.run("send trial warning email",async()=>{awaitsendEmail( 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()=>{awaitsendEmail( email,"Your trial has ended. Please upgrade your plan to keep using our platform.");});});asyncfunctionsendProblemSolvedEmail({ context: WorkflowContext<UserCreatedPayload> email:string, stats:{ totalProblemsSolved:number}}){if(stats.totalProblemsSolved ===0){await context.run("send no answers email",async()=>{awaitsendEmail( email,"Hey, you haven't solved any questions in the last 7 days...");});}else{await context.run("send stats email",async()=>{awaitsendEmail( email,`You have solved ${stats.totalProblemsSolved} problems in the last 7 days. Keep it up!`);});}}asyncfunctioncreateUserInDatabase({ name, email,}:{ name:string; email:string;}){console.log("Creating a user in the database:", name, email);return{ userid:"12345"};}asyncfunctioncreateNewUserInStripe(email:string){// Implement logic to create a new user in Stripeconsole.log("Creating a user in Stripe for", email);}asyncfunctionstartTrialInStripe(email:string){// Implement logic to start a trial in Stripeconsole.log("Starting a trial of 14 days in Stripe for", email);}asyncfunctiongetUserStats(userid:string){// Implement logic to get user statsconsole.log("Getting user stats for", userid);return{ totalProblemsSolved:10_000, mostInterestedTopic:"JavaScript",};}asyncfunctioncheckUpgradedPlan(email:string){// Implement logic to check if the user has upgraded the planconsole.log("Checking if the user has upgraded the plan", email);returnfalse;}asyncfunctionsendEmail(email:string, content:string){// Implement logic to send an emailconsole.log("Sending email to", email, content);}
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()=>{returnawaitgetUserStats(userid);});awaitsendProblemSolvedEmail({context, email, stats});
The sendProblemSolvedEmail method:
asyncfunctionsendProblemSolvedEmail({ context: WorkflowContext<UserCreatedPayload> email:string, stats:{ totalProblemsSolved:number}}){if(stats.totalProblemsSolved ===0){await context.run("send no answers email",async()=>{awaitsendEmail( email,"Hey, you haven't solved any questions in the last 7 days...");});}else{await context.run("send stats email",async()=>{awaitsendEmail( 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()=>{returnawaitcheckUpgradedPlan(email);});if(isUpgraded)return;await context.run("send trial warning email",async()=>{awaitsendEmail( 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.
If the user hasn’t upgraded after the trial ends, we send a trial ended email:
await context.sleep("wait for trial end",2*24*60*60);await context.run("send trial end email",async()=>{awaitsendEmail( email,"Your trial has ended. Please upgrade your plan to keep using our platform.");});