Advanced Stripe subscription patterns for Google Antigravity IDE SaaS applications
# Stripe Subscriptions Advanced Patterns for Google Antigravity IDE
Build sophisticated subscription billing with Stripe using Google Antigravity IDE. This comprehensive guide covers metered billing, prorations, trials, entitlements, and usage-based pricing for SaaS applications.
## Subscription Management
```typescript
// src/lib/stripe.ts
import Stripe from "stripe";
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2024-04-10",
typescript: true,
});
// Subscription service
export class SubscriptionService {
async createCheckoutSession(
customerId: string,
priceId: string,
options?: {
trialDays?: number;
metadata?: Record<string, string>;
successUrl?: string;
cancelUrl?: string;
}
) {
const session = await stripe.checkout.sessions.create({
customer: customerId,
mode: "subscription",
line_items: [{ price: priceId, quantity: 1 }],
subscription_data: {
trial_period_days: options?.trialDays,
metadata: options?.metadata,
},
success_url: options?.successUrl ?? `${process.env.NEXT_PUBLIC_URL}/billing?success=true`,
cancel_url: options?.cancelUrl ?? `${process.env.NEXT_PUBLIC_URL}/billing?canceled=true`,
allow_promotion_codes: true,
billing_address_collection: "auto",
customer_update: {
address: "auto",
name: "auto",
},
});
return session;
}
async createSubscription(
customerId: string,
priceId: string,
options?: {
trialDays?: number;
paymentBehavior?: "default_incomplete" | "allow_incomplete" | "error_if_incomplete";
prorationBehavior?: "create_prorations" | "none" | "always_invoice";
metadata?: Record<string, string>;
}
) {
const subscription = await stripe.subscriptions.create({
customer: customerId,
items: [{ price: priceId }],
trial_period_days: options?.trialDays,
payment_behavior: options?.paymentBehavior ?? "default_incomplete",
proration_behavior: options?.prorationBehavior ?? "create_prorations",
metadata: options?.metadata,
expand: ["latest_invoice.payment_intent"],
});
return subscription;
}
async changePlan(
subscriptionId: string,
newPriceId: string,
options?: {
prorate?: boolean;
billingCycleAnchor?: "now" | "unchanged";
}
) {
const subscription = await stripe.subscriptions.retrieve(subscriptionId);
const currentItem = subscription.items.data[0];
const updated = await stripe.subscriptions.update(subscriptionId, {
items: [
{
id: currentItem.id,
price: newPriceId,
},
],
proration_behavior: options?.prorate ? "create_prorations" : "none",
billing_cycle_anchor: options?.billingCycleAnchor,
});
return updated;
}
async cancelSubscription(
subscriptionId: string,
options?: {
immediately?: boolean;
feedback?: string;
}
) {
if (options?.immediately) {
return stripe.subscriptions.cancel(subscriptionId, {
cancellation_details: {
feedback: options.feedback as any,
},
});
}
return stripe.subscriptions.update(subscriptionId, {
cancel_at_period_end: true,
cancellation_details: {
feedback: options?.feedback as any,
},
});
}
async resumeSubscription(subscriptionId: string) {
return stripe.subscriptions.update(subscriptionId, {
cancel_at_period_end: false,
});
}
}
```
## Metered Billing
```typescript
// src/services/usage-billing.ts
import { stripe } from "@/lib/stripe";
import { db } from "@/lib/db";
export class UsageBillingService {
async reportUsage(
subscriptionItemId: string,
quantity: number,
options?: {
timestamp?: number;
action?: "increment" | "set";
}
) {
const usageRecord = await stripe.subscriptionItems.createUsageRecord(
subscriptionItemId,
{
quantity,
timestamp: options?.timestamp ?? Math.floor(Date.now() / 1000),
action: options?.action ?? "increment",
}
);
return usageRecord;
}
async getUsageSummary(subscriptionItemId: string) {
const summary = await stripe.subscriptionItems.listUsageRecordSummaries(
subscriptionItemId,
{ limit: 1 }
);
return summary.data[0];
}
// Track and report API usage
async trackApiUsage(userId: string) {
const user = await db.user.findUnique({
where: { id: userId },
include: { subscription: true },
});
if (!user?.subscription?.stripeSubscriptionItemId) {
throw new Error("No active subscription");
}
// Get usage for current period
const periodStart = new Date(user.subscription.currentPeriodStart);
const usage = await db.apiUsage.aggregate({
where: {
userId,
createdAt: { gte: periodStart },
},
_sum: { count: true },
});
const currentUsage = usage._sum.count ?? 0;
// Check limits based on plan
const planLimits: Record<string, number> = {
free: 1000,
pro: 50000,
enterprise: Infinity,
};
const limit = planLimits[user.subscription.planId] ?? 0;
if (currentUsage >= limit) {
throw new Error("Usage limit exceeded");
}
// Record usage increment
await db.apiUsage.create({
data: { userId, count: 1 },
});
// Report to Stripe for metered billing
if (user.subscription.planId !== "free") {
await this.reportUsage(
user.subscription.stripeSubscriptionItemId,
1,
{ action: "increment" }
);
}
return { current: currentUsage + 1, limit };
}
}
```
## Entitlement System
```typescript
// src/services/entitlements.ts
import { db } from "@/lib/db";
interface PlanFeatures {
apiCalls: number;
teamMembers: number;
storage: number; // in GB
features: string[];
}
const PLAN_FEATURES: Record<string, PlanFeatures> = {
free: {
apiCalls: 1000,
teamMembers: 1,
storage: 1,
features: ["basic_analytics", "email_support"],
},
pro: {
apiCalls: 50000,
teamMembers: 5,
storage: 50,
features: ["advanced_analytics", "priority_support", "api_access", "custom_domain"],
},
enterprise: {
apiCalls: Infinity,
teamMembers: Infinity,
storage: 500,
features: ["advanced_analytics", "priority_support", "api_access", "custom_domain", "sso", "audit_logs", "dedicated_support"],
},
};
export class EntitlementService {
async getUserEntitlements(userId: string) {
const user = await db.user.findUnique({
where: { id: userId },
include: { subscription: true },
});
const planId = user?.subscription?.planId ?? "free";
const features = PLAN_FEATURES[planId] ?? PLAN_FEATURES.free;
return {
planId,
...features,
isActive: user?.subscription?.status === "active",
};
}
async hasFeature(userId: string, feature: string): Promise<boolean> {
const entitlements = await this.getUserEntitlements(userId);
return entitlements.features.includes(feature);
}
async checkLimit(
userId: string,
resource: "apiCalls" | "teamMembers" | "storage",
currentUsage: number
): Promise<{ allowed: boolean; limit: number; remaining: number }> {
const entitlements = await this.getUserEntitlements(userId);
const limit = entitlements[resource];
const remaining = Math.max(0, limit - currentUsage);
return {
allowed: currentUsage < limit,
limit,
remaining,
};
}
}
```
## Best Practices for Google Antigravity IDE
When implementing Stripe subscriptions with Google Antigravity, use Checkout for initial purchases. Handle all webhook events for state consistency. Implement proper proration for plan changes. Track usage accurately for metered billing. Build an entitlement system for feature access. Let Gemini 3 generate subscription flows from your pricing model.
Google Antigravity excels at building complete subscription management systems.This Stripe prompt is ideal for developers working on:
By using this prompt, you can save hours of manual coding and ensure best practices are followed from the start. It's particularly valuable for teams looking to maintain consistency across their stripe implementations.
Yes! All prompts on Antigravity AI Directory are free to use for both personal and commercial projects. No attribution required, though it's always appreciated.
This prompt works excellently with Claude, ChatGPT, Cursor, GitHub Copilot, and other modern AI coding assistants. For best results, use models with large context windows.
You can modify the prompt by adding specific requirements, constraints, or preferences. For Stripe projects, consider mentioning your framework version, coding style, and any specific libraries you're using.