Creá, consultá, pausá, reanudá, cancelá y reactivá suscripciones.
Instalá la Skill de Commet para que tu agente implemente el ciclo de vida actual de suscripciones y verifique el resultado.
npx skills add commet-labs/skills --skill commetLas suscripciones conectan un customer con un plan y controlan checkout, invoices, acceso a features, uso y renovaciones.
Los estados persistidos son:
| Estado | Significado |
|---|---|
draft | Creada pero todavía no lista para facturar |
pending_payment | Esperando checkout |
trialing | El acceso de prueba está activo |
active | Facturación normal |
past_due | Falló la renovación y dunning está activo |
paused | Acceso y renovaciones pausados hasta reanudar |
canceled | Finalizaron la facturación y el acceso |
import { Commet } from "@commet/node";const commet = new Commet({ apiKey: "ck_xxx" });const createdSubscription = await commet.subscriptions.create({ customerId: "user_123", planId: "pln_xxx",});from commet import Commetcommet = Commet("ck_xxx")created_subscription = commet.subscriptions.create( customer_id="user_123", plan_id="pln_xxx",)client, err := commet.New("ck_xxx")if err != nil { log.Fatal(err)}ctx := context.Background()createdSubscription, err := client.Subscriptions.Create(ctx, &commet.CreateSubscriptionParams{ CustomerID: "user_123", PlanID: func(value string) *string { return &value }("pln_xxx"),})if err != nil { log.Fatal(err)}import co.commet.Commet;import co.commet.params.CreateSubscriptionParams;var commet = Commet.builder().apiKey("ck_xxx").build();var createdSubscription = commet.subscriptions().create( CreateSubscriptionParams.builder("user_123").planId("pln_xxx").build());use Commet\Commet;$commet = new Commet('ck_xxx');$createdSubscription = $commet->subscriptions->create( customerId: 'user_123', planId: 'pln_xxx',);Para un plan pago, redirigí al customer a checkoutUrl. Los planes gratuitos pueden activarse sin checkout y devolver checkoutUrl: null.
El flujo normal solo necesita customerId y planCode o planId. Los campos opcionales de selección son:
| Campo | Cuándo enviarlo |
|---|---|
billingInterval | El customer eligió un intervalo que no es el default |
priceId | El customer eligió una variante concreta de precio |
offerId | Tu aplicación seleccionó una Offer directamente; reemplaza la selección introductoria automática |
promoCode | El customer ingresó un Promo Code |
initialSeats | Conocés las cantidades iniciales de seats |
skipTrial o customTrialDays | Querés reemplazar intencionalmente la prueba configurada |
Omitir priceId conserva la resolución por defecto de precio y Market. Omitir offerId conserva la selección automática de la Introductory Offer.
Un checkout pending_payment compatible puede reutilizarse. Una selección pendiente incompatible puede reemplazarse sin duplicar una suscripción pagada.
import { Commet } from "@commet/node";const commet = new Commet({ apiKey: "ck_xxx" });const subscription = await commet.subscriptions.getActive({ customerId: "user_123" });from commet import Commetcommet = Commet("ck_xxx")subscription = commet.subscriptions.get_active(customer_id="user_123")client, err := commet.New("ck_xxx")if err != nil { log.Fatal(err)}ctx := context.Background()subscription, err := client.Subscriptions.GetActive(ctx, &commet.GetActiveSubscriptionParams{ CustomerID: "user_123",})if err != nil { log.Fatal(err)}import co.commet.Commet;import co.commet.params.GetActiveSubscriptionParams;var commet = Commet.builder().apiKey("ck_xxx").build();var subscription = commet.subscriptions().getActive( GetActiveSubscriptionParams.builder("user_123").build());use Commet\Commet;$commet = new Commet('ck_xxx');$subscription = $commet->subscriptions->getActive(customerId: 'user_123');getActive devuelve la relación de suscripción actual del customer o null.
import { Commet } from "@commet/node";const commet = new Commet({ apiKey: "ck_xxx" });const subscription = await commet.subscriptions.get({ id: "sub_xxx" });from commet import Commetcommet = Commet("ck_xxx")subscription = commet.subscriptions.get("sub_xxx")client, err := commet.New("ck_xxx")if err != nil { log.Fatal(err)}ctx := context.Background()subscription, err := client.Subscriptions.Get(ctx, "sub_xxx")if err != nil { log.Fatal(err)}import co.commet.Commet;var commet = Commet.builder().apiKey("ck_xxx").build();var subscription = commet.subscriptions().get("sub_xxx");use Commet\Commet;$commet = new Commet('ck_xxx');$subscription = $commet->subscriptions->get(id: 'sub_xxx');Usá get con el ID público para obtener cualquier estado persistido, incluidos pending_payment, past_due y canceled.
Una pausa detiene temporalmente el acceso y las renovaciones sin cancelar la suscripción. Podés pausar una suscripción de un plan pago recurrente en estado active o trialing. No aplica a planes gratuitos, pagos únicos ni suscripciones pendientes de pago, past-due o canceladas. Antes de crear una pausa, resolvé cualquier cancelación programada, cambio de plan programado o checkout pendiente de cambio de plan.
| Modo | Acceso y facturación | Qué pasa al reanudar |
|---|---|---|
immediate | El acceso se corta en el momento. Se conserva el tiempo restante del período pago o de prueba. | Recupera el tiempo restante sin un cobro nuevo. La renovación pasa al final de ese tiempo. |
period_end | El acceso continúa hasta el final del período de facturación o de prueba. Se evita la renovación siguiente. | Cobra un período nuevo con el medio de pago guardado. El acceso vuelve cuando se completa el pago. |
Por ejemplo, si pausás inmediatamente cuando quedan 10 días pagos, esos 10 días se conservan. Si reanudás una semana después, todavía quedan 10 días antes de renovar.
Mientras está pausada, la suscripción no genera facturas de renovación. Una pausa al final del período puede generar una factura final por consumo, excedentes o ajustes pendientes de seats/quota del período terminado. No cobra capacidad por adelantado para el período siguiente.
Usá un entero positivo en durationDays para programar un intento de reanudación automática, o null para una pausa indefinida que requiere reanudación manual. La duración cuenta desde que la pausa se hace efectiva, no desde que se programa una pausa futura.
En Dashboard, abrí el detalle de la suscripción y elegí Pause. Seleccioná el modo y la duración y confirmá. El cliente puede editar una pausa existente, cancelar una pausa programada y reanudar una suscripción pausada desde el Customer Portal, pero no crear pausas; Commet Admin los muestra en el detalle de la suscripción. Para modificar pausas desde Dashboard necesitás permiso para editar suscripciones.
La pausa muestra su fecha de inicio y de reanudación. Sus acciones permiten editar la duración, revocar una pausa programada o reanudar una pausa efectiva.
En el Dashboard y el Customer Portal, elegí una duración sugerida o ingresá un número de días, semanas o meses calendario. El diálogo muestra cuándo empieza la pausa y cuándo se intentará reanudar. Dejá la duración vacía para una pausa indefinida. Al editar se reconstruye una duración equivalente desde las fechas guardadas, contando desde el inicio original de la pausa. Las suscripciones semanales priorizan semanas completas; las demás, meses calendario completos y luego semanas o días. Si el mes de destino es más corto, se usa su último día.
Este pedido programa una pausa de siete días al final del período:
curl -X POST https://commet.co/api/v1/subscriptions/sub_xxx/pause \
-H "x-api-key: $COMMET_API_KEY" \
-H "commet-version: 2026-08-27" \
-H "Content-Type: application/json" \
-d '{"mode":"period_end","durationDays":7}'Usá "mode":"immediate" para pausar ahora, o "durationDays":null para dejar abierta la fecha de reanudación.
La creación devuelve la suscripción actualizada. Una pausa futura tiene pause.status: "scheduled" y la suscripción sigue active o trialing. Cuando se hace efectiva, la suscripción pasa a paused y pause.status vale "active". El objeto pause incluye mode, effectiveAt y resumeAt; vale null cuando no hay una pausa actual ni programada.
Cambiá la duración de una pausa programada o efectiva:
curl -X PATCH https://commet.co/api/v1/subscriptions/sub_xxx/pause \
-H "x-api-key: $COMMET_API_KEY" \
-H "commet-version: 2026-08-27" \
-H "Content-Type: application/json" \
-d '{"durationDays":14}'Esto fija una duración total de 14 días desde la fecha de inicio original; no suma 14 días desde hoy. Enviá null para hacerla indefinida. Esta operación no cambia el modo de pausa.
Revocá una pausa antes de que se haga efectiva:
curl -X DELETE https://commet.co/api/v1/subscriptions/sub_xxx/pause \
-H "x-api-key: $COMMET_API_KEY" \
-H "commet-version: 2026-08-27"La suscripción conserva su período y acceso actuales. Si la pausa ya está efectiva, usá la reanudación.
Usá resume para una suscripción pausada; reactivate es otra operación para suscripciones canceladas o past-due.
curl -X POST https://commet.co/api/v1/subscriptions/sub_xxx/resume \
-H "x-api-key: $COMMET_API_KEY" \
-H "commet-version: 2026-08-27"La respuesta incluye subscriptionId, invoiceId y status. Al reanudar una pausa inmediata no hay una factura nueva, por lo que invoiceId vale null.
| Respuesta | Significado |
|---|---|
200, status: "succeeded" | La reanudación terminó y el acceso se restauró. |
200, status: "processing" | El pago o su confirmación todavía están pendientes. No restaures acceso sólo por recibir esta respuesta. |
402, charge_failed | El pago fue rechazado. La suscripción sigue pausada. |
422, no_payment_method | Para reanudar una pausa de fin de período hace falta un medio de pago guardado. |
500, internal_error | Una falla interna impidió completar la operación; es distinta de un rechazo del pago. |
Un pago de reanudación rechazado deja la factura pendiente. Los reintentos automáticos ocurren en los días 1, 3, 5 y 7 desde el rechazo original y reutilizan esa factura. Durante los reintentos, la suscripción sigue pausada. Si todos fallan, se cancela y la factura de reanudación pasa a incobrable. Los intentos manuales de reanudación no consumen intentos automáticos.
La reanudación de una pausa de fin de período usa el precio base vigente al crear la factura nueva. Si esa factura queda pendiente, sus reintentos conservan el monto y los créditos o balance incluidos aunque el catálogo vuelva a cambiar. Las Introductory Offers y los descuentos aceptados conservan los términos que todavía no se consumieron; reanudar no otorga una Introductory Offer nueva ni vuelve a canjear un promo code.
Consultá las referencias de Pause y Resume para ver los esquemas completos.
Usá Feature Access para autorizar pedidos según el estado actual de la suscripción. Suscribite a estos webhooks para procesar actualizaciones asincrónicas en tu aplicación:
subscription.pause_scheduled: se programó una pausa futura; el acceso todavía continúa.subscription.pause_updated: cambió la duración de la pausa.subscription.pause_revoked: se quitó la pausa programada.subscription.paused: la pausa se hizo efectiva y se cortó el acceso de la suscripción.subscription.resumed: terminó la reanudación y volvió el acceso.subscription.resume_failed: falló el pago de reanudación y la suscripción sigue pausada.import { Commet } from "@commet/node";const commet = new Commet({ apiKey: "ck_xxx" });const subscription = await commet.subscriptions.cancel({ id: "sub_xxx" });from commet import Commetcommet = Commet("ck_xxx")subscription = commet.subscriptions.cancel("sub_xxx")client, err := commet.New("ck_xxx")if err != nil { log.Fatal(err)}ctx := context.Background()subscription, err := client.Subscriptions.Cancel(ctx, "sub_xxx", nil)if err != nil { log.Fatal(err)}import co.commet.Commet;import co.commet.params.CancelSubscriptionParams;var commet = Commet.builder().apiKey("ck_xxx").build();var subscription = commet.subscriptions().cancel( "sub_xxx", CancelSubscriptionParams.builder().build());use Commet\Commet;$commet = new Commet('ck_xxx');$subscription = $commet->subscriptions->cancel(id: 'sub_xxx');Una suscripción paga y activa programa la cancelación al final del período salvo que envíes immediate: true. Las relaciones gratuitas, pendientes y past-due se cancelan inmediatamente. La cancelación no borra el balance almacenado.
Cancelar una suscripción pausada es inmediato y descarta el tiempo conservado. El consumo, los excedentes o los ajustes de seats pendientes todavía pueden generar una factura final. Para cancelar cuando hay una pausa futura programada, revocá esa pausa primero.
import { Commet } from "@commet/node";const commet = new Commet({ apiKey: "ck_xxx" });const subscription = await commet.subscriptions.uncancel({ id: "sub_xxx" });from commet import Commetcommet = Commet("ck_xxx")subscription = commet.subscriptions.uncancel("sub_xxx")client, err := commet.New("ck_xxx")if err != nil { log.Fatal(err)}ctx := context.Background()subscription, err := client.Subscriptions.Uncancel(ctx, "sub_xxx", nil)if err != nil { log.Fatal(err)}import co.commet.Commet;import co.commet.params.UncancelSubscriptionParams;var commet = Commet.builder().apiKey("ck_xxx").build();var subscription = commet.subscriptions().uncancel( "sub_xxx", UncancelSubscriptionParams.builder().build());use Commet\Commet;$commet = new Commet('ck_xxx');$subscription = $commet->subscriptions->uncancel(id: 'sub_xxx');uncancel funciona solamente antes de que una cancelación al final del período se haga efectiva. Conserva la misma suscripción y período actual.
Reactivate reintenta el cobro de renovación pendiente y conserva la relación original:
import { Commet } from "@commet/node";const commet = new Commet({ apiKey: "ck_xxx" });const reactivatedSubscription = await commet.subscriptions.reactivate({ id: "sub_xxx" });from commet import Commetcommet = Commet("ck_xxx")reactivated_subscription = commet.subscriptions.reactivate("sub_xxx")client, err := commet.New("ck_xxx")if err != nil { log.Fatal(err)}ctx := context.Background()reactivatedSubscription, err := client.Subscriptions.Reactivate(ctx, "sub_xxx", nil)if err != nil { log.Fatal(err)}import co.commet.Commet;import co.commet.params.ReactivateSubscriptionParams;var commet = Commet.builder().apiKey("ck_xxx").build();var reactivatedSubscription = commet.subscriptions().reactivate( "sub_xxx", ReactivateSubscriptionParams.builder().build());use Commet\Commet;$commet = new Commet('ck_xxx');$reactivatedSubscription = $commet->subscriptions->reactivate(id: 'sub_xxx');Si el customer debe actualizar su medio de pago, creá un link de recuperación:
import { Commet } from "@commet/node";const commet = new Commet({ apiKey: "ck_xxx" });const recoveryLink = await commet.subscriptions.createRecoveryLink({ id: "sub_xxx" });from commet import Commetcommet = Commet("ck_xxx")recovery_link = commet.subscriptions.create_recovery_link("sub_xxx")client, err := commet.New("ck_xxx")if err != nil { log.Fatal(err)}ctx := context.Background()recoveryLink, err := client.Subscriptions.CreateRecoveryLink(ctx, "sub_xxx", nil)if err != nil { log.Fatal(err)}import co.commet.Commet;import co.commet.params.CreateSubscriptionRecoveryLinkParams;var commet = Commet.builder().apiKey("ck_xxx").build();var recoveryLink = commet.subscriptions().createRecoveryLink( "sub_xxx", CreateSubscriptionRecoveryLinkParams.builder().build());use Commet\Commet;$commet = new Commet('ck_xxx');$recoveryLink = $commet->subscriptions->createRecoveryLink(id: 'sub_xxx');Los reintentos automáticos de dunning se anclan al rechazo original en los días 1, 3, 5 y 7. Un cobro exitoso devuelve la suscripción a active.
La misma operación reactivate cobra el medio de pago guardado, reutiliza el registro de suscripción y comienza un período nuevo anclado a la fecha de reactivación. Podés enviar un offerId; las fases aceptadas se persisten como una Offer Application inmutable.
El precio seleccionado no se guarda como snapshot. Las renovaciones futuras usan su valor actual de catálogo. Archivar ese precio impide nuevas selecciones, pero no rompe la suscripción existente.
¿Cómo está esta guía?