Commet
  • Pricing
Log InTry out
Introduction

Quickstart

Learn

Resources

SDK ReferenceError HandlingTestingCLI

Plugins

Better Auth
DocumentationKnowledge BaseBuild with AIAPI ReferenceWebhooks

Better Auth

Better Auth Plugin for Billing and Subscriptions using Commet

Better Auth is a modern authentication library for TypeScript. This plugin integrates Commet directly into your Better Auth setup.

Features

  • Automatic customer creation on signup
  • Customer Portal for self-service billing management
  • Subscription management (get, cancel)
  • Feature access control (boolean, metered, seats)
  • Usage tracking for metered billing
  • Seat management for per-user pricing
  • Optional webhook handling with signature verification

Installation

pnpm add better-auth @commet/better-auth @commet/node
npm install better-auth @commet/better-auth @commet/node
yarn add better-auth @commet/better-auth @commet/node
bun add better-auth @commet/better-auth @commet/node

Preparation

Get your API key from the Commet dashboard. Use a key from a sandbox organization while you're integrating; switch to a live-org key when you go to production.

.env
COMMET_API_KEY=ck_...

Server Configuration

auth.ts
import { betterAuth } from "better-auth";
import {
  commet,
  portal,
  subscriptions,
  features,
  usage,
  seats,
} from "@commet/better-auth";
import { Commet } from "@commet/node";

const commetClient = new Commet({
  apiKey: process.env.COMMET_API_KEY,
  environment: process.env.COMMET_ENVIRONMENT, // 'sandbox' or 'production'
});

export const auth = betterAuth({
  // ... your config
  plugins: [
    commet({
      client: commetClient,
      createCustomerOnSignUp: true,
      use: [
        portal(),
        subscriptions(),
        features(),
        usage(),
        seats(),
      ],
    }),
  ],
});

Client Configuration

auth-client.ts
import { createAuthClient } from "better-auth/react";
import { commetClient } from "@commet/better-auth";

export const authClient = createAuthClient({
  plugins: [commetClient()],
});

Configuration Options

commet({
  client: commetClient,                    // Required: Commet SDK instance
  createCustomerOnSignUp: true,            // Auto-create customer on signup
  getCustomerCreateParams: ({ user }) => ({
    legalName: user.name,
    metadata: { source: "web" },
  }),
  use: [/* plugins */],
})

When createCustomerOnSignUp is enabled, a Commet customer is automatically created using the user's ID as the customerId. No database mapping required.

Portal Plugin

Redirects users to the Commet customer portal for self-service billing management.

Server
import { commet, portal } from "@commet/better-auth";

commet({
  client: commetClient,
  use: [
    portal({ returnUrl: "/dashboard" }),
  ],
})
Client
// Redirects to Commet customer portal
await authClient.customer.portal();

Subscriptions Plugin

Manage customer subscriptions.

Server
import { commet, subscriptions } from "@commet/better-auth";

commet({
  client: commetClient,
  use: [subscriptions()],
})
Client
// Get current subscription
const { data: subscription } = await authClient.subscription.get();

// Cancel subscription
await authClient.subscription.cancel({
  subscriptionId: "sub_xxx",
  reason: "Too expensive",
  immediate: false, // Cancel at period end
});

Features Plugin

Check feature access for the authenticated user.

Server
import { commet, features } from "@commet/better-auth";

commet({
  client: commetClient,
  use: [features()],
})
Client
// List all features
const { data: featuresList } = await authClient.features.list();

// Get specific feature
const { data: feature } = await authClient.features.get("api_calls");

// Check if feature is enabled (boolean)
const { data: check } = await authClient.features.check("sso");

// Check if user can use one more unit (metered)
const { data: canUse } = await authClient.features.canUse("api_calls");
// Returns: { allowed: boolean, willBeCharged: boolean }

Usage Plugin

Track usage events for metered billing.

Server
import { commet, usage } from "@commet/better-auth";

commet({
  client: commetClient,
  use: [usage()],
})
Client
await authClient.usage.track({
  feature: "api_calls",
  value: 1,
  idempotencyKey: `evt_${Date.now()}`
});

The authenticated user is automatically associated with the event.

Seats Plugin

Manage seat-based licenses.

Server
import { commet, seats } from "@commet/better-auth";

commet({
  client: commetClient,
  use: [seats()],
})
Client
// List all seat balances
const { data: seatBalances } = await authClient.seats.list();

// Add seats
await authClient.seats.add({ seatType: "member", count: 5 });

// Remove seats
await authClient.seats.remove({ seatType: "member", count: 2 });

// Set exact count
await authClient.seats.set({ seatType: "admin", count: 3 });

// Set all seat types at once
await authClient.seats.setAll({ admin: 2, member: 10, viewer: 50 });

Webhooks Plugin

Handle Commet webhooks. This is optional since you can always query state directly.

Server
import { commet, webhooks } from "@commet/better-auth";

commet({
  client: commetClient,
  use: [
    webhooks({
      secret: process.env.COMMET_WEBHOOK_SECRET,
      onPayload: (payload) => {
        // Catch-all handler
      },
      onSubscriptionCreated: (payload) => {},
      onSubscriptionActivated: (payload) => {},
      onSubscriptionCanceled: (payload) => {},
      onSubscriptionUpdated: (payload) => {},
    }),
  ],
})

Configure the webhook endpoint in your Commet dashboard: /api/auth/commet/webhooks

Full Example

Server Setup

auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import {
  commet as commetPlugin,
  portal,
  subscriptions,
  features,
  usage,
  seats,
} from "@commet/better-auth";
import { Commet } from "@commet/node";
import { db } from "./db";
import * as schema from "./schema";

const commetClient = new Commet({
  apiKey: process.env.COMMET_API_KEY!,
  environment: process.env.COMMET_ENVIRONMENT as "sandbox" | "production",
});

export const auth = betterAuth({
  database: drizzleAdapter(db, { provider: "pg", schema }),
  emailAndPassword: { enabled: true },
  plugins: [
    commetPlugin({
      client: commetClient,
      createCustomerOnSignUp: true,
      getCustomerCreateParams: ({ user }) => ({
        legalName: user.name,
      }),
      use: [
        portal({ returnUrl: "/dashboard" }),
        subscriptions(),
        features(),
        usage(),
        seats(),
      ],
    }),
  ],
});

Client Setup

auth-client.ts
import { createAuthClient } from "better-auth/react";
import { commetClient } from "@commet/better-auth";

export const authClient = createAuthClient({
  baseURL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL,
  plugins: [commetClient()],
});

export const { signIn, signUp, signOut, useSession } = authClient;

Usage in Components

dashboard.tsx
"use client";

import { authClient } from "@/lib/auth-client";

export function BillingSection() {
  const handlePortal = async () => {
    await authClient.customer.portal();
  };

  const checkFeature = async () => {
    const { data } = await authClient.features.canUse("api_calls");
    if (data?.allowed) {
      // Proceed with action
      await authClient.usage.track({ feature: "api_calls" });
    }
  };

  return (
    <div>
      <button onClick={handlePortal}>Manage Billing</button>
      <button onClick={checkFeature}>Use Feature</button>
    </div>
  );
}

Related

  • Subscriptions
  • Usage Events
  • Seat Management
  • Customer Portal

How is this guide?

CLI

Install and use the Commet CLI to generate TypeScript types from your dashboard.

On this page

Features
Installation
Preparation
Server Configuration
Client Configuration
Configuration Options
Portal Plugin
Subscriptions Plugin
Features Plugin
Usage Plugin
Seats Plugin
Webhooks Plugin
Full Example
Server Setup
Client Setup
Usage in Components
Related