Installation
Install with your preferred package manager:Copy
npm install creem_io
Quick Start
Copy
import { createCreem } from "creem_io";
const creem = createCreem({
apiKey: process.env.CREEM_API_KEY!,
webhookSecret: process.env.CREEM_WEBHOOK_SECRET, // optional, for webhooks
testMode: false, // set to true for test mode
});
// Retrieve a product
const product = await creem.products.get({
productId: "prod_7CIbZEZnRC5DWibmoOboOu",
});
console.log(product);
// Create a checkout session
const checkout = await creem.checkouts.create({
productId: "prod_xxxxx",
successUrl: "https://yourapp.com/success",
metadata: {
userId: "user_123",
},
});
console.log(checkout.checkoutUrl); // Redirect user to this URL
Environment Variables
We recommend storing your credentials in environment variables:Copy
CREEM_API_KEY=your_api_key
CREEM_WEBHOOK_SECRET=your_webhook_secret
API Resources
The SDK organizes all operations into logical resources:Products
Copy
// List products
const products = await creem.products.list({
page: 1,
limit: 10,
});
// Get a product
const product = await creem.products.get({
productId: "prod_7CIbb...",
});
// Create a product
creem.products.create({
name: "Test Product",
description: "Test Product Description",
price: 1000, // In cents
currency: "USD",
billingType: "recurring",
billingPeriod: "every-month",
})
// Search products
const products = await creem.products.list({
page: 1,
limit: 10,
})
Checkouts
Copy
// Create a checkout session
const checkout = await creem.checkouts.create({
productId: "prod_xxxxx",
units: 2, // Optional: Number of units (default: 1)
discountCode: "SUMMER2024", // Optional: Apply discount
customer: {
email: "[email protected]", // Optional: Pre-fill customer info
},
customField: [
// Optional: Max 3 custom fields
{
key: "company",
label: "Company Name",
type: "text",
optional: false,
},
],
successUrl: "https://yourapp.com/success",
metadata: {
userId: "user_123",
source: "web",
},
});
console.log(checkout.checkoutUrl); // Redirect user to this URL
// Get a checkout session
const retrievedCheckout = await creem.checkouts.get({
checkoutId: "chck_1234567890",
});
Customers
Copy
// List customers
const customers = await creem.customers.list({
page: 1,
limit: 10,
});
// Get a customer by ID
const customer = await creem.customers.get({
customerId: "cust_abc123",
});
// Get a customer by email
const customerByEmail = await creem.customers.get({
email: "[email protected]",
});
// Create customer portal link
const portal = await creem.customers.createPortal({
customerId: "cust_abc123",
});
console.log(portal.customerPortalLink); // Redirect user to portal
Subscriptions
Copy
// Get a subscription
const subscription = await creem.subscriptions.get({
subscriptionId: "sub_abc123",
});
// Cancel a subscription
const canceledSubscription = await creem.subscriptions.cancel({
subscriptionId: "sub_abc123",
});
// Update a subscription (change units/seats)
const updated = await creem.subscriptions.update({
subscriptionId: "sub_abc123",
items: [
{
id: "item_abc123", // Subscription item ID
units: 5, // Update to 5 seats
},
],
updateBehavior: "proration-charge-immediately",
});
// Upgrade a subscription to a different product
const upgraded = await creem.subscriptions.upgrade({
subscriptionId: "sub_abc123",
productId: "prod_premium", // New product ID
updateBehavior: "proration-charge-immediately",
});
Update Behavior Options:
proration-charge-immediately: Calculate proration and charge immediatelyproration-charge: Calculate proration and charge at next billing cycleproration-none: No proration, just switch the plan
Licenses
Copy
// Activate a license
const license = await creem.licenses.activate({
key: "license_key_here",
instanceName: "Production Server",
});
console.log(license.instance?.id); // Use this instance ID for validation
// Validate a license
const validatedLicense = await creem.licenses.validate({
key: "license_key_here",
instanceId: "inst_abc123",
});
console.log(validatedLicense.status); // "active" | "inactive" | "expired" | "disabled"
// Deactivate a license
const deactivatedLicense = await creem.licenses.deactivate({
key: "license_key_here",
instanceId: "inst_abc123",
});
Discounts
Copy
// Create a discount code
const discount = await creem.discounts.create({
name: "Summer Sale 2024",
code: "SUMMER2024", // Optional: Auto-generated if not provided
type: "percentage",
percentage: 20, // 20% off
duration: "forever", // "forever" | "once" | "repeating"
maxRedemptions: 100,
});
// Retrieve a discount by ID
const discount = await creem.discounts.get({
discountId: "disc_xxxxx",
});
// Retrieve a discount by code
const discountByCode = await creem.discounts.get({
discountCode: "SUMMER2024",
});
// Delete a discount
await creem.discounts.delete({
discountId: "disc_xxxxx",
});
Transactions
Copy
// Get a transaction
const transaction = await creem.transactions.get({
transactionId: "txn_xxxxx",
});
// List transactions
const transactions = await creem.transactions.list({
customerId: "cust_xxxxx", // Optional: filter by customer
page: 1,
limit: 50,
});
Webhooks
Handle Creem webhook events in your application. The SDK provides automatic signature verification and type-safe event handlers.Basic Webhook Setup
Copy
import { createCreem } from "creem_io";
const creem = createCreem({
apiKey: process.env.CREEM_API_KEY!,
webhookSecret: process.env.CREEM_WEBHOOK_SECRET!,
});
// In your webhook endpoint
app.post("/webhook", async (req, res) => {
try {
await creem.webhooks.handleEvents(
req.body, // raw body as string
req.headers["creem-signature"],
{
onCheckoutCompleted: async (data) => {
console.log("Checkout completed:", data.customer?.email);
},
onGrantAccess: async (context) => {
// Grant user access when subscription is active/trialing/paid
const userId = context.metadata?.userId;
await grantUserAccess(userId);
},
onRevokeAccess: async (context) => {
// Revoke access when subscription is paused/expired
const userId = context.metadata?.userId;
await revokeUserAccess(userId);
},
}
);
res.status(200).send("OK");
} catch (error) {
console.error("Webhook error:", error);
res.status(400).send("Invalid signature");
}
});
Access Management Callbacks
TheonGrantAccess and onRevokeAccess callbacks simplify subscription access management:
Copy
onGrantAccess: async ({ reason, customer, product, metadata }) => {
// Called for: subscription.active, subscription.trialing, subscription.paid
const userId = metadata?.userId as string;
await db.user.update({
where: { id: userId },
data: { subscriptionActive: true },
});
console.log(`Granted ${reason} to ${customer.email}`);
},
onRevokeAccess: async ({ reason, customer, product, metadata }) => {
// Called for: subscription.paused, subscription.expired
const userId = metadata?.userId as string;
await db.user.update({
where: { id: userId },
data: { subscriptionActive: false },
});
console.log(`Revoked access (${reason}) from ${customer.email}`);
},
All Available Webhook Events
Copy
await creem.webhooks.handleEvents(body, signature, {
// Checkout events
onCheckoutCompleted: async (data) => {},
// Access management (simplified)
onGrantAccess: async (context) => {},
onRevokeAccess: async (context) => {},
// Individual subscription events
onSubscriptionActive: async (data) => {},
onSubscriptionTrialing: async (data) => {},
onSubscriptionCanceled: async (data) => {},
onSubscriptionPaid: async (data) => {},
onSubscriptionExpired: async (data) => {},
onSubscriptionUnpaid: async (data) => {},
onSubscriptionPastDue: async (data) => {},
onSubscriptionPaused: async (data) => {},
onSubscriptionUpdate: async (data) => {},
// Other events
onRefundCreated: async (data) => {},
onDisputeCreated: async (data) => {},
});
Framework-Specific Examples
- Next.js App Router
- Express
- Fastify
- Hono
Copy
import { NextRequest } from "next/server";
import { createCreem } from "creem_io";
const creem = createCreem({
apiKey: process.env.CREEM_API_KEY!,
webhookSecret: process.env.CREEM_WEBHOOK_SECRET!,
});
export async function POST(req: NextRequest) {
try {
const body = await req.text();
const signature = req.headers.get("creem-signature")!;
await creem.webhooks.handleEvents(body, signature, {
onCheckoutCompleted: async (data) => {
// Handle checkout completion
},
onGrantAccess: async (context) => {
// Grant access to user
},
});
return new Response("OK", { status: 200 });
} catch (error) {
return new Response("Invalid signature", { status: 400 });
}
}
Copy
import express from "express";
app.post(
"/webhook",
express.raw({ type: "application/json" }),
async (req, res) => {
try {
await creem.webhooks.handleEvents(
req.body,
req.headers["creem-signature"],
{
onCheckoutCompleted: async (data) => {
// Handle checkout
},
}
);
res.status(200).send("OK");
} catch (error) {
res.status(400).send("Invalid signature");
}
}
);
Copy
fastify.post("/webhook", async (request, reply) => {
try {
await creem.webhooks.handleEvents(
request.rawBody,
request.headers["creem-signature"],
{
onCheckoutCompleted: async (data) => {
// Handle checkout
},
}
);
reply.code(200).send("OK");
} catch (error) {
reply.code(400).send("Invalid signature");
}
});
Copy
app.post("/webhook", async (c) => {
try {
const body = await c.req.text();
const signature = c.req.header("creem-signature");
await creem.webhooks.handleEvents(body, signature, {
onCheckoutCompleted: async (data) => {
// Handle checkout
},
});
return c.text("OK");
} catch (error) {
return c.text("Invalid signature", 400);
}
});
TypeScript Support
The SDK is written in TypeScript and provides comprehensive type definitions:Copy
import type {
Checkout,
Customer,
Product,
Subscription,
Transaction,
License,
Discount,
WebhookOptions,
CheckoutCompletedEvent,
SubscriptionEvent,
GrantAccessContext,
RevokeAccessContext,
} from "creem_io";
Error Handling
The SDK throws errors when API calls fail. Always wrap SDK calls in try-catch blocks:Copy
try {
const product = await creem.products.get({
productId: "prod_xxxxx",
});
} catch (error) {
console.error("Failed to retrieve product:", error);
// Handle error appropriately
}
References
For feedback or issues, open a PR or issue on the Creem SDK GitHub.