Plans

Overview

Plan webhooks notify your application when subscription plans are created or updated. Use these events to sync pricing information, update your catalog, and track plan configuration changes.


Use Cases

  • Sync plan pricing and details to your storefront
  • Track plan configuration changes (pricing, intervals, trial periods)
  • Update external billing systems when plans change
  • Monitor plan activation and archival

Events

EventDescription
plan.createdA new subscription plan was created
plan.updatedAn existing plan was modified

plan.created

Triggered When

  • A plan is created via the Core API
  • A plan is created from the Platform

Payload

{
  "type": "plan.created",
  "id": "evt_a1B2c3D4e5F6g7H8i9J0k1L2",
  "created": 1704067200,
  "data": {
    "object": {
      "id": 100001,
      "product_id": 200001,
      "parent_plan_id": null,
      "object_id": "plan_XXXXXXXXXXXXXX",
      "active": "active",
      "type": "regular",
      "amount": 1999,
      "recognized_revenue_type": null,
      "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": 7,
      "ip_addresses": null,
      "domains": null,
      "created_at": "2026-01-01T12:00:00.000000Z",
      "updated_at": "2026-01-01T12:00:00.000000Z",
      "site_ids": [1],
      "product": {
        "id": 200001,
        "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]
      }
    }
  }
}

plan.updated

Triggered When

  • A plan is updated via the Core API
  • A plan is updated from the Platform
  • A plan is activated or archived

Payload

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

{
  "type": "plan.updated",
  "id": "evt_b2C3d4E5f6G7h8I9j0K1l2M3",
  "created": 1704153600,
  "data": {
    "object": {
      "id": 100001,
      "product_id": 200001,
      "parent_plan_id": null,
      "object_id": "plan_XXXXXXXXXXXXXX",
      "active": "archived",
      "type": "regular",
      "amount": 1999,
      "recognized_revenue_type": null,
      "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": 7,
      "ip_addresses": null,
      "domains": null,
      "created_at": "2026-01-01T12:00:00.000000Z",
      "updated_at": "2026-01-02T12:00:00.000000Z",
      "site_ids": [1],
      "product": {
        "id": 200001,
        "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]
      }
    },
    "previous_attributes": {
      "active": "active",
      "updated_at": "2026-01-01T12:00:00.000000Z"
    }
  }
}

Payload Fields

Plan Object

FieldTypeDescription
idintegerUnique identifier for the plan
product_idintegerParent product ID
parent_plan_idinteger | nullParent plan ID (for child/tiered plans)
object_idstring | nullExternal gateway identifier (e.g., Stripe plan ID)
activestringPlan status: "active" or "archived"
typestring | nullPlan type (e.g., "regular", "membership")
amountintegerPrice in cents (e.g., 1999 = $19.99)
recognized_revenue_typestring | nullRevenue recognition method: "time" or "shipments"
renewal_strategystring | nullRenewal strategy (e.g., "regular")
auto_renewbooleanWhether the plan auto-renews at the end of each interval
available_onlinebooleanWhether the plan is available for online purchase
allow_send_invoicebooleanWhether invoices can be sent for this plan
auto_uncollectible_daysinteger | nullDays before an unpaid invoice is marked uncollectible
invoice_upcoming_notificationinteger | nullDays before renewal to send an upcoming invoice notification
currencystringThree-letter ISO currency code
countriesarray | nullArray of ISO country codes where the plan is available
entitlementsarray | nullEntitlement keys granted by this plan
intervalstringBilling interval: "minute", "hour", "day", "week", "month", or "year"
interval_countintegerNumber of intervals between billings (e.g., 3 with "month" = quarterly)
is_importedbooleanWhether the plan was imported from an external system
is_hiddenbooleanWhether the plan is hidden from customers
is_donationbooleanWhether the plan is a donation plan
metadataobject | nullCustom key-value metadata
member_seat_capacityinteger | nullMaximum number of member seats (for membership plans)
nicknamestring | nullPlan display name
name_internalstring | nullInternal plan name (not shown to customers)
refundablebooleanWhether payments on this plan are refundable
shipments_per_intervalinteger | nullNumber of shipments per billing interval (for shipment-based plans)
descriptionstring | nullPlan description
trial_period_daysinteger | nullNumber of free trial days
ip_addressesarray | nullIP address restrictions for access
domainsarray | nullDomain restrictions for access
site_idsarrayArray of site IDs where the plan is available (derived from the parent product)
productobjectNested product object (see Product Webhooks for field descriptions)
created_atstringISO 8601 timestamp when the plan was created
updated_atstringISO 8601 timestamp when the plan was last modified

Previous Attributes (updated events only)

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

Notes

  • The Plan object does not include an object field in the payload (unlike most other webhook resources). It uses the top-level type field to identify the event.
  • active is a string ("active" or "archived"), not a boolean.
  • interval is a string (e.g., "month", "year"), not an integer.
  • amount is in cents (e.g., 1999 = $19.99).
  • There is no plan.deleted event — plans are archived (active: "archived") rather than deleted, which triggers a plan.updated event.
  • The nested product object uses the same structure as Product Webhooks but does not include an object field.

Related