Commet is now fully headless. Everything you can do in the dashboard, you can now do through the SDK, API, and CLI. Ships across all five languages with the same resources, methods, and types.
Every API version ever released still works. From v1 to v5, every version is accepted and will continue to be.
New resources
These were dashboard-only before. Now you can manage them programmatically:
- Plans — create, update, delete, manage features and prices, set visibility, configure regional pricing
- Invoices — list, get details, download PDF, send to customer, update status, create adjustments
- Transactions — list, get details, refund, retry failed payments
- Plan Groups — organize plans into groups, reorder, manage membership
- Promo Codes — create and manage discount codes
- Credit Packs — create and manage credit pack offerings
- API Keys — create, list, delete keys programmatically
- Webhooks — create, list, delete endpoints and trigger test deliveries
- Addons — full CRUD for addon definitions, plus activate/deactivate on a subscription
Existing resources also got new methods:
- Subscriptions —
list(),previewChange(),activateAddon(),deactivateAddon(),adjustBalance(),topupBalance(),purchaseCredits() - Features —
create(),update(),delete()
Breaking changes
All .get() methods now take objects
Every resource getter changed from positional arguments to a params object.
// v4
await commet.customers.get("cus_xxx");
await commet.plans.get("pro");
// v5
await commet.customers.get({ id: "cus_xxx" });
await commet.plans.get({ id: "pro" });subscriptions.get() → getActive()
Renamed and takes an object.
// v4
const sub = await commet.subscriptions.get(userId);
// v5
const sub = await commet.subscriptions.getActive({ customerId: userId });subscriptionId → id in cancel, uncancel, changePlan
// v4
await commet.subscriptions.cancel({ subscriptionId: "sub_xxx", reason: "..." });
await commet.subscriptions.uncancel({ subscriptionId: "sub_xxx" });
await commet.subscriptions.changePlan({ subscriptionId: "sub_xxx", newPlanId: "plan_xxx" });
// v5
await commet.subscriptions.cancel({ id: "sub_xxx", reason: "..." });
await commet.subscriptions.uncancel({ id: "sub_xxx" });
await commet.subscriptions.changePlan({ id: "sub_xxx", newPlanId: "plan_xxx" });customerId → id in customers.update
// v4
await commet.customers.update({ customerId: "cus_xxx", email: "new@co.com" });
// v5
await commet.customers.update({ id: "cus_xxx", email: "new@co.com" });features.check() removed
Use canUse() instead — it returns more context (billing impact, reason if blocked).
// v4
const { allowed } = await commet.features.check({ customerId: userId, code: "api_calls" });
// v5
const { allowed } = await commet.features.canUse({ customerId: userId, code: "api_calls" });features.list() takes an object
// v4
const features = await commet.features.list(userId);
// v5
const features = await commet.features.list({ customerId: userId });addons.getActive() → listActive()
// v4
const addons = await commet.addons.getActive({ customerId: userId });
// v5
const addons = await commet.addons.listActive({ customerId: userId });seatType → featureCode
Seats are features. The parameter name now reflects that. featureCode is now required (it was optional alongside the deprecated seatType in v4).
// v4
commet.seats.add({ customerId: userId, seatType: "member", count: 1 });
// v5
commet.seats.add({ customerId: userId, featureCode: "member" });count defaults to 1 — no need to pass it for single seat operations.
No more customer() context
All methods now take customerId as a direct parameter. Less indirection, easier to understand.
// v4
const customer = commet.customer(userId);
await customer.features.canUse("editor");
await customer.seats.add("member");
// v5
await commet.features.canUse({ customerId: userId, code: "editor" });
await commet.seats.add({ customerId: userId, featureCode: "member" });externalId removed
If you were passing externalId to identify customers on seats, usage, or subscriptions — use customerId instead. For customer creation, keep using id. Also removed from WebhookData payloads.
// v4
commet.usage.track({ feature: "api_calls", externalId: userId });
// v5
commet.usage.track({ feature: "api_calls", customerId: userId });Error response shape
ApiResponse no longer has code, message, details at the top level. Use the error object instead.
// v4
if (!response.success) {
console.log(response.code, response.message);
}
// v5
if (!response.success) {
console.log(response.error?.code, response.error?.message);
}Thrown errors also got richer. CommetAPIError now includes type, param, and docUrl.
try {
await commet.subscriptions.create({ customerId, planCode: "pro" });
} catch (error) {
if (error instanceof CommetAPIError) {
console.log(error.type); // "invalid_request_error"
console.log(error.param); // "planCode"
console.log(error.docUrl); // link to docs
}
}Debug mode
Pass debug: true to see every request and response in your console. Useful when integrating.
const commet = new Commet({ apiKey: "ck_...", debug: true });
// [Commet SDK] POST https://commet.co/api/v1/subscriptions
// [Commet SDK] Response status: 201 CreatedCLI resource commands
Every SDK method is now available from the terminal. No code needed — create customers, plans, subscriptions, issue refunds, all from the command line.
commet customers create --email user@example.com --id user_123
commet plans create --name "Pro" --code pro
commet plans add-price --plan-id pln_abc --billing-interval monthly --price 2900
commet subscriptions create --customer-id user_123 --plan-code pro
commet invoices list --customer-id user_123
commet transactions refund --id txn_abcSame structure everywhere: commet <resource> <action> [--flags].
--output agent returns raw JSON. --help at every level shows available actions and flags. Errors always tell you what went wrong and what values are valid.
commet link now auto-generates an API key for your org — no extra step needed.
Every language, same API
Node, Python, Go, Java, and PHP — all with the same resources and identical method signatures.
npm install @commet/node@5
pip install commet-sdk==5.0.0
go get github.com/commet-labs/commet-go/v5
composer require commet/commet-php:^5.0
implementation("co.commet:commet-java:5.0.0") // Gradle