From commet
Use when setting up Commet webhook endpoints, verifying signatures, handling billing events (subscription.created, subscription.activated, subscription.canceled, subscription.updated, payment.received, payment.failed, invoice.created), or building event-driven billing workflows.
npx claudepluginhub commet-labs/commet-skills --plugin commetThis skill uses the workspace's default tool permissions.
Receive real-time HTTP notifications when billing events happen in Commet -- subscriptions activating, payments failing, invoices being created, and more.
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.
Webhook validation patterns with signature verification, event logging, and testing tools. Use when implementing webhooks, validating webhook signatures, securing payment webhooks, testing webhook endpoints, preventing replay attacks, or when user mentions webhook security, Stripe webhooks, signature verification, webhook testing, or event validation.
Designs reliable webhook systems using Stripe patterns: resource.action event naming, JSON envelope payloads, HMAC-SHA256 signing, exponential backoff retries, deduplication, and endpoint implementation.
Share bugs, ideas, or general feedback.
Receive real-time HTTP notifications when billing events happen in Commet -- subscriptions activating, payments failing, invoices being created, and more.
// app/api/webhooks/commet/route.ts
import { Webhooks } from "@commet/next";
export const POST = Webhooks({
webhookSecret: process.env.COMMET_WEBHOOK_SECRET!,
onSubscriptionActivated: async (payload) => {
await sendWelcomeEmail(payload.data.externalId);
},
onSubscriptionCanceled: async (payload) => {
await sendCancellationEmail(payload.data.externalId);
},
});
Install the handler package:
npm install @commet/next
Webhooks are for background tasks (sending emails, provisioning resources, logging). They should never be the source of truth for access control or subscription state.
Always query the SDK directly when you need to check a customer's status:
import { Commet } from "@commet/node";
const commet = new Commet({ apiKey: process.env.COMMET_API_KEY! });
// Check subscription status -- do this, not webhook state sync
const { data: sub } = await commet.subscriptions.get("user_123");
if (sub?.status === "active" || sub?.status === "trialing") {
// grant access
}
// Check feature access
const { data } = await commet.features.check({
code: "advanced_analytics",
customerId: "user_123",
});
| Event | When Fired | Common Use |
|---|---|---|
subscription.created | New subscription created, before payment | Logging, analytics |
subscription.activated | Payment successful, subscription active | Welcome email, provision resources |
subscription.canceled | Subscription canceled | Cancellation email, schedule cleanup |
subscription.updated | Subscription details changed | Sync external systems |
subscription.plan_changed | Plan upgrade/downgrade | Notify of plan change, adjust resources |
payment.received | Recurring payment processed | Receipt email, update accounting |
payment.failed | Recurring charge failed | Alert customer, dunning flow |
invoice.created | New invoice generated | Custom invoice handling |
See references/events.md for full payload shapes and examples.
Every webhook delivers a JSON payload with this structure:
{
"event": "subscription.activated",
"timestamp": "2026-03-25T14:30:00.000Z",
"organizationId": "org_abc123",
"data": { }
}
| Header | Description |
|---|---|
X-Commet-Signature | HMAC-SHA256 hex signature of the raw body |
X-Commet-Event | The event type |
X-Commet-Timestamp | ISO 8601 datetime when the event was emitted |