npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@levee/sdk

v0.1.1

Published

Official TypeScript SDK for Levee - server-side only

Readme

Levee SDK for TypeScript

Official TypeScript SDK for integrating Levee into your TypeScript/JavaScript applications.

Table of Contents

Installation

npm install @levee/sdk
# or
pnpm add @levee/sdk
# or
bun add @levee/sdk

Quick Start

import { Levee } from "@levee/sdk";

// Initialize the client with your API key
const levee = new Levee(process.env.LEVEE_API_KEY!);

// Create a contact
const contact = await levee.contacts.create({
  email: "[email protected]",
  name: "John Doe",
});

console.log("Contact created:", contact.id);

Auto-Generated Code

The following files in src/ are auto-generated from the Levee API definition and should not be edited manually:

  • types.ts - All TypeScript interfaces and types
  • client.ts - The main Levee client class with all resource methods

To regenerate these files when the API changes, run make gen-sdk from the main Levee backend directory.


Configuration

Basic Configuration

// Default configuration - connects to https://levee.sh/sdk/v1
const levee = new Levee("lv_your_api_key");

Custom Base URL

For self-hosted instances or development environments:

const levee = new Levee("lv_your_api_key", {
  baseURL: "https://your-domain.com/sdk/v1",
});

Custom Timeout

For longer-running requests:

const levee = new Levee("lv_your_api_key", {
  timeout: 60000, // 60 seconds (default: 30s)
});

Custom Fetch

For custom HTTP handling or testing:

const levee = new Levee("lv_your_api_key", {
  fetch: customFetchImplementation,
});

Authentication

The SDK provides customer authentication endpoints for building login/signup flows in your application. These endpoints are for your end-users (customers), not for SDK API access.

Register a Customer

const result = await levee.auth.register({
  orgSlug: "your-org",
  email: "[email protected]",
  password: "securePassword123",
  name: "John Doe", // optional
});

console.log("Token:", result.token);
console.log("Refresh Token:", result.refreshToken);
console.log("Expires At:", result.expiresAt);
console.log("Customer:", result.customer);
// Customer includes: id, email, name, emailVerified, createdAt

Login

const result = await levee.auth.login({
  orgSlug: "your-org",
  email: "[email protected]",
  password: "securePassword123",
});

console.log("Token:", result.token);
console.log("Customer:", result.customer.email);

Refresh Token

const result = await levee.auth.refreshToken({
  refreshToken: "current_refresh_token",
});

console.log("New Token:", result.token);
console.log("New Refresh Token:", result.refreshToken);

Forgot Password

Initiates a password reset flow by sending a reset email to the customer.

await levee.auth.forgotPassword({
  orgSlug: "your-org",
  email: "[email protected]",
});
// Email with reset link will be sent

Reset Password

Completes the password reset using the token from the email.

await levee.auth.resetPassword({
  token: "reset_token_from_email",
  password: "newSecurePassword123",
  confirmPassword: "newSecurePassword123",
});

Verify Email

Verifies a customer's email address using the token from the verification email.

await levee.auth.verifyEmail({
  token: "verification_token_from_email",
});

Change Password

Change password while logged in (requires current password).

const result = await levee.auth.changePassword({
  orgSlug: "your-org",
  email: "[email protected]",
  currentPassword: "currentPassword123",
  newPassword: "newSecurePassword456",
});

if (result.success) {
  console.log("Password changed successfully");
} else {
  console.log("Error:", result.message);
}

LLM/AI Chat

The SDK provides access to Levee's LLM gateway for AI-powered chat capabilities. Supports both simple request/response and streaming via gRPC.

Simple Chat (Non-Streaming)

const response = await levee.llm.chat({
  messages: [{ role: "user", content: "What is the capital of France?" }],
  model: "sonnet", // 'haiku', 'sonnet', or 'opus'
  maxTokens: 1024,
  temperature: 0.7,
});

console.log("Response:", response.content);
console.log(`Tokens: ${response.inputTokens} in, ${response.outputTokens} out`);
console.log(`Cost: $${response.costUsd?.toFixed(4)}`);

Streaming Chat (gRPC)

For streaming responses, use the separate LLMClient:

import { LLMClient } from "@levee/sdk";

