lemonsqueezy.js
The official TypeScript SDK for the Lemon Squeezy API, covering checkouts, subscriptions, license keys, and billing.
Repository Health
Technical Analysis
lemonsqueezy.js is the official JavaScript/TypeScript SDK maintained by Lemon Squeezy for its merchant-of-record billing platform. It wraps the full Lemon Squeezy REST API — stores, products, variants, prices, checkouts, orders, subscriptions, discounts, license keys, and webhooks — behind a set of small, tree-shakeable functions instead of a single monolithic client class.
Each resource (checkouts, orders, subscriptions, license keys, and so on) lives in its own directory with a matching types.ts, and every exported function calls through a shared internal $fetch wrapper that handles authentication, JSON:API serialization, and error normalization consistently. Setup is a single lemonSqueezySetup({ apiKey }) call that stores the API key and an optional onError handler for the process, after which any exported function can be called directly.
Because it’s designed for server-side use only — the README explicitly warns against bundling it into a browser build, since the API key would be exposed — it fits naturally into Node/Bun backends, serverless functions, and framework API routes that need to create checkouts, manage subscriptions, or validate license keys on behalf of a Lemon Squeezy store.
What You Get
- Typed functions for every Lemon Squeezy resource — stores, products, variants, prices, orders, subscriptions, discounts, license keys, webhooks, and checkouts
- A single
lemonSqueezySetup()call to configure the API key and a globalonErrorhandler once per process - Tree-shakeable exports so a bundle only pays for the functions it actually imports
- Consistent
{ data, error, statusCode }response shape returned by every function, so callers handle success and failure the same way everywhere - License key activation/validation/deactivation functions for building self-serve license checks outside the main API surface
Common Use Cases
- Creating a checkout session server-side and redirecting a customer to it from a Node/Next.js API route
- Reacting to subscription lifecycle events (renew, pause, cancel) by calling
getSubscription/updateSubscription/cancelSubscriptionfrom a backend job or webhook handler - Validating and activating software license keys issued through Lemon Squeezy from a desktop or CLI app’s activation flow
- Building an internal admin dashboard that lists orders, customers, and subscriptions for a Lemon Squeezy store
- Generating and refunding invoices for orders and subscriptions from a support tool
Under The Hood
Architecture
The package is organized as one directory per API resource (src/checkouts, src/orders, src/subscriptions, src/licenseKeys, etc.), each exporting a small set of functions plus a colocated types.ts, all re-exported from a single src/index.ts barrel. Every resource function funnels through a shared internal/fetch module’s $fetch() helper, which reads the API key set by lemonSqueezySetup() from an internal key-value store (internal/utils/kv.ts), attaches JSON:API headers and bearer auth, serializes the body for POST/PATCH requests, and normalizes both transport and API-level errors into a consistent { statusCode, data, error } envelope. This keeps cross-cutting concerns (auth, error shaping, query-string building) in one place while each resource module stays a thin, declarative wrapper around one or two endpoints; changing the core $fetch behavior propagates to every resource without touching resource-specific files.
Tech Stack
Written in TypeScript with a Bun-based development workflow (bun run, bun test) and tsup for building dual CJS/ESM output with generated .d.ts/.d.cts declarations. It has no runtime dependencies beyond the platform fetch API, keeping the published package extremely lightweight. Tooling includes ESLint with the TypeScript plugin, Prettier, Changesets for versioned releases and changelog generation, simple-git-hooks plus lint-staged for pre-commit checks, and commitlint enforcing conventional commits.
Code Quality
Tests use Bun’s built-in test runner (bun:test) and are organized to mirror src/, with one test file per resource plus an index.test.ts that asserts the full public export surface matches an explicit list — a lightweight but effective guard against accidental breaking changes to the package’s API. Most resource tests are integration-style, calling the real Lemon Squeezy API against a test-mode store and asserting on response shape and status codes rather than mocking the network layer, so coverage depends on a configured test store and API key. Naming is consistent between JSON:API’s snake_case wire format and the SDK’s camelCase public API. Typing is strict throughout, with dedicated types.ts files per resource and shared generic response types.
API Design
The SDK avoids a client-class/object pattern in favor of directly exported functions per operation, which keeps call sites terse and lets bundlers tree-shake unused endpoints — the README documents the min+brotli size of every individual export. A single lemonSqueezySetup() call replaces constructor boilerplate, and every function returns the same { statusCode, data, error } shape, so callers write one error-handling pattern regardless of which resource they’re calling. Parameter validation for required IDs happens via a shared requiredCheck() helper that throws a descriptive error before a network call is attempted, giving fast, consistent feedback on misuse.
Used by 2 apps in this directory
Bigcapital
Invoicing Finance
Self-hostable double-entry accounting platform with invoicing, inventory, multi-currency, and real-time financial reporting for small and medium businesses.
Tianji
Analytics · Monitoring
Replace Google Analytics, UptimeKuma, and Prometheus with one self-hosted platform that tracks websites, monitors uptime, and reports server health.