Subscriptions

Receive notifications for subscription lifecycle events including creation, renewal, cancellation, and expiration.

Overview

Subscription webhooks notify your application about every stage of the subscription lifecycle — from creation and renewal to cancellation and expiration. These are the most commonly used Pelcro webhooks and carry a deeply nested payload including customer, plan, invoice, and payment method details.


Use Cases

  • Provision or revoke access when subscriptions are created, renewed, or expire
  • Trigger dunning flows when subscriptions are canceled or past due
  • Sync subscription status to your CMS or access control system
  • Alert customers before their trial ends
  • Track gift subscription fulfillment
  • Monitor churn risk with prediction scores

Events

EventDescription
subscription.createdA new subscription was created
subscription.updatedA subscription was modified
subscription.changedA subscription was changed (e.g., plan switch)
subscription.canceledA subscription was canceled
subscription.renewedA subscription was renewed for a new billing period
subscription.expiredA subscription has expired
subscription.trial_will_endA subscription's trial period is about to end
subscription.gift_notificationA gift subscription notification was sent

subscription.created

Triggered When

  • A customer subscribes via the SDK
  • A subscription is created via the Core API
  • A subscription is created from the Platform

Note: This event is not fired during data migrations (when the subscription is flagged as migrating).

Payload

{
  "type": "subscription.created",
  "id": "evt_a1B2c3D4e5F6g7H8i9J0k1L2",
  "created": 1704067200,
  "data": {
    "object": {
      "object": "subscription",
      "id": 100001,
      "address_id": 200001,
      "address_shipping": {
        "object": "address",
        "id": 200001,
        "city": "Springfield",
        "company": null,
        "country": "US",
        "country_name": "United States",
        "created_at": "2025-06-15T10:00:00.000000Z",
        "department": null,
        "first_name": "Jane",
        "is_default": true,
        "last_name": "Doe",
        "line1": "123 Main Street",
        "line2": null,
        "postal_code": "62704",
        "salutation": null,
        "site_ids": [1],
        "state": "IL",
        "state_name": "Illinois",
        "title": null,
        "type": "shipping",
        "updated_at": "2025-06-15T10:00:00.000000Z"
      },
      "agency_id": null,
      "auto_renew": true,
      "backdate_start_date": null,
      "billing": 1,
      "billing_cycle_anchor": "2026-01-01T12:00:00.000000Z",
      "campaign_id": null,
      "campaign_key": null,
      "cancel_at": null,
      "cancel_at_period_end": 0,
      "cancel_reason": null,
      "canceled_at": null,
      "canceled_by_email": null,
      "canceled_by_type": null,
      "churn_prediction_created_at": null,
      "churn_prediction_updated_at": null,
      "churn_risk_bucket": null,
      "churn_risk_score": null,
      "coupon": null,
      "created": "2026-01-01T12:00:00.000000Z",
      "current_period_end": "2026-02-01T12:00:00.000000Z",
      "current_period_start": "2026-01-01T12:00:00.000000Z",
      "customer": {
        "object": "customer",
        "id": 300001,
        "balance": 0,
        "billing_email": null,
        "created": "2025-06-15T10:00:00.000000Z",
        "currency": "usd",
        "default_source": {
          "object": "source",
          "id": 400001,
          "object_id": "pm_XXXXXXXXXXXXXXXXXXXX",
          "object_gateway": "stripe",
          "brand": "visa",
          "country": "US",
          "exp_month": 12,
          "exp_year": 2028,
          "funding": "credit",
          "last4": "4242",
          "site_ids": [1]
        },
        "delinquent": false,
        "display_name": null,
        "email": "[email protected]",
        "email_confirm": 0,
        "email_hardbounce": false,
        "first_name": "Jane",
        "has_password": 1,
        "language": null,
        "last_active_at": 1704067190,
        "last_login_method": "email",
        "last_name": "Doe",
        "mail_marketing": null,
        "metadata": null,
        "object_id": "cus_XXXXXXXXXXXXXX",
        "organization": null,
        "password_last_updated_at": null,
        "phone": null,
        "phone_confirm": null,
        "salutation": null,
        "site_ids": [1],
        "tele_marketing": null,
        "title": null,
        "username": null
      },
      "days_until_due": null,
      "default_source": {
        "object": "source",
        "id": 400001,
        "object_id": "pm_XXXXXXXXXXXXXXXXXXXX",
        "object_gateway": "stripe",
        "brand": "visa",
        "country": "US",
        "exp_month": 12,
        "exp_year": 2028,
        "funding": "credit",
        "last4": "4242",
        "site_ids": [1]
      },
      "default_tax_rates": null,
      "ended_at": null,
      "expires_at": null,
      "gift_code": null,
      "gift_donor_subscription_id": null,
      "gift_message": null,
      "gift_notification_sent": 0,
      "gift_recipient_email": null,
      "gift_recipient_first_name": null,
      "gift_recipient_last_name": null,
      "gift_start_date": null,
      "is_gift_donor": 0,
      "is_gift_recipient": 0,
      "is_redeemed": null,
      "latest_invoice": {
        "object": "invoice",
        "id": 500001,
        "...": "full invoice object (see Invoice Webhooks)"
      },
      "metadata": null,
      "object_id": "sub_XXXXXXXXXXXXXXXXXXXXXXXX",
      "plan": {
        "id": 600001,
        "product_id": 700001,
        "parent_plan_id": null,
        "object_id": "plan_XXXXXXXXXXXXXX",
        "active": "active",
        "type": "regular",
        "amount": 1999,
        "recognized_revenue_type": "time",
        "renewal_strategy": null,
        "auto_renew": true,
        "available_online": true,
        "allow_send_invoice": true,
        "auto_uncollectible_days": null,
        "invoice_upcoming_notification": null,
        "currency": "usd",
        "countries": null,
        "entitlements": null,
        "interval": "month",
        "interval_count": 1,
        "is_imported": false,
        "is_hidden": false,
        "is_donation": false,
        "metadata": null,
        "member_seat_capacity": null,
        "nickname": "Monthly Premium",
        "name_internal": null,
        "refundable": false,
        "shipments_per_interval": null,
        "description": "Monthly access to premium content.",
        "trial_period_days": 0,
        "ip_addresses": null,
        "domains": null,
        "created_at": "2025-12-15T10:00:00.000000Z",
        "updated_at": "2025-12-15T10:00:00.000000Z",
        "site_ids": [1],
        "product": {
          "id": 700001,
          "object_id": "prod_XXXXXXXXXXXXXX",
          "type": "service",
          "active": "active",
          "address_required": null,
          "countries": null,
          "description": "Premium content subscription.",
          "entitlements": null,
          "is_imported": null,
          "is_hidden": null,
          "language": null,
          "livemode": true,
          "metadata": null,
          "name": "Premium Content",
          "name_internal": null,
          "shippable": false,
          "statement_descriptor": null,
          "created_at": "2025-12-15T10:00:00.000000Z",
          "updated_at": "2025-12-15T10:00:00.000000Z",
          "site_ids": [1]
        }
      },
      "quantity": 1,
      "recommended_plan_id": null,
      "renews_at": 1738411200,
      "schedules": null,
      "shipments_remaining": null,
      "shipments_suspended_until": null,
      "shipments_undeliverable": false,
      "shipping_address": {
        "...": "same as address_shipping (deprecated)"
      },
      "site_id": 1,
      "source": null,
      "start_date": "2026-01-01T12:00:00.000000Z",
      "status": "active",
      "trial_end": null,
      "trial_start": null
    }
  }
}

