Este release sale en conjunto para la API REST (versión 2026-06-07) y los cinco SDKs (Node, Python, Go, Java y PHP en 6.0.0): nuevas APIs de Payouts y Test Clock, dos nuevos lookups, y una limpieza grande de las shapes de request/response — objetos unificados y anidados en lugar de un mar de campos planos.
Todas las versiones de la API que se publicaron siguen funcionando. De v1 a v6, todas se aceptan. Los cambios de shape de abajo aplican cuando pedís 2026-06-07 — fijá una versión anterior con el header commet-version y la API sigue devolviendo la shape previa (plana), derivada automáticamente. Migrás cuando vos quieras.
Las shapes de respuesta ahora son unificadas y anidadas
El cambio más grande. Las respuestas de Subscription y Plan eran varios tipos con decenas de campos planos. Ahora son un solo tipo cada una, con objetos anidados.
Una respuesta de subscription, antes y después de 2026-06-07:
// fijado antes de 2026-06-07 (plano)
{
"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 (anidado)
{
"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 }
}El set completo de cambios de shape de 2026-06-07 (todos versionados — fijá una versión anterior para conservar la shape vieja):
| Recurso | Cambio |
|---|---|
| Subscription | Un tipo unificado. plan, currentPeriod y discount ahora son objetos anidados (eran planos: planId / planName / currentPeriodStart / currentPeriodEnd / discount*). |
| Plan | Un tipo unificado (era PlanListItem / PlanDetail). El overage de una feature va anidado bajo overage (era plano: overageEnabled / overageUnitPrice). |
| Uso de Subscription / Feature | overage → overageQuantity (en features[].usage). |
| Precio de plan | El intro offer va anidado bajo introOffer (eran planos: introOfferEnabled / introOfferDiscountType / introOfferDiscountValue / introOfferDurationCycles). |
| Customer | billingEmail → email (requests y responses, incluido el batch create). |
| Promo code | isActive → active. |
| Usage check | en la response, feature → featureCode. |
Nuevo recurso: Payouts
Gestioná cuentas bancarias de payout, solicitá payouts y completá la verificación de la cuenta — por primera vez de forma programática.
await commet.payouts.addBankAccount({
accountNumber: "000123456789",
accountHolderName: "Acme Inc.",
routingNumber: "110000000",
accountType: "checking",
setDefault: true,
});
// amount va en centavos, mínimo 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() rechaza montos por debajo de 1000 centavos. Pasá individual o company a completeVerification() según el businessType.
REST: POST /payouts/bank-accounts · POST /payouts · POST /payouts/verification
Nuevo recurso: Test Clock
Simulá el paso del tiempo en sandbox para probar renovaciones, trials y ciclos de facturación sin esperar.
Solo sandbox. Los métodos de Test Clock tiran error contra organizaciones live.
await commet.testClock.get();
await commet.testClock.advance({ advanceDays: 30 });
// o saltar a un momento exacto
await commet.testClock.advance({ frozenTime: "2026-07-01T00:00:00Z" });
await commet.testClock.processBilling();advance() mueve el reloj hacia adelante. processBilling() corre el motor de facturación contra el tiempo actual del reloj para que puedas verificar invoices y renovaciones al instante.
REST: GET /test-clock · POST /test-clock · POST /test-clock/process-billing
Nuevos métodos en recursos existentes
subscriptions.get() trae una subscription por id — distinto de getActive(), que resuelve la subscription activa de un customer.
const sub = await commet.subscriptions.get({ id: "sub_xxx" });REST: GET /subscriptions/{id}
plans.setRegionalPricing() configura el precio en moneda local de un plan en una sola llamada.
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
Breaking changes del SDK
Las shapes anidadas de arriba llegan a los SDKs como breaking changes de v6. Los ejemplos son TypeScript; cada SDK usa su naming idiomático.
Intro offers en subscriptions.create()
customIntroOffer ahora es introOffer, un objeto anidado. Los campos planos introOfferEndsAt, introOfferDiscountType e introOfferDiscountValue se quitaron del objeto subscription.
// 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,
},
});Email del customer: billingEmail → email
El campo es email en los params de create/update y en el objeto customer.
// 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;Nombres de tipos exportados
CreateParams y UpdateParams ahora son CreateCustomerParams y UpdateCustomerParams. CreateAddonParams es una sola interfaz — antes era una unión.
// v5
import type { CreateParams, UpdateParams } from "@commet/node";
// v6
import type { CreateCustomerParams, UpdateCustomerParams } from "@commet/node";quota.add() / quota.remove() requieren count
count ya no asume 1 por defecto. Pasalo explícitamente.
// v5
await commet.quota.add({ customerId: userId, featureCode: "seats" });
// v6
await commet.quota.add({ customerId: userId, featureCode: "seats", count: 1 });Llamando a la API directamente
Seteá la versión con el header commet-version. Los endpoints nuevos son aditivos — funcionan en cualquier versión fijada:
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"Pedí 2026-06-07 para obtener las shapes anidadas; omitilo o fijá una versión anterior y la API transforma las responses de vuelta a la shape plana que tu integración ya espera.
Todos los lenguajes, la misma API
Node, Python, Go, Java y PHP salen todos en v6 con los mismos recursos y métodos. Cada SDK sigue el naming idiomático de su lenguaje — TypeScript, PHP y Java son camelCase, Python es snake_case, y Go usa campos exportados en PascalCase.
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") // GradleEn Go, el major ahora es parte del import path (/v6).