# Suscripciones

Lista, consulta y cancela las suscripciones de tus links recurrentes, y obtén la página donde el cliente gestiona la suya.

> [!WARNING]
> El SDK `vexor` de npm (Stripe, MercadoPago, PayPal, Square, Talo) está **deprecado**: ya no se mantiene y no debe usarse. vexorpay es hoy una **API REST de links de pago en USD, sin SDK oficial**. Migración: <https://developers.vexorpay.com/docs/migracion-desde-el-sdk>

Fuente: <https://developers.staging.vexorpay.com/docs/api/subscriptions>

Las suscripciones se crean cuando un comprador paga uno de los planes de tu [link recurrente](/docs/api/create-recurring-payment-link). Cada ciclo se cobra solo, en USD, y cada cobro llega como una [venta](/docs/api/orders) nueva (`billingReason: "subscription_cycle"`) con su webhook `payment.completed`.

## El objeto Subscription

```json
{
  "id": "66f1c1e2c8a4b0d1f2e3a4b7",
  "paymentLinkId": "66f1c1e2c8a4b0d1f2e3a4b6",
  "priceId": "66f1c1e2c8a4b0d1f2e3a4c1",
  "status": "active",
  "amountCents": 900,
  "interval": "month",
  "intervalCount": 1,
  "currentPeriodStart": "2026-01-02T12:00:00.000Z",
  "currentPeriodEnd": "2026-02-02T12:00:00.000Z",
  "cancelAtPeriodEnd": false,
  "canceledAt": null,
  "customerEmail": "cliente@ejemplo.com",
  "manageUrl": "https://…",
  "sandbox": false,
  "createdAt": "2026-01-02T12:00:00.000Z"
}
```

| Campo | Qué es |
| --- | --- |
| `paymentLinkId` / `priceId` | El link y el plan (`prices[].id`) al que se suscribió el comprador. |
| `status` | `trialing` (en prueba gratis), `active`, `past_due` (falló el último cobro), `canceled` o `expired`. Trata cualquier otro valor como no activo. |
| `amountCents` / `interval` / `intervalCount` | El precio por ciclo en centavos de USD y la frecuencia. |
| `currentPeriodStart` / `currentPeriodEnd` | El ciclo en curso. En una prueba gratis, `currentPeriodEnd` es el fin de la prueba (el primer cobro). |
| `cancelAtPeriodEnd` | `true` si la suscripción se cancela al terminar el ciclo en curso (sigue activa hasta entonces). |
| `canceledAt` | Cuándo se pidió la cancelación. |
| `manageUrl` | Portal del comprador de vexorpay, donde el cliente gestiona su suscripción (tarjeta, cancelación, recibos) entrando con su email y un código. `null` si no está disponible. |

Una suscripción es siempre de **una unidad** (no hay precio por asiento).

## Listar suscripciones

`GET /api/v1/subscriptions`

| Query param | Descripción |
| --- | --- |
| `status` | Filtra por estado (`trialing`, `active`, `past_due`, `canceled` o `expired`). |
| `payment_link_id` | Filtra por link. |
| `limit` | Tamaño de página (default 10, máx 100). |
| `starting_after` / `ending_before` | Paginación por cursor (id de suscripción). |

```bash
curl "https://api.vexorpay.com/api/v1/subscriptions?status=active" \
  -H "Authorization: Bearer vxp_live_tu_clave"
```

La respuesta usa el formato de lista con `data`, `has_more` y `total_count`.

## Ver una suscripción

`GET /api/v1/subscriptions/{id}`

El entorno lo define la API key: con una clave `vxp_test_...` operas sobre suscripciones de prueba.

```bash
curl "https://api.vexorpay.com/api/v1/subscriptions/66f1c1e2c8a4b0d1f2e3a4b7" \
  -H "Authorization: Bearer vxp_live_tu_clave"
```

## Cancelar una suscripción

`POST /api/v1/subscriptions/{id}/cancel`

Programa la cancelación **al final del período** (`cancelAtPeriodEnd: true`): el cliente conserva el acceso hasta que termine el ciclo pago y no se le vuelve a cobrar. Es idempotente: cancelar una suscripción ya cancelada responde `200` con su estado actual. Se dispara el webhook `subscription.canceled` al programarse la baja y `subscription.updated` cuando el ciclo termina y la suscripción pasa a `canceled`.

El cuerpo es `{}`. El entorno lo define la API key, no el body.

```bash
curl https://api.vexorpay.com/api/v1/subscriptions/66f1c1e2c8a4b0d1f2e3a4b7/cancel \
  -X POST \
  -H "Authorization: Bearer vxp_live_tu_clave" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Página de gestión del cliente

`POST /api/v1/subscriptions/{id}/portal`

Devuelve `{ "url": "https://…" }`: un acceso directo (sin código) al portal del comprador de vexorpay, **limitado a esta suscripción** y válido por **24 horas**. Ahí el suscriptor cambia su tarjeta, cancela al final del período (o deshace la cancelación) y descarga sus recibos. Redirige al comprador a esa URL.

```bash
curl https://api.vexorpay.com/api/v1/subscriptions/66f1c1e2c8a4b0d1f2e3a4b7/portal \
  -X POST \
  -H "Authorization: Bearer vxp_live_tu_clave" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Errores

| Error | HTTP | Causa |
| --- | --- | --- |
| `unauthorized` | 401 | Falta el header `Authorization`. |
| `invalid_key` | 401 | La API key es inválida o fue revocada. |
| `validation_error` | 400 | `status` inválido en el listado o cursor inexistente. |
| `subscription_not_found` | 404 | No existe esa suscripción, o es de otro modo (prueba/producción). |
| `upstream_error` | 502 | El procesador de pagos rechazó o no respondió la cancelación o la página de gestión. Reintenta. |
| `unexpected_error` | 500 | Error interno inesperado. |
| `rate_limited` | 429 | Superaste el límite de 100 requests por minuto. |