subscription.updated

Triggered When

  • Any subscription attribute is saved (the most frequently fired subscription event)
  • A subscription is updated via the Core API or from the Platform
  • A subscription is updated during an agency import

Payload

The payload includes a previous_attributes object containing only the fields that changed.

{
  "type": "subscription.updated",
  "id": "evt_b2C3d4E5f6G7h8I9j0K1l2M3",
  "created": 1704153600,
  "data": {
    "object": {
      "object": "subscription",
      "id": 100001,
      "...": "full subscription object (same structure as subscription.created)"
    },
    "previous_attributes": {
      "current_period_start": "2025-12-01T12:00:00.000000Z",
      "current_period_end": "2026-01-01T12:00:00.000000Z",
      "billing_cycle_anchor": "2025-12-01T12:00:00.000000Z"
    }
  }
}

subscription.changed

Triggered When

  • A subscription's plan is changed (upgrade or downgrade)

Payload

The payload may include a previous_attributes object containing the fields that changed.

{
  "type": "subscription.changed",
  "id": "evt_c3D4e5F6g7H8i9J0k1L2m3N4",
  "created": 1704240000,
  "data": {
    "object": {
      "object": "subscription",
      "id": 100001,
      "...": "full subscription object with the new plan and updated fields"
    },
    "previous_attributes": {
      "plan": {
        "id": 600001,
        "nickname": "Monthly Basic",
        "amount": 999
      }
    }
  }
}

