Webhook event reference
Webhooks notify your website/app of events that happen in Memberful, such as when a member creates an account, a subscription is updated, or a plan is deleted.
This article lists all the events that can trigger a webhook. If you're looking for an explanation of how to set up and use webhooks, check out our main article about Webhooks.
In this help doc:
- Member events
- Subscription events
- Order events
- Plan events
- Download events
- How upgrades/downgrades are handled
Member events
Member accounts are created automatically when a member purchases a subscription or registers for free (if that feature is enabled). You can also create member accounts manually from your dashboard.
Most webhook types follow the object.event naming convention. Member events currently follow an object_event convention instead. Pay close attention to the event names laid out in this doc.
member_signup
Sent when a member account is created.
{
"event": "member_signup",
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"custom_field": "Custom field value",
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
}
}
member_updated
Sent when a member's profile information is updated.
{
"event": "member_updated",
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"custom_field": "Custom field value",
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
},
"changed": {
"email": [
"old_email@example.com",
"john.doe@example.com"
]
}
}
member.deleted
Sent when a member is deleted.
{
"event": "member.deleted",
"member": {
"deleted": true,
"id": 0
}
}
tax_id.updated
Sent when a member adds, updates, or removes their Tax ID.
{
"event": "tax_id.updated",
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"custom_field": "Custom field value",
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
},
"tax_id": {
"country": "FR",
"type": "eu_vat",
"value": "FR1234567890"
}
}
custom_fields.updated
Sent when a member answers the custom fields. The value
field can be a String, an Array of Strings, or an empty Array.
{
"event": "custom_fields.updated",
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
},
"custom_fields": [
{
"field": {
"id": 1,
"label": "Who's your favorite writer?"
},
"value": "John Doe"
},
{
"field": {
"id": 2,
"label": "What's your t-shirt size?"
},
"value": ""
},
{
"field": {
"id": 3,
"label": "How do you consume our content?"
},
"value": [
"Podcast",
"Newsletter"
]
}
]
}
Subscription events
Sent when a member subscribes to a plan or when that subscription is updated, renewed, or deleted.
Almost all times across all webhooks are returned as Unix time, but subscription events use ISO 8601 for the following attributes: `activated_at`, `created_at`, `expires_at`, `trial_end_at`, and `trial_start_at`.
subscription.created
Sent when a subscription is created. This could be at checkout, when a gift is activated, when created by a site admin, or when a member is added to a group subscription.
{
"event": "subscription.created",
"subscription": {
"active": true,
"autorenew": true,
"created_at": "2024-12-20T17:24:47Z",
"expires_at": "2025-01-19T17:24:47Z",
"id": 1,
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"custom_field": "Custom field value",
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
},
"subscription_plan": {
"id": 0,
"interval_count": 1,
"interval_unit": "month",
"name": "Sample plan",
"price_cents": 100000000,
"slug": "0-sample-plan"
},
"trial_end_at": null,
"trial_start_at": null
}
}
subscription.updated
Sent when a member's subscription is updated. If you want to know if the update is a plan change, you'll need to see if the plan_id field is present in the changed object. The first value is the old plan and the second value is the new one. The same applies for the other fields.
{
"event": "subscription.updated",
"subscription": {
"active": true,
"autorenew": true,
"created_at": "2024-12-20T17:24:47Z",
"expires_at": "2025-01-19T17:24:47Z",
"id": 1,
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"custom_field": "Custom field value",
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
},
"subscription_plan": {
"id": 0,
"interval_count": 1,
"interval_unit": "month",
"name": "Sample plan",
"price_cents": 100000000,
"slug": "0-sample-plan"
},
"trial_end_at": null,
"trial_start_at": null
},
"changed": {
"plan_id": [
42,
0
],
"expires_at": [
"2025-01-19T17:24:47Z",
"2025-02-18T17:24:47Z"
],
"autorenew": [
false,
true
]
}
}
subscription.renewed
Sent when a member's subscription is renewed.
{
"event": "subscription.renewed",
"subscription": {
"active": true,
"autorenew": true,
"created_at": "2024-12-20T17:24:47Z",
"expires_at": "2025-01-19T17:24:47Z",
"id": 1,
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"custom_field": "Custom field value",
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
},
"subscription_plan": {
"id": 0,
"interval_count": 1,
"interval_unit": "month",
"name": "Sample plan",
"price_cents": 100000000,
"slug": "0-sample-plan"
},
"trial_end_at": null,
"trial_start_at": null
},
"order": {
"created_at": "2024-12-20T17:24:47Z",
"status": "completed",
"total": 9900,
"uuid": "4DACB7B0-B728-0130-F9E8-102B343DC979"
}
}
subscription.activated
Sent when a suspended order is marked completed by staff and the subscription becomes active again.
{
"event": "subscription.activated",
"subscription": {
"active": true,
"autorenew": true,
"created_at": "2024-12-20T17:24:47Z",
"expires_at": "2025-01-19T17:24:47Z",
"id": 1,
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"custom_field": "Custom field value",
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
},
"subscription_plan": {
"id": 0,
"interval_count": 1,
"interval_unit": "month",
"name": "Sample plan",
"price_cents": 100000000,
"slug": "0-sample-plan"
},
"trial_end_at": null,
"trial_start_at": null
}
}
subscription.deactivated
Sent when a member's subscription fails to renew, expires, or becomes inactive.
{
"event": "subscription.deactivated",
"subscription": {
"active": false,
"autorenew": true,
"created_at": "2024-12-20T17:24:47Z",
"expires_at": "2025-01-19T17:24:47Z",
"id": 1,
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"custom_field": "Custom field value",
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
},
"subscription_plan": {
"id": 0,
"interval_count": 1,
"interval_unit": "month",
"name": "Sample plan",
"price_cents": 100000000,
"slug": "0-sample-plan"
},
"trial_end_at": null,
"trial_start_at": null
}
}
subscription.deleted
Sent when a member's subscription is deleted.
{
"event": "subscription.deleted",
"subscription": {
"active": true,
"autorenew": true,
"created_at": "2024-12-20T17:24:47Z",
"expires_at": "2025-01-19T17:24:47Z",
"id": 1,
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"custom_field": "Custom field value",
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
},
"subscription_plan": {
"id": 0,
"interval_count": 1,
"interval_unit": "month",
"name": "Sample plan",
"price_cents": 100000000,
"slug": "0-sample-plan"
},
"trial_end_at": null,
"trial_start_at": null
}
}
Order events
Sent when a member places an order to purchase plans or downloads.
Custom fields are now collected after checkout, which means they're no longer set when the order_purchased event is triggered. To access them, webhook recipients must now use the custom_fields.updated event instead.
order.purchased
Sent when a member places an order or when staff manually adds a new order. Not sent for subscription renewal orders.
{
"event": "order.purchased",
"order": {
"uuid": "4DACB7B0-B728-0130-F9E8-102B343DC979",
"number": "4DACB7B0",
"total": 9900,
"status": "completed",
"receipt": "receipt text",
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"custom_field": "Custom field value",
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
},
"products": [
],
"subscriptions": [
{
"active": true,
"created_at": 1734715487,
"expires": true,
"expires_at": 1737307487,
"id": 0,
"in_trial_period": false,
"subscription": {
"id": 0,
"price": 1000,
"name": "Sample plan",
"slug": "0-sample-plan",
"renewal_period": "monthly",
"interval_unit": "month",
"interval_count": 1,
"for_sale": true
},
"trial_end_at": null,
"trial_start_at": null
}
]
}
}
order.refunded
Sent when an order is refunded.
{
"event": "order.refunded",
"order": {
"uuid": "4DACB7B0-B728-0130-F9E8-102B343DC979",
"number": "4DACB7B0",
"total": 9900,
"status": "refunded",
"receipt": "receipt text",
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"custom_field": "Custom field value",
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
},
"products": [
],
"subscriptions": [
{
"active": true,
"created_at": 1734715487,
"expires": true,
"expires_at": 1737307487,
"id": 0,
"in_trial_period": false,
"subscription": {
"id": 0,
"price": 1000,
"name": "Sample plan",
"slug": "0-sample-plan",
"renewal_period": "monthly",
"interval_unit": "month",
"interval_count": 1,
"for_sale": true
},
"trial_end_at": null,
"trial_start_at": null
}
]
}
}
order.suspended
Sent when an order is suspended by staff.
{
"event": "order.suspended",
"order": {
"uuid": "4DACB7B0-B728-0130-F9E8-102B343DC979",
"number": "4DACB7B0",
"total": 9900,
"status": "suspended",
"receipt": "receipt text",
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"custom_field": "Custom field value",
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
},
"products": [
],
"subscriptions": [
{
"active": true,
"created_at": 1734715487,
"expires": true,
"expires_at": 1737307487,
"id": 0,
"in_trial_period": false,
"subscription": {
"id": 0,
"price": 1000,
"name": "Sample plan",
"slug": "0-sample-plan",
"renewal_period": "monthly",
"interval_unit": "month",
"interval_count": 1,
"for_sale": true
},
"trial_end_at": null,
"trial_start_at": null
}
]
}
}
order.completed
Sent when a suspended order is marked completed by staff.
{
"event": "order.completed",
"order": {
"uuid": "4DACB7B0-B728-0130-F9E8-102B343DC979",
"number": "4DACB7B0",
"total": 9900,
"status": "completed",
"receipt": "receipt text",
"member": {
"address": {
"street": "Street",
"city": "City",
"state": "State",
"postal_code": "Postal code",
"country": "City"
},
"created_at": 1734715487,
"credit_card": {
"exp_month": 1,
"exp_year": 2040
},
"custom_field": "Custom field value",
"discord_user_id": "000000000000000000",
"email": "john.doe@example.com",
"first_name": "John",
"full_name": "John Doe",
"id": 0,
"last_name": "Doe",
"phone_number": "555-12345",
"signup_method": "checkout",
"stripe_customer_id": "cus_00000",
"tracking_params": {
"utm_term": "shoes",
"utm_campaign": "summer_sale",
"utm_medium": "social",
"utm_source": "instagram",
"utm_content": "textlink"
},
"unrestricted_access": false,
"username": "john_doe"
},
"products": [
],
"subscriptions": [
{
"active": true,
"created_at": 1734715487,
"expires": true,
"expires_at": 1737307487,
"id": 0,
"in_trial_period": false,
"subscription": {
"id": 0,
"price": 1000,
"name": "Sample plan",
"slug": "0-sample-plan",
"renewal_period": "monthly",
"interval_unit": "month",
"interval_count": 1,
"for_sale": true
},
"trial_end_at": null,
"trial_start_at": null
}
]
}
}
Plan events
Sent when staff accounts create, update, or delete plans.
subscription_plan.created
Sent when a new plan is created.
{
"event": "subscription_plan.created",
"subscription": {
"id": 0,
"price": 1000,
"name": "Sample plan",
"slug": "0-sample-plan",
"renewal_period": "monthly",
"interval_unit": "month",
"interval_count": 1,
"for_sale": true
}
}
subscription_plan.updated
Sent when a plan is updated.
{
"event": "subscription_plan.updated",
"subscription": {
"id": 0,
"price": 1000,
"name": "Sample plan",
"slug": "0-sample-plan",
"renewal_period": "monthly",
"interval_unit": "month",
"interval_count": 1,
"for_sale": true
}
}
subscription_plan.deleted
Sent when a plan is deleted.
{
"event": "subscription_plan.deleted",
"subscription": {
"id": 0,
"price": 1000,
"name": "Sample plan",
"slug": "0-sample-plan",
"renewal_period": "monthly",
"interval_unit": "month",
"interval_count": 1,
"for_sale": true
}
}
Download events
Staff can create downloads to include with plans or to sell separately.
download.created
Sent when a download is created.
{
"event": "download.created",
"product": {
"id": 0,
"name": "Sample download",
"price": 1000,
"slug": "0-sample-download",
"for_sale": true
}
}
download.updated
Sent when a download is updated.
{
"event": "download.updated",
"product": {
"id": 0,
"name": "Sample download",
"price": 1000,
"slug": "0-sample-download",
"for_sale": true
}
}
download.deleted
Sent when a download is deleted.
{
"event": "download.deleted",
"product": {
"id": 0,
"name": "Sample download",
"price": 1000,
"slug": "0-sample-download",
"for_sale": true
}
}
How upgrades/downgrades are handled
Both upgrades and downgrades trigger the subscription.updated webhook.
Upgrades include a "changed" section detailing the changes:
"changed": {
"plan_id": [
42,
0
],
"expires_at": [
"2023-05-12T15:09:58Z",
"2023-06-11T15:09:58Z"
],
"autorenew": [
false,
true
]
}
Downgrades tend to happen on the next renewal date (since the member already paid a higher price for their current period, they're not downgraded immediately). In that case, the "Changed" section will be empty.
Related help docs: