Skip to content

Billing

VentureKit provides billing support through @venturekit-pro/billing with plan definitions, feature limits, and usage-to-invoice mapping.

Terminal window
npm install @venturekit-pro/billing@dev

@venturekit-pro/billing handles plan logic and invoicing, not payment processing. It provides:

  • Plan definitions with feature limits
  • Feature checking (hasFeature, getFeatureLimit)
  • Usage-to-invoice-item mapping
  • Auto-migration support for billing database tables

Integrate any payment provider separately when needed.

import { definePlans } from '@venturekit-pro/billing';
const plans = definePlans([
{
id: 'free',
name: 'Free',
features: {
projects: { limit: 3 },
storage: { limit: 1_000_000_000 }, // 1 GB
apiRequests: { limit: 10_000, period: 'month' },
customDomains: false,
support: false,
},
},
{
id: 'pro',
name: 'Pro',
features: {
projects: { limit: 50 },
storage: { limit: 100_000_000_000 }, // 100 GB
apiRequests: { limit: 1_000_000, period: 'month' },
customDomains: true,
support: true,
},
},
{
id: 'enterprise',
name: 'Enterprise',
features: {
projects: { limit: -1 }, // Unlimited
storage: { limit: -1 },
apiRequests: { limit: -1 },
customDomains: true,
support: true,
},
},
]);

Use in handlers to enforce plan limits:

import { handler } from '@venturekit/runtime';
import { getFeatureLimit, hasFeature } from '@venturekit-pro/billing';
export const main = handler(async (body, ctx, logger) => {
const userPlan = 'free'; // Resolve from tenant/user
// Check boolean feature
if (!hasFeature(plans, userPlan, 'customDomains')) {
throw new ForbiddenError('Custom domains require a Pro plan');
}
// Check numeric limit
const maxProjects = getFeatureLimit(plans, userPlan, 'projects');
const currentCount = await getProjectCount(ctx.user!.id);
if (maxProjects !== -1 && currentCount >= maxProjects) {
throw new ForbiddenError(`Project limit reached (${maxProjects})`);
}
return { allowed: true };
}, { scopes: ['projects.write'] });

Generate invoice line items from usage data:

import { mapUsageToLineItems } from '@venturekit-pro/billing';
const lineItems = mapUsageToLineItems(currentUsage, planFeatures);
// Returns structured line items for invoice generation

When @venturekit-pro/billing is installed, vk migrate discovers and applies billing-related database tables automatically:

import { getBillingMigrationsDir } from '@venturekit-pro/billing';
const migrationsDir = getBillingMigrationsDir();

Billing works well with @venturekit-pro/tenancy for per-tenant plan enforcement:

import { createTenantMiddleware, createQuotaMiddleware } from '@venturekit-pro/tenancy';
import { getFeatureLimit } from '@venturekit-pro/billing';
export const main = handler(async (_body, ctx, logger) => {
const tenant = ctx.tenant!;
const plan = tenant.metadata.plan as string;
const limit = getFeatureLimit(plans, plan, 'apiRequests');
return { tenantId: tenant.id, plan, apiRequestLimit: limit };
}, {
scopes: ['api.read'],
middleware: [
createTenantMiddleware({ strategy: 'subdomain' }),
createQuotaMiddleware(),
],
});