const llm = new LLMClient("lv_your_api_key", {
  grpcAddress: "llm.levee.sh:9889", // optional, this is the default
});

// Stream with async iterator
for await (const chunk of llm.chatStream({
  messages: [{ role: "user", content: "Tell me a story" }],
  systemPrompt: "You are a helpful assistant.",
  model: "sonnet",
  maxTokens: 2048,
})) {
  process.stdout.write(chunk.content); // Print each token as it arrives
}

// Don't forget to close when done
llm.close();

Convenience Streaming Method

const response = await llm.chatStreamCallback(
  {
    messages: [{ role: "user", content: "Explain quantum computing" }],
    model: "haiku",
    maxTokens: 1024,
  },
  (chunk) => {
    process.stdout.write(chunk.content);
  }
);

console.log(`\nTotal tokens: ${response.outputTokens}`);

Content/CMS

Access published content for your static site or application. Perfect for static site generation (SSG).

List Posts

const posts = await levee.content.listPosts({
  page: 1,
  pageSize: 10,
  categorySlug: "tutorials", // Optional: filter by category
});

for (const post of posts.posts) {
  console.log(`${post.slug}: ${post.title}`);
}
console.log(`Total posts: ${posts.total}`);

Get a Post

const post = await levee.content.getPost("getting-started-guide");

console.log("Title:", post.title);
console.log("Content:", post.content);
console.log("Category:", post.categoryName);
console.log("Published:", post.publishedAt);

List Pages

const pages = await levee.content.listPages({
  page: 1,
  pageSize: 20,
});

for (const page of pages.pages) {
  console.log(`${page.slug}: ${page.title} (template: ${page.templateName})`);
}

Get a Page

const page = await levee.content.getPage("about-us");

console.log("Title:", page.title);
console.log("Content:", page.content);
console.log("Meta Title:", page.metaTitle);

List Categories

const categories = await levee.content.listCategories();

for (const cat of categories.categories) {
  console.log(`${cat.slug}: ${cat.name}`);
}

Site Configuration

Access site settings, navigation menus, and author information for building your frontend.

Get Site Settings

const settings = await levee.site.getSettings();

console.log(`Site: ${settings.siteName} - ${settings.tagline}`);
console.log("Logo:", settings.logoUrl);
console.log("Contact:", settings.contactEmail);
console.log("Social:", settings.socialLinks); // Record<string, string>
console.log("Default Meta:", settings.defaultMetaTitle);

List Navigation Menus

// Get all menus
const menus = await levee.site.listMenus();

// Filter by location (header, footer, sidebar)
const headerMenus = await levee.site.listMenus({ location: "header" });

for (const menu of menus.menus) {
  console.log(`Menu: ${menu.name} (${menu.location})`);
  for (const item of menu.items) {
    console.log(`  - ${item.label}: ${item.url}`);
    for (const child of item.children ?? []) {
      console.log(`    - ${child.label}: ${child.url}`);
    }
  }
}

Get a Menu by Slug

const menu = await levee.site.getMenu("main-nav");

for (const item of menu.items) {
  console.log(`${item.label} -> ${item.url}`);
}

List Authors

const authors = await levee.site.listAuthors();

for (const author of authors.authors) {
  console.log(`${author.displayName}: ${author.bio}`);
}

Get Author by ID

const author = await levee.site.getAuthor("author-123");

console.log("Name:", author.displayName);
console.log("Bio:", author.bio);
console.log("Avatar:", author.avatarUrl);
console.log("Twitter:", `@${author.twitterHandle}`);

Contacts

Contacts are the core of Levee. Create and manage contacts when users sign up, submit forms, or interact with your application.

Create a Contact

const contact = await levee.contacts.create({
  email: "[email protected]",
  name: "John Doe",
});

Get a Contact

// Get by ID or email
const contact = await levee.contacts.get("[email protected]");

console.log(
  `Contact: ${contact.name}, Status: ${contact.status}, Tags: ${contact.tags}`
);
console.log(
  `Emails sent: ${contact.emailsSent}, opened: ${contact.emailsOpened}, clicked: ${contact.emailsClicked}`
);

Update a Contact

