What triggers the member updated webhook?

Latest version, hosting on Ghost pro. I couldn’t find this documented, so I’ll drop it here as I’m trying to debug a client’s webhook behavior.

Here’s when the member updated webhook fires in my testing

Actions that produce a fire on this webhook

  • Creating a new paying user (three fires, actually)
  • Unsubscribing or subscribing to a newsletter
  • Moving between tiers
  • Comping a member to a paid tier/removing the comp subscription
  • adding/removing a newsletter subscription in the admin panel

Actions that do not trigger the webhook:

  • cancelling a paying subscription (at least, not immediately - maybe it fires when the subscription expires?)
  • changing between yearly/monthly on the same tier
  • switching from pending cancellation to will renew.
  • adding a new member manually in the admin panel (even though they’re getting a newsletter subscription) **
  • importing a member via csv (even if adding subscriptions) **

** these are probably covered by the member created webhook?

Update: Importing a CSV file does not seem to trigger the member created webhook.

2 Likes

Months later, but this makes it hard to detect memberships ending or changing, without doing it via Stripe. How do people detect those events and trigger webhooks?

1 Like

I’m looking into this as well. Adding a comped subscription to user triggers a member update event, but it seems that the expiration of a comped subscription doesn’t send any event—which is really unfortunate.

I’m running into this exact issue. The member.updated event fires when adding a comped subscription, but nothing when it expires - which is indeed unfortunate for integrations. I’m building something that needs these expiration events. Currently considering tracking expiration dates locally (capturing them from member.updated events) and handling expiration myself, but that feels fragile and prone to drift. Looking at the clean-expired-comped-subscriptions.js job in Ghost, I’d be happy to contribute a PR to add webhook support directly where the expirations are processed. Two approaches come to mind:

  • Fire individual member.updated webhooks as each comped subscription expires (follows existing patterns)
  • Single batch webhook with all expired member IDs (more efficient but new pattern)

I lean toward the first option for consistency but it might send a lot of webhooks in a short time because it’s ran on a schedule.

Just found out the member.updated webhook doesn’t include the expiry timestamp so would need to do an extra request just to get the expiry. :confused: