@@ -10,6 +10,8 @@ import {
1010 Paddle ,
1111 SubscriptionActivatedEvent ,
1212 SubscriptionCanceledEvent ,
13+ TransactionCompletedEvent ,
14+ TransactionPastDueEvent ,
1315} from '@paddle/paddle-node-sdk'
1416import { ok } from 'node:assert/strict'
1517
@@ -75,6 +77,8 @@ export async function handleStripeCheckoutSessionCompleted({
7577export async function handlePaddleSubscriptionActivated (
7678 event : SubscriptionActivatedEvent
7779) {
80+ log . info ( 'handlePaddleSubscriptionActivated: %j' , event )
81+
7882 const { jwt : token } = event . data . customData as {
7983 jwt : string
8084 }
@@ -96,6 +100,7 @@ export async function handlePaddleSubscriptionActivated(
96100export async function handlePaddleSubscriptionCanceled (
97101 event : SubscriptionCanceledEvent
98102) {
103+ log . info ( 'handlePaddleSubscriptionCanceled: %j' , event )
99104 const userId = ( event . data . customData as { userId : string } ) . userId
100105
101106 ok ( userId , 'userId is missing in customData' )
@@ -109,6 +114,38 @@ export async function handlePaddleSubscriptionCanceled(
109114 }
110115}
111116
117+ export async function handlePaddleTransactionPastDue (
118+ event : TransactionPastDueEvent
119+ ) {
120+ log . info ( 'handlePaddleTransactionPastDue: %j' , event )
121+
122+ const subscription = await paddle . subscriptions . get ( event . data . subscriptionId )
123+
124+ const userId = ( subscription . customData as { userId : string } ) . userId
125+
126+ ok ( userId , 'userId is missing in customData' )
127+
128+ await switchToPlan ( userId , PlanName . FREE )
129+ }
130+
131+ export async function handlePaddleTransactionCompleted (
132+ event : TransactionCompletedEvent
133+ ) {
134+ log . info ( 'handlePaddleTransactionCompleted: %j' , event )
135+
136+ const subscription = await paddle . subscriptions . get ( event . data . subscriptionId )
137+
138+ const userId = ( subscription . customData as { userId : string } ) . userId
139+
140+ // userId might be missing if this is the first transaction of a new customer
141+ // and there is a race condition as we haven't set the customData yet.
142+ // In this case, the user should get PRO access via handlePaddleSubscriptionActivated()
143+ // a few moments later. Since we don't know the userId yet, we can't set the plan here.
144+ if ( userId ) {
145+ await switchToPlan ( userId , PlanName . PRO )
146+ }
147+ }
148+
112149export async function handleStripeCustomerSubscriptionDeleted ( {
113150 metadata,
114151 customer : stripeCustomerId ,
0 commit comments