Suscripciones
Una suscripción cobra a un cliente con una cadencia fija usando un token de pago previamente guardado. Genius Checkout es dueño del calendario — cobramos en cada renovación, reintentamos rechazos y emitimos webhooks. No necesitas un cron.
Una suscripción siempre necesita dos cosas: un customer_id (devuelto por cualquier checkout previo) y un token_id (pt_…). Ambos están aislados por comercio.
Ciclo de vida
trial ─▶ active ─▶ past_due ─▶ cancelled
└▶ suspended ─▶ active
└▶ cancelled
└▶ expired (se alcanzó total_cycles)| Estado | Significado |
|---|---|
trial | Creada con trial_period_days. Aún no hay cobro — el primer cargo es al terminar el periodo de prueba. |
active | Facturando según el calendario. Cada ciclo emite subscription.charged en caso de éxito. |
past_due | La renovación más reciente falló. El job de dunning reintenta según el calendario del comercio. |
suspended | Pausada por el comercio vía POST /subscriptions/{id}/pause. No se cobran ciclos hasta resumir. |
cancelled | Terminal. No habrá más cobros. Se establece vía POST /subscriptions/{id}/cancel. |
expired | Terminal. Se alcanzó total_cycles (suscripciones de duración fija). |
Crear una suscripción
POST /api/v1/subscriptions| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
customer_id | string | Sí | ID externo del cliente (cus_…) |
token_id | string | Sí | ID externo del token (pt_…). Debe estar active. |
amount | integer | Sí | Monto por ciclo en unidades menores (ver Monedas) |
currency | string | Sí | Código alfa ISO 4217 |
interval | string | Sí | day, week, month, year |
interval_count | integer | No | Multiplicador de interval. Defecto 1. Rango 1–365. |
trial_period_days | integer | No | Si se define, el primer cobro ocurre tras la prueba. |
setup_fee | integer | No | Cargo único cobrado al crearse. |
total_cycles | integer | No | Suscripción de duración fija. El estado pasa a expired tras el último ciclo. |
start_date | date | No | Fecha ISO 8601 en el futuro. Por defecto, hoy. |
metadata | object | No | Se replica en cada webhook subscription.*. |
curl -X POST https://app.geniuscheckout.com/api/v1/subscriptions \
-H "Authorization: Bearer gc_test_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"customer_id": "cus_abc123",
"token_id": "pt_xyz789",
"amount": 2999,
"currency": "USD",
"interval": "month",
"trial_period_days": 14,
"metadata": {"plan": "pro"}
}'Respuesta (201)
{
"id": "sub_abc123",
"status": "trial",
"amount": 2999,
"currency": "USD",
"interval": "month",
"interval_count": 1,
"setup_fee": null,
"trial_ends_at": "2026-06-05T12:00:00+00:00",
"current_period_start": "2026-05-22T12:00:00+00:00",
"current_period_end": "2026-06-22T12:00:00+00:00",
"next_charge_at": "2026-06-05T12:00:00+00:00",
"total_cycles": null,
"completed_cycles": 0,
"dunning_attempts": 0,
"cancelled_at": null,
"cancel_reason": null,
"customer": {"id": "cus_abc123", "name": "Jane Doe", "email": "[email protected]"},
"payment_method": {"id": "pt_xyz789", "brand": "Visa", "last4": "0071"},
"created_at": "2026-05-22T12:00:00+00:00"
}Listar suscripciones
GET /api/v1/subscriptions?status=active&limit=20&offset=0Filtros: status, customer_id. Paginación con limit/offset (máx limit=100). Ver Paginación.
{
"data": [ /* objetos suscripción */ ],
"total": 142,
"limit": 20,
"offset": 0
}Recuperar una suscripción
GET /api/v1/subscriptions/{id}Devuelve el objeto completo más un array events con los eventos de ciclo recientes (status_changed, charged, charge_failed).
Cancelar
POST /api/v1/subscriptions/{id}/cancel{ "reason": "Solicitud del cliente", "immediate": true }Cuando immediate es false, la cancelación se programa al current_period_end (el cliente conserva acceso hasta entonces). Por defecto es true.
Pausar / reanudar
POST /api/v1/subscriptions/{id}/pause
POST /api/v1/subscriptions/{id}/resumePausar cambia el estado a suspended y detiene todos los cobros futuros. Reanudar vuelve a active y recalcula next_charge_at.
Actualizar método de pago
PUT /api/v1/subscriptions/{id}/payment-method{ "token_id": "pt_new_card" }El nuevo token debe estar active y pertenecer al mismo comercio. Úsalo cuando una tarjeta expire y el cliente agregue otra desde tu portal.
Webhooks
Cada ciclo y cada transición de estado emite un webhook — ver Webhooks para la lista completa. Los más comunes:
subscription.created— creada (entrialoactive)subscription.charged— renovación exitosasubscription.charge_failed— renovación rechazada; el dunning reintentasubscription.cancelled— cancelación terminalsubscription.updated— cambió el método de pago o el calendario
Ejemplos de código
// Node — crear suscripción con prueba de 14 días
const res = await fetch('https://app.geniuscheckout.com/api/v1/subscriptions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.GC_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
customer_id: 'cus_abc123',
token_id: 'pt_xyz789',
amount: 2999,
currency: 'USD',
interval: 'month',
trial_period_days: 14,
}),
})
const subscription = await res.json()// PHP (Guzzle) — cancelar al final del periodo
$client = new \GuzzleHttp\Client();
$client->post("https://app.geniuscheckout.com/api/v1/subscriptions/{$id}/cancel", [
'headers' => [
'Authorization' => 'Bearer ' . getenv('GC_API_KEY'),
'Content-Type' => 'application/json',
],
'json' => [
'reason' => 'Solicitud del cliente',
'immediate' => false,
],
]);Siguiente
- Tokens de pago — listar / desactivar tarjetas guardadas
- Webhooks — escucha eventos de renovación
- Tokenización y recurrencia — captura inicial de tarjeta
