Use this pre-built prompt to migrate to API 2026-06-07 and SDK v6 from any version with AI assistants.
This release ships together to the REST API (version 2026-06-07) and all five SDKs (Node, Python, Go, Java, PHP at 6.0.0): new Payouts and Test Clock APIs, two new lookups, and a big cleanup of request/response shapes — unified, nested objects instead of flat field soup.
API response shapes are now unified and nested
The biggest change. Subscription and Plan responses used to be several types with dozens of flat fields. They're now one type each, with nested objects.
A subscription response, before and after 2026-06-07:
// pinned before 2026-06-07 (flat)
{
"id": "sub_xxx",
"planId": "pln_abc",
"planName": "Pro",
"currentPeriodStart": "2026-06-01T00:00:00Z",
"currentPeriodEnd": "2026-07-01T00:00:00Z",
"discountType": "percentage",
"discountValue": 20
}
// 2026-06-07 (nested)
{
"id": "sub_xxx",
"plan": { "id": "pln_abc", "name": "Pro", "basePrice": 2900 },
"currentPeriod": {
"start": "2026-06-01T00:00:00Z",
"end": "2026-07-01T00:00:00Z",
"daysRemaining": 12
},
"discount": { "type": "percentage", "value": 20 }
}The full set of 2026-06-07 shape changes (all version-gated — pin earlier to keep the old shape):
| Resource | Change |
|---|---|
| Subscription | One unified type. plan, currentPeriod, discount are now nested objects (were flat planId / planName / currentPeriodStart / currentPeriodEnd / discount*). |
| Plan | One unified type (was PlanListItem / PlanDetail). A feature's overage is nested under overage (was flat overageEnabled / overageUnitPrice). |
| Subscription / Feature usage | overage → overageQuantity (in features[].usage). |
| Plan price | Intro offer nested under introOffer (was flat introOfferEnabled / introOfferDiscountType / introOfferDiscountValue / introOfferDurationCycles). |
| Customer | billingEmail → email (requests and responses, including batch create). |
| Promo code | isActive → active. |
| Usage check | response feature → featureCode. |
New resource: Payouts
Manage payout bank accounts, request payouts, and complete account verification — programmatically for the first time.
await commet.payouts.addBankAccount({
accountNumber: "000123456789",
accountHolderName: "Acme Inc.",
routingNumber: "110000000",
accountType: "checking",
setDefault: true,
});
// amount is in cents, minimum 1000 ($10)
await commet.payouts.request({
amount: 50000,
description: "Weekly payout",
});
await commet.payouts.completeVerification({
email: "owner@acme.com",
businessType: "company",
businessUrl: "https://acme.com",
documentUrl: "https://files.acme.com/incorporation.pdf",
bank: { accountNumber: "000123456789", routingNumber: "110000000" },
company: { name: "Acme Inc.", taxId: "12-3456789" },
});request() rejects amounts below 1000 cents. Pass either individual or company to completeVerification() depending on businessType.
REST: POST /payouts/bank-accounts · POST /payouts · POST /payouts/verification
New resource: Test Clock
Simulate the passage of time in sandbox to test renewals, trials, and billing cycles without waiting.
Sandbox only. Test Clock methods throw against live organizations.
await commet.testClock.get();
await commet.testClock.advance({ advanceDays: 30 });
// or jump to an exact moment
await commet.testClock.advance({ frozenTime: "2026-07-01T00:00:00Z" });
await commet.testClock.processBilling();advance() moves the clock forward. processBilling() runs the billing engine against the current clock time so you can assert invoices and renewals immediately.
REST: GET /test-clock · POST /test-clock · POST /test-clock/process-billing
New methods on existing resources
subscriptions.get() fetches a single subscription by id — distinct from getActive(), which resolves the active subscription for a customer.
const sub = await commet.subscriptions.get({ id: "sub_xxx" });REST: GET /subscriptions/{id}
plans.setRegionalPricing() configures local-currency pricing for a plan in one call.
await commet.plans.setRegionalPricing({
id: "pln_abc",
currency: "BRL",
exchangeRate: 5.2,
prices: [{ priceId: "price_xxx", price: 14900 }],
features: [{ featureId: "feat_xxx", overageUnitPrice: 50 }],
introOffers: [{ priceId: "price_xxx", discountType: "percentage", discountValue: 20, durationCycles: 3 }],
});REST: PUT /plans/{id}/regional
SDK breaking changes
The nested shapes above land in the SDKs as v6 breaking changes. The examples are TypeScript; each SDK uses its own idiomatic naming.
Intro offers on subscriptions.create()
customIntroOffer is now introOffer, a nested object. The flat fields introOfferEndsAt, introOfferDiscountType, and introOfferDiscountValue were removed from the subscription object.
// v5
await commet.subscriptions.create({
customerId: userId,
planCode: "pro",
customIntroOffer: {
introOfferDiscountType: "percentage",
introOfferDiscountValue: 50,
introOfferEndsAt: "2026-09-01T00:00:00Z",
},
});
// v6
await commet.subscriptions.create({
customerId: userId,
planCode: "pro",
introOffer: {
discountType: "percentage",
discountValue: 50,
durationCycles: 3,
},
});Customer email: billingEmail → email
The field is email on create/update params and on the customer object.
// v5
await commet.customers.create({ id: "user_123", billingEmail: "user@co.com" });
const email = customer.billingEmail;
// v6
await commet.customers.create({ id: "user_123", email: "user@co.com" });
const email = customer.email;Exported type names
CreateParams and UpdateParams are now CreateCustomerParams and UpdateCustomerParams. CreateAddonParams is a single interface — it was previously a union.
// v5
import type { CreateParams, UpdateParams } from "@commet/node";
// v6
import type { CreateCustomerParams, UpdateCustomerParams } from "@commet/node";quota.add() / quota.remove() require count
count no longer defaults to 1. Pass it explicitly.
// v5
await commet.quota.add({ customerId: userId, featureCode: "seats" });
// v6
await commet.quota.add({ customerId: userId, featureCode: "seats", count: 1 });Calling the API directly
Set the version with the commet-version header. New endpoints are additive — they work on any pinned version:
POST /payouts/bank-accounts·POST /payouts·POST /payouts/verificationGET /test-clock·POST /test-clock·POST /test-clock/process-billingGET /subscriptions/{id}PUT /plans/{id}/regional
curl https://commet.co/api/v1/subscriptions/sub_xxx \
-H "Authorization: Bearer ck_..." \
-H "commet-version: 2026-06-07"Request 2026-06-07 to get the nested shapes; omit it or pin earlier and the API transforms responses back to the flat shape your integration already expects.
Every language, same API
Node, Python, Go, Java, and PHP all ship v6 with the same resources and methods. Each SDK follows its language's idiomatic naming — TypeScript, PHP, and Java are camelCase, Python is snake_case, and Go uses exported PascalCase fields.
npm install @commet/node@6
pip install commet-sdk==6.0.0
go get github.com/commet-labs/commet-go/v6
composer require commet/commet-php:^6.0
implementation("co.commet:commet-java:6.0.0") // GradleFor Go, the major version is now part of the import path (/v6).
Every API version ever released still works. From v1 to v6, every version is accepted. The shape changes above apply when you request 2026-06-07 — pin an earlier version with the commet-version header and the API keeps returning the previous (flat) shape, derived automatically. You migrate on your own schedule.
Visit the API versioning docs to see how version pinning works, or the SDK reference for the full v6 surface.