const contact = await levee.contacts.update("[email protected]", {
  name: "John Smith",
  phone: "+1-555-123-4567",
  company: "Acme Inc",
  customFields: {
    plan: "enterprise",
  },
});

Manage Contact Tags

// Add tags
await levee.contacts.addTags("[email protected]", ["vip", "enterprise"]);

// Remove tags
await levee.contacts.removeTags("[email protected]", ["trial"]);

View Contact Activity

const activities = await levee.contacts.listActivity("[email protected]", 50);

for (const activity of activities) {
  console.log(`${activity.timestamp}: ${activity.event} - ${activity.details}`);
}

Global Unsubscribe

// Unsubscribe from all communications
await levee.contacts.globalUnsubscribe(
  "[email protected]",
  "User requested to stop all emails"
);

Email Lists

Manage email list subscriptions for newsletters, updates, and marketing.

Subscribe to a List

await levee.lists.subscribe("newsletter", "[email protected]", "John Doe");

Unsubscribe from a List

await levee.lists.unsubscribe("newsletter", "[email protected]");

Transactional Emails

Send transactional emails for receipts, notifications, password resets, and more.

Send an Email

// Using a template
const result = await levee.emails.send({
  to: "[email protected]",
  templateSlug: "welcome-email",
  variables: {
    name: "John",
    loginUrl: "https://app.example.com/login",
  },
});

// Custom email
const result = await levee.emails.send({
  to: "[email protected]",
  subject: "Your order has shipped!",
  body: "<h1>Order Shipped</h1><p>Your order #12345 is on its way.</p>",
  textBody: "Order Shipped\n\nYour order #12345 is on its way.",
  fromName: "Acme Store",
  tags: ["shipping", "order-12345"],
});

console.log(
  `Email sent, message ID: ${result.messageId}, status: ${result.status}`
);

Check Email Status

const status = await levee.emails.getStatus(messageId);

console.log(`Email to ${status.to}: ${status.status}`);
console.log(
  `Sent: ${status.sentAt}, Delivered: ${status.deliveredAt}, Opened: ${status.openedAt}`
);
console.log(`Opens: ${status.opens}, Clicks: ${status.clicks}`);

Get Email Events

const events = await levee.emails.listEvents(messageId);

for (const event of events) {
  console.log(`${event.timestamp}: ${event.event} ${event.data ?? ""}`);
}
// Output:
// 2024-01-15T10:00:00Z: sent
// 2024-01-15T10:00:02Z: delivered
// 2024-01-15T10:15:30Z: opened
// 2024-01-15T10:16:45Z: clicked https://example.com/link

Email Sequences

Enroll contacts in automated email sequences for onboarding, nurturing, and drip campaigns.

Enroll in a Sequence

const result = await levee.sequences.enroll({
  sequenceSlug: "onboarding",
  email: "[email protected]",
  variables: {
    firstName: "John",
    plan: "Pro",
  },
});

console.log(`Enrollment ID: ${result.enrollmentId}, Status: ${result.status}`);

Get Sequence Enrollments

// Get all enrollments for an email
const enrollments = await levee.sequences.getEnrollments("[email protected]");

// Get specific sequence enrollment
const enrollments = await levee.sequences.getEnrollments(
  "[email protected]",
  "onboarding"
);

for (const e of enrollments) {
  console.log(
    `Sequence: ${e.sequenceName}, Step ${e.currentStep}/${e.totalSteps}, Status: ${e.status}`
  );
  console.log(`Next email at: ${e.nextEmailAt}`);
}

Unenroll from Sequences

// Unenroll from specific sequence
await levee.sequences.unenroll("[email protected]", "onboarding");

// Unenroll from all sequences
await levee.sequences.unenroll("[email protected]");

Pause and Resume

// Pause enrollment
await levee.sequences.pause("[email protected]", "onboarding");

// Resume enrollment
await levee.sequences.resume("[email protected]", "onboarding");

Orders & Checkout

Create checkout sessions for products, courses, or any purchasable items.

Create an Order

const order = await levee.orders.create({
  email: "[email protected]",
  productSlug: "pro-plan",
  successUrl: "https://yourapp.com/success",
  cancelUrl: "https://yourapp.com/cancel",
});

// Redirect user to checkout
// In Express: res.redirect(order.checkoutUrl)
// In Next.js: redirect(order.checkoutUrl)

