JSPM

  • Created
  • Published
  • Downloads 181
  • Score
    100M100P100Q89280F
  • License MIT

Official JavaScript/TypeScript SDK for StackBE - the billing backend for your side project

Package Exports

  • @stackbe/sdk

Readme

@stackbe/sdk

Official JavaScript/TypeScript SDK for StackBE - the billing backend for your side project.

Installation

npm install @stackbe/sdk
# or
yarn add @stackbe/sdk
# or
pnpm add @stackbe/sdk

Quick Start

import { StackBE } from '@stackbe/sdk';

const stackbe = new StackBE({
  apiKey: process.env.STACKBE_API_KEY!,
  appId: process.env.STACKBE_APP_ID!,
});

// Track usage
await stackbe.usage.track('customer_123', 'api_calls');

// Check if within limits
const { allowed, remaining } = await stackbe.usage.check('customer_123', 'api_calls');

// Check feature access
const { hasAccess } = await stackbe.entitlements.check('customer_123', 'premium_export');

Usage Tracking

Track billable usage events for your customers:

// Track a single event
await stackbe.usage.track('customer_123', 'api_calls');

// Track multiple units
await stackbe.usage.track('customer_123', 'tokens', { quantity: 1500 });

// Check current usage
const usage = await stackbe.usage.get('customer_123');
console.log(usage.metrics);
// [{ metric: 'api_calls', currentUsage: 150, limit: 1000, remaining: 850 }]

// Check specific metric
const { allowed, remaining } = await stackbe.usage.check('customer_123', 'api_calls');
if (!allowed) {
  throw new Error('Usage limit exceeded');
}

// Track and check in one call
const result = await stackbe.usage.trackAndCheck('customer_123', 'api_calls');
if (!result.allowed) {
  // Handle limit exceeded
}

Entitlements

Check feature access based on customer's plan:

// Check single feature
const { hasAccess } = await stackbe.entitlements.check('customer_123', 'premium_export');

if (!hasAccess) {
  return res.status(403).json({ error: 'Upgrade to access this feature' });
}

// Get all entitlements
const { entitlements, planName } = await stackbe.entitlements.getAll('customer_123');
console.log(`Customer is on ${planName}`);
console.log(entitlements);
// { premium_export: true, api_access: true, max_projects: 10 }

// Check multiple features at once
const features = await stackbe.entitlements.checkMany('customer_123', [
  'premium_export',
  'advanced_analytics',
  'api_access'
]);
// { premium_export: true, advanced_analytics: false, api_access: true }

// Require a feature (throws if not available)
await stackbe.entitlements.require('customer_123', 'premium_export');

Customer Management

// Get customer
const customer = await stackbe.customers.get('customer_123');

// Get by email
const customer = await stackbe.customers.getByEmail('user@example.com');

// Create customer
const newCustomer = await stackbe.customers.create({
  email: 'user@example.com',
  name: 'John Doe',
  metadata: { source: 'api' }
});

// Get or create (idempotent)
const customer = await stackbe.customers.getOrCreate({
  email: 'user@example.com',
  name: 'John Doe'
});

// Update customer
await stackbe.customers.update('customer_123', {
  name: 'Jane Doe'
});

Express Middleware

The SDK includes ready-to-use middleware for Express:

Track Usage Automatically

import express from 'express';
import { StackBE } from '@stackbe/sdk';

const app = express();
const stackbe = new StackBE({ apiKey: '...', appId: '...' });

// Track all API calls
app.use(stackbe.middleware({
  getCustomerId: (req) => req.user?.customerId,
  metric: 'api_calls',
  skip: (req) => req.path === '/health', // Skip health checks
}));

Require Feature Entitlements

// Protect premium endpoints
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 to access exports' });
    }
  }),
  exportHandler
);

Enforce Usage Limits

// Block requests when limit exceeded
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',
        current,
        limit,
        upgradeUrl: 'https://myapp.com/upgrade'
      });
    }
  })
);

Next.js Integration

API Routes (App Router)

// 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 before processing
  const { allowed, remaining } = await stackbe.usage.check(customerId, 'generations');

  if (!allowed) {
    return NextResponse.json(
      { error: 'Generation limit reached', remaining: 0 },
      { status: 429 }
    );
  }

  // Track usage
  await stackbe.usage.track(customerId, 'generations');

  // Do the work...
  const result = await generateSomething();

  return NextResponse.json({ result, remaining: remaining! - 1 });
}

Server Actions

// app/actions.ts
'use server';

import { StackBE } from '@stackbe/sdk';

const stackbe = new StackBE({
  apiKey: process.env.STACKBE_API_KEY!,
  appId: process.env.STACKBE_APP_ID!,
});

export async function exportData(customerId: string) {
  // Check feature access
  const { hasAccess } = await stackbe.entitlements.check(customerId, 'data_export');

  if (!hasAccess) {
    throw new Error('Upgrade to Pro to export data');
  }

  // Perform export...
}

Error Handling

import { StackBE, StackBEError } from '@stackbe/sdk';

try {
  await stackbe.usage.track('customer_123', 'api_calls');
} catch (error) {
  if (error instanceof StackBEError) {
    console.error(`StackBE Error: ${error.message}`);
    console.error(`Status: ${error.statusCode}`);
    console.error(`Code: ${error.code}`);
  }
}

Configuration

const stackbe = new StackBE({
  // Required
  apiKey: 'sk_live_...',  // Your API key
  appId: 'app_...',       // Your App ID

  // Optional
  baseUrl: 'https://api.stackbe.io',  // API base URL
  timeout: 30000,                      // Request timeout in ms
});

TypeScript

The SDK is written in TypeScript and includes full type definitions:

import type {
  Customer,
  Subscription,
  TrackUsageResponse,
  CheckEntitlementResponse,
} from '@stackbe/sdk';

License

MIT