subscription.canceled

Triggered When

  • A customer cancels their subscription via the SDK
  • A subscription is canceled via the Core API or from the Platform
  • A subscription is immediately canceled (cancelNow) with or without a refund
  • A subscription schedule triggers a cancellation

Payload

When a subscription is canceled, the canceled_at, canceled_by_email, canceled_by_type, and cancel_reason fields are populated. If the subscription will remain active until the end of the billing period, cancel_at_period_end is 1 and status remains "active".

{
  "type": "subscription.canceled",
  "id": "evt_d4E5f6G7h8I9j0K1l2M3n4O5",
  "created": 1704326400,
  "data": {
    "object": {
      "object": "subscription",
      "id": 100001,
      "...": "full subscription object",
      "auto_renew": false,
      "cancel_at_period_end": 1,
      "cancel_reason": "Too expensive",
      "canceled_at": "2026-01-04T12:00:00.000000Z",
      "canceled_by_email": "[email protected]",
      "canceled_by_type": "Admin/Collaborator",
      "expires_at": 1738411200,
      "status": "active"
    }
  }
}

subscription.renewed

Triggered When

  • A subscription is renewed at the end of a billing period by the Pelcro Billing Engine
  • A subscription is manually renewed via the Core API, SDK, or Platform
  • A canceled or expired subscription is reactivated/restarted (Pelcro-owned subscriptions)
  • A campaign-driven renewal is processed
  • An agency import renews a subscription

Payload

{
  "type": "subscription.renewed",
  "id": "evt_e5F6g7H8i9J0k1L2m3N4o5P6",
  "created": 1706832000,
  "data": {
    "object": {
      "object": "subscription",
      "id": 100001,
      "...": "full subscription object with updated billing period dates",
      "current_period_start": "2026-02-01T12:00:00.000000Z",
      "current_period_end": "2026-03-01T12:00:00.000000Z",
      "status": "active"
    }
  }
}

subscription.expired

Triggered When

  • A subscription's billing period has ended and the Pelcro Billing Engine expiration workflow runs
  • A subscription is immediately canceled (cancelNow) — this fires both subscription.canceled and subscription.expired back-to-back

Payload

{
  "type": "subscription.expired",
  "id": "evt_f6G7h8I9j0K1l2M3n4O5p6Q7",
  "created": 1738411200,
  "data": {
    "object": {
      "object": "subscription",
      "id": 100001,
      "...": "full subscription object",
      "auto_renew": false,
      "cancel_at_period_end": 0,
      "ended_at": "2026-02-01T12:00:00.000000Z",
      "status": "canceled"
    }
  }
}

subscription.trial_will_end

Triggered When

  • A subscription's trial period is approaching its end date (a scheduled job scans for trials ending soon and fires this event)

Payload

The payload includes a previous_attributes object containing only the fields that changed.

{
  "type": "subscription.trial_will_end",
  "id": "evt_g7H8i9J0k1L2m3N4o5P6q7R8",
  "created": 1704240000,
  "data": {
    "object": {
      "object": "subscription",
      "id": 100001,
      "...": "full subscription object",
      "status": "trialing",
      "trial_start": "2026-01-01T12:00:00.000000Z",
      "trial_end": "2026-01-14T12:00:00.000000Z"
    },
    "previous_attributes": {
      "status": "trialing"
    }
  }
}

subscription.gift_notification