Customer Billing History

Access customer billing data including invoices, orders, subscriptions, and payments. Perfect for building customer account pages.

Get Customer Info

const customer = await levee.customers.getByEmail("[email protected]");

console.log("Customer:", customer.name);
console.log(`Total spent: $${(customer.totalSpent / 100).toFixed(2)}`);
console.log(
  `Orders: ${customer.orderCount}, Subscriptions: ${customer.subscriptionCount}`
);

List Invoices

const invoices = await levee.customers.listInvoices("[email protected]", 10);

for (const inv of invoices) {
  console.log(
    `Invoice #${inv.number}: $${(inv.amountPaid / 100).toFixed(2)} ${
      inv.status
    }`
  );
  if (inv.invoicePdfUrl) {
    console.log(`  PDF: ${inv.invoicePdfUrl}`);
  }
}

List Orders

const orders = await levee.customers.listOrders("[email protected]", 10);

for (const order of orders) {
  console.log(
    `Order ${order.orderNumber}: $${(order.totalCents / 100).toFixed(2)} ${
      order.status
    }`
  );
  for (const item of order.items) {
    console.log(
      `  - ${item.productName} x${item.quantity}: $${(
        item.totalPrice / 100
      ).toFixed(2)}`
    );
  }
}

List Subscriptions

const subs = await levee.customers.listSubscriptions("[email protected]");

for (const sub of subs) {
  console.log(
    `Subscription: ${sub.productName} - ${sub.status} ($${(
      sub.amountCents / 100
    ).toFixed(2)}/${sub.interval})`
  );
  console.log(
    `  Current period: ${sub.currentPeriodStart} to ${sub.currentPeriodEnd}`
  );
}

List Payments

const payments = await levee.customers.listPayments("[email protected]", 20);

for (const p of payments) {
  console.log(
    `Payment: $${(p.amountCents / 100).toFixed(2)} ${p.status} via ${
      p.paymentMethod
    }`
  );
  if (p.receiptUrl) {
    console.log(`  Receipt: ${p.receiptUrl}`);
  }
}

Update Customer

Update customer profile information.

const customer = await levee.customers.updateCustomer("customer-123", {
  name: "John Smith",
  phone: "+1-555-123-4567",
  avatarUrl: "https://example.com/avatar.jpg",
  status: "active",
  metadata: JSON.stringify({ tier: "premium" }),
});

console.log("Updated customer:", customer.name);

Delete Customer

Permanently delete a customer (GDPR compliance, hard delete).

const result = await levee.customers.deleteCustomer("customer-123");

if (result.success) {
  console.log("Customer deleted successfully");
} else {
  console.log("Error:", result.message);
}

Custom Event Tracking

Track custom events for analytics, automation triggers, and user behavior analysis.

Track Events

await levee.tracking.track({
  event: "purchase_completed",
  email: "[email protected]",
  properties: {
    product: "pro-plan",
    amount: "99.00",
    currency: "usd",
  },
});

Products

Access product information and pricing.

Get a Product

const product = await levee.products.getProduct("pro-plan");

console.log("Name:", product.name);
console.log("Description:", product.description);
console.log("Type:", product.type);
console.log("Category:", product.category);
console.log("Active:", product.active);

// Access pricing
for (const price of product.prices ?? []) {
  console.log(
    `Price: $${(price.unitAmountCents / 100).toFixed(2)} ${price.currency}`
  );
  if (price.recurringInterval) {
    console.log(
      `  Recurring: every ${price.recurringIntervalCount} ${price.recurringInterval}`
    );
  }
}

// Access features
for (const feature of product.features ?? []) {
  console.log(
    `Feature: ${feature.name} - ${
      feature.included ? "Included" : "Not included"
    }`
  );
}

Events

Track custom events for analytics and automation triggers.

Track an Event

await levee.events.trackEvent({
  event: "page_view",
  email: "[email protected]",
  visitorId: "visitor-123",
  sessionId: "session-456",
  page: "/pricing",
  referrer: "https://google.com",
  properties: {
    source: "organic",
  },
  utmSource: "google",
  utmMedium: "cpc",
  utmCampaign: "spring-sale",
});

Funnels

