These events are designed for B2B SaaS and subscription-based businesses .
If you’re running an e-commerce store, see Standard Events instead.
When to Use SaaS Events
Use these events when your business model includes:
Subscription billing (monthly/annual plans)
Free trials with conversion tracking
Seat-based pricing with expansion revenue
Multi-user accounts with role-based access
Product-led growth with feature usage tracking
Account Lifecycle
Track account creation and deletion to measure growth and churn.
account_created
Fires when a new account (organization/workspace) is created.
JavaScript
window . _upstack ( 'track' , 'account_created' , {
accountId: 'acct_abc123' ,
accountName: 'Acme Corporation' ,
planId: 'plan_starter_monthly' ,
planName: 'Starter' ,
userId: 'usr_xyz789' ,
userEmail: 'jane@acme.com'
});
Properties
Property Type Required Description accountId string Yes Unique account identifier accountName string No Account/organization name planId string No Initial plan identifier planName string No Initial plan name userId string No Creating user’s ID userEmail string No Creating user’s email
When to Fire
After account registration completes
After organization setup wizard finishes
After SSO provisioning creates a new workspace
account_deleted
Fires when an account is permanently deleted.
JavaScript
window . _upstack ( 'track' , 'account_deleted' , {
accountId: 'acct_abc123' ,
accountName: 'Acme Corporation' ,
cancelReason: 'no_longer_needed' ,
cancelFeedback: 'Switching to a different solution' ,
mrr: 9900
});
Properties
Property Type Required Description accountId string Yes Deleted account identifier accountName string No Account name cancelReason string No Reason code for deletion cancelFeedback string No User-provided feedback mrr number No Lost MRR in cents
When to Fire
After account deletion confirmation
After workspace removal completes
After data retention period expires
Acquisition
Track the lead-to-signup funnel to measure conversion rates.
signup_started
Fires when a user begins the signup flow.
JavaScript
window . _upstack ( 'track' , 'signup_started' , {
planId: 'plan_pro_monthly' ,
source: 'pricing_page'
});
Properties
Property Type Required Description planId string No Pre-selected plan (if applicable) source string No Where signup was initiated
When to Fire
When signup form is opened
When registration page loads
When “Start Free Trial” button is clicked
signup_completed
Fires when a user completes signup and creates an account.
JavaScript
window . _upstack ( 'track' , 'signup_completed' , {
userId: 'usr_xyz789' ,
accountId: 'acct_abc123' ,
userEmail: 'jane@acme.com' ,
planId: 'plan_pro_monthly' ,
planName: 'Pro Plan'
});
Properties
Property Type Required Description userId string Yes New user identifier accountId string Yes New account identifier userEmail string No User email address planId string No Selected plan planName string No Plan display name
When to Fire
After signup form submission succeeds
After email verification completes
After OAuth signup flow finishes
demo_requested
Fires when a user requests a product demo.
JavaScript
window . _upstack ( 'track' , 'demo_requested' , {
userEmail: 'buyer@enterprise.com' ,
companyName: 'Enterprise Corp' ,
companySize: '500-1000' ,
useCase: 'marketing_analytics'
});
Properties
Property Type Required Description userEmail string No Requester email companyName string No Company name companySize string No Company size range useCase string No Primary use case
When to Fire
After demo request form submission
After sales call booking confirmation
After Calendly/HubSpot meeting scheduled
Trial Events
Track the trial lifecycle from start to conversion or expiry.
trial_started
Fires when a user begins a free trial.
JavaScript
window . _upstack ( 'track' , 'trial_started' , {
accountId: 'acct_abc123' ,
planId: 'plan_pro_monthly' ,
planName: 'Pro Plan' ,
trialEndDate: '2026-03-04T14:30:00.000Z' ,
trialDaysRemaining: 14
});
Properties
Property Type Required Description accountId string Yes Account identifier planId string Yes Trial plan identifier planName string No Human-readable plan name trialEndDate string No ISO 8601 trial expiration date trialDaysRemaining number No Days until trial expires
When to Fire
After trial signup confirmation
After trial activation in billing system
After Stripe customer.subscription.created with trial
trial_activated
Fires when a trial user reaches a meaningful activation milestone.
JavaScript
window . _upstack ( 'track' , 'trial_activated' , {
accountId: 'acct_abc123' ,
planId: 'plan_pro_monthly' ,
trialDaysRemaining: 12 ,
activationMilestone: 'first_integration_connected'
});
Properties
Property Type Required Description accountId string Yes Account identifier planId string No Trial plan identifier trialDaysRemaining number No Days remaining in trial activationMilestone string No Which milestone was reached
When to Fire
After first key feature is used
After onboarding checklist is completed
After first data import succeeds
trial_extended
Fires when a trial period is extended.
JavaScript
window . _upstack ( 'track' , 'trial_extended' , {
accountId: 'acct_abc123' ,
trialEndDate: '2026-03-11T14:30:00.000Z' ,
trialDaysRemaining: 7 ,
extensionReason: 'support_request'
});
Properties
Property Type Required Description accountId string Yes Account identifier trialEndDate string No New trial end date trialDaysRemaining number No New days remaining extensionReason string No Why trial was extended
When to Fire
After support manually extends trial
After promotional extension is applied
After win-back campaign grants extension
trial_ending_soon
Fires when a trial is about to expire (typically 3 days before).
JavaScript
window . _upstack ( 'track' , 'trial_ending_soon' , {
accountId: 'acct_abc123' ,
trialDaysRemaining: 3 ,
planId: 'plan_pro_monthly' ,
trialEndDate: '2026-03-04T14:30:00.000Z'
});
Properties
Property Type Required Description accountId string Yes Account identifier trialDaysRemaining number Yes Days until expiry planId string No Trial plan identifier trialEndDate string No Trial expiration date
When to Fire
3 days before trial expires (common)
When Stripe sends customer.subscription.trial_will_end
When automated warning email triggers
trial_expired
Fires when a trial ends without conversion.
JavaScript
window . _upstack ( 'track' , 'trial_expired' , {
accountId: 'acct_abc123' ,
planId: 'plan_pro_monthly' ,
planName: 'Pro Plan' ,
trialDays: 14
});
Properties
Property Type Required Description accountId string Yes Account identifier planId string No Expired trial plan planName string No Plan display name trialDays number No Total trial length
When to Fire
When trial end date is reached without payment
When account is downgraded to free tier
When access is revoked after grace period
trial_converted
Fires when a trial converts to a paid subscription. This is a key conversion event.
JavaScript
window . _upstack ( 'track' , 'trial_converted' , {
accountId: 'acct_abc123' ,
subscriptionId: 'sub_def456' ,
planId: 'plan_pro_monthly' ,
planName: 'Pro Plan' ,
mrr: 9900 ,
billingInterval: 'month'
});
Properties
Property Type Required Description accountId string Yes Account identifier subscriptionId string Yes New subscription ID planId string Yes Converted plan identifier planName string No Plan display name mrr number No Monthly recurring revenue in cents billingInterval string No month or year
When to Fire
After first successful payment
When Stripe subscription status changes from trialing to active
After payment method is charged successfully
Track mrr to measure trial-to-paid conversion value and calculate average revenue per converted trial.
Subscription Lifecycle
Track the complete subscription journey from creation through churn or reactivation.
subscription_created
Fires when a subscription record is created in your billing system.
JavaScript
window . _upstack ( 'track' , 'subscription_created' , {
subscriptionId: 'sub_def456' ,
accountId: 'acct_abc123' ,
planId: 'plan_pro_monthly' ,
planName: 'Pro Plan' ,
billingInterval: 'month'
});
Properties
Property Type Required Description subscriptionId string Yes Subscription identifier accountId string Yes Account identifier planId string Yes Plan identifier planName string No Plan display name billingInterval string No day, week, month, or year
When to Fire
When subscription object is created in Stripe
May precede first payment (for trials)
After checkout session completes
subscription_started
Fires when a new subscription begins (first billing period starts).
JavaScript
window . _upstack ( 'track' , 'subscription_started' , {
subscriptionId: 'sub_def456' ,
accountId: 'acct_abc123' ,
planId: 'plan_pro_monthly' ,
planName: 'Pro Plan' ,
mrr: 9900 ,
billingInterval: 'month'
});
Properties
Property Type Required Description subscriptionId string Yes Subscription identifier accountId string Yes Account identifier planId string Yes Plan identifier planName string No Plan display name mrr number No Monthly recurring revenue in cents billingInterval string No Billing frequency
When to Fire
After first successful charge
When subscription status becomes active
After trial converts to paid
subscription_upgraded
Fires when a customer upgrades to a higher-tier plan.
JavaScript
window . _upstack ( 'track' , 'subscription_upgraded' , {
subscriptionId: 'sub_def456' ,
accountId: 'acct_abc123' ,
planId: 'plan_business_monthly' ,
planName: 'Business' ,
previousPlanId: 'plan_pro_monthly' ,
mrr: 19900 ,
mrrDelta: 10000
});
Properties
Property Type Required Description subscriptionId string Yes Subscription identifier accountId string Yes Account identifier planId string No New plan identifier planName string No New plan name previousPlanId string No Previous plan identifier mrr number No New MRR after upgrade in cents mrrDelta number No MRR increase in cents (positive)
When to Fire
When plan changes from lower to higher tier
When Stripe subscription item is updated with higher-priced plan
After upgrade checkout completes
Track mrrDelta alongside subscription_downgraded to calculate net revenue retention.
subscription_downgraded
Fires when a customer downgrades to a lower-tier plan.
JavaScript
window . _upstack ( 'track' , 'subscription_downgraded' , {
subscriptionId: 'sub_def456' ,
accountId: 'acct_abc123' ,
planId: 'plan_starter_monthly' ,
planName: 'Starter' ,
previousPlanId: 'plan_pro_monthly' ,
mrr: 4900 ,
mrrDelta: - 5000
});
Properties
Property Type Required Description subscriptionId string Yes Subscription identifier accountId string Yes Account identifier planId string No New plan identifier planName string No New plan name previousPlanId string No Previous plan identifier mrr number No New MRR after downgrade in cents mrrDelta number No MRR decrease in cents (negative)
When to Fire
When plan changes from higher to lower tier
When features are removed from subscription
When scheduled downgrade takes effect at period end
subscription_renewed
This is a custom event name . For standard renewal tracking, consider using payment_succeeded or invoice_paid events instead.
Fires when a subscription successfully renews for another billing period.
JavaScript
window . _upstack ( 'track' , 'subscription_renewed' , {
subscriptionId: 'sub_def456' ,
accountId: 'acct_abc123' ,
planId: 'plan_pro_monthly' ,
mrr: 9900 ,
renewalCount: 6
});
Properties
Property Type Required Description subscriptionId string Yes Subscription identifier accountId string Yes Account identifier planId string No Current plan identifier mrr number No Renewed MRR in cents renewalCount number No Number of times renewed
When to Fire
When recurring payment succeeds
When billing period advances
When Stripe invoice.paid fires for subscription
subscription_paused
Fires when a subscription is paused.
JavaScript
window . _upstack ( 'track' , 'subscription_paused' , {
subscriptionId: 'sub_def456' ,
accountId: 'acct_abc123' ,
planId: 'plan_pro_monthly' ,
mrr: 9900 ,
pauseReason: 'seasonal_business'
});
Properties
Property Type Required Description subscriptionId string Yes Subscription identifier accountId string Yes Account identifier planId string No Plan identifier mrr number No Paused MRR in cents pauseReason string No Why subscription was paused
When to Fire
When customer requests pause
When seasonal pause is activated
When Stripe subscription pause feature triggers
subscription_resumed
Fires when a paused subscription is resumed.
JavaScript
window . _upstack ( 'track' , 'subscription_resumed' , {
subscriptionId: 'sub_def456' ,
accountId: 'acct_abc123' ,
planId: 'plan_pro_monthly' ,
mrr: 9900 ,
pausedDays: 30
});
Properties
Property Type Required Description subscriptionId string Yes Subscription identifier accountId string Yes Account identifier planId string No Plan identifier mrr number No Resumed MRR in cents pausedDays number No How long subscription was paused
When to Fire
When customer manually resumes
When pause period ends automatically
When billing restarts
subscription_cancelled
Fires when a cancellation is requested (may still be active until period end).
JavaScript
window . _upstack ( 'track' , 'subscription_cancelled' , {
subscriptionId: 'sub_def456' ,
accountId: 'acct_abc123' ,
planId: 'plan_pro_monthly' ,
cancelReason: 'too_expensive' ,
cancelFeedback: 'Budget constraints this quarter' ,
mrr: 9900 ,
cancelAtPeriodEnd: true
});
Properties
Property Type Required Description subscriptionId string Yes Subscription identifier accountId string Yes Account identifier planId string No Cancelled plan cancelReason string No Cancellation reason code cancelFeedback string No User-provided feedback mrr number No MRR being cancelled in cents cancelAtPeriodEnd boolean No If true, cancels at end of billing period
When to Fire
When customer clicks cancel button
When cancellation request is submitted
When Stripe subscription is set to cancel at period end
subscription_churned
Fires when a subscription ends completely (no longer billing). This is the final churn event.
JavaScript
window . _upstack ( 'track' , 'subscription_churned' , {
subscriptionId: 'sub_def456' ,
accountId: 'acct_abc123' ,
planId: 'plan_pro_monthly' ,
cancelReason: 'switched_competitor' ,
mrr: 9900 ,
ltv: 118800 ,
subscriptionMonths: 12
});
Properties
Property Type Required Description subscriptionId string Yes Subscription identifier accountId string Yes Account identifier planId string No Churned plan cancelReason string No Churn reason mrr number No Lost MRR in cents ltv number No Customer lifetime value in cents subscriptionMonths number No How long they were subscribed
When to Fire
When final billing period ends
When subscription is deactivated
When Stripe customer.subscription.deleted fires
Use this event to calculate churn rate and analyze churn reasons. Track ltv to understand which customer segments have the highest lifetime value.
subscription_initial_purchase
Fires when a customer’s first subscription payment is processed (distinct from trial conversion).
JavaScript
window . _upstack ( 'track' , 'subscription_initial_purchase' , {
subscriptionId: 'sub_def456' ,
accountId: 'acct_abc123' ,
planId: 'plan_pro_monthly' ,
planName: 'Pro Plan' ,
value: 9900 ,
currency: 'USD' ,
billingInterval: 'month'
});
Properties
Property Type Required Description subscriptionId string Yes Subscription identifier accountId string Yes Account identifier planId string No Plan identifier planName string No Plan display name value number No Payment amount in cents currency string No ISO 4217 currency code billingInterval string No month or year
When to Fire
First subscription charge succeeds
After trial converts (first paid billing period)
When new customer’s initial payment processes
subscription_recurring_purchase
Fires when a recurring subscription payment is processed (not the initial purchase).
JavaScript
window . _upstack ( 'track' , 'subscription_recurring_purchase' , {
subscriptionId: 'sub_def456' ,
accountId: 'acct_abc123' ,
planId: 'plan_pro_monthly' ,
planName: 'Pro Plan' ,
value: 9900 ,
currency: 'USD' ,
billingInterval: 'month' ,
renewalNumber: 6
});
Properties
Property Type Required Description subscriptionId string Yes Subscription identifier accountId string Yes Account identifier planId string No Plan identifier planName string No Plan display name value number No Payment amount in cents currency string No ISO 4217 currency code billingInterval string No month or yearrenewalNumber number No Which renewal this is (2nd, 3rd, etc.)
When to Fire
Each recurring billing cycle
When Stripe invoice.paid fires for an existing subscription
Monthly/annual renewal charge succeeds
Use subscription_initial_purchase for acquisition metrics and subscription_recurring_purchase for retention/LTV analysis. Together they give a complete picture of subscription revenue.
subscription_reactivated
Fires when a previously churned customer resubscribes.
JavaScript
window . _upstack ( 'track' , 'subscription_reactivated' , {
subscriptionId: 'sub_ghi789' ,
accountId: 'acct_abc123' ,
planId: 'plan_pro_monthly' ,
planName: 'Pro Plan' ,
mrr: 9900 ,
daysSinceChurn: 45
});
Properties
Property Type Required Description subscriptionId string Yes New subscription identifier accountId string Yes Account identifier planId string No New plan identifier planName string No Plan display name mrr number No Recovered MRR in cents daysSinceChurn number No Days between churn and reactivation
When to Fire
When former customer signs up again
When win-back campaign converts
When churned account starts new subscription
Order Fulfillment Events
Track order fulfillment and shipping for e-commerce subscription boxes, physical product deliveries, and Klaviyo flow triggers.
order_fulfilled
Fires when an order has been completely fulfilled (all items prepared for shipment).
JavaScript
window . _upstack ( 'track' , 'order_fulfilled' , {
orderId: 'ORD_12345' ,
orderName: '#1042' ,
value: 149.99 ,
currency: 'USD' ,
fulfillmentStatus: 'fulfilled' ,
items: [
{
id: 'SKU_001' ,
name: 'Monthly Snack Box' ,
price: 39.99 ,
quantity: 1
}
],
email: 'customer@example.com'
});
Properties
Property Type Required Description orderId string Yes Order identifier orderName string No Human-readable order name value number No Order value currency string No ISO 4217 currency code fulfillmentStatus string No Fulfillment status (e.g., 'fulfilled', 'partial') items array No Products fulfilled email string No Customer email
When to Fire
When warehouse marks order as packed/ready
When Shopify fulfillment is created
When all items in an order are fulfilled
order_shipped
Fires when an order has been shipped and tracking information is available.
JavaScript
window . _upstack ( 'track' , 'order_shipped' , {
orderId: 'ORD_12345' ,
orderName: '#1042' ,
value: 149.99 ,
currency: 'USD' ,
trackingNumber: '1Z999AA10123456784' ,
trackingCompany: 'UPS' ,
trackingUrl: 'https://www.ups.com/track?tracknum=1Z999AA10123456784' ,
estimatedDelivery: '2026-02-25T00:00:00.000Z' ,
items: [
{
id: 'SKU_001' ,
name: 'Monthly Snack Box' ,
price: 39.99 ,
quantity: 1
}
],
email: 'customer@example.com'
});
Properties
Property Type Required Description orderId string Yes Order identifier orderName string No Human-readable order name value number No Order value currency string No ISO 4217 currency code trackingNumber string No Carrier tracking number trackingCompany string No Shipping carrier (e.g., 'UPS', 'FedEx', 'USPS') trackingUrl string No Direct link to tracking page estimatedDelivery string No ISO 8601 estimated delivery date items array No Products shipped email string No Customer email
When to Fire
When shipping label is created with tracking
When carrier picks up package
When Shopify fulfillment_events/create webhook fires
Klaviyo integration: order_shipped is commonly used to trigger post-purchase flows like “Your order is on the way” emails with tracking information.
User Events
Track team growth and user engagement within accounts.
user_invited
Fires when a user is invited to join an account.
JavaScript
window . _upstack ( 'track' , 'user_invited' , {
accountId: 'acct_abc123' ,
inviteeEmail: 'newmember@acme.com' ,
inviteeRole: 'member' ,
invitedByUserId: 'usr_xyz789'
});
Properties
Property Type Required Description accountId string Yes Account identifier inviteeEmail string No Invitee email address inviteeRole string No Assigned role invitedByUserId string No Inviter’s user ID
When to Fire
When team invite is sent
When collaboration request is initiated
After invite email is dispatched
user_joined
Fires when an invited user accepts and joins the account.
JavaScript
window . _upstack ( 'track' , 'user_joined' , {
userId: 'usr_newmember' ,
accountId: 'acct_abc123' ,
userEmail: 'newmember@acme.com' ,
userRole: 'member'
});
Properties
Property Type Required Description userId string Yes New user identifier accountId string Yes Account identifier userEmail string No User email address userRole string No User’s assigned role
When to Fire
When invite is accepted
When account access is granted
After user completes join flow
user_role_changed
This is a custom event name . Track it using the Custom Events pattern if you need role change analytics.
Fires when a user’s role is changed within an account.
JavaScript
window . _upstack ( 'track' , 'user_role_changed' , {
userId: 'usr_xyz789' ,
accountId: 'acct_abc123' ,
previousRole: 'member' ,
newRole: 'admin' ,
changedByUserId: 'usr_admin123'
});
Properties
Property Type Required Description userId string Yes User whose role changed accountId string Yes Account identifier previousRole string No Previous role newRole string No New role changedByUserId string No Admin who made the change
When to Fire
When user is promoted to admin
When permissions are modified
After role update is saved
Billing Events
Track payment activity for revenue analytics and dunning workflows.
payment_succeeded
Fires when a payment is processed successfully.
JavaScript
window . _upstack ( 'track' , 'payment_succeeded' , {
accountId: 'acct_abc123' ,
invoiceId: 'inv_ghi012' ,
subscriptionId: 'sub_def456' ,
amount: 9900 ,
currency: 'USD'
});
Properties
Property Type Required Description accountId string Yes Account identifier amount number Yes Payment amount in cents invoiceId string No Invoice identifier subscriptionId string No Subscription identifier currency string No ISO 4217 currency code
When to Fire
When charge succeeds
When invoice is paid
When Stripe invoice.paid webhook fires
payment_failed
Fires when a payment attempt fails.
JavaScript
window . _upstack ( 'track' , 'payment_failed' , {
accountId: 'acct_abc123' ,
invoiceId: 'inv_ghi012' ,
subscriptionId: 'sub_def456' ,
amount: 9900 ,
failureReason: 'card_declined' ,
failureCode: 'insufficient_funds' ,
currency: 'USD'
});
Properties
Property Type Required Description accountId string Yes Account identifier amount number Yes Failed payment amount in cents invoiceId string No Invoice identifier subscriptionId string No Subscription identifier failureReason string No Failure reason code failureCode string No Detailed failure code currency string No ISO 4217 currency code
When to Fire
When card is declined
When insufficient funds error occurs
When Stripe invoice.payment_failed webhook fires
Track payment failures to identify at-risk customers and trigger dunning workflows.
invoice_paid
Fires when an invoice is marked as paid.
JavaScript
window . _upstack ( 'track' , 'invoice_paid' , {
accountId: 'acct_abc123' ,
invoiceId: 'inv_ghi012' ,
subscriptionId: 'sub_def456' ,
amount: 9900 ,
currency: 'USD'
});
Properties
Property Type Required Description accountId string Yes Account identifier invoiceId string Yes Invoice identifier amount number Yes Paid amount in cents subscriptionId string No Subscription identifier currency string No ISO 4217 currency code
When to Fire
When payment is received
When manual reconciliation marks invoice paid
When Stripe invoice.paid webhook fires
Expansion Events
Track seat-based and add-on revenue expansion.
seat_added
Fires when additional seats are purchased.
JavaScript
window . _upstack ( 'track' , 'seat_added' , {
accountId: 'acct_abc123' ,
subscriptionId: 'sub_def456' ,
seatCount: 15 ,
seatDelta: 5 ,
mrrDelta: 2500
});
Properties
Property Type Required Description accountId string Yes Account identifier seatCount number Yes Total seats after addition subscriptionId string No Subscription identifier seatDelta number No Number of seats added mrrDelta number No MRR increase from seats in cents
When to Fire
When seats are purchased
When user is added beyond plan limit
When Stripe subscription quantity increases
seat_removed
Fires when seats are removed from the plan.
JavaScript
window . _upstack ( 'track' , 'seat_removed' , {
accountId: 'acct_abc123' ,
subscriptionId: 'sub_def456' ,
seatCount: 10 ,
seatDelta: - 5 ,
mrrDelta: - 2500
});
Properties
Property Type Required Description accountId string Yes Account identifier seatCount number Yes Total seats after removal subscriptionId string No Subscription identifier seatDelta number No Number of seats removed (negative) mrrDelta number No MRR decrease in cents (negative)
When to Fire
When seats are removed
When user is deactivated
When Stripe subscription quantity decreases
Engagement Events
Track user activity and product milestones.
feature_used
Fires when a specific feature is used. Track key features to understand product adoption.
JavaScript
window . _upstack ( 'track' , 'feature_used' , {
accountId: 'acct_abc123' ,
userId: 'usr_xyz789' ,
featureId: 'feat_export' ,
featureName: 'CSV Export' ,
featureCategory: 'reporting'
});
Properties
Property Type Required Description accountId string Yes Account identifier featureId string Yes Feature identifier userId string No User who used the feature featureName string No Feature display name featureCategory string No Feature category
When to Fire
When key features are used
When premium features are accessed
When usage-based actions are performed
milestone_reached
Fires when a key milestone is achieved.
JavaScript
window . _upstack ( 'track' , 'milestone_reached' , {
accountId: 'acct_abc123' ,
milestoneId: 'milestone_100_orders' ,
milestoneName: '100 Orders Processed' ,
milestoneValue: 100
});
Properties
Property Type Required Description accountId string Yes Account identifier milestoneId string Yes Milestone identifier milestoneName string No Milestone display name milestoneValue number No Numeric value achieved
When to Fire
When usage threshold is crossed
When achievement is unlocked
When significant product milestone occurs
Stripe Webhook Integration
If you use Stripe for billing, handle webhooks to track events automatically.
Webhook handlers run server-side where window._upstack() is not available. Server-side event tracking requires the Upstack Server API. Contact support for early access, or use the patterns below to queue events for client-side tracking.
Server-Side Helper Pattern
Create a helper to queue events for server-side tracking:
// utils/tracking.js
async function trackServerEvent ( eventName , properties ) {
// Option 1: Direct API call (requires Server API access)
await fetch ( 'https://api.getupstack.com/v1/events' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'Authorization' : `Bearer ${ process . env . UPSTACK_API_KEY } `
},
body: JSON . stringify ({
event: eventName ,
properties ,
timestamp: new Date (). toISOString ()
})
});
// Option 2: Store in database for later sync
// await db.pendingEvents.create({ eventName, properties });
}
Example Webhook Handler
// Express.js webhook handler (server-side)
app . post ( '/webhooks/stripe' , async ( req , res ) => {
const event = stripe . webhooks . constructEvent (
req . body ,
req . headers [ 'stripe-signature' ],
process . env . STRIPE_WEBHOOK_SECRET
);
switch ( event . type ) {
case 'customer.subscription.created' :
const sub = event . data . object ;
await trackServerEvent ( 'subscription_created' , {
subscriptionId: sub . id ,
accountId: sub . metadata . account_id ,
planId: sub . items . data [ 0 ]. price . id ,
billingInterval: sub . items . data [ 0 ]. price . recurring . interval
});
break ;
case 'customer.subscription.updated' :
const updated = event . data . object ;
const previous = event . data . previous_attributes ;
if ( previous . items ) {
const newPrice = updated . items . data [ 0 ]. price . unit_amount ;
const oldPrice = previous . items . data [ 0 ]. price . unit_amount ;
if ( newPrice > oldPrice ) {
await trackServerEvent ( 'subscription_upgraded' , {
subscriptionId: updated . id ,
accountId: updated . metadata . account_id ,
planId: updated . items . data [ 0 ]. price . id ,
mrrDelta: newPrice - oldPrice
});
} else {
await trackServerEvent ( 'subscription_downgraded' , {
subscriptionId: updated . id ,
accountId: updated . metadata . account_id ,
planId: updated . items . data [ 0 ]. price . id ,
mrrDelta: newPrice - oldPrice
});
}
}
break ;
case 'customer.subscription.deleted' :
const deleted = event . data . object ;
await trackServerEvent ( 'subscription_churned' , {
subscriptionId: deleted . id ,
accountId: deleted . metadata . account_id ,
planId: deleted . items . data [ 0 ]. price . id ,
mrr: deleted . items . data [ 0 ]. price . unit_amount
});
break ;
case 'invoice.paid' :
const invoice = event . data . object ;
await trackServerEvent ( 'payment_succeeded' , {
accountId: invoice . metadata . account_id ,
invoiceId: invoice . id ,
subscriptionId: invoice . subscription ,
amount: invoice . amount_paid ,
currency: invoice . currency . toUpperCase ()
});
break ;
case 'invoice.payment_failed' :
const failed = event . data . object ;
await trackServerEvent ( 'payment_failed' , {
accountId: failed . metadata . account_id ,
invoiceId: failed . id ,
subscriptionId: failed . subscription ,
amount: failed . amount_due ,
failureReason: failed . last_payment_error ?. code
});
break ;
case 'customer.subscription.trial_will_end' :
const trial = event . data . object ;
await trackServerEvent ( 'trial_ending_soon' , {
accountId: trial . metadata . account_id ,
trialDaysRemaining: 3 ,
planId: trial . items . data [ 0 ]. price . id ,
trialEndDate: new Date ( trial . trial_end * 1000 ). toISOString ()
});
break ;
}
res . json ({ received: true });
});
Stripe Webhook Mapping
Stripe Webhook Upstack Event customer.subscription.createdsubscription_createdcustomer.subscription.updatedsubscription_upgraded / subscription_downgradedcustomer.subscription.deletedsubscription_churnedcustomer.subscription.pausedsubscription_pausedcustomer.subscription.resumedsubscription_resumedinvoice.paidinvoice_paid, payment_succeededinvoice.payment_failedpayment_failedcustomer.subscription.trial_will_endtrial_ending_sooncharge.refundedpayment_refunded
What’s Next
Standard Events E-commerce event reference for Shopify stores.
Custom Events Define your own events beyond the standard taxonomy.
Properties & Context Complete reference for all event fields.
Event Taxonomy How events flow through the Upstack pipeline.