> ## Documentation Index
> Fetch the complete documentation index at: https://commet.co/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Versiones de plan

> Edita un plan sin cambiar lo que pagan tus suscriptores: publica una versión nueva o un experimento y muévelos cuando lo decidas.

Cada suscripción está fijada a una versión de su plan. Una versión guarda los términos completos: precios, trials, features, reglas de créditos y balance, add-ons, packs de créditos y precios por país. El plan apunta a su versión actual, que es la que recibe cada comprador nuevo.

Editar un plan publica una versión nueva y no mueve a nadie. Los suscriptores existentes conservan los precios, las features y las reglas de su versión, también al renovar, hasta que los muevas.

## Qué guarda una versión

| Con versión | Sin versión |
| - | - |
| Precios por intervalo de cobro, días de trial y el intervalo que se muestra primero | Nombre y descripción |
| La Introductory Offer de cada precio | Visibilidad |
| Features, cantidades incluidas, precios de overage y límites | Precios de [Market](https://commet.co/docs/es/regional-prices.md#crear-un-market) |
| Reglas de créditos y balance: carry-over, límites de gasto, compra de créditos y recargas | |
| Los add-ons y packs de créditos que vende el plan, con sus precios | |
| Países con su moneda y sus precios | |

**Edit details** cambia el nombre, la descripción y la visibilidad al instante, para todos. Los precios de Market aplican a todas las versiones: un cambio en un precio de Market llega a los suscriptores que lo pagan en su próxima renovación.

Las versiones del plan se numeran 1, 2, 3. Las versiones propias de un experimento llevan su código, como `price-test 2`.

## Editar en el dashboard

Abre un plan desde **Plans**. El menú de versiones abre la versión actual, los borradores, los experimentos y las versiones anteriores. La página del plan tiene seis pestañas:

| Pestaña | Qué muestra |
| - | - |
| **Plan** | Los precios, las features, las reglas, los add-ons y los packs de créditos de la versión que abriste |
| **Regional prices** | Los países de la versión, con su moneda y sus precios |
| **Subscribers** | Los suscriptores del plan con su versión y el movimiento pendiente, con su fecha, además de **Needs a change** |
| **Versions** | Las versiones publicadas con lo que cambió en cada una, y los borradores del plan |
| **Experiments** | Cada experimento con su estado, la versión que vende y sus suscriptores |
| **Moves** | Cada movimiento con cuántos suscriptores se movieron, siguen en curso, necesitan un cambio o quedaron fuera. Un movimiento que todavía no terminó se puede cancelar desde aquí |

1. Edita cualquier versión. El primer cambio inicia un borrador a partir de ella. El borrador se guarda mientras editas y nadie lo ve hasta que lo publicas. Un precio, feature, add-on o pack de créditos quitado queda en su lugar, tachado, con **Undo**. Desactivar una feature aparece en los cambios como **Disabled**, y quitarla aparece como eliminada.
2. El encabezado del plan muestra cuántos cambios tiene el borrador. Haz clic ahí para revisar **Changes in this draft** y deshacer cualquiera de ellos, o elige **Discard draft**.
3. Elige **Review and publish** en el encabezado y publícalo como:
   * **The current version**, la que reciben los compradores nuevos.
   * **A new experiment**, que se vende solo con su propio código. Solo para borradores iniciados desde la versión actual.
   * **Next version of an experiment**, para borradores iniciados desde la última versión de un experimento.
4. Elige qué pasa con los suscriptores de versiones anteriores: **Keep them on their version**, **Move them at their next renewal** o **Move them now**. Cuando algunos no encajan en la versión nueva, el diálogo lista a cada uno con lo que lo haría encajar.

Un borrador publica exactamente su contenido. Un borrador iniciado desde una versión anterior deshace lo que cambiaron las versiones posteriores, y la revisión lista esos cambios.

La publicación se detiene mientras a un país le falta un precio, o cuando la versión actual perdería el trial sin método de pago del [trial de registro](https://commet.co/docs/es/plan-groups.md#plan-predeterminado-y-trial-de-registro) del grupo de planes.

Para mover suscriptores más tarde, abre **Subscribers**, selecciónalos y elige **Move to another version**.

## Editar con la API

Cada edición de un plan hecha con la API, MCP o el CLI publica al instante una versión actual nueva y no mueve a nadie. Eso incluye agregar, cambiar o quitar precios y features, el pricing regional y las reglas de créditos y balance de `PATCH /plans/{id}`. Los compradores nuevos reciben la versión nueva; los suscriptores existentes siguen en la suya hasta que los [muevas](#mover-suscriptores).

Para preparar varios cambios y publicarlos juntos, inicia un borrador:

```bash theme={null}
curl -X POST https://commet.co/api/v1/plans/pln_xxx/drafts \
  -H "x-api-key: $COMMET_API_KEY" \
  -H "commet-version: 2026-08-27" \
  -H "Content-Type: application/json" \
  -d '{}'
```

El borrador parte de la versión actual, salvo que envíes `fromVersionId`. Cámbialo con `PATCH /plans/{id}/drafts/{draftId}` y los bloques `prices`, `countries`, `rules` y `undo`. Cada bloque que envías reemplaza ese bloque, así que `prices` lista todos los intervalos que vende el borrador:

```bash theme={null}
curl -X PATCH https://commet.co/api/v1/plans/pln_xxx/drafts/plr_draft \
  -H "x-api-key: $COMMET_API_KEY" \
  -H "commet-version: 2026-08-27" \
  -H "Content-Type: application/json" \
  -d '{"prices":[{"billingInterval":"monthly","price":5900,"isDefault":true},{"billingInterval":"yearly","price":59000}]}'
```

Publícalo primero con `"preview": true` para revisar todo sin publicar:

```bash theme={null}
curl -X POST https://commet.co/api/v1/plans/pln_xxx/drafts/plr_draft/publish \
  -H "x-api-key: $COMMET_API_KEY" \
  -H "commet-version: 2026-08-27" \
  -H "Content-Type: application/json" \
  -d '{"publishAs":"current","move":"period_end","preview":true}'
```

| Campo | Valores |
| - | - |
| `publishAs` | `current`, `experiment` con `experimentCode`, o `experiment_version` |
| `move` | `keep` (por defecto), `period_end` o `now`, para los suscriptores de versiones anteriores. Un experimento no acepta `move` |
| `changes` | Cambios por suscriptor que hacen encajar a cada uno. Ver [Resolver conflictos](#resolver-conflictos) |

Las features y los add-ons y packs de créditos que vende un plan no forman parte de un borrador de la API: sus propios endpoints publican una versión nueva al instante. Las Introductory Offers se configuran en un borrador del dashboard.

`POST /plans/{id}/versions` publica una versión actual nueva sin borrador. Solo cambia términos de dinero: precios, créditos o balance incluidos, montos por moneda y el tope de carry-over.

## Mover suscriptores

Solo tú mueves suscriptores, y un movimiento cambia la versión de una suscripción, nunca su plan. Mueve una suscripción con `change-version`:

```bash theme={null}
curl -X POST https://commet.co/api/v1/subscriptions/sub_xxx/change-version \
  -H "x-api-key: $COMMET_API_KEY" \
  -H "commet-version: 2026-08-27" \
  -H "Content-Type: application/json" \
  -d '{"planVersionId":"plr_new","effective":"period_end"}'
```

Repetir el mismo pedido no cambia nada, y uno nuevo reemplaza el movimiento pendiente. Mueve muchas a la vez con `POST /plans/{id}/moves`, enviando `subscriptionIds` (hasta 10.000) o `fromVersionId` para mover todas las suscripciones de esa versión:

```bash theme={null}
curl -X POST https://commet.co/api/v1/plans/pln_xxx/moves \
  -H "x-api-key: $COMMET_API_KEY" \
  -H "commet-version: 2026-08-27" \
  -H "Content-Type: application/json" \
  -d '{"fromVersionId":"plr_old","toVersionId":"plr_new","effective":"period_end","preview":true}'
```

| `effective` | Qué cambia |
| - | - |
| `now` | Las features, los límites y los créditos o el balance incluidos cambian hoy, sin reiniciar el uso. El precio nuevo se cobra desde la próxima renovación |
| `period_end` | Todo cambia en la próxima renovación. Hasta entonces nada del período actual cambia: el balance, las verificaciones de uso, las features y el acceso siguen igual |

Un movimiento nunca prorratea ni reembolsa. Con `now`, una cantidad incluida mayor primero paga la deuda de créditos o balance del plan, una menor nunca crea deuda nueva, y los créditos y el balance comprados no cambian.

### Qué conserva un movimiento

* **Moneda, país, intervalo y precio.** Un movimiento conserva la moneda de una suscripción, salvo que pidas cobrarle en USD. Una versión que no vende su moneda devuelve `422 missing_regional_price`, y una que no vende el precio que paga devuelve `404 price_not_found`.
* **Cobrar en USD.** Cuando la versión no vende la moneda que un suscriptor paga en su país, o el precio en USD de su país, enviá `currency: "usd"` con el movimiento: desde su próxima renovación paga el precio en USD de la versión para su país, o el precio base en USD. La moneda cambia solo en una renovación, también en un movimiento hecho ahora, y el uso del período que cierra se cobra a los precios base en USD de la versión que deja. No se convierte nada: cuando algo mantiene a la suscripción en su moneda, el movimiento se rechaza con un código que lo nombra: `currency_held_by_payment_method` (paga por dLocal), `currency_held_by_customer_credit`, `currency_held_by_balance_plan`, `currency_held_by_fixed_amount_discount`, `currency_held_by_prepaid_period` o `currency_held_by_scheduled_pause`. Se vuelve a revisar en la renovación; si ya no entra, el movimiento se cancela con ese código como `reason` de `subscription.version_change_canceled`.
* **Precios de Market.** Una suscripción que paga un precio de Market lo sigue pagando.
* **Gratis o pago.** Una versión free solo se mueve a una versión free, y una paga solo a una paga (`400 validation_error`).

### Quién puede moverse

* Las suscripciones solo se mueven a una versión más nueva (`422 version_not_newer`). Una que está en un experimento en curso solo se mueve a una versión posterior de ese experimento.
* Solo se mueven las suscripciones `active`, `trialing` y `past_due`; `change-version` rechaza a las demás con `409 invalid_subscription_status`. Un movimiento de plan deja fuera a las demás, como las pausadas, y a las de la lista que ya están en la versión destino; siguen en su versión. Una cancelación, pausa, downgrade o cambio de intervalo programado no deja fuera a una suscripción.
* Una suscripción de pago único nunca renueva, así que solo se mueve ahora. `change-version` con `period_end` devuelve `409 invalid_subscription_status`, y un movimiento de plan en la renovación la deja fuera.
* Un add-on activo que la versión no vende (`409 addon_unavailable`), o más licencias de las que permite la versión (`400 seat_limit_exceeded`), impiden mover la suscripción hasta que lo resuelvas.

### Resolver conflictos

Un movimiento de plan, una publicación con `move` y el archivo de un experimento revisan primero a cada suscriptor. Si alguno no encaja, nadie se mueve y la respuesta es `409 subscribers_do_not_fit`, con cada uno y sus motivos. Envía un cambio para cada uno en `changes`:

| Cambio | Efecto en la renovación del suscriptor |
| - | - |
| `billingInterval` | Lo pasa a otro intervalo que vende la versión |
| `seatLimit: true` | Baja sus licencias al límite de la versión |
| `removeAddonIds` | Deja de cobrar los add-ons indicados |
| `currency: "usd"` | Le cobra en USD cuando la versión no vende su moneda, o el precio en USD de su país |
| `keepOnVersion: true` | Lo deja en su versión |

```json theme={null}
{
  "fromVersionId": "plr_old",
  "toVersionId": "plr_new",
  "effective": "now",
  "changes": [{ "subscriptionId": "sub_xxx", "removeAddonIds": ["adn_xxx"] }]
}
```

Un suscriptor con un cambio siempre se mueve en su renovación, incluso en un movimiento hecho ahora.

### Cuándo se aplica un movimiento en la renovación

Un movimiento en la renovación espera la próxima renovación de la suscripción, la fecha que muestra `scheduledVersionChange.effectiveAt`. La renovación factura el período nuevo en la versión nueva y envía un `subscription.version_changed`.

| Suscripción | Cuándo se mueve |
| - | - |
| `active` | Al final de su período actual |
| `trialing` | Cuando termina el trial. Su primer cobro ya es en la versión nueva |
| `past_due` | Conserva su versión mientras Commet cobra la renovación vencida. Una vez pagada, se mueve al final del período que pagó; mientras tanto `effectiveAt` muestra esa fecha |
| Pausada y reanudada, o con cambio de intervalo | En su próxima renovación después de eso, con esa fecha |

Una suscripción que termina en lugar de renovar termina en su versión, ya sea por una cancelación al final de su período o de su trial, por dunning agotado, por la suspensión de la organización o por una cancelación inmediata. No envía ningún webhook de versión, `scheduledVersionChange` pasa a `null` y su movimiento de plan deja de esperarla. Un cambio a otro plan, ahora o en esa renovación, como un downgrade programado o el plan predeterminado del grupo, queda en la versión actual del otro plan, también sin webhook de versión.

Mientras hay una cancelación o un downgrade programado, la API y la pestaña Subscribers siguen mostrando el movimiento con su fecha. Si se revoca la cancelación o el downgrade, la suscripción se mueve en su renovación.

### Seguir y cancelar movimientos

* `GET /plans/{id}/moves` lista los movimientos del plan, y `GET /plans/{id}/moves/{moveId}` informa cada suscriptor como `moving`, `moved`, `needs_a_change`, `left_out`, `canceled` o `kept_on_version`.
* Un cambio de una suscripción con `change-version` se registra como un movimiento de ese único suscriptor. Aparece en `GET /plans/{id}/moves` y en la pestaña **Moves** como cualquier otro movimiento.
* `POST /plans/{id}/moves/{moveId}/cancel` cancela el movimiento para todos los que todavía no se movieron. `POST /plans/{id}/moves/{moveId}/subscriptions/{subscriptionId}/cancel` lo cancela para uno.
* `DELETE /subscriptions/{id}/scheduled-version-change` revoca el movimiento pendiente de una suscripción.

Cancelar o revocar un movimiento pendiente envía `subscription.version_change_canceled` con `reason: "canceled_by_merchant"` por cada suscriptor que cancela, y los registra como `canceled`.

Un movimiento programado para la renovación se revisa de nuevo en la renovación. Si la suscripción ya no encaja, renueva en su versión y aparece en `GET /plans/{id}/needs-a-change` y en **Needs a change** de la pestaña Subscribers. Cada entrada lleva el `moveId` del movimiento que no pudo completar. Muévela de nuevo con un cambio, o déjala en su versión con `POST /plans/{id}/needs-a-change/{subscriptionId}/keep`.

## Hacer un experimento

Un experimento vende una versión solo a los compradores que envías a él; el resto sigue comprando la versión actual. Publica un borrador iniciado desde la versión actual como **A new experiment**, o crea uno con `POST /plans/{id}/experiments`. Su código usa letras minúsculas, números, guiones y guiones bajos, y nunca se reutiliza en el plan.

Véndelo enviando el código del experimento después del código del plan:

```bash theme={null}
curl -X POST https://commet.co/api/v1/subscriptions \
  -H "x-api-key: $COMMET_API_KEY" \
  -H "commet-version: 2026-08-27" \
  -H "Content-Type: application/json" \
  -d '{"customerId":"user_123","planCode":"pro:price-test"}'
```

Un código de experimento desconocido devuelve `404 plan_experiment_not_found`.

| Acción | Endpoint | Resultado |
| - | - | - |
| Publicar su próxima versión | `POST /plans/{id}/experiments/{code}/versions` | Su código vende la versión nueva; los suscriptores anteriores del experimento siguen en la suya |
| Hacerlo actual | `POST /plans/{id}/experiments/{code}/make-current` | Su última versión pasa a ser la versión actual del plan con el número siguiente. Sus suscriptores ya están en ella, y desde entonces su código vende la versión actual |
| Archivarlo | `POST /plans/{id}/experiments/{code}/archive` | Su código vende la versión actual, así que los links ya compartidos siguen funcionando. `subscribers` elige `keep`, `period_end` o `now` para sus suscriptores |

Hacer actual un experimento con la API no mueve a nadie más. El dashboard además pregunta qué pasa con los suscriptores de versiones anteriores.

## Vender una versión específica

Envía `planVersionId` en `POST /subscriptions` para crear la suscripción en cualquier versión publicada, actual o no, incluidas las versiones de un experimento. El checkout cobra el precio de esa versión, y la activación otorga sus créditos, add-ons y packs de créditos. Enviar `planVersionId` junto con un código de experimento devuelve `400`.

## Checkouts sin pagar

Un checkout que todavía no se pagó no es un suscriptor, así que sigue la última versión de lo que se pidió:

| Pedido con | El checkout cobra |
| - | - |
| El código del plan, como `pro` | La versión actual del plan |
| Un código de experimento, como `pro:price-test` | La última versión del experimento, nunca la versión actual del plan |
| `planVersionId` | Esa versión |

Su link cobra esa versión sin un pedido nuevo. Repetir el mismo `POST /subscriptions` después de editar el plan reutiliza el checkout: la respuesta es `200` con el mismo ID de suscripción y el mismo `checkoutUrl`.

Un pedido distinto lo reemplaza: otro plan, experimento, versión, intervalo o precio, el código del plan después de un código de experimento, o `planVersionId` en lugar de un código o al revés. La suscripción anterior se cancela, su recibo se anula y su link deja de funcionar.

## Reactivar una suscripción cancelada

Reactivar una suscripción cancelada la devuelve en la última versión de lo que se compró:

* la versión actual del plan, cuando se compró con el código del plan;
* la última versión del experimento, cuando se compró con un código de experimento, o la versión actual del plan cuando el experimento ya no está en curso;
* la misma versión, cuando se compró con `planVersionId`.

Los add-ons que esa versión no vende se desactivan. Una versión que no vende la moneda de la suscripción devuelve `422 missing_regional_price`. Reactivar una suscripción `past_due` conserva su versión.

## Add-ons, packs de créditos y países

Cada versión lista los add-ons y packs de créditos que vende, con sus precios. Crear o editar un add-on o un pack de créditos publica una versión nueva de cada plan que lo vende. Un suscriptor solo compra lo que vende su versión: un add-on o pack agregado en una versión más nueva devuelve `409 addon_unavailable` o `409 credit_pack_unavailable` hasta que muevas al suscriptor. Ver [Add-ons](https://commet.co/docs/es/add-ons.md#addons-y-versiones-de-plan) y [Packs de créditos](https://commet.co/docs/es/credit-packs.md#packs-de-créditos-y-versiones-de-plan).

Cada versión también define países con su propia moneda y sus precios. Ver [Configurar precios por país](https://commet.co/docs/es/regional-prices.md#configurar-precios-por-país).

## Leer versiones

| Pedido | Devuelve |
| - | - |
| `GET /plans/{id}/versions` | Las versiones publicadas del plan, de la más nueva a la más vieja, con sus precios y cantidad de suscripciones |
| `GET /plans/{id}/versions/{versionId}` | Una versión |
| `GET /plans/{id}/versions/{versionId}/changes?against={otherVersionId}` | Cada término que difiere entre dos versiones. Una feature desactivada figura como `Disabled`; un término quitado tiene `after: null` |

Las versiones publicadas antes de que Commet registrara todos sus términos no se listan, y leer una por ID devuelve `404 plan_version_not_found`.

Cada suscripción incluye `planVersion`, con su `id` y `label`, y `scheduledVersionChange`, con el `planVersionId`, el `label` y el `effectiveAt` del movimiento pendiente para su próxima renovación, o `null`. Ver [Cuándo se aplica un movimiento en la renovación](#cuándo-se-aplica-un-movimiento-en-la-renovación). Filtra `GET /subscriptions` por versión con `planVersionId`.

## Webhooks

| Evento | Cuándo se envía |
| - | - |
| [`subscription.version_changed`](https://commet.co/docs/es/webhooks/subscription-version-changed) | Una suscripción cambió de versión: un movimiento hecho ahora o un movimiento programado en la renovación. Hacer actual un experimento no mueve a nadie, así que no lo envía |
| [`subscription.version_change_canceled`](https://commet.co/docs/es/webhooks/subscription-version-change-canceled) | Un movimiento pendiente no va a ocurrir. `reason` es `canceled_by_merchant` cuando lo cancelaste o revocaste, `version_change_failed`, o el código de lo que la suscripción ya no cumple |

No se envía ninguno de los dos cuando la suscripción termina o pasa a otro plan antes de que se aplique el movimiento, ni cuando un movimiento nuevo reemplaza al pendiente.

Ambos llegan solo a los endpoints de webhook que los listan. Agrégalos a los eventos de tu endpoint para recibirlos.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.