Access sales funnel information for building multi-step checkout flows.

Get a Funnel Step

const step = await levee.funnels.getFunnelStep("checkout-step-1");

console.log("Step Type:", step.stepType);
console.log("Title:", step.title);
console.log("Headline:", step.headline);
console.log("Product:", step.product?.name);

// Check for order bump
if (step.orderBumpProduct) {
  console.log("Order Bump:", step.orderBumpProduct.name);
  console.log("Order Bump Headline:", step.orderBumpHeadline);
}

Offers

Process offer accepts/declines in sales funnels (upsells, downsells, order bumps).

Process an Offer

const result = await levee.offers.processOffer({
  sessionId: "checkout-session-123",
  stepSlug: "upsell-step",
  accept: true,
});

if (result.success) {
  console.log("Offer accepted!");
  console.log("Next URL:", result.nextUrl);
} else {
  console.log("Message:", result.message);
}

Quizzes

Access and submit quiz responses for lead qualification and segmentation.

Get a Quiz

const quiz = await levee.quizzes.getQuiz("lead-qualification");

console.log("Title:", quiz.title);
console.log("Description:", quiz.description);

for (const question of quiz.questions) {
  console.log(`Q: ${question.question} (${question.type})`);
  for (const option of question.options ?? []) {
    console.log(`  - ${option.label}: ${option.value}`);
  }
}

Submit Quiz Answers

const result = await levee.quizzes.submitQuiz("lead-qualification", {
  quizSlug: "lead-qualification",
  email: "[email protected]",
  name: "John Doe",
  answers: {
    q1: "answer1",
    q2: "answer2",
  },
});

console.log("Segments:", result.segments);
console.log("Redirect URL:", result.redirectUrl);
console.log("Lead ID:", result.leadId);

Workshops

Access workshop and event information.

Get a Workshop

const workshop = await levee.workshops.getWorkshop("spring-bootcamp");

console.log("Title:", workshop.title);
console.log("Dates:", `${workshop.startDate} to ${workshop.endDate}`);
console.log(
  "Time:",
  `${workshop.startTime} - ${workshop.endTime} ${workshop.timezone}`
);
console.log("Location:", workshop.locationType, workshop.locationDetails);
console.log(
  `Price: $${(workshop.priceCents / 100).toFixed(2)} ${workshop.currency}`
);
console.log(
  `Seats: ${workshop.seatsRemaining} of ${workshop.maxSeats} remaining`
);

// Agenda
for (const day of workshop.agenda) {
  console.log(`Day ${day.day}: ${day.title}`);
  for (const item of day.items) {
    console.log(`  - ${item}`);
  }
}

Get Workshop by Product

const workshop = await levee.workshops.getWorkshopByProduct("bootcamp-product");

console.log("Workshop:", workshop.title);

Billing

Full Stripe billing integration for customers, subscriptions, and usage-based billing.

Create a Customer

const customer = await levee.billing.createCustomer({
  email: "[email protected]",
  name: "John Doe",
});

Create a Checkout Session

const checkout = await levee.billing.createCheckout({
  customerEmail: "[email protected]",
  lineItems: [{ priceId: "price_xxx", quantity: 1 }],
  mode: "subscription",
  successUrl: "https://yourapp.com/success",
  cancelUrl: "https://yourapp.com/cancel",
});

// Redirect to checkout.checkoutUrl

Cancel a Subscription

await levee.billing.cancelSubscription("sub_123");

Record Metered Usage

await levee.billing.recordUsage({
  subscriptionItemId: "si_xxx",
  quantity: 150,
});

Customer Portal

const portal = await levee.billing.getPortal({
  customerId: "cust_123",
  returnUrl: "https://yourapp.com/settings",
});

// Redirect to portal.portalUrl

Webhooks

Register webhook endpoints to receive real-time events from Levee.

Register a Webhook

import { WebhookEvents } from "@levee/sdk";

const result = await levee.webhooks.register({
  url: "https://yourapp.com/webhooks/levee",
  events: [
    WebhookEvents.ContactCreated,
    WebhookEvents.EmailOpened,
    WebhookEvents.PaymentSucceeded,
    WebhookEvents.SubscriptionCreated,
  ],
});

