StackBE SDK
Official TypeScript SDK for integrating StackBE into your application.
Installation
npm install @stackbe/sdkThe SDK works in Node.js, Edge runtimes, and modern browsers.
Quick Setup
import { StackBE } from '@stackbe/sdk';
const stackbe = new StackBE({
apiKey: process.env.STACKBE_API_KEY!,
appId: process.env.STACKBE_APP_ID!,
sessionCacheTTL: 120, // Optional: cache sessions for 2 min
devCallbackUrl: 'http://localhost:3000/auth/callback', // Optional: for local dev
});Customers
Create, retrieve, and manage customers in your application.
// Get or create customer (idempotent)
const customer = await stackbe.customers.getOrCreate({
email: 'user@example.com',
name: 'John Doe',
});
// Get customer by email
const existing = await stackbe.customers.getByEmail('user@example.com');
// Get customer by ID
const customer = await stackbe.customers.get('cust_123');
// Create a new customer
const newCustomer = await stackbe.customers.create({
email: 'new@example.com',
name: 'Jane Doe',
metadata: { source: 'website' },
});
// Update customer
const updated = await stackbe.customers.update('cust_123', {
name: 'Updated Name',
metadata: { tier: 'premium' },
});Authentication
Passwordless magic link authentication for your customers.
// Send magic link email
await stackbe.auth.sendMagicLink('user@example.com', {
redirectUrl: 'https://yourapp.com/dashboard',
});
// Verify magic link token (returns session)
const session = await stackbe.auth.verifyToken(token);
// Get current session
const session = await stackbe.auth.getSession(token);
console.log(session.customer);
console.log(session.entitlements);Checkout
Create Stripe checkout sessions for subscriptions.
// Create checkout session
const { url } = await stackbe.checkout.createSession({
customer: customer.id, // or email
planId: 'plan_pro',
successUrl: 'https://yourapp.com/success',
cancelUrl: 'https://yourapp.com/pricing',
});
// Redirect user to checkout
window.location.href = url;Entitlements
Check feature access based on subscription plan.
// Check if customer has access to a feature
const { hasAccess } = await stackbe.entitlements.check(
customer.id,
'premium_export'
);
if (hasAccess) {
// Allow feature
} else {
// Prompt upgrade
}
// List all entitlements for a customer
const entitlements = await stackbe.entitlements.list(customer.id);Usage Tracking
Track and check usage for metered billing.
// Track usage event
await stackbe.usage.track(customer.id, 'api_calls');
// Track with custom amount
await stackbe.usage.track(customer.id, 'storage_gb', { amount: 2.5 });
// Check usage limits
const { allowed, remaining, limit, used } = await stackbe.usage.check(
customer.id,
'api_calls'
);
if (!allowed) {
throw new Error('Usage limit exceeded');
}Subscriptions
Manage customer subscriptions.
// Get current subscription
const subscription = await stackbe.subscriptions.get(customer.id);
// Pause subscription
await stackbe.subscriptions.pause('sub_123', {
resumesAt: new Date('2025-02-01'), // Optional: auto-resume date
});
// Resume subscription
await stackbe.subscriptions.resume('sub_123');
// Cancel subscription
await stackbe.subscriptions.cancel('sub_123', {
atPeriodEnd: true, // Cancel at end of billing period
});Plans & Products
List available pricing plans for your pricing page.
// List all plans sorted by price
const plans = await stackbe.plans.listByPrice();
// [Free ($0), Starter ($9), Pro ($29), Enterprise ($99)]
// Get a specific plan
const plan = await stackbe.plans.get('plan_123');
console.log(plan.name, plan.priceCents, plan.entitlements);
// Dynamic pricing page
{plans.map((plan) => (
<div key={plan.id}>
<h3>{plan.name}</h3>
<p>${plan.priceCents / 100}/{plan.interval}</p>
<a href={`/checkout?plan=${plan.id}`}>Subscribe</a>
</div>
))}Organizations (B2B)
Multi-user support for B2B apps. Organizations share subscriptions across members.
// Create organization with customer as owner
const org = await stackbe.organizations.create({
name: 'Acme Corp',
ownerId: customer.id,
});
// Add member to organization
await stackbe.organizations.addMember(org.id, {
customerId: 'cust_456',
role: 'member', // 'admin' | 'member'
});
// Invite by email
await stackbe.organizations.invite(org.id, {
email: 'newuser@company.com',
role: 'member',
});
// Update member role
await stackbe.organizations.updateMember(org.id, 'member_456', {
role: 'admin',
});Coupons & Promo Codes
Create and validate discount codes for checkout.
// Create a coupon
const coupon = await stackbe.coupons.create({
code: 'LAUNCH50',
discountType: 'percentage', // or 'fixed'
discountValue: 50, // 50% off or $50 off
duration: 'once', // 'once' | 'repeating' | 'forever'
maxRedemptions: 100, // Optional limit
expiresAt: '2025-12-31', // Optional expiry
});
// Validate a coupon
const result = await stackbe.coupons.validate('LAUNCH50', {
planId: 'plan_pro', // Optional: check if valid for plan
});
if (result.valid) {
console.log('Discount:', result.discountValue);
}
// Apply at checkout
const { url } = await stackbe.checkout.createSession({
customer: 'cust_123',
planId: 'plan_pro',
couponCode: 'LAUNCH50', // Apply discount
successUrl: 'https://yourapp.com/success',
});
// List all coupons
const coupons = await stackbe.coupons.list();
// Get coupon stats
const coupon = await stackbe.coupons.get('coupon_123');
console.log(coupon.redemptions, coupon.maxRedemptions);Analytics & Metrics
Access business metrics for dashboards and reporting.
// Full dashboard summary
const dashboard = await stackbe.analytics.getDashboard();
console.log('MRR:', dashboard.revenue.mrr);
console.log('ARPU:', dashboard.revenue.arpu);
console.log('Active:', dashboard.subscriptions.active);
console.log('Churn Rate:', dashboard.subscriptions.churnRate);
console.log('Trial Conversion:', dashboard.trials.conversionRate);
console.log('Net Growth:', dashboard.growth.netGrowth);
// MRR history for charts
const mrrHistory = await stackbe.analytics.getMRRHistory({ days: 30 });
// [{ date: '2025-01-01', mrr: 1234.56 }, ...]
// Revenue by plan
const byPlan = await stackbe.analytics.getRevenueByPlan();
// [{ planName: 'Pro', mrr: 890, percentage: 65 }, ...]
// Trial metrics (for freemium/trial models)
const trials = await stackbe.analytics.getTrialMetrics({ days: 30 });
console.log(trials.trialStarts, trials.trialConversions);
console.log('Conversion Rate:', trials.trialConversionRate);
// Growth chart (new vs churned)
const growth = await stackbe.analytics.getGrowthChart({ days: 30 });
// [{ date: '2025-01-01', new: 5, churned: 1, net: 4 }, ...]
// Filter by specific app (multi-app tenants)
const appMetrics = await stackbe.analytics.getDashboard({
appId: 'app_123',
});Subscription Access & Dunning
Check access with grace period support for failed payments.
// Check if customer has access (respects grace period)
const hasAccess = await stackbe.subscriptions.checkAccess('cust_123');
// Returns true if active OR within grace period
// Get dunning status for failed payments
const dunning = await stackbe.subscriptions.getDunningStatus('sub_123');
console.log(dunning.isPastDue); // true if payment failed
console.log(dunning.isInGracePeriod); // true if still has access
console.log(dunning.daysUntilAccessRevoked); // days remaining
console.log(dunning.failedPaymentCount); // number of failures
console.log(dunning.hasAccess); // convenience field
// List past due subscriptions
const pastDue = await stackbe.subscriptions.listPastDue();
// Filter: { inGracePeriod: true } or { gracePeriodExpired: true }
// Get subscription with plan details
const sub = await stackbe.subscriptions.get('cust_123', {
expand: ['plan'],
});
console.log(sub.plan.name, sub.plan.priceCents);Feature Requests
Collect and prioritize user feedback with voting.
// Create a feature request
const request = await stackbe.featureRequests.create({
title: 'Dark mode support',
description: 'Add a dark theme option',
customerId: 'cust_123', // Optional: associate with customer
});
// List feature requests (public roadmap)
const requests = await stackbe.featureRequests.list({
status: 'open', // 'open' | 'planned' | 'in_progress' | 'completed'
sortBy: 'votes', // 'votes' | 'created' | 'updated'
});
// Vote on a feature
await stackbe.featureRequests.vote(request.id, {
customerId: 'cust_123',
});
// Add comment
await stackbe.featureRequests.addComment(request.id, {
customerId: 'cust_123',
content: 'This would be great for accessibility!',
});
// Update status (admin)
await stackbe.featureRequests.updateStatus(request.id, 'planned');Affiliate Program
Enable customers to earn commissions for referrals.
// Enroll customer as affiliate
const affiliate = await stackbe.affiliates.enroll({
customerId: 'cust_123',
code: 'JOHN20', // Optional: custom referral code
});
console.log(affiliate.referralLink);
// https://yourapp.com?ref=JOHN20
// Get affiliate stats
const stats = await stackbe.affiliates.getStats('cust_123');
console.log(stats.totalReferrals);
console.log(stats.totalCommissions);
console.log(stats.pendingPayout);
// Track referral (on signup)
await stackbe.affiliates.trackReferral({
referralCode: 'JOHN20',
newCustomerId: 'cust_456',
});
// List commissions
const commissions = await stackbe.affiliates.getCommissions('cust_123');Early Access & Waitlist
Collect signups before launch or for new features.
// Add to waitlist
const signup = await stackbe.earlyAccess.signup({
email: 'eager@example.com',
name: 'Eager User',
source: 'landing_page',
metadata: { referrer: 'twitter' },
});
// Check if already signed up
const existing = await stackbe.earlyAccess.getByEmail('eager@example.com');
// List signups (admin)
const signups = await stackbe.earlyAccess.list({
limit: 50,
offset: 0,
});Express Middleware
Built-in middleware for Express/Node.js apps.
// Auto-track usage on every request
app.use(stackbe.middleware({
getCustomerId: (req) => req.user?.customerId,
metric: 'api_calls',
skip: (req) => req.path === '/health',
}));
// Require feature entitlements
app.get('/api/export',
stackbe.requireFeature({
getCustomerId: (req) => req.user?.customerId,
feature: 'premium_export',
onDenied: (req, res) => {
res.status(403).json({ error: 'Upgrade to Pro' });
},
}),
exportHandler
);
// Enforce usage limits
app.use('/api',
stackbe.enforceLimit({
getCustomerId: (req) => req.user?.customerId,
metric: 'api_calls',
onLimitExceeded: (req, res, { current, limit }) => {
res.status(429).json({ error: 'Rate limit exceeded' });
},
})
);Next.js Integration
Works with App Router, Server Actions, and API routes.
// app/api/generate/route.ts
import { StackBE } from '@stackbe/sdk';
import { NextResponse } from 'next/server';
const stackbe = new StackBE({
apiKey: process.env.STACKBE_API_KEY!,
appId: process.env.STACKBE_APP_ID!,
});
export async function POST(request: Request) {
const { customerId } = await request.json();
// Check limits
const { allowed, remaining } = await stackbe.usage.check(
customerId,
'generations'
);
if (!allowed) {
return NextResponse.json({ error: 'Limit reached' }, { status: 429 });
}
// Track usage
await stackbe.usage.track(customerId, 'generations');
// Do work...
return NextResponse.json({ success: true, remaining: remaining! - 1 });
}Webhooks
Typed webhook payloads for handling StackBE events.
import type { AnyWebhookEvent } from '@stackbe/sdk';
app.post('/webhooks/stackbe', (req, res) => {
const event = req.body as AnyWebhookEvent;
switch (event.type) {
case 'subscription_created':
console.log('New subscription:', event.data.planName);
break;
case 'subscription_cancelled':
console.log('Cancelled:', event.data.id);
break;
case 'payment_failed':
console.log('Payment failed:', event.data.failureReason);
// Send dunning email
break;
}
res.json({ received: true });
});
// Event types: subscription_created, subscription_updated,
// subscription_cancelled, subscription_renewed, trial_started,
// trial_ended, payment_succeeded, payment_failed,
// customer_created, customer_updatedError Handling
The SDK throws typed errors for easy handling.
import { StackBEError } from '@stackbe/sdk';
try {
const customer = await stackbe.customers.get('invalid_id');
} catch (error) {
if (error instanceof StackBEError) {
console.log(error.code); // 'CUSTOMER_NOT_FOUND'
console.log(error.statusCode); // 404
console.log(error.message); // 'Customer not found'
}
}
// Common error codes:
// - CUSTOMER_NOT_FOUND
// - SUBSCRIPTION_NOT_FOUND
// - PLAN_NOT_FOUND
// - USAGE_LIMIT_EXCEEDED
// - TOKEN_EXPIRED
// - UNAUTHORIZEDConfiguration Options
| Option | Type | Default | Description |
|---|---|---|---|
| apiKey | string | required | Your StackBE API key |
| appId | string | required | Your StackBE app ID |
| baseUrl | string | api.stackbe.io | API base URL |
| timeout | number | 30000 | Request timeout in ms |
| sessionCacheTTL | number | 0 | Session cache TTL in seconds |
| devCallbackUrl | string | - | Callback URL for local development |