Subscription Packages
Package configuration defines the pricing tiers and feature limits for TendSocial subscriptions.
API Endpoints
GET /public/packages
Public endpoint - Returns active packages for pricing page and onboarding.
typescript
// Response
[{
id: string,
name: string, // "Starter", "Professional", "Agency"
description: string,
price: number, // Monthly price in currency
interval: "month" | "year",
currency: "USD",
maxUsers: number,
maxAiPosts: number,
displayFeatures: string[],// Features for pricing UI
salePrice: number | null, // Discounted price if on sale
saleStartsAt: Date | null,
saleEndsAt: Date | null,
variantId: string | null, // Lemon Squeezy variant
isActive: boolean,
isPopular: boolean // Highlight on pricing page
}]GET /admin/packages
Admin only - Returns all packages including inactive.
POST /admin/packages
Create or update a package (upsert pattern).
typescript
// Request
{
id?: string, // Provide to update, omit to create
name: string,
description?: string,
price: number,
interval: "month" | "year",
currency: "USD",
maxUsers: number,
maxAiPosts: number,
displayFeatures: string[],
salePrice?: number,
saleStartsAt?: string, // ISO date
saleEndsAt?: string,
variantId?: string,
isActive: boolean,
isPopular: boolean
}DELETE /admin/packages/:id
Permanently delete a package.
Feature Limits
Each package defines limits that are enforced at runtime:
| Limit | Description |
|---|---|
maxUsers | Team members allowed |
maxAiPosts | AI generations per month |
maxSocialAccounts | Connected platforms |
maxCampaigns | Active campaigns |
Sale Pricing
Packages support time-limited sale pricing:
typescript
{
price: 29.00, // Regular price
salePrice: 19.00, // Sale price
saleStartsAt: "2024-11-25",
saleEndsAt: "2024-11-30"
}Frontend should check if sale is active and display sale price accordingly.
Lemon Squeezy Integration
The variantId field links packages to Lemon Squeezy variants for checkout.
Setup:
- Create products/variants in Lemon Squeezy dashboard
- Copy variant IDs
- Update packages via admin API
- Checkout flow uses variantId for payment
Database Schema
prisma
model PackageConfig {
id String @id @default(cuid())
name String
description String?
price Decimal @db.Decimal(10, 2)
interval String @default("month")
currency String @default("USD")
maxUsers Int @default(1)
maxAiPosts Int @default(50)
displayFeatures String[]
salePrice Decimal? @db.Decimal(10, 2)
saleStartsAt DateTime?
saleEndsAt DateTime?
variantId String?
isActive Boolean @default(true)
isPopular Boolean @default(false)
}