Skip to content

✨ Cancelar Suscripción

Este endpoint permite a un usuario autenticado cancelar su suscripción activa de forma diferida: no la elimina de inmediato, sino que la marca para que se cancele automáticamente al finalizar el período de facturación actual.

POST

/api/user-endpoints/cancel-subscription Auth JWT Requiere token en header Authorization


  1. Autenticación — Verifica que el usuario tenga un JWT válido.

  2. Validación del body — Comprueba que origin, vertical y subscriptionID estén presentes y sean válidos.

  3. Selección de Stripe — Usa selectStripeCrm(origin) para obtener la instancia de Stripe correcta según el CRM (Inspiria o Alebat).

  4. Búsqueda del customer — Localiza al cliente en Stripe por su email.

  5. Verificación de suscripción — Confirma que el usuario tiene una suscripción activa en Strapi y en Stripe para esa vertical.

  6. Cancelación diferida — Llama a stripe.subscriptions.update() con cancel_at_period_end: true para programar la cancelación al final del ciclo.

  7. Actualización en Strapi — Guarda cancelAtPeriodEnd: true y cancelAt (fecha de expiración) en la base de datos.

  8. Respuesta — Retorna success: true junto con activeUntil indicando hasta cuándo tiene acceso el usuario.


Archivo: src/api/user-endpoints/controllers/check-subscription.ts

async cancelSubscription(ctx) {
const user = ctx.state.user;
if (!user) return ctx.unauthorized(ERROR_UNAUTHORIZED);
validateKeys(ctx.request.body, CANCEL_SUBSCRIPTION_KEYS, FIELD_ROOT);
validateRequiredFields(ctx.request.body, CANCEL_SUBSCRIPTION_KEYS);
const { origin, vertical, subscriptionID } = ctx.request.body;
const stripe = await selectStripeCrm(origin);
const customer = await searchCustomer(stripe, user.email);
const isUserSubscribed = await strapi
.service(USER_SERVICE)
.isUserSubscribed(stripe, customer.data[0].id, user.email, origin, vertical);
if (!isUserSubscribed) { ... }
const cancelledSubscription = await strapi
.service(SUBSCRIPTION_STRIPE_SERVICES)
.cancelSubscription(stripe, user.email, origin, vertical, subscriptionID);
return ctx.send({
success: true,
message: SUBSCRIPTION_CANCELLED_MESSAGE,
activeUntil: cancelledSubscription.activeUntil,
});
}
CampoValor
cancelAtPeriodEndtrue
cancelAtFecha de fin de período (convertida desde timestamp Stripe)
ErrorCuándo ocurre
ERROR_SUBSCRIPTION_NOT_FOUND_FOR_CANCELLATIONNo existe suscripción activa con ese ID y vertical
ERROR_SUBSCRIPTION_ALREADY_CANCELLEDLa suscripción ya estaba marcada para cancelarse

POST /api/user-endpoints/cancel-subscription
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
{
"origin": "Inspiria",
"vertical": "cirugia",
"subscriptionID": 42
}
CampoTipoRequeridoDescripción
originstringCRM de Stripe. Valores: "Inspiria" o "Alebat"
verticalstringVertical del producto (ej: "cirugia", "farma")
subscriptionIDnumberID interno (Strapi) de la suscripción a cancelar
{
"success": true,
"message": "Subscription cancelled successfully. It will remain active until the end of the current billing period.",
"activeUntil": "2026-05-15T00:00:00.000Z"
}

activeUntil indica la fecha hasta la cual el usuario mantiene acceso.

const response = await fetch("/api/user-endpoints/cancel-subscription", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
origin: "Inspiria",
vertical: "cirugia",
subscriptionID: 42,
}),
});
const data = await response.json();
if (data.success) {
console.log(`Suscripción activa hasta: ${data.activeUntil}`);
}

POST /cancel-subscription
¿Autenticado? ──No──▶ 401 Unauthorized
│ Sí
Validar body (origin, vertical, subscriptionID)
selectStripeCrm(origin) → Stripe instance
searchCustomer(stripe, email)
isUserSubscribed() ──No──▶ 400 Sin suscripción
│ Sí
cancelSubscription()
├─ findOne() → suscripción activa
├─ ¿Ya cancelada? ─Sí─▶ Error
├─ stripe.subscriptions.update({ cancel_at_period_end: true })
└─ update Strapi (cancelAtPeriodEnd, cancelAt)
200 { success, activeUntil }

1. Usuario cancela

Se marca cancelAtPeriodEnd = true y cancelAt = "2026-05-15". El usuario sigue con acceso hasta esa fecha.

2. Llega la fecha de corte

Stripe cancela la suscripción automáticamente. El acceso premium se revoca.


ArchivoRol
src/api/user-endpoints/controllers/check-subscription.tsControlador — valida auth, body y orquesta el flujo
src/api/user-endpoints/routes/user-endpoints.tsDefinición de la ruta
src/api/subscription/services/stripe.tsServicio — lógica de Stripe y actualización en Strapi
src/extensions/users-permissions/services/userServices.tsVerifica si el usuario tiene suscripción activa
src/utils/stripe-crm.tsSelecciona la instancia de Stripe según origin