console.log("Webhook ID:", result.webhookId);
console.log(
  "Secret:",
  result.secret,
  "(save this for signature verification!)"
);

Available Webhook Events

import { WebhookEvents } from "@levee/sdk";

// Contact events
WebhookEvents.ContactCreated; // 'contact.created'
WebhookEvents.ContactUpdated; // 'contact.updated'
WebhookEvents.ContactUnsubscribed; // 'contact.unsubscribed'
WebhookEvents.ContactBounced; // 'contact.bounced'

// Email events
WebhookEvents.EmailSent; // 'email.sent'
WebhookEvents.EmailDelivered; // 'email.delivered'
WebhookEvents.EmailOpened; // 'email.opened'
WebhookEvents.EmailClicked; // 'email.clicked'
WebhookEvents.EmailBounced; // 'email.bounced'
WebhookEvents.EmailComplained; // 'email.complained'

// Sequence events
WebhookEvents.SequenceEnrolled; // 'sequence.enrolled'
WebhookEvents.SequenceCompleted; // 'sequence.completed'
WebhookEvents.SequencePaused; // 'sequence.paused'
WebhookEvents.SequenceResumed; // 'sequence.resumed'

// Payment events
WebhookEvents.PaymentSucceeded; // 'payment.succeeded'
WebhookEvents.PaymentFailed; // 'payment.failed'
WebhookEvents.PaymentRefunded; // 'payment.refunded'

// Subscription events
WebhookEvents.SubscriptionCreated; // 'subscription.created'
WebhookEvents.SubscriptionUpdated; // 'subscription.updated'
WebhookEvents.SubscriptionCancelled; // 'subscription.cancelled'
WebhookEvents.SubscriptionRenewed; // 'subscription.renewed'

// Order events
WebhookEvents.OrderCreated; // 'order.created'
WebhookEvents.OrderCompleted; // 'order.completed'
WebhookEvents.OrderRefunded; // 'order.refunded'

List Webhooks

const webhooks = await levee.webhooks.list();

for (const wh of webhooks) {
  console.log(`Webhook ${wh.id}: ${wh.url}`);
  console.log(`  Events: ${wh.events.join(", ")}`);
  console.log(`  Success rate: ${wh.deliveriesSuccess}/${wh.deliveriesTotal}`);
}

Update a Webhook

const wh = await levee.webhooks.update(webhookId, {
  events: [WebhookEvents.PaymentSucceeded, WebhookEvents.PaymentFailed],
  active: true,
});

Test a Webhook

const result = await levee.webhooks.test(webhookId);

if (result.success) {
  console.log(`Webhook test succeeded! Status: ${result.statusCode}`);
} else {
  console.log(`Webhook test failed: ${result.error}`);
}

View Webhook Logs

const logs = await levee.webhooks.listLogs(webhookId, 20);

for (const log of logs) {
  console.log(
    `${log.deliveredAt}: ${log.event} (status ${log.statusCode}, ${log.durationMs}ms)`
  );
}

Delete a Webhook

await levee.webhooks.delete(webhookId);

Stats & Analytics

Access statistics and analytics for your organization.

Overview Stats

const stats = await levee.stats.getOverview({
  startDate: "2024-01-01T00:00:00Z",
  endDate: "2024-01-31T23:59:59Z",
});

console.log(
  `Contacts: ${stats.totalContacts} total, ${stats.newContacts} new, ${stats.activeContacts} active`
);
console.log(
  `Emails: ${stats.emailsSent} sent, ${stats.openRate.toFixed(
    1
  )}% open rate, ${stats.clickRate.toFixed(1)}% click rate`
);
console.log(
  `Revenue: $${(stats.totalRevenue / 100).toFixed(2)} from ${
    stats.orderCount
  } orders`
);

Email Stats

const emailStats = await levee.stats.getEmailStats({
  startDate: "2024-01-01T00:00:00Z",
  endDate: "2024-01-31T23:59:59Z",
  groupBy: "day", // 'day', 'week', or 'month'
});

console.log(
  `Totals: ${emailStats.totalSent} sent, ${emailStats.avgOpenRate.toFixed(
    1
  )}% open rate, ${emailStats.avgClickRate.toFixed(1)}% click rate`
);

