Billing Cycles
Purpose
A billing cycle belongs to one plan and defines its duration, such as one month or forever. Subscriptions select a billing cycle; an optional external product ID maps it to a payment-provider price.
Access and initialization
Access
Method catalog
Database and connection failures may propagate from any operation. Method-specific errors are listed with each method.
| Method | Purpose |
|---|---|
createBillingCycle | Creates an active billing cycle. |
updateBillingCycle | Updates cadence or display properties. |
getBillingCycle | Gets a billing cycle or null. |
listBillingCycles | Lists matching billing cycles. |
getBillingCyclesByPlan | Lists every cycle for a plan. |
archiveBillingCycle | Archives a billing cycle. |
unarchiveBillingCycle | Restores a billing cycle. |
deleteBillingCycle | Deletes an unused archived cycle. |
calculateNextPeriodEnd | Calculates a period-end date. |
getBillingCyclesByDurationUnit | Finds cycles by duration unit. |
getDefaultBillingCycles | Looks up the conventional cycle keys. |
| Method | Purpose |
|---|---|
CreateBillingCycleAsync | Creates an active billing cycle. |
UpdateBillingCycleAsync | Updates cadence or display properties. |
GetBillingCycleAsync | Gets a billing cycle or null. |
ListBillingCyclesAsync | Lists matching billing cycles. |
GetBillingCyclesByPlanAsync | Lists every cycle for a plan. |
ArchiveBillingCycleAsync | Archives a billing cycle. |
UnarchiveBillingCycleAsync | Restores a billing cycle. |
DeleteBillingCycleAsync | Deletes an unused archived cycle. |
CalculateNextPeriodEndAsync | Calculates a period-end date. |
GetBillingCyclesByDurationUnitAsync | Finds cycles by duration unit. |
GetDefaultBillingCyclesAsync | Looks up the conventional cycle keys. |
Method details
createBillingCycle
Create an active billing cycle with a globally unique key. A finite duration requires a positive count; forever requires the count to be omitted.
Parameters
dto: CreateBillingCycleDto with its plan, key, label, and duration.
Returns BillingCycleDto: Saved cycle details, including plan and product keys.
Example
// pro exists.
await subscrio.billingCycles.createBillingCycle({
planKey: 'pro', key: 'pro-monthly', displayName: 'Monthly',
durationUnit: 'months', durationValue: 1
});
Errors (3)
ValidationError: The properties or duration combination are invalid.NotFoundError: The plan does not exist.ConflictError: The billing cycle key already exists.
Parameters
dto: CreateBillingCycleDto with its plan, key, label, and duration.
Returns BillingCycleDto: Saved cycle details, including plan and product keys.
Example
// pro exists.
await subscrio.BillingCycles.CreateBillingCycleAsync(new CreateBillingCycleDto(
PlanKey: "pro", Key: "pro-monthly", DisplayName: "Monthly",
DurationUnit: "months", DurationValue: 1));
Errors (3)
ValidationException: The properties or duration combination are invalid.NotFoundException: The plan does not exist.ConflictException: The billing cycle key already exists.
updateBillingCycle
Update the cycle without changing its key or plan. Changing its duration affects future period calculations; this method does not rewrite dates already stored on subscriptions. When changing the unit, supply a count for finite durations and omit it for forever. A previous count may remain stored for forever but is ignored by period calculation.
Parameters
key: Billing cycle to update.dto: UpdateBillingCycleDto. Uses partial updates.
Returns BillingCycleDto: Saved cycle details, including plan and product keys.
Example
await subscrio.billingCycles.updateBillingCycle('pro-monthly', {
durationUnit: 'months', durationValue: 3
});
Errors (2)
ValidationError: The properties or duration combination are invalid.NotFoundError: The cycle or its related plan is missing.
Parameters
key: Billing cycle to update.dto: UpdateBillingCycleDto. Uses partial updates.
Returns BillingCycleDto: Saved cycle details, including plan and product keys.
Example
await subscrio.BillingCycles.UpdateBillingCycleAsync("pro-monthly",
new UpdateBillingCycleDto(DurationUnit: "months", DurationValue: 3));
Errors (2)
ValidationException: The properties or duration combination are invalid.NotFoundException: The cycle or its related plan is missing.
getBillingCycle
Retrieve a billing cycle, including archived cycles.
Parameters
key: Billing cycle key.
Returns BillingCycleDto | null: Cycle details, or null when missing.
Example
const cycle = await subscrio.billingCycles.getBillingCycle('pro-monthly');
console.log(cycle?.durationUnit);
Errors (1)
NotFoundError: A cycle exists but its related plan or product cannot be resolved.
Parameters
key: Billing cycle key.
Returns BillingCycleDto?: Cycle details, or null when missing.
Example
var cycle = await subscrio.BillingCycles.GetBillingCycleAsync("pro-monthly");
Console.WriteLine(cycle?.DurationUnit);
Errors (1)
NotFoundException: A cycle exists but its related plan or product cannot be resolved.
listBillingCycles
List cycles with filtering, sorting, and pagination. Supplying a plan key instead returns all cycles for that plan; after validation, the other filters, sort options, and pagination are ignored. Without a plan key, results default to creation time ascending.
Parameters
filters: Optional BillingCycleFilterDto. Defaults to 50 results at offset zero when not filtering by plan.
Returns BillingCycleDto[]: Matching cycles, or an empty collection.
Example
const cycles = await subscrio.billingCycles.listBillingCycles({
status: 'active', limit: 20, offset: 0
});
console.log(cycles);
Errors (2)
ValidationError: A filter or pagination value is invalid.NotFoundError: The specified plan does not exist.
Parameters
filters: Optional BillingCycleFilterDto. Defaults to 50 results at offset zero when not filtering by plan.
Returns List<BillingCycleDto>: Matching cycles, or an empty collection.
Example
var cycles = await subscrio.BillingCycles.ListBillingCyclesAsync(
new BillingCycleFilterDto(Status: "active", Limit: 20));
Console.WriteLine(cycles.Count);
Errors (2)
ValidationException: A filter or pagination value is invalid.NotFoundException: The specified plan does not exist.
getBillingCyclesByPlan
List all cycles for a plan, including archived cycles, in creation-time order. This lookup does not paginate.
Parameters
planKey: Plan key.
Returns BillingCycleDto[]: Plan cycles, or an empty collection.
Example
Errors (1)
NotFoundError: The plan does not exist.
Parameters
planKey: Plan key.
Returns List<BillingCycleDto>: Plan cycles, or an empty collection.
Example
var cycles = await subscrio.BillingCycles.GetBillingCyclesByPlanAsync("pro");
Console.WriteLine(cycles.Count);
Errors (1)
NotFoundException: The plan does not exist.
archiveBillingCycle
Mark the cycle as archived while retaining its definition and subscriptions. This does not cancel subscriptions.
Parameters
key: Billing cycle key.
Returns No returned value.
Example
Errors (1)
NotFoundError: The billing cycle does not exist.
unarchiveBillingCycle
Restore the cycle to active status while retaining its saved definition.
Parameters
key: Billing cycle key.
Returns No returned value.
Example
Errors (1)
NotFoundError: The billing cycle does not exist.
deleteBillingCycle
Permanently delete an archived cycle. Any referencing subscription, including cancelled or expired subscriptions, blocks deletion. Clear plan expiration-transition references first as well.
Parameters
key: Billing cycle key.
Returns No returned value.
Example
// pro-monthly is archived and has no references.
await subscrio.billingCycles.deleteBillingCycle('pro-monthly');
Errors (2)
NotFoundError: The billing cycle does not exist.DomainError: The cycle is active or has references that block deletion.
Parameters
key: Billing cycle key.
Returns No returned value.
Example
// pro-monthly is archived and has no references.
await subscrio.BillingCycles.DeleteBillingCycleAsync("pro-monthly");
Errors (2)
NotFoundException: The billing cycle does not exist.DomainException: The cycle is active or has references that block deletion.
calculateNextPeriodEnd
Calculate a date without updating a subscription. Forever cycles return null. TypeScript uses JavaScript local-calendar date arithmetic, which can overflow into the following month; .NET uses DateTime arithmetic, which clamps a missing day to the end of the target month.
Parameters
billingCycleKey: Cycle defining the duration.currentPeriodEnd: Date from which to add one cycle duration.
Returns Date | null: Calculated date, or null for forever.
Example
const next = await subscrio.billingCycles.calculateNextPeriodEnd(
'pro-monthly', new Date('2026-01-15T00:00:00Z')
);
console.log(next);
Errors (1)
NotFoundError: The billing cycle does not exist.
Parameters
billingCycleKey: Cycle defining the duration.currentPeriodEnd: Date from which to add one cycle duration.
Returns DateTime?: Calculated date, or null for forever.
Example
var next = await subscrio.BillingCycles.CalculateNextPeriodEndAsync(
"pro-monthly", new DateTime(2026, 1, 15, 0, 0, 0, DateTimeKind.Utc));
Console.WriteLine(next);
Errors (1)
NotFoundException: The billing cycle does not exist.
getBillingCyclesByDurationUnit
Find cycles by unit as a catalog helper. TypeScript checks all cycles and returns null plan/product keys in these snapshots. .NET filters its first 50 cycles before returning results and resolves their plan/product keys; use the normal list method for explicit pagination.
Parameters
durationUnit: DurationUnit to match.
Returns BillingCycleDto[]: Matching cycles, or an empty collection.
Example
Parameters
durationUnit: DurationUnit to match.
Returns List<BillingCycleDto>: Matching cycles, or an empty collection.
Example
getDefaultBillingCycles
Look up existing cycles with the exact keys monthly, quarterly, and yearly, in that order. This helper does not create defaults or verify that their durations match their names. TypeScript returns null plan/product keys for these snapshots; .NET resolves those keys.
Returns BillingCycleDto[]: Existing conventional-key cycles, or an empty collection.
Example
Returns List<BillingCycleDto>: Existing conventional-key cycles, or an empty collection.
Example
Data types
Required refers to supplied input fields or guaranteed returned properties. Conditional duration requirements apply in addition to nullable or optional types.
CreateBillingCycleDto
Properties for a billing cycle. The plan and key cannot be changed later.
| Field | Type | Required | Default | Meaning |
|---|---|---|---|---|
planKey | string | Yes | None | Owning plan key; null in TypeScript helper results that do not resolve relationships. |
key | string | Yes | None | Stable identifier. |
displayName | string | Yes | None | Human-readable label, 1 to 255 characters. |
durationUnit | "days" | "weeks" | "months" | "years" | "forever" | Yes | None | days, weeks, months, years, or forever. |
description | string | undefined | No | None | Optional description, up to 1,000 characters. |
durationValue | number | undefined | No | None | Positive integer for finite durations. On creation, required unless the unit is forever; omit for forever. |
externalProductId | string | undefined | No | None | Optional payment-provider price identifier, at most 255 characters. |
| Property | Type | Required | Default | Meaning |
|---|---|---|---|---|
PlanKey | string | Yes | None | Owning plan key; null in TypeScript helper results that do not resolve relationships. |
Key | string | Yes | None | Stable identifier. |
DisplayName | string | Yes | None | Human-readable label, 1 to 255 characters. |
DurationUnit | string | Yes | None | days, weeks, months, years, or forever. |
Description | string? | No | null | Optional description, up to 1,000 characters. |
DurationValue | int? | No | null | Positive integer for finite durations. On creation, required unless the unit is forever; omit for forever. |
ExternalProductId | string? | No | null | Optional payment-provider price identifier, at most 255 characters. |
BillingCycleDto
Billing cycle details returned by catalog methods.
| Field | Type | Required | Default | Meaning |
|---|---|---|---|---|
productKey | string | null | Yes | Not applicable | Owning product key; null in TypeScript helper results that do not resolve relationships. |
planKey | string | null | Yes | Not applicable | Owning plan key; null in TypeScript helper results that do not resolve relationships. |
key | string | Yes | Not applicable | Stable identifier. |
displayName | string | Yes | Not applicable | Human-readable label, 1 to 255 characters. |
description | string | null | undefined | No | Not applicable | Optional description, up to 1,000 characters. |
status | string | Yes | Not applicable | Current record status. |
durationValue | number | null | undefined | No | Not applicable | Stored duration count; ignored when the duration unit is forever. |
durationUnit | string | Yes | Not applicable | days, weeks, months, years, or forever. |
externalProductId | string | null | undefined | No | Not applicable | Optional payment-provider price identifier, at most 255 characters. |
createdAt | string | Yes | Not applicable | Creation time in UTC. |
updatedAt | string | Yes | Not applicable | Last update time in UTC. |
| Property | Type | Required | Default | Meaning |
|---|---|---|---|---|
ProductKey | string? | Yes | Not applicable | Owning product key; null in TypeScript helper results that do not resolve relationships. |
PlanKey | string? | Yes | Not applicable | Owning plan key; null in TypeScript helper results that do not resolve relationships. |
Key | string | Yes | Not applicable | Stable identifier. |
DisplayName | string | Yes | Not applicable | Human-readable label, 1 to 255 characters. |
Description | string? | Yes | Not applicable | Optional description, up to 1,000 characters. |
Status | string | Yes | Not applicable | Current record status. |
DurationValue | int? | Yes | Not applicable | Stored duration count; ignored when the duration unit is forever. |
DurationUnit | string | Yes | Not applicable | days, weeks, months, years, or forever. |
ExternalProductId | string? | Yes | Not applicable | Optional payment-provider price identifier, at most 255 characters. |
CreatedAt | string | Yes | Not applicable | Creation time in UTC. |
UpdatedAt | string | Yes | Not applicable | Last update time in UTC. |
UpdateBillingCycleDto
Editable properties. Uses partial updates.
| Field | Type | Required | Default | Meaning |
|---|---|---|---|---|
displayName | string | undefined | No | None | Human-readable label, 1 to 255 characters. |
description | string | undefined | No | None | Optional description, up to 1,000 characters. |
durationValue | number | undefined | No | None | Positive integer. Required when supplying a finite duration unit; omit when supplying forever. Otherwise omission keeps the current count. |
durationUnit | "days" | "weeks" | "months" | "years" | "forever" | undefined | No | None | days, weeks, months, years, or forever. |
externalProductId | string | undefined | No | None | Optional payment-provider price identifier, at most 255 characters. |
| Property | Type | Required | Default | Meaning |
|---|---|---|---|---|
DisplayName | string? | No | null | Human-readable label, 1 to 255 characters. |
Description | string? | No | null | Optional description, up to 1,000 characters. |
DurationValue | int? | No | null | Positive integer. Required when supplying a finite duration unit; omit when supplying forever. Otherwise omission keeps the current count. |
DurationUnit | string? | No | null | days, weeks, months, years, or forever. |
ExternalProductId | string? | No | null | Optional payment-provider price identifier, at most 255 characters. |
BillingCycleFilterDto
Catalog filters. TypeScript requires limit and offset when a filter object is supplied.
| Field | Type | Required | Default | Meaning |
|---|---|---|---|---|
limit | number | Yes | 50 | Maximum page size, 1 to 100. |
offset | number | Yes | 0 | Nonnegative number of rows to skip. |
durationUnit | "days" | "weeks" | "months" | "years" | "forever" | undefined | No | None | Restrict to days, weeks, months, years, or forever. |
search | string | undefined | No | None | Match display name or description. |
sortBy | "displayName" | "createdAt" | undefined | No | None | displayName or createdAt; defaults to creation time. |
sortOrder | "asc" | "desc" | undefined | No | None | asc or desc; defaults to asc. |
planKey | string | undefined | No | None | Selects all cycles for a plan and bypasses the remaining filters and pagination. |
status | "active" | "archived" | undefined | No | None | active or archived. |
| Property | Type | Required | Default | Meaning |
|---|---|---|---|---|
PlanKey | string? | No | null | Selects all cycles for a plan and bypasses the remaining filters and pagination. |
Status | string? | No | null | active or archived. |
Limit | int | No | 50 | Maximum page size, 1 to 100. |
Offset | int | No | 0 | Nonnegative number of rows to skip. |
DurationUnit | string? | No | null | Restrict to days, weeks, months, years, or forever. |
Search | string? | No | null | Match display name or description. |
SortBy | string? | No | null | displayName or createdAt; defaults to creation time. |
SortOrder | string? | No | null | asc or desc; defaults to asc. |
DurationUnit
Duration enum accepted by the unit lookup helper. DTOs use the corresponding lowercase strings.
| Value | Meaning |
|---|---|
DurationUnit.Days | Calendar days. |
DurationUnit.Weeks | Seven-day periods. |
DurationUnit.Months | Calendar months. |
DurationUnit.Years | Calendar years. |
DurationUnit.Forever | No finite period end. |
| Value | Meaning |
|---|---|
DurationUnit.Days | Calendar days. |
DurationUnit.Weeks | Seven-day periods. |
DurationUnit.Months | Calendar months. |
DurationUnit.Years | Calendar years. |
DurationUnit.Forever | No finite period end. |
Related guides
- Plans: define offerings and expiration-transition targets.
- Subscriptions: select a billing cycle and manage stored period dates.
- Stripe Integration: map external price IDs.
- Subscription Lifecycle: expiration and renewal.