Files
nixpanel-website/api/src/services/stripeService.ts
T
NixReaperandClaude Sonnet 4.6 72f5cc1060 feat: initial website commit + installation guide page
- Full nixpanel-website monorepo: web (React/Vite) + api (Fastify)
- Add /install page with one-liner, manual steps, requirements,
  software table, firewall ports, service management, and update/uninstall
- Add Install link to header nav and footer
- Add 'Install guide' CTA button to home page hero
- Add 'outline' variant to Button component
- Add .gitignore and .gitattributes

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-04-05 11:16:42 -05:00

111 lines
3.3 KiB
TypeScript

import Stripe from 'stripe';
import { config } from '../config';
import { query } from '../db';
const stripe = new Stripe(config.stripe.secretKey, { apiVersion: '2024-06-20' });
// Annual plans are 20% off (pay 10 months, get 12)
export const PLAN_PRICES: Record<string, { monthly: number; annual: number; label: string }> = {
free: { monthly: 0, annual: 0, label: 'Free' },
solo: { monthly: 9.99, annual: 95.90, label: 'Solo' },
host: { monthly: 29.99, annual: 287.90, label: 'Host' },
agency: { monthly: 79.99, annual: 767.90, label: 'Agency' },
};
export async function getOrCreateStripeCustomer(data: {
customerId: string;
email: string;
name: string;
stripeCustomerId?: string | null;
}): Promise<string> {
if (data.stripeCustomerId) return data.stripeCustomerId;
const stripeCustomer = await stripe.customers.create({
email: data.email,
name: data.name,
metadata: { nixpanel_customer_id: data.customerId },
});
await query(
'UPDATE customers SET stripe_customer_id = ? WHERE id = ?',
[stripeCustomer.id, data.customerId]
);
return stripeCustomer.id;
}
export async function createCheckoutSession(data: {
stripeCustomerId: string;
priceId: string;
planKey: string;
interval: 'monthly' | 'annual';
serverIp: string;
customerId: string;
successUrl: string;
cancelUrl: string;
}): Promise<string> {
const session = await stripe.checkout.sessions.create({
customer: data.stripeCustomerId,
mode: 'subscription',
line_items: [{ price: data.priceId, quantity: 1 }],
success_url: data.successUrl,
cancel_url: data.cancelUrl,
metadata: {
nixpanel_customer_id: data.customerId,
plan_key: data.planKey,
billing_interval: data.interval,
server_ip: data.serverIp,
},
subscription_data: {
metadata: {
nixpanel_customer_id: data.customerId,
plan_key: data.planKey,
server_ip: data.serverIp,
},
},
});
return session.url!;
}
export async function createBillingPortalSession(
stripeCustomerId: string,
returnUrl: string
): Promise<string> {
const session = await stripe.billingPortal.sessions.create({
customer: stripeCustomerId,
return_url: returnUrl,
});
return session.url;
}
export async function cancelSubscription(stripeSubscriptionId: string): Promise<void> {
await stripe.subscriptions.update(stripeSubscriptionId, {
cancel_at_period_end: true,
});
await query(
'UPDATE subscriptions SET cancel_at_period_end = 1 WHERE stripe_subscription_id = ?',
[stripeSubscriptionId]
);
}
export async function changeSubscriptionPlan(data: {
stripeSubscriptionId: string;
newPriceId: string;
}): Promise<void> {
const sub = await stripe.subscriptions.retrieve(data.stripeSubscriptionId);
await stripe.subscriptions.update(data.stripeSubscriptionId, {
items: [{ id: sub.items.data[0].id, price: data.newPriceId }],
proration_behavior: 'create_prorations',
});
}
export async function constructWebhookEvent(
payload: Buffer,
signature: string
): Promise<Stripe.Event> {
return stripe.webhooks.constructEvent(payload, signature, config.stripe.webhookSecret);
}
export { stripe };