@86d-app/subscriptions
v0.0.4
Published
Subscription plans and recurring billing module for 86d commerce platform
Downloads
167
Maintainers
Readme
[!WARNING] This project is under active development and is not ready for production use. Please proceed with caution. Use at your own risk.
@86d-app/subscriptions
Subscription plan and subscriber management for the 86d commerce platform. Handles recurring billing cycles, trial periods, and subscription lifecycle. Payment processing is delegated to your payment provider.
Installation
npm install @86d-app/subscriptionsUsage
import subscriptions from "@86d-app/subscriptions";
import { createModuleClient } from "@86d-app/core";
const client = createModuleClient([
subscriptions({
currency: "USD",
}),
]);Configuration
| Option | Type | Default | Description |
|---|---|---|---|
| currency | string | undefined | Default currency for subscription plans |
Subscription Lifecycle
subscribe() → active
└─ if plan.trialDays > 0 → trialing
expireSubscriptions() → expired (currentPeriodEnd < now)
cancelSubscription() → cancelled (immediate or at period end)
renewSubscription() → active (advances period dates)Billing Intervals
| Interval | Description |
|---|---|
| day | Daily billing |
| week | Weekly billing |
| month | Monthly billing |
| year | Annual billing |
intervalCount multiplies the interval (e.g. interval: "month", intervalCount: 3 = quarterly).
Store Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /subscriptions/subscribe | Subscribe to a plan |
| GET | /subscriptions/me | Get subscriptions for an email address |
| POST | /subscriptions/me/cancel | Cancel a subscription |
Query parameters for GET /subscriptions/me: email (required)
Admin Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /admin/subscriptions | List all subscriptions |
| GET | /admin/subscriptions/:id | Get a subscription by ID |
| GET | /admin/subscriptions/plans | List all plans |
| POST | /admin/subscriptions/plans/create | Create a subscription plan |
| PUT | /admin/subscriptions/plans/:id/update | Update a plan |
| DELETE | /admin/subscriptions/plans/:id/delete | Delete a plan |
Controller API
// ── Plans ──────────────────────────────────────────────────────────────
controller.createPlan(params: {
name: string;
description?: string;
price: number; // in cents
currency?: string;
interval: SubscriptionInterval;
intervalCount?: number; // default 1
trialDays?: number;
isActive?: boolean;
}): Promise<SubscriptionPlan>
controller.getPlan(id: string): Promise<SubscriptionPlan | null>
controller.listPlans(params?: {
activeOnly?: boolean;
take?: number;
skip?: number;
}): Promise<SubscriptionPlan[]>
controller.updatePlan(id: string, params: {
name?: string;
description?: string;
price?: number;
trialDays?: number;
isActive?: boolean;
}): Promise<SubscriptionPlan | null>
controller.deletePlan(id: string): Promise<boolean>
// ── Subscriptions ──────────────────────────────────────────────────────
// Subscribe a customer to a plan
// Sets status to "trialing" if the plan has trialDays > 0
controller.subscribe(params: {
planId: string;
email: string;
customerId?: string;
}): Promise<Subscription>
controller.getSubscription(id: string): Promise<Subscription | null>
controller.getSubscriptionByEmail(params: {
email: string;
planId?: string;
}): Promise<Subscription | null>
// Cancel immediately or flag for end-of-period cancellation
controller.cancelSubscription(params: {
id: string;
cancelAtPeriodEnd?: boolean;
}): Promise<Subscription | null>
// Advance period dates to the next billing cycle
controller.renewSubscription(id: string): Promise<Subscription | null>
// Mark overdue subscriptions as expired — call periodically (e.g. cron)
// Scans active and trialing subscriptions; returns the count expired
controller.expireSubscriptions(): Promise<number>
controller.listSubscriptions(params?: {
email?: string;
planId?: string;
status?: SubscriptionStatus;
take?: number;
skip?: number;
}): Promise<Subscription[]>Example: Full Subscription Flow
// Create a monthly plan with a 14-day trial
const plan = await controller.createPlan({
name: "Pro",
price: 1999,
interval: "month",
trialDays: 14,
});
// Subscribe a customer
const sub = await controller.subscribe({
planId: plan.id,
email: "[email protected]",
customerId: "cust_123",
});
// sub.status === "trialing"
// On webhook from payment provider: renew
await controller.renewSubscription(sub.id);
// Customer cancels at end of period
await controller.cancelSubscription({ id: sub.id, cancelAtPeriodEnd: true });
// Cron job: expire overdue subscriptions
const count = await controller.expireSubscriptions();Types
type SubscriptionInterval = "day" | "week" | "month" | "year";
type SubscriptionStatus = "active" | "trialing" | "cancelled" | "expired" | "past_due";
interface SubscriptionPlan {
id: string;
name: string;
description?: string;
price: number;
currency: string;
interval: SubscriptionInterval;
intervalCount: number;
trialDays?: number;
isActive: boolean;
createdAt: Date;
updatedAt: Date;
}
interface Subscription {
id: string;
planId: string;
customerId?: string;
email: string;
status: SubscriptionStatus;
currentPeriodStart: Date;
currentPeriodEnd: Date;
trialStart?: Date;
trialEnd?: Date;
cancelledAt?: Date;
cancelAtPeriodEnd: boolean;
createdAt: Date;
updatedAt: Date;
}