Plan Management Service Reference
Service Overview
The Plan Management Service manages purchasable tiers within each product. It handles plan lifecycle, feature value overrides, and transition settings that affect billing cycles and subscriptions.
- Plan keys are globally unique and immutable.
- Each plan belongs to exactly one product (
productKey) and may define transition targets via onExpireTransitionToBillingCycleKey. - Deletion is only allowed when a plan is archived and unused by billing cycles or subscriptions.
Accessing the Service
import { Subscrio } from '@subscrio/core';
const subscrio = new Subscrio({ database: { connectionString: process.env.DATABASE_URL! } });
const plans = subscrio.plans;
Method Catalog
| Method | Description | Returns |
createPlan | Creates a new plan for an existing product | Promise<PlanDto> |
updatePlan | Updates mutable plan fields | Promise<PlanDto> |
getPlan | Retrieves a plan by key | Promise<PlanDto | null> |
listPlans | Lists plans with filters and pagination | Promise<PlanDto[]> |
getPlansByProduct | Lists plans for a specific product | Promise<PlanDto[]> |
archivePlan | Archives a plan | Promise<void> |
unarchivePlan | Reactivates an archived plan | Promise<void> |
deletePlan | Deletes an archived plan with no dependencies | Promise<void> |
setFeatureValue | Sets a plan-level feature value | Promise<void> |
removeFeatureValue | Removes a plan feature override | Promise<void> |
getFeatureValue | Gets a plan’s value for a feature | Promise<string | null> |
getPlanFeatures | Lists all feature values stored on a plan | Promise<Array<{ featureKey: string; value: string }>> |
Method Reference
createPlan
Description
Validates payload, ensures the product exists, and persists a new plan with active status.
Signature
createPlan(dto: CreatePlanDto): Promise<PlanDto>
| Name | Type | Required | Description |
dto | CreatePlanDto | Yes | Plan definition including product and metadata. |
| Field | Type | Required | Description |
productKey | string | Yes | Product that owns the plan. |
key | string | Yes | Immutable plan key (1–255 chars). |
displayName | string | Yes | 1–255 char label. |
description | string | No | ≤1000 characters. |
onExpireTransitionToBillingCycleKey | string | No | Optional billing cycle key for automatic transitions. |
metadata | Record<string, unknown> | No | JSON-safe metadata. |
Returns
Promise<PlanDto> – persisted plan snapshot.
Return Properties
- See
PlanDto in the DTO Reference.
Expected Results
- Validates DTO via Zod schema.
- Ensures product exists.
- Rejects duplicate plan keys.
- Persists plan with empty feature values array.
Potential Errors
| Error | When |
ValidationError | DTO invalid. |
NotFoundError | Product key not found. |
ConflictError | Plan key already exists. |
Example
await plans.createPlan({
productKey: 'pro-suite',
key: 'annual-pro',
displayName: 'Annual Pro',
metadata: { priceUsd: 499 }
});
updatePlan
Description
Applies partial updates such as display name, description, transition target, or metadata.
Signature
updatePlan(planKey: string, dto: UpdatePlanDto): Promise<PlanDto>
| Name | Type | Required | Description |
planKey | string | Yes | Plan to mutate. |
dto | UpdatePlanDto | Yes | Partial update payload. |
| Field | Type | Required | Description |
displayName | string | No | Updated label. |
description | string | No | New description. |
onExpireTransitionToBillingCycleKey | string | No | Replacement transition target. |
metadata | Record<string, unknown> | No | Replaces metadata blob. |
Returns
Promise<PlanDto> – updated plan snapshot.
Expected Results
- Validates provided fields.
- Loads plan, applies updates, persists entity.
Potential Errors
| Error | When |
ValidationError | DTO invalid. |
NotFoundError | Plan key not found. |
Example
await plans.updatePlan('annual-pro', {
onExpireTransitionToBillingCycleKey: 'monthly-pro',
metadata: { priceUsd: 399 }
});
getPlan
Description
Retrieves a plan by key, returning null when it is missing.
Signature
getPlan(planKey: string): Promise<PlanDto | null>
| Name | Type | Required | Description |
planKey | string | Yes | Plan identifier. |
Returns
Promise<PlanDto | null>
Return Properties
PlanDto when found; null otherwise.
Expected Results
- Loads plan from repository and maps to DTO.
Potential Errors
| Error | When |
| None | Returns null when not found. |
Example
const plan = await plans.getPlan('annual-pro');
listPlans
Description
Lists plans using optional status, product, search, and pagination filters.
Signature
listPlans(filters?: PlanFilterDto): Promise<PlanDto[]>
| Name | Type | Required | Description |
filters | PlanFilterDto | No | Optional filter and pagination controls. |
| Field | Type | Description |
productKey | string | Restrict to a product. |
status | 'active' | 'archived' | Lifecycle filter. |
search | string | Text search across key/display name. |
sortBy | 'displayName' | 'createdAt' | Sort column. |
sortOrder | 'asc' | 'desc' | Sort direction (default 'asc'). |
limit | number | 1–100 (default 50). |
offset | number | ≥0 (default 0). |
Returns
Promise<PlanDto[]>
Return Properties
- Array of
PlanDto entries.
Expected Results
- Validates filters.
- Executes query and maps results to DTOs.
Potential Errors
| Error | When |
ValidationError | Filters invalid. |
Example
const archivedPlans = await plans.listPlans({ status: 'archived', limit: 20 });
getPlansByProduct
Description
Returns all plans owned by a product.
Signature
getPlansByProduct(productKey: string): Promise<PlanDto[]>
| Name | Type | Required | Description |
productKey | string | Yes | Product key to inspect. |
Returns
Promise<PlanDto[]>
Return Properties
- Array of
PlanDto entries scoped to the product.
Expected Results
- Ensures product exists.
- Queries repository for all plans referencing the product.
Potential Errors
| Error | When |
NotFoundError | Product key missing. |
Example
const proPlans = await plans.getPlansByProduct('pro-suite');
archivePlan
Description
Marks a plan as archived so it cannot be sold to new customers.
Signature
archivePlan(planKey: string): Promise<void>
| Name | Type | Required | Description |
planKey | string | Yes | Plan to archive. |
Returns
Promise<void>
Expected Results
- Loads plan, calls entity
archive(), saves.
Potential Errors
| Error | When |
NotFoundError | Plan missing. |
Example
await plans.archivePlan('legacy-tier');
unarchivePlan
Description
Restores an archived plan to active.
Signature
unarchivePlan(planKey: string): Promise<void>
| Name | Type | Required | Description |
planKey | string | Yes | Archived plan key. |
Returns
Promise<void>
Expected Results
- Loads plan, calls
unarchive(), persists change.
Potential Errors
| Error | When |
NotFoundError | Plan missing. |
Example
await plans.unarchivePlan('legacy-tier');
deletePlan
Description
Deletes a plan after confirming it is archived and unused by billing cycles or subscriptions.
Signature
deletePlan(planKey: string): Promise<void>
| Name | Type | Required | Description |
planKey | string | Yes | Plan targeted for deletion. |
Returns
Promise<void>
Expected Results
- Loads plan and checks
plan.canDelete() (requires archived status). - Ensures no billing cycles reference the plan.
- Ensures no subscriptions exist for the plan.
- Deletes plan record.
Potential Errors
| Error | When |
NotFoundError | Plan missing. |
DomainError | Plan still active or has dependent records. |
Example
await plans.deletePlan('legacy-tier');
setFeatureValue
Description
Sets or updates a plan-level override for a feature.
Signature
setFeatureValue(planKey: string, featureKey: string, value: string): Promise<void>
| Name | Type | Required | Description |
planKey | string | Yes | Plan receiving the override. |
featureKey | string | Yes | Feature key being overridden. |
value | string | Yes | Stored string value validated against feature type. |
value must satisfy the feature’s valueType and validator metadata.
Returns
Promise<void>
Expected Results
- Ensures plan and feature exist.
- Validates the value via
FeatureValueValidator. - Inserts or updates the plan’s feature value entry.
Potential Errors
| Error | When |
NotFoundError | Plan or feature missing. |
ValidationError | Value fails validation rules. |
Example
await plans.setFeatureValue('annual-pro', 'max-projects', '100');
removeFeatureValue
Description
Removes a stored feature override from a plan.
Signature
removeFeatureValue(planKey: string, featureKey: string): Promise<void>
| Name | Type | Required | Description |
planKey | string | Yes | Plan losing the override. |
featureKey | string | Yes | Feature key to remove. |
Returns
Promise<void>
Expected Results
- Ensures plan and feature exist.
- Removes the stored value when present.
Potential Errors
| Error | When |
NotFoundError | Plan or feature missing. |
Example
await plans.removeFeatureValue('annual-pro', 'max-projects');
getFeatureValue
Description
Retrieves the value a plan has stored for a specific feature.
Signature
getFeatureValue(planKey: string, featureKey: string): Promise<string | null>
| Name | Type | Required | Description |
planKey | string | Yes | Plan to inspect. |
featureKey | string | Yes | Feature key. |
Returns
Promise<string | null>
Return Properties
string when a stored value exists. null when the plan has no override.
Expected Results
- Loads plan and returns the stored feature value if present.
Potential Errors
| Error | When |
NotFoundError | Plan missing. |
Example
const value = await plans.getFeatureValue('annual-pro', 'max-projects');
getPlanFeatures
Description
Lists all feature overrides configured on a plan.
Signature
getPlanFeatures(planKey: string): Promise<Array<{ featureKey: string; value: string }>>
| Name | Type | Required | Description |
planKey | string | Yes | Plan identifier. |
Returns
Promise<Array<{ featureKey: string; value: string }>>
Return Properties
- Array of
{ featureKey, value } pairs for overrides stored on the plan.
Expected Results
- Loads plan and returns all feature value entries.
Potential Errors
| Error | When |
NotFoundError | Plan missing. |
Example
const overrides = await plans.getPlanFeatures('annual-pro');
DTO Reference
CreatePlanDto
| Field | Type | Required | Notes |
productKey | string | Yes | Existing product key. |
key | string | Yes | Unique plan identifier. |
displayName | string | Yes | 1–255 characters. |
description | string | No | ≤1000 characters. |
onExpireTransitionToBillingCycleKey | string | No | Billing cycle key for auto transition. |
metadata | Record<string, unknown> | No | JSON-safe metadata. |
UpdatePlanDto
All CreatePlanDto fields become optional for updates.
PlanDto
| Field | Type | Description |
productKey | string | Parent product key. |
key | string | Plan key. |
displayName | string | Human-friendly name. |
description | string | null | Optional description. |
status | string | active or archived. |
onExpireTransitionToBillingCycleKey | string | null | Transition target key. |
metadata | Record<string, unknown> | null | Stored metadata. |
createdAt | string | ISO timestamp. |
updatedAt | string | ISO timestamp. |
PlanFilterDto
| Field | Type | Description |
productKey | string | Filter by product. |
status | 'active' | 'archived' | Lifecycle filter. |
search | string | Text search. |
sortBy | 'displayName' | 'createdAt' | Sort column. |
sortOrder | 'asc' | 'desc' | Sort direction. |
limit | number | 1–100 (default 50). |
offset | number | ≥0 (default 0). |
- Products must exist before plans can be created (
ProductManagementService). - Plans cannot be deleted while billing cycles (
BillingCycleManagementService) or subscriptions (SubscriptionManagementService) reference them. - Plan feature values participate in the feature resolution hierarchy enforced by
FeatureCheckerService.