Triggered When

  • A gift subscription is created and the gift_start_date is today or in the past (fires immediately at creation)
  • A scheduled job processes gift subscriptions whose gift_start_date has arrived (for future-dated gifts)

Payload

Gift-related fields are populated when this event fires.

{
  "type": "subscription.gift_notification",
  "id": "evt_h8I9j0K1l2M3n4O5p6Q7r8S9",
  "created": 1704067200,
  "data": {
    "object": {
      "object": "subscription",
      "id": 100001,
      "...": "full subscription object",
      "is_gift_donor": 1,
      "is_gift_recipient": 0,
      "gift_code": "GIFT-XXXX-XXXX",
      "gift_recipient_email": "[email protected]",
      "gift_recipient_first_name": "John",
      "gift_recipient_last_name": "Smith",
      "gift_message": "Enjoy your subscription!",
      "gift_start_date": "2026-02-01T00:00:00.000000Z",
      "gift_notification_sent": 1,
      "gift_donor_subscription_id": null
    }
  }
}

Payload Fields

Subscription Object

FieldTypeDescription
objectstringObject type identifier, always subscription
idintegerUnique identifier for the subscription
object_idstring | nullExternal gateway identifier (e.g., Stripe subscription ID)
site_idintegerSite the subscription belongs to
address_idinteger | nullShipping address ID
statusstringSubscription status: "active", "canceled", "past_due", "trialing", "unpaid", "incomplete", "incomplete_expired", "extended", "pending_payment", or "scheduled"
auto_renewbooleanWhether the subscription will auto-renew (true when active and not set to cancel)
cancel_at_period_endintegerWhether the subscription will cancel at period end: 0 (no) or 1 (yes)
billingintegerBilling type
billing_cycle_anchorstring | nullISO 8601 timestamp of the billing cycle anchor
cancel_atstring | nullISO 8601 timestamp when the subscription is scheduled to cancel
canceled_atstring | nullISO 8601 timestamp when the subscription was canceled
canceled_by_emailstring | nullEmail of the user who canceled the subscription
canceled_by_typestring | nullWho canceled: "Customer", "Admin/Collaborator", "System", "churn_prediction", or null
cancel_reasonstring | nullReason provided for cancellation
createdstringISO 8601 timestamp when the subscription was created
current_period_startstring | nullISO 8601 timestamp of the current billing period start
current_period_endstring | nullISO 8601 timestamp of the current billing period end
days_until_dueinteger | nullNumber of days before an invoice is due (for send-invoice billing)
ended_atstring | nullISO 8601 timestamp when the subscription ended
expires_atinteger | nullUnix timestamp when the subscription will expire (null if auto-renewing)
renews_atinteger | nullUnix timestamp when the subscription will next renew (null if not renewing)
quantityinteger | nullNumber of seats or units
start_datestring | nullISO 8601 timestamp when the subscription started
trial_startstring | nullISO 8601 timestamp when the trial started
trial_endstring | nullISO 8601 timestamp when the trial ends
sourcestring | nullDeprecated source field
backdate_start_datestring | nullISO 8601 timestamp for backdated subscriptions
metadataobject | nullCustom key-value metadata
recommended_plan_idinteger | nullRecommended plan ID for upgrades
agency_idinteger | nullAssociated agency ID

Gift Fields

FieldTypeDescription
is_gift_donorintegerWhether this subscription is a gift donation: 0 or 1
is_gift_recipientintegerWhether this is a gift recipient subscription: 0 or 1
is_redeemedinteger | nullWhether the gift has been redeemed
gift_codestring | nullGift redemption code
gift_recipient_emailstring | nullEmail of the gift recipient
gift_recipient_first_namestring | nullGift recipient's first name
gift_recipient_last_namestring | nullGift recipient's last name
gift_messagestring | nullMessage from the gift donor
gift_start_datestring | nullISO 8601 timestamp when the gift starts
gift_notification_sentintegerWhether the gift notification was sent: 0 or 1
gift_donor_subscription_idinteger | nullID of the donor's subscription

Shipment Fields

FieldTypeDescription
shipments_remaininginteger | nullNumber of shipments remaining in the current period
shipments_undeliverablebooleanWhether shipments are undeliverable
shipments_suspended_untilstring | nullISO 8601 timestamp until when shipments are suspended