for (const day of emailStats.stats) {
  console.log(
    `${day.date}: ${day.sent} sent, ${
      day.opened
    } opened (${day.openRate.toFixed(1)}%)`
  );
}

Revenue Stats

const revenueStats = await levee.stats.getRevenueStats({
  startDate: "2024-01-01T00:00:00Z",
  endDate: "2024-01-31T23:59:59Z",
  groupBy: "week",
});

console.log(`Total revenue: $${(revenueStats.totalRevenue / 100).toFixed(2)}`);
console.log(`MRR: $${(revenueStats.mrr / 100).toFixed(2)}`);
console.log(
  `Orders: ${revenueStats.totalOrders}, Subscriptions: ${revenueStats.totalSubscriptions}, Churned: ${revenueStats.totalChurned}`
);

Contact Stats

const contactStats = await levee.stats.getContactStats({
  startDate: "2024-01-01T00:00:00Z",
  endDate: "2024-01-31T23:59:59Z",
  groupBy: "day",
});

console.log(
  `Active: ${contactStats.totalActive}, Unsubscribed: ${contactStats.totalUnsubscribed}, Net growth: ${contactStats.netGrowth}`
);

Error Handling

The SDK provides typed error classes for different error scenarios.

import {
  APIError,
  BadRequestError,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
} from "@levee/sdk";

try {
  await levee.contacts.get("[email protected]");
} catch (error) {
  if (error instanceof NotFoundError) {
    console.log("Contact not found");
  } else if (error instanceof AuthenticationError) {
    console.log("Invalid API key");
  } else if (error instanceof RateLimitError) {
    console.log(`Rate limited. Retry after ${error.retryAfter}ms`);
  } else if (error instanceof BadRequestError) {
    console.log("Bad request:", error.message);
  } else if (error instanceof APIError) {
    console.log(`API error (${error.status}): ${error.message}`);
  } else {
    throw error;
  }
}

Complete Example

A complete SaaS application integration with SvelteKit:

// src/lib/server/levee.ts
import { Levee } from "@levee/sdk";
import { LEVEE_API_KEY } from "$env/static/private";

export const levee = new Levee(LEVEE_API_KEY);
// src/routes/+layout.server.ts
import { levee } from "$lib/server/levee";

export async function load() {
  const [settings, menu] = await Promise.all([
    levee.site.getSettings(),
    levee.site.getMenu("header"),
  ]);

  return { settings, menu };
}
// src/routes/blog/+page.server.ts
import { levee } from "$lib/server/levee";

export async function load({ url }) {
  const page = parseInt(url.searchParams.get("page") ?? "1");

  const posts = await levee.content.listPosts({
    page,
    pageSize: 10,
  });

  return { posts: posts.posts, total: posts.total };
}
// src/routes/api/signup/+server.ts
import { json } from "@sveltejs/kit";
import { levee } from "$lib/server/levee";

export async function POST({ request }) {
  const { email, name } = await request.json();

  // Create contact and enroll in onboarding sequence
  const contact = await levee.contacts.create({
    email,
    name,
    funnelSlug: "signup",
    tags: ["trial"],
  });

  // Enroll in onboarding sequence
  await levee.sequences.enroll({
    sequenceSlug: "onboarding",
    email,
    variables: { firstName: name },
  });

  // Send welcome email
  await levee.emails.send({
    to: email,
    templateSlug: "welcome",
    variables: { name },
  });

  return json({ contactId: contact.id });
}

API Reference

All methods use the resource-based pattern: levee.resource.method(...)

