Skip to main content

Plan Items and Add-ons

PlanItem is the structured way to attach priced, quantified add-ons to a plan. Use it whenever a feature has a price, an included quantity, or an overage behaviour — not just a boolean flag.

When to use PlanItem vs features JSON

Booleans stay in features. Anything with a price or quantity goes in PlanItem.

Creating plan items

CapBehavior enum

SubscriptionItem — per-subscriber state

When a subscriber has a plan with PlanItems, a SubscriptionItem record is created per item at subscription time. SubscriptionItem tracks:
  • quantity — how many units the subscriber is currently using
  • price_override / price_override_expires_at — admin-set per-subscriber price
  • gateway_item_id — the gateway’s item ID for native gateways (Stripe)

Updating quantities

For gateways that manage items natively (Stripe), this also updates the subscription item at the gateway.

Entitlement checks

Entitlements resolves plan items automatically:
Resolution order:
  1. Check Plan.features[$key] — if a value is set here, use it.
  2. Check PlanItem by key — use included_quantity as the limit.

Price overrides

Apply a per-subscriber price override to any SubscriptionItem:
When an override’s expires_at passes at renewal, RenewSubscription fires SubscriptionPriceOverrideReverted and reverts to price_snapshot.

Overage billing at renewal

At renewal, RenewSubscription automatically charges overages for items with CapBehavior::Charge or CapBehavior::ChargeUntilCeiling:
effective_unit_price is SubscriptionItem.price_override when active, otherwise PlanItem.unit_price. For gateways with native subscription item support (Stripe), overage is reported via the gateway’s items API and included in the gateway’s renewal invoice. For other gateways, subscribd issues a separate charge() call.

Next steps