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

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": 1714006663,
    "credit_card": {
      "exp_month": 1,
      "exp_year": 2040
    },
    "custom_field": "Custom field value",
    "discord_user_id": "000000000000000000",
    "email": "[email protected]",
    "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": 1714006663,
    "credit_card": {
      "exp_month": 1,
      "exp_year": 2040
    },
    "custom_field": "Custom field value",
    "discord_user_id": "000000000000000000",
    "email": "[email protected]",
    "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": [
      "[email protected]",
      "[email protected]"
    ]
  }
}

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": 1714006663,
    "credit_card": {
      "exp_month": 1,
      "exp_year": 2040
    },
    "custom_field": "Custom field value",
    "discord_user_id": "000000000000000000",
    "email": "[email protected]",
    "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": 1714006663,
    "credit_card": {
      "exp_month": 1,
      "exp_year": 2040
    },
    "discord_user_id": "000000000000000000",
    "email": "[email protected]",
    "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-04-25T00:57:43Z",
    "expires_at": "2024-05-25T00:57:43Z",
    "id": 1,
    "member": {
      "address": {
        "street": "Street",
        "city": "City",
        "state": "State",
        "postal_code": "Postal code",
        "country": "City"
      },
      "created_at": 1714006663,
      "credit_card": {
        "exp_month": 1,
        "exp_year": 2040
      },
      "custom_field": "Custom field value",
      "discord_user_id": "000000000000000000",
      "email": "[email protected]",
      "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-04-25T00:57:43Z",
    "expires_at": "2024-05-25T00:57:43Z",
    "id": 1,
    "member": {
      "address": {
        "street": "Street",
        "city": "City",
        "state": "State",
        "postal_code": "Postal code",
        "country": "City"
      },
      "created_at": 1714006663,
      "credit_card": {
        "exp_month": 1,
        "exp_year": 2040
      },
      "custom_field": "Custom field value",
      "discord_user_id": "000000000000000000",
      "email": "[email protected]",
      "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": [
      "2024-05-25T00:57:43Z",
      "2024-06-24T00:57:43Z"
    ],
    "autorenew": [
      false,
      true
    ]
  }
}

subscription.renewed

Sent when a member's subscription is renewed.

 {
  "event": "subscription.renewed",
  "subscription": {
    "active": true,
    "autorenew": true,
    "created_at": "2024-04-25T00:57:43Z",
    "expires_at": "2024-05-25T00:57:43Z",
    "id": 1,
    "member": {
      "address": {
        "street": "Street",
        "city": "City",
        "state": "State",
        "postal_code": "Postal code",
        "country": "City"
      },
      "created_at": 1714006663,
      "credit_card": {
        "exp_month": 1,
        "exp_year": 2040
      },
      "custom_field": "Custom field value",
      "discord_user_id": "000000000000000000",
      "email": "[email protected]",
      "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-04-25T00:57:43Z",
    "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-04-25T00:57:43Z",
    "expires_at": "2024-05-25T00:57:43Z",
    "id": 1,
    "member": {
      "address": {
        "street": "Street",
        "city": "City",
        "state": "State",
        "postal_code": "Postal code",
        "country": "City"
      },
      "created_at": 1714006663,
      "credit_card": {
        "exp_month": 1,
        "exp_year": 2040
      },
      "custom_field": "Custom field value",
      "discord_user_id": "000000000000000000",
      "email": "[email protected]",
      "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-04-25T00:57:43Z",
    "expires_at": "2024-05-25T00:57:43Z",
    "id": 1,
    "member": {
      "address": {
        "street": "Street",
        "city": "City",
        "state": "State",
        "postal_code": "Postal code",
        "country": "City"
      },
      "created_at": 1714006663,
      "credit_card": {
        "exp_month": 1,
        "exp_year": 2040
      },
      "custom_field": "Custom field value",
      "discord_user_id": "000000000000000000",
      "email": "[email protected]",
      "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-04-25T00:57:43Z",
    "expires_at": "2024-05-25T00:57:43Z",
    "id": 1,
    "member": {
      "address": {
        "street": "Street",
        "city": "City",
        "state": "State",
        "postal_code": "Postal code",
        "country": "City"
      },
      "created_at": 1714006663,
      "credit_card": {
        "exp_month": 1,
        "exp_year": 2040
      },
      "custom_field": "Custom field value",
      "discord_user_id": "000000000000000000",
      "email": "[email protected]",
      "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": 1714006663,
      "credit_card": {
        "exp_month": 1,
        "exp_year": 2040
      },
      "custom_field": "Custom field value",
      "discord_user_id": "000000000000000000",
      "email": "[email protected]",
      "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": 1714006663,
        "expires": true,
        "expires_at": 1716598663,
        "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": 1714006663,
      "credit_card": {
        "exp_month": 1,
        "exp_year": 2040
      },
      "custom_field": "Custom field value",
      "discord_user_id": "000000000000000000",
      "email": "[email protected]",
      "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": 1714006663,
        "expires": true,
        "expires_at": 1716598663,
        "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": 1714006663,
      "credit_card": {
        "exp_month": 1,
        "exp_year": 2040
      },
      "custom_field": "Custom field value",
      "discord_user_id": "000000000000000000",
      "email": "[email protected]",
      "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": 1714006663,
        "expires": true,
        "expires_at": 1716598663,
        "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": 1714006663,
      "credit_card": {
        "exp_month": 1,
        "exp_year": 2040
      },
      "custom_field": "Custom field value",
      "discord_user_id": "000000000000000000",
      "email": "[email protected]",
      "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": 1714006663,
        "expires": true,
        "expires_at": 1716598663,
        "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:

Can't find what you're looking for? We'd love to help! 💪

Send us a message through the orange chat bubble in the lower right corner of the page. You'll hear back within a few hours Monday - Friday. 😀