From commet
Integrates Commet billing and payments into Node.js and Next.js apps via @commet/node, @commet/next, @commet/better-auth. Handles subscriptions, usage tracking, seats, checkouts, portals, webhooks, feature gating.
npx claudepluginhub commet-labs/commetThis skill uses the workspace's default tool permissions.
Commet is an all-in-one billing and payments platform. Merchant of Record handling taxes, compliance, refunds, and payouts. Integrate with a few lines of code.
Clerk Billing and Stripe subscription management setup. Use when implementing subscriptions, configuring pricing plans, setting up billing, adding payment flows, managing entitlements, or when user mentions Clerk Billing, Stripe integration, subscription management, pricing tables, payment processing, or monetization.
Implements Stripe payment processing for checkout sessions, subscriptions, webhooks, refunds, and customer management in PCI-compliant flows for web/mobile apps.
Guides Stripe API choices for payments (Checkout Sessions vs PaymentIntents), Connect Accounts v2, billing/subscriptions, Treasury accounts, Payment Element, and deprecated migrations.
Share bugs, ideas, or general feedback.
Commet is an all-in-one billing and payments platform. Merchant of Record handling taxes, compliance, refunds, and payouts. Integrate with a few lines of code.
| Package | Purpose | Install |
|---|---|---|
@commet/node | Core SDK - customers, subscriptions, usage, seats, features, portal, webhooks | npm i @commet/node |
@commet/next | Next.js helpers - webhook handler, customer portal, pricing markdown | npm i @commet/next |
@commet/ai-sdk | Vercel AI SDK middleware - automatic AI token usage billing | npm i @commet/ai-sdk |
@commet/better-auth | Better Auth plugin - auto customer sync, auth-scoped billing | npm i @commet/better-auth |
@commet/cli | CLI - login, link, pull types, scaffold projects from templates | npm i -g @commet/cli |
import { Commet } from "@commet/node";
const commet = new Commet({
apiKey: process.env.COMMET_API_KEY!, // ck_xxx format
environment: "production", // "sandbox" | "production"
});
Sandbox: https://sandbox.commet.co. Production: https://commet.co.
commet login -> commet link -> commet pull (generates .commet/types.d.ts for autocomplete)externalId = your user IDsubscriptions.create() -> redirect to checkoutUrlsubscriptions.get() to check subscription status (preferred over webhooks)usage.track() for metered features, seats.add/remove/set() for seatsfeatures.check(), features.canUse(), features.get()portal.getUrl() -> redirect for self-service billing managementSee references/sdk.md for the complete API surface of @commet/node.
See references/nextjs.md for @commet/next webhook handlers, customer portal routes, and pricing markdown.
See references/ai-sdk.md for @commet/ai-sdk middleware that auto-tracks AI token usage for billing.
See references/better-auth.md for the @commet/better-auth plugin that auto-syncs customers and provides auth-scoped billing endpoints.
See references/billing-concepts.md for plan structure, feature types, consumption models, and charging behavior.
Always query subscription/feature state directly with the SDK instead of relying on webhooks to sync state. The recommended pattern is to call subscriptions.get(), features.check(), or features.list() when you need to know a customer's status. Webhooks are useful for background tasks (sending emails, provisioning resources) but should never be the source of truth for access control.
// Recommended: query state directly
const { data: sub } = await commet.subscriptions.get("user_123");
if (sub?.status === "active") { /* grant access */ }
// Recommended: feature gating
const { data } = await commet.features.check({ code: "advanced_analytics", externalId: "user_123" });
if (!data?.allowed) { /* show upgrade prompt */ }
Always use externalId (your user/org ID) to identify customers. The SDK accepts either customerId (Commet's cus_xxx) or externalId - prefer externalId to avoid storing Commet IDs.
const customer = commet.customer("user_123");
await customer.usage.track("api_calls", 1);
await customer.features.canUse("team_members");
await customer.seats.add("editor");
await customer.subscription.get();
await customer.portal.getUrl();
All POST requests auto-generate idempotency keys. For critical operations, pass explicit keys:
await commet.usage.track({
externalId: "user_123",
feature: "api_calls",
idempotencyKey: `req_${requestId}`,
});
import { CommetAPIError, CommetValidationError } from "@commet/node";
try {
await commet.subscriptions.create({ ... });
} catch (error) {
if (error instanceof CommetValidationError) {
console.log(error.validationErrors); // { field: ["message"] }
}
if (error instanceof CommetAPIError) {
console.log(error.statusCode, error.code);
}
}
COMMET_API_KEY=ck_xxx # API key from dashboard
COMMET_ENVIRONMENT=sandbox # sandbox | production
COMMET_WEBHOOK_SECRET=whsec_xxx # Optional - webhook secret for signature verification