Quickstart
Create a client, create a checkout, verify a webhook in a Cloudflare Worker, and check subscription status — with the same code on all five providers.
This guide takes you from an empty file to a working integration: a client, a hosted checkout, a verified webhook handler, and an entitlement check.
Install
npm install revenue-sdkpnpm add revenue-sdkyarn add revenue-sdkbun add revenue-sdkCreate a client
Import createClient from the package root and a provider factory from its subpath. Every factory
also accepts an injectable fetch for tests and edge runtimes.
import { createClient } from 'revenue-sdk';
import { polar } from 'revenue-sdk/polar';
const client = createClient({
provider: polar({
accessToken: process.env.POLAR_ACCESS_TOKEN!,
server: 'sandbox',
}),
});Create a checkout
checkouts.create takes one or more items and returns a normalized Checkout with a url you
redirect the customer to. The product field of an item is the provider’s purchasable identifier —
Price.checkoutRef tells you what that is for the active provider.
const { items: products } = await client.products.list({ limit: 10 });
const price = products[0]!.prices[0]!;
const checkout = await client.checkouts.create({
items: [{ product: price.checkoutRef }],
customerEmail: 'ada@example.com',
successUrl: 'https://example.com/thanks',
metadata: { userId: 'user_123' },
});
// Redirect the customer here.
console.log(checkout.url);Handle the webhook
verifyWebhook and parseWebhookEvent are standalone exports on each provider subpath. Read the
raw body once, verify it, then parse it. This example is a Cloudflare Worker fetch handler.
import { parseWebhookEvent, verifyWebhook } from 'revenue-sdk/polar';
interface Env {
POLAR_WEBHOOK_SECRET: string;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const headers = request.headers;
const body = await request.text();
const valid = await verifyWebhook({ headers, body, secret: env.POLAR_WEBHOOK_SECRET });
if (!valid) {
return new Response('invalid signature', { status: 401 });
}
const event = await parseWebhookEvent({ headers, body });
switch (event.type) {
case 'subscription.created':
case 'subscription.updated':
case 'subscription.canceled':
// Upsert by event.subscription!.id.
break;
case 'order.paid':
// Money received — including renewals.
break;
case 'checkout.completed':
// The checkout was paid.
break;
}
return new Response(null, { status: 204 });
},
};Check subscription status
A subscription grants access while its status is active or trialing. canceled is terminal;
a scheduled cancellation keeps the status unchanged and sets cancelAtPeriodEnd.
const subscription = await client.subscriptions.get({ id: 'SUBSCRIPTION_ID' });
const entitled = subscription.status === 'active' || subscription.status === 'trialing';
if (entitled && subscription.cancelAtPeriodEnd) {
console.log(`Access ends on ${subscription.endsAt?.toISOString()}`);
}Switch providers
Switching providers means swapping the provider — the rest of your code stays the same.
import { createClient } from 'revenue-sdk';
import { polar } from 'revenue-sdk/polar';
const client = createClient({
provider: polar({
accessToken: process.env.POLAR_ACCESS_TOKEN!,
server: 'sandbox',
}),
});import { createClient } from 'revenue-sdk';
import { lemonSqueezy } from 'revenue-sdk/lemon-squeezy';
const client = createClient({
provider: lemonSqueezy({
apiKey: process.env.LEMON_SQUEEZY_API_KEY!,
storeId: process.env.LEMON_SQUEEZY_STORE_ID!,
}),
});import { createClient } from 'revenue-sdk';
import { stripe } from 'revenue-sdk/stripe';
const client = createClient({
provider: stripe({ secretKey: process.env.STRIPE_SECRET_KEY! }),
});import { createClient } from 'revenue-sdk';
import { paddle } from 'revenue-sdk/paddle';
const client = createClient({
provider: paddle({
apiKey: process.env.PADDLE_API_KEY!,
server: 'sandbox',
}),
});import { createClient } from 'revenue-sdk';
import { dodoPayments } from 'revenue-sdk/dodo-payments';
const client = createClient({
provider: dodoPayments({
apiKey: process.env.DODO_PAYMENTS_API_KEY!,
server: 'test',
}),
});Next steps
Client & providers
How the client and provider factories fit together.
Subscription lifecycle
The unified status model, scheduled cancellations, and entitlement checks.
Webhooks
Verify-then-parse, normalized events, and idempotency.
Capabilities
What each provider can and can’t do, and how the client gates on it.