Subscriptions
/v1/subscriptions — ligan un Customer a un Plan y disparan los cobros
recurrentes. Ver también el concepto Suscripción.
El objeto Subscription
{
"id": "sub_01HZXK7QJ5M8Z9X2R3TVQ7A1B2",
"customer_id": "cus_01HZXK7QJ5M8Z9X2R3TVQ7A1B2",
"plan_id": "plan_01HZXK7QJ5M8Z9X2R3TVQ7A1B2",
"status": "active",
"cycle": "monthly",
"current_period_start": "2026-08-24T00:00:00Z",
"current_period_end": "2026-09-24T00:00:00Z",
"next_charge_date": "2026-09-24T00:00:00Z",
"default_payment_method_id": "pm_01HZXK7QJ5M8Z9X2R3TVQ7A1B2",
"trial_end": null,
"cancel_at_period_end": false,
"failed_attempts": 0,
"created_at": "2026-08-24T15:00:00Z"
}| Campo | Tipo | Descripción |
|---|---|---|
id | string | Identificador único |
customer_id | string | Cliente dueño de la suscripción |
plan_id | string | Plan al que está suscrito |
status | string | trialing · active · past_due · paused · paused_insufficient_balance · canceled |
cycle | string | monthly o annual |
current_period_start / current_period_end | datetime | Inicio y fin del periodo de facturación actual |
next_charge_date | datetime | Próxima fecha de cobro programada |
default_payment_method_id | string | Método de pago usado para los cobros |
trial_end | datetime | null | Fin del periodo de prueba, si aplica |
cancel_at_period_end | boolean | Si se cancelará al terminar el periodo actual |
failed_attempts | integer | Intentos de cobro fallidos consecutivos |
created_at | datetime | Fecha de creación |
Crear una suscripción
Las suscripciones se crean con el checkout hospedado, no con una llamada
directa a este recurso: creas una checkout session, rediriges a tu cliente y
Rekurra crea el Customer, el PaymentMethod y la Subscription en un solo
flujo. Ver la guía Crear una suscripción y
API → Checkout sessions.
Este recurso (/v1/subscriptions) se usa para consultar y gestionar
suscripciones ya creadas: listarlas, obtener una, cancelar, pausar/reanudar,
cambiar de plan, forzar un cobro y administrar addons.
También expone POST /v1/subscriptions para crear una suscripción
directamente (sin checkout hospedado) cuando ya tienes un customer_id
y un payment_method_id propios — por ejemplo, al migrar suscripciones
desde otro proveedor. Acepta customer_id, plan_id, cycle,
payment_method_id, trial_days, start_date y, al igual que la creación
vía checkout, un metadata opcional (objeto libre, máx. 60 KB
serializado). Ese metadata queda guardado en la suscripción y se repite
en data.metadata de cada webhook que dispares para ella — ver
Webhooks → metadata en cada evento.
Listar suscripciones
GET /v1/subscriptions
Filtros opcionales: ?status=, ?customer_id=, ?plan_id=, más paginación
estándar.
curl "https://api.rekurra.dev/v1/subscriptions?status=active" \
-H "Authorization: Bearer rk_live_XXXXXXXXXXXXXXXXXXXXXXXX"Obtener una suscripción
GET /v1/subscriptions/{id}
curl https://api.rekurra.dev/v1/subscriptions/sub_01HZXK7QJ5M8Z9X2R3TVQ7A1B2 \
-H "Authorization: Bearer rk_live_XXXXXXXXXXXXXXXXXXXXXXXX"Errores posibles
| Status | error.type | Causa |
|---|---|---|
404 | invalid_request | La suscripción no existe |
Cancelar una suscripción
POST /v1/subscriptions/{id}/cancel
{ "at_period_end": true }curl -X POST https://api.rekurra.dev/v1/subscriptions/sub_01HZXK7QJ5M8Z9X2R3TVQ7A1B2/cancel \
-H "Authorization: Bearer rk_live_XXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{ "at_period_end": true }'Si at_period_end es true (u omitido), la suscripción sigue active
hasta el fin del periodo actual con cancel_at_period_end: true, y luego
pasa a canceled. Si es false, cancela de inmediato.
Pausar / reanudar
POST /v1/subscriptions/{id}/pause · POST /v1/subscriptions/{id}/resume
curl -X POST https://api.rekurra.dev/v1/subscriptions/sub_01HZXK7QJ5M8Z9X2R3TVQ7A1B2/pause \
-H "Authorization: Bearer rk_live_XXXXXXXXXXXXXXXXXXXXXXXX"Cambiar de plan
POST /v1/subscriptions/{id}/change-plan
Cambia el plan (y opcionalmente el ciclo) de una suscripción activa, con prorrateo por tiempo restante del periodo actual (igual que Stripe).
{ "plan_id": "plan_01HZ...", "cycle": "annual", "prorate": true }| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
plan_id | string | Sí | Plan destino |
cycle | string | No | monthly o annual; si se omite, conserva el ciclo actual de la suscripción |
prorate | boolean | No | Por defecto true. Ver semántica abajo |
Semántica del prorrateo
Rekurra calcula la diferencia prorrateada entre el plan actual y el nuevo plan según la fracción de tiempo que falta del periodo de facturación vigente:
- Upgrade (diferencia positiva) → se cobra de inmediato esa diferencia prorrateada, en el mismo momento en que aplicas el cambio, por el tiempo restante del periodo actual.
- Downgrade (diferencia negativa) → no se reembolsa nada; el precio
más bajo simplemente empieza a aplicarse desde el siguiente renovación
(
next_charge_date). "prorate": falseaplica el cambio de plan/ciclo sin el cobro inmediato — el nuevo precio rige a partir del siguiente ciclo, sin importar si es upgrade o downgrade.
Este endpoint dispara el webhook subscription.plan_changed. Si quieres
saber cuánto se cobraría antes de aplicar el cambio, usa la
vista previa de abajo.
curl -X POST https://api.rekurra.dev/v1/subscriptions/sub_01HZXK7QJ5M8Z9X2R3TVQ7A1B2/change-plan \
-H "Authorization: Bearer rk_live_XXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{ "plan_id": "plan_01HZ...", "cycle": "annual", "prorate": true }'Errores posibles
| Status | error.type | Causa |
|---|---|---|
404 | invalid_request | La suscripción o el plan_id no existen |
400 | invalid_request | cycle inválido (ni monthly ni annual) |
Vista previa de cambio de plan
POST /v1/subscriptions/{id}/change-plan/preview
Calcula cuánto se cobraría (o no) si aplicaras un cambio de plan sin aplicarlo: es un dry-run puro — no muta la suscripción, no dispara webhooks y no genera ningún cobro. Úsalo para mostrarle a tu usuario el monto de la diferencia antes de que confirme el upgrade/downgrade.
La vista previa es solo para el ciclo de facturación actual de la
suscripción: el cuerpo únicamente acepta plan_id (no cycle), así que
previsualiza un cambio de plan manteniendo el ciclo vigente. Si necesitas
cambiar de ciclo (ej. monthly → annual) a la vez que el plan, aplica
directamente POST /{id}/change-plan con el cycle deseado — ese
endpoint sí lo soporta, solo la vista previa está limitada al ciclo
actual.
{ "plan_id": "plan_01HZ..." }curl -X POST https://api.rekurra.dev/v1/subscriptions/sub_01HZXK7QJ5M8Z9X2R3TVQ7A1B2/change-plan/preview \
-H "Authorization: Bearer rk_live_XXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{ "plan_id": "plan_01HZ..." }'Response — 200 OK
{ "prorated_amount_cents": 850000, "immediate_charge": true }| Campo | Tipo | Descripción |
|---|---|---|
prorated_amount_cents | integer | Diferencia prorrateada, en centavos de COP. Positiva en un upgrade, negativa en un downgrade |
immediate_charge | boolean | true cuando prorated_amount_cents > 0 (upgrade) — es decir, lo que se cobraría de inmediato si aplicas el cambio con prorate: true. false en downgrades o si no hay diferencia |
Errores posibles
| Status | error.type | Causa |
|---|---|---|
404 | invalid_request | La suscripción o el plan_id no existen |
Forzar un reintento de cobro
POST /v1/subscriptions/{id}/charge-now
curl -X POST https://api.rekurra.dev/v1/subscriptions/sub_01HZXK7QJ5M8Z9X2R3TVQ7A1B2/charge-now \
-H "Authorization: Bearer rk_live_XXXXXXXXXXXXXXXXXXXXXXXX"Errores posibles (acciones)
| Status | error.type | Causa |
|---|---|---|
404 | invalid_request | La suscripción no existe |
409 | invalid_request | La acción no es válida para el estado actual (ej. pause en una ya canceled) |
422 | insufficient_balance | Saldo prepago insuficiente para procesar el cobro |
422 | wompi_error | Wompi rechazó el cobro |
Addons de la suscripción
El monto recurrente de una suscripción es la suma del precio del Plan más
el precio de cada Addon activo adjunto a ella.
Adjuntar un addon
POST /v1/subscriptions/{id}/addons
{ "addon_id": "addon_01HZXK7QJ5M8Z9X2R3TVQ7A1B2", "prorate": true }curl -X POST https://api.rekurra.dev/v1/subscriptions/sub_01HZXK7QJ5M8Z9X2R3TVQ7A1B2/addons \
-H "Authorization: Bearer rk_live_XXXXXXXXXXXXXXXXXXXXXXXX" \
-H "Content-Type: application/json" \
-d '{ "addon_id": "addon_01HZXK7QJ5M8Z9X2R3TVQ7A1B2", "prorate": true }'prorate es opcional y por defecto true: cobra de inmediato la parte
proporcional del periodo actual (desde ahora hasta current_period_end).
Si es false, el addon queda adjunto sin cobro inmediato y su costo se
incluye a partir del siguiente ciclo de facturación.
Errores posibles
| Status | error.type | Causa |
|---|---|---|
404 | invalid_request | La suscripción o el addon no existen |
409 | invalid_request | El addon ya está adjunto a esta suscripción |
409 | invalid_request | La suscripción está canceled y no admite addons |
422 | invalid_request | El addon está desactivado (active: false) |
Quitar un addon
DELETE /v1/subscriptions/{id}/addons/{addon_id}
curl -X DELETE https://api.rekurra.dev/v1/subscriptions/sub_01HZXK7QJ5M8Z9X2R3TVQ7A1B2/addons/addon_01HZXK7QJ5M8Z9X2R3TVQ7A1B2 \
-H "Authorization: Bearer rk_live_XXXXXXXXXXXXXXXXXXXXXXXX"Detiene el cobro del addon a partir del siguiente periodo; el periodo actual ya facturado no se reembolsa.
Listar los addons de una suscripción
GET /v1/subscriptions/{id}/addons
curl https://api.rekurra.dev/v1/subscriptions/sub_01HZXK7QJ5M8Z9X2R3TVQ7A1B2/addons \
-H "Authorization: Bearer rk_live_XXXXXXXXXXXXXXXXXXXXXXXX"{ "data": [ /* Addon[] */ ], "has_more": false, "next_cursor": null }