Skip to main content

Installation

Install with your preferred package manager:
npm install creem_io

Quick Start

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:
CREEM_API_KEY=your_api_key
CREEM_WEBHOOK_SECRET=your_webhook_secret

API Resources

The SDK organizes all operations into logical resources:

Products

// 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

// 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: "customer@example.com", // 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

// 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: "customer@example.com",
});

// Create customer portal link
const portal = await creem.customers.createPortal({
  customerId: "cust_abc123",
});

console.log(portal.customerPortalLink); // Redirect user to portal

Subscriptions

// 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 immediately
  • proration-charge: Calculate proration and charge at next billing cycle
  • proration-none: No proration, just switch the plan

Licenses

// 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

// 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

// 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

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

The onGrantAccess and onRevokeAccess callbacks simplify subscription access management:
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

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
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 });
  }
}

TypeScript Support

The SDK is written in TypeScript and provides comprehensive type definitions:
import type {
  Checkout,
  Customer,
  Product,
  Subscription,
  Transaction,
  License,
  Discount,
  WebhookOptions,
  CheckoutCompletedEvent,
  SubscriptionEvent,
  GrantAccessContext,
  RevokeAccessContext,
} from "creem_io";
All API responses are fully typed, and the SDK automatically converts snake_case to camelCase for better TypeScript/JavaScript experience.

Error Handling

The SDK throws errors when API calls fail. Always wrap SDK calls in try-catch blocks:
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.