Skip to content

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

const billingCycles = subscrio.billingCycles;
using Subscrio.Core.Application.DTOs;

var billingCycles = subscrio.BillingCycles;

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.

createBillingCycle(dto: CreateBillingCycleDto): Promise<BillingCycleDto>

Parameters

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.
Task<BillingCycleDto> CreateBillingCycleAsync(CreateBillingCycleDto dto)

Parameters

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.

updateBillingCycle(key: string, dto: UpdateBillingCycleDto): Promise<BillingCycleDto>

Parameters

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.
Task<BillingCycleDto> UpdateBillingCycleAsync(string key, UpdateBillingCycleDto dto)

Parameters

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.

getBillingCycle(key: string): Promise<BillingCycleDto | null>

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.
Task<BillingCycleDto?> GetBillingCycleAsync(string key)

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.

listBillingCycles(filters?: BillingCycleFilterDto): Promise<BillingCycleDto[]>

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.
Task<List<BillingCycleDto>> ListBillingCyclesAsync(BillingCycleFilterDto? filters)

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.

getBillingCyclesByPlan(planKey: string): Promise<BillingCycleDto[]>

Parameters

  • planKey: Plan key.

Returns BillingCycleDto[]: Plan cycles, or an empty collection.

Example

const cycles = await subscrio.billingCycles.getBillingCyclesByPlan('pro');
console.log(cycles);
Errors (1)
  • NotFoundError: The plan does not exist.
Task<List<BillingCycleDto>> GetBillingCyclesByPlanAsync(string planKey)

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.

archiveBillingCycle(key: string): Promise<void>

Parameters

  • key: Billing cycle key.

Returns No returned value.

Example

// pro-monthly exists.
await subscrio.billingCycles.archiveBillingCycle('pro-monthly');
Errors (1)
  • NotFoundError: The billing cycle does not exist.
Task ArchiveBillingCycleAsync(string key)

Parameters

  • key: Billing cycle key.

Returns No returned value.

Example

// pro-monthly exists.
await subscrio.BillingCycles.ArchiveBillingCycleAsync("pro-monthly");
Errors (1)
  • NotFoundException: The billing cycle does not exist.

unarchiveBillingCycle

Restore the cycle to active status while retaining its saved definition.

unarchiveBillingCycle(key: string): Promise<void>

Parameters

  • key: Billing cycle key.

Returns No returned value.

Example

// pro-monthly exists.
await subscrio.billingCycles.unarchiveBillingCycle('pro-monthly');
Errors (1)
  • NotFoundError: The billing cycle does not exist.
Task UnarchiveBillingCycleAsync(string key)

Parameters

  • key: Billing cycle key.

Returns No returned value.

Example

// pro-monthly exists.
await subscrio.BillingCycles.UnarchiveBillingCycleAsync("pro-monthly");
Errors (1)
  • NotFoundException: 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.

deleteBillingCycle(key: string): Promise<void>

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.
Task DeleteBillingCycleAsync(string key)

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.

calculateNextPeriodEnd(billingCycleKey: string, currentPeriodEnd: Date): Promise<Date | null>

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.
Task<DateTime?> CalculateNextPeriodEndAsync(string billingCycleKey, DateTime currentPeriodEnd)

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.

getBillingCyclesByDurationUnit(durationUnit: DurationUnit): Promise<BillingCycleDto[]>

Parameters

Returns BillingCycleDto[]: Matching cycles, or an empty collection.

Example

import { DurationUnit } from 'subscrio';

const cycles = await subscrio.billingCycles.getBillingCyclesByDurationUnit(DurationUnit.Months);
console.log(cycles);
Task<List<BillingCycleDto>> GetBillingCyclesByDurationUnitAsync(DurationUnit durationUnit)

Parameters

Returns List<BillingCycleDto>: Matching cycles, or an empty collection.

Example

var cycles = await subscrio.BillingCycles.GetBillingCyclesByDurationUnitAsync(
    Subscrio.Core.Domain.ValueObjects.DurationUnit.Months);
Console.WriteLine(cycles.Count);

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.

getDefaultBillingCycles(): Promise<BillingCycleDto[]>

Returns BillingCycleDto[]: Existing conventional-key cycles, or an empty collection.

Example

const cycles = await subscrio.billingCycles.getDefaultBillingCycles();
console.log(cycles);
Task<List<BillingCycleDto>> GetDefaultBillingCyclesAsync()

Returns List<BillingCycleDto>: Existing conventional-key cycles, or an empty collection.

Example

var cycles = await subscrio.BillingCycles.GetDefaultBillingCyclesAsync();
Console.WriteLine(cycles.Count);

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.