Churn Prediction Fields

📘

Premium Feature

Churn Prediction Score is a premium add-on. Contact [email protected] to activate it for your account. Additional fees apply. These fields will be null until the feature is enabled.

FieldTypeDescription
churn_risk_scoreinteger | nullPredicted churn risk score
churn_risk_bucketstring | nullChurn risk category: "low", "medium", or "high"
churn_prediction_created_atinteger | nullUnix timestamp when the prediction was created
churn_prediction_updated_atinteger | nullUnix timestamp when the prediction was last updated

Campaign Fields

FieldTypeDescription
campaign_idinteger | nullAssociated campaign ID
campaign_keystring | nullCampaign key used for acquisition tracking

Nested Objects

FieldTypeDescription
customerobject | nullFull customer object (see Customer Webhooks)
planobject | nullFull plan object with nested product (see Plan Webhooks)
couponobject | nullApplied coupon (see below)
default_sourceobject | nullDefault payment method (see Payment Method Webhooks). The nested customer field is excluded to avoid circular nesting.
latest_invoiceobject | nullMost recent invoice with nested charge (see Invoice Webhooks). The nested subscription field is excluded to avoid circular nesting.
address_shippingobject | nullShipping address (see Address Webhooks)
shipping_addressobject | nullSame as address_shipping (deprecated naming, kept for backwards compatibility)
schedulesobject | nullSubscription schedules list (see below)
default_tax_ratesobject | nullApplied tax rates list (see below)

Coupon Object (Nested)

FieldTypeDescription
objectstringAlways coupon
object_idstringExternal gateway coupon ID
typestringCoupon type (e.g., "subscription")
amount_offinteger | nullDiscount amount in cents
codestringCoupon code
createdstringISO 8601 timestamp
currencystring | nullThree-letter ISO currency code
durationstringDuration: "once", "repeating", or "forever"
duration_in_monthsinteger | nullNumber of months (for repeating coupons)
livemodebooleanWhether this is a live coupon
namestringCoupon display name
max_redemptionsinteger | nullMaximum number of times the coupon can be used
percent_offfloat | nullDiscount percentage
redeem_bystring | nullISO 8601 timestamp when the coupon expires
times_redeemedintegerNumber of times the coupon has been used
validbooleanWhether the coupon is still valid

Schedules Object (Nested)

When present, schedules use a list format:

{
  "object": "list",
  "data": [
    {
      "object": "subscription_schedule",
      "object_id": "sub_sched_XXXXXXXXXXXX",
      "status": "active",
      "phases": {
        "object": "list",
        "data": [
          {
            "object": "subscription_schedule_phase",
            "start_date": "2026-01-01T12:00:00.000000Z",
            "end_date": "2026-04-01T12:00:00.000000Z",
            "coupon": null,
            "plans": {
              "object": "list",
              "data": [{ "...": "phase plan objects" }]
            }
          }
        ]
      }
    }
  ]
}

Previous Attributes (updated, changed, and trial_will_end events)

FieldTypeDescription
previous_attributesobjectContains only the publishable fields that changed, with their previous values before the update.

Notes

  • The subscription payload is the most deeply nested of all webhook resources — it includes full customer, plan (with product), invoice (with charge), payment method, and address objects.
  • status is a string (e.g., "active", "canceled"), not an integer.
  • auto_renew is computed: it is true when the subscription is active or trialing and cancel_at_period_end is 0.
  • expires_at and renews_at are unix timestamps (integers), unlike most other date fields which use ISO 8601 strings.
  • cancel_at_period_end is an integer (0 or 1), not a boolean.
  • canceled_by_type maps the internal value "Publisher" to "Admin/Collaborator" in the webhook payload.
  • The default_source object in the subscription payload excludes the nested customer to avoid circular nesting. Similarly, latest_invoice excludes the nested subscription.
  • Both shipping_address (deprecated) and address_shipping (current) are included in the payload with identical data for backwards compatibility.
  • subscription.expired is the event name shown to subscribers, even though it corresponds to the internal event code SUBSCRIPTION_DELETED (305).

Related