| Resource.Method | Description | | ------------------------------------------------ | ------------------------------- | | Client | | | new Levee(apiKey, options?) | Create a new client | | options.baseURL | Custom API base URL | | options.timeout | Request timeout in milliseconds | | options.fetch | Custom fetch implementation | | Auth | | | auth.register(input) | Register a new customer | | auth.login(input) | Login a customer | | auth.refreshToken(input) | Refresh authentication token | | auth.forgotPassword(input) | Initiate password reset | | auth.resetPassword(input) | Complete password reset | | auth.verifyEmail(input) | Verify customer email | | auth.changePassword(input) | Change password while logged in | | Contacts | | | contacts.create(input) | Create or get a contact | | contacts.get(idOrEmail) | Get contact details | | contacts.update(idOrEmail, input) | Update a contact | | contacts.addTags(idOrEmail, tags) | Add tags to contact | | contacts.removeTags(idOrEmail, tags) | Remove tags from contact | | contacts.listActivity(idOrEmail, limit?) | Get contact activity | | contacts.globalUnsubscribe(email, reason?) | Unsubscribe from all | | Lists | | | lists.subscribe(listSlug, email, name?) | Subscribe to list | | lists.unsubscribe(listSlug, email) | Unsubscribe from list | | Emails | | | emails.send(input) | Send transactional email | | emails.getStatus(messageId) | Get email delivery status | | emails.listEvents(messageId) | Get email tracking events | | Sequences | | | sequences.enroll(input) | Enroll in sequence | | sequences.getEnrollments(email, sequenceSlug?) | Get enrollments | | sequences.unenroll(email, sequenceSlug?) | Unenroll from sequence | | sequences.pause(email, sequenceSlug) | Pause enrollment | | sequences.resume(email, sequenceSlug) | Resume enrollment | | Orders | | | orders.create(input) | Create checkout session | | Customers (Billing History) | | | customers.getByEmail(email) | Get customer info | | customers.listInvoices(email, limit?) | List invoices | | customers.listOrders(email, limit?) | List orders | | customers.listSubscriptions(email) | List subscriptions | | customers.listPayments(email, limit?) | List payments | | customers.updateCustomer(id, input) | Update customer profile | | customers.deleteCustomer(id) | Delete customer (GDPR) | | Products | | | products.getProduct(slug) | Get product info | | Events | | | events.trackEvent(input) | Track a custom event | | Funnels | | | funnels.getFunnelStep(slug) | Get funnel step info | | Offers | | | offers.processOffer(input) | Accept/decline an offer | | Quizzes | | | quizzes.getQuiz(slug) | Get quiz info | | quizzes.submitQuiz(slug, input) | Submit quiz answers | | Workshops | | | workshops.getWorkshop(slug) | Get workshop info | | workshops.getWorkshopByProduct(productSlug) | Get workshop by product | | Billing | | | billing.createCustomer(input) | Create billing customer | | billing.createCheckout(input) | Create Stripe checkout | | billing.createSubscription(input) | Create subscription | | billing.cancelSubscription(subscriptionId) | Cancel subscription | | billing.recordUsage(input) | Record metered usage | | billing.getPortal(input) | Get portal URL | | Webhooks | | | webhooks.register(input) | Register webhook | | webhooks.list() | List webhooks | | webhooks.get(webhookId) | Get webhook details | | webhooks.update(webhookId, input) | Update webhook | | webhooks.delete(webhookId) | Delete webhook | | webhooks.test(webhookId) | Send test event | | webhooks.listLogs(webhookId, limit?) | Get delivery logs | | Stats | | | stats.getOverview(options?) | Get overview stats | | stats.getEmailStats(options?) | Get email stats | | stats.getRevenueStats(options?) | Get revenue stats | | stats.getContactStats(options?) | Get contact stats | | Tracking | | | tracking.track(input) | Track custom event | | LLM/AI (HTTP) | | | llm.chat(input) | Simple chat (non-streaming) | | llm.getConfig() | Get LLM configuration | | LLMClient (gRPC Streaming) | | | new LLMClient(apiKey, options?) | Create LLM streaming client | | chatStream(input) | Stream chat (async generator) | | chatStreamCallback(input, callback) | Stream chat with callback | | chat(input) | Simple chat via gRPC | | close() | Close gRPC connection | | Content/CMS | | | content.listPosts(options?) | List published posts | | content.getPost(slug) | Get post by slug | | content.listPages(options?) | List published pages | | content.getPage(slug) | Get page by slug | | content.listCategories() | List content categories | | Site Configuration | | | site.getSettings() | Get site branding/settings | | site.listMenus(options?) | List navigation menus | | site.getMenu(slug) | Get menu by slug | | site.listAuthors() | List all authors | | site.getAuthor(id) | Get author by ID |


Requirements

  • Node.js 18+ (for native fetch)
  • TypeScript 5.0+ (recommended)

License

MIT License - see LICENSE for details.