Una suscripción nunca se cobra a sí misma. La suscripción es el acuerdo (qué, cada cuánto, a quién). Cada ciclo de facturación, la suscripción genera un cobro, y el cobro es lo que se paga.
| Objeto | Qué es |
|---|---|
Producto (prod_) | El ítem de catálogo: "Plan Pro", "Caja mensual de café". |
Precio (price_) | Un precio del producto: monto, moneda, y si es recurring (con billing_period + billing_interval) o one_time. Un producto puede tener varios precios (mensual, anual, USD, COP). |
Cliente (cus_) | El comprador. Único por (email, modo test/live). |
Suscripción (sub_) | El acuerdo recurrente: ítems, descuentos, frecuencia, método de cobro, próxima renovación, prueba gratis. |
Cobro (col_) | Un ciclo de facturación concreto: "la cuenta de este mes". Se crea al crear la suscripción y en cada renovación. Es el objeto al que se le atribuye el dinero. |
Transacción (tx_) | Un intento de pago contra un cobro. |
Charge (ch_) | El intento a nivel de pasarela (Wompi, PlaceToPay, Stripe…). Una transacción puede tener varios charges (reintentos). |
Factura (inv_) | El documento fiscal (DIAN) generado en tu proveedor (Siigo, Alegra, Stripe). Opcional y configurable: antes o después del pago. |
Medio de pago (pm_) | Tarjeta / Nequi / Daviplata / PSE tokenizado y guardado contra el cliente. |
active. Es incomplete, y pasa a active cuando el primer cobro queda pagado. Es el error de integración más común.sk_live_… / sk_test_…). No hay llave publicable — el checkout alojado de Treli no la necesita, porque el objeto de sesión ya viene firmado.sk_test_ todos los objetos que crees quedan marcados is_test: true y viven separados de los reales: mismos endpoints, misma lógica, sin dinero.billing_period: day · week · month · year. billing_interval: cada cuántos (3 + month = trimestral).pricing_model: standard · graduated (escalonado) · volume (por volumen) · ntp (name the price, el cliente elige el monto).| Pasarela | Métodos |
|---|---|
wompi | card, pse, nequi, daviplata, bancolombia_transfer, bancolombia_collect, pago_rapido |
epayco | card, pse, efecty |
payu · openpay · mercadopago · placetopay · payzen | card, pse |
paymentsway | card, pse, efecty |
stripe | card |
dlocalgo | card, bank_transfer, cash |
Solo card,nequiydaviplatase pueden tokenizar y por lo tanto sirven para cobro automático recurrente.pse,efectyy afines requieren acción del cliente en cada ciclo.
collection_methodcharge — cobro automático | collect — cobro manual / enviado | |
|---|---|---|
| Qué hace Treli en cada renovación | Genera el cobro y lo cobra al medio de pago guardado | Genera el cobro y se lo envía al cliente (email/WhatsApp) con un link de pago |
| Requiere medio de pago guardado | Sí (pm_, payment_information, o el medio por defecto del cliente) | No |
| Campos | payment_method o payment_information (nunca los dos) | days_until_due (obligatorio) |
| Estado inicial | incomplete → active cuando se paga el primer cobro | active de inmediato (o trialing / scheduled) |
| Si nunca se paga el primer cobro | La suscripción expira a las ~23 horas (expired) | El cobro queda past_due y entra en recordatorios |
| Típico para | B2C, SaaS, membresías, cajas de suscripción | B2B, facturación a crédito, transferencia, efectivo, clientes corporativos |
collect: switch_to_charge: true — si el cliente paga un cobro con un método tokenizable, la suscripción se pasa sola a cobro automático a partir de ahí. Es la forma limpia de arrancar "envío la primera cuenta" y terminar en automático.| # | Forma | Quién captura el pago | Código | Cuándo usarla |
|---|---|---|---|---|
| 1 | Sesión de checkout | Treli (página alojada) | Bajo | Default para casi todo |
| 2 | Enlace de pago | Treli | Ninguno | Una oferta fija, reutilizable, compartible |
| 3 | API directa, cobro automático | Tú | Alto | Ya tienes el medio de pago guardado |
| 4 | API directa, cobro manual | Treli | Medio | B2B / facturación a crédito |
| 5 | Migración / importación | — | Bajo | Traer suscripciones que ya existen en otra parte |
| 6 | Dashboard | Treli | Ninguno | Manual |
{
"session": { "id": "cs_xxx", "mode": "subscription", "status": "open", "total": "89900", "expires_at": "2026-09-09 10:00:00", "...": "..." },
"url": "https://checkout.treli.co/c/pay/cs_xxx#<hash>"
}url. Cuando paga, Treli emite checkout_session.completed, subscription.created, collection.created y (si el pago se aprueba) collection.paid + subscription.activated.expires_at. Al expirar, la sesión queda expired y el cobro asociado se anula.#…) de la URL. Redirige con la URL completa y textual; no la reconstruyas ni la recortes.payment_methods (opcional) restringe qué métodos se ofrecen, con la forma {"wompi": ["card","pse"], "offline": ["transferencia"]}. La pasarela debe estar configurada en tu cuenta o la petición se rechaza.customer (opcional) preasocia un cus_ existente. Si no lo mandas, el checkout identifica o crea al cliente solo (incluye reconocimiento por OTP al email).discounts: [{ "code": "BIENVENIDO20", "duration_in_collections": 3 }].mode, que resuelven problemas vecinos:mode | Para qué |
|---|---|
subscription | Crear una suscripción (esta sección) |
payment | Un cobro único, sin suscripción |
setup | Guardar un medio de pago sin cobrar. Total 0. Con setup_subscription_id reemplaza el medio de pago de una suscripción existente (recuperar una suscripción past_due, actualizar una tarjeta vencida). Sin él, deja un pm_ guardado que puedes usar luego en la Opción 3 |
pl_)https://checkout.treli.co/pl/{pl_id}recurring, el enlace crea suscripciones; si todos son one_time, crea cobros únicos.subscription_settings sin ningún precio recurrente, la petición se rechaza.ntp (name the price): solo uno por enlace, y no admiten prueba gratis.usage_limit limita cuántas veces se puede usar; cta_text acepta Pagar, Suscribirse, Donar, Reservar.collection_method: "charge")payment_method y payment_information, Treli usa el medio de pago por defecto del cliente (y falla si no tiene uno).pm_?mode: "setup" (Opción 1).GET /v1/customers/{id}/payment_methods para listar los que ya existen.No hay un endpoint "crear medio de pago" con datos de tarjeta sueltos: los medios de pago nacen de un intento de pago o de un flujo de tokenización.
payment_method y payment_information son mutuamente excluyentes.days_until_due no se permite con charge.first_payment_invoicing, con charge solo puede ser "after" (no puedes emitir la factura fiscal antes de cobrar automáticamente).schedule_date no se permite payment_information (se cobrará luego, con el medio guardado).status: "incomplete" y latest_collection: "col_xxx". El primer cobro se genera y se intenta pagar en el mismo request:collection.paid + subscription.activated casi de inmediato.processing y su additional_data contiene la información de redirección/instrucción que debes mostrarle al cliente. Para métodos asíncronos, la sesión de checkout es bastante más simple, porque esa redirección ya viene resuelta.expired.collection_method: "collect")days_until_due es obligatorio y define la fecha de vencimiento de cada cobro.payment_method ni payment_information.active de inmediato (o trialing si hay prueba, scheduled si hay schedule_date).https://checkout.treli.co/col/{col_id}), que Treli envía por email/WhatsApp y sobre la que corren recordatorios y reglas de vencimiento.first_payment_invoicing: "create" emite la factura fiscal antes del pago — el caso clásico de facturación a crédito. Con "after" se emite al pagar.switch_to_charge: true convierte la suscripción a cobro automático en cuanto el cliente pague con un método tokenizable.POST /v1/subscriptions: no genera un primer cobro ni intenta pagar nada. Respeta el next_renewal_date que le des, así que el cliente no paga dos veces ni pierde días.https://p.treli.co/p/login/{url_id}) — no crea suscripciones nuevas, pero es donde el cliente cancela, pausa, reanuda y actualiza su medio de pago. Vale integrarlo desde el día uno: reduce mucho el churn involuntario por tarjeta vencida.POST /v1/subscriptions y, cuando corresponde, vía subscription_settings en checkout / enlaces / tiendas.| Campo | Qué hace |
|---|---|
trial_days | Prueba gratis. En el primer cobro, los ítems recurrentes quedan en 0 (los one_time sí se cobran), así que se valida el medio de pago sin cobrar la mensualidad. La suscripción queda trialing y se activa al primer cobro real. No se combina con schedule_date. |
schedule_date | Inicio futuro: estado scheduled, sin cobro hasta la fecha. |
duration | Número total de ciclos. Al alcanzarlo, la suscripción pasa a ended (y avisa un ciclo antes con subscription.will_end). |
commitment_periods | Periodos de permanencia mínima; se usa para las reglas de cancelación. |
usage_based | Suscripción por consumo: en cada renovación Treli emite subscription.report_usage y espera ~5 minutos antes de generar el cobro, para que reportes el consumo del periodo (actualizando ítems/cantidades vía API). |
discounts | Cupones por código: [{ "code": "X", "duration_in_collections": 3 }]. Sin duration_in_collections, aplica a todos los ciclos. |
days_until_due | Días de plazo de cada cobro. Obligatorio en collect, prohibido en charge. |
first_payment_invoicing | create (factura fiscal antes del pago) · after (después del pago). Con charge solo after. |
renewal_invoicing | Si cada renovación genera factura fiscal. Por defecto true. |
invoice_settings / invoice_retentions | Parámetros del proveedor de facturación (Siigo/Alegra) y retenciones (reteiva, reteica, retefte). |
meta_data | Tus propias llaves/valores (máx. 255 caracteres cada valor). Ideal para tu user_id. Viaja en los webhooks. |
| Estado | Significado |
|---|---|
incomplete | Creada con charge, esperando que se pague el primer cobro. Todavía no da acceso. |
trialing | En prueba gratis. |
scheduled | Programada, aún no arranca. |
active | Al día. |
past_due | Un cobro se venció sin pagarse; corren reintentos y recordatorios. |
unpaid | Se agotó la política de reintentos/dunning. |
paused | Pausada (opcionalmente con resumes_at). |
pending_cancel | Cancelación agendada para el fin del periodo; no renueva. |
canceled | Cancelada. |
ended | Alcanzó su duration. |
expired | Nació con charge y nunca completó el primer pago (~23 h). |
subscription.created (o subscription.scheduled), y se genera el primer cobro (collection.created).charge se intenta en el momento; con collect se envía la cuenta (collection.sent).collection.paid + charge.paid → la suscripción se activa (subscription.activated).next_renewal_date); al llegar, genera un cobro nuevo y repite el paso 2. No hay que hacer nada.collection.past_due + subscription.past_due → reintentos → si se agotan, subscription.unpaid / collection.uncollectible.POST /v1/subscriptions/{id}/cancel (con cancel_at: "period_end" o "now"), /pause, /resume; o ended al cumplir duration.subscription.activated → dale acceso al cliente.collection.paid → entró el dinero de este ciclo. Se dispara en cada renovación pagada, no solo en la primera.| Evento | Para qué |
|---|---|
subscription.created | Registrar la suscripción en tu sistema (aún sin acceso si vino con charge). |
subscription.past_due / unpaid | Avisar, limitar o suspender el acceso. |
subscription.canceled / pending_canceled / ended / expired | Revocar acceso (pending_canceled = revocar al final del periodo). |
subscription.paused / resumed | Suspender y restaurar. |
subscription.will_end | Un ciclo antes de agotar duration: momento de ofrecer renovación. |
subscription.report_usage | Reportar consumo antes de que se genere el cobro (solo usage_based). |
collection.created / sent / reminder / payment_failed / voided / refunded | Seguir la cobranza ciclo a ciclo. |
checkout_session.completed / expired | Cerrar el flujo de checkout de tu lado. |
invoice.created / paid / voided | Documentos fiscales, si facturas con Siigo/Alegra. |
id del evento (evt_…) y hazlo idempotente por objeto (sub_, col_).collection_method: "charge".collection_method: "collect" + days_until_due (+ switch_to_charge si quieres migrarlo a automático).mode: "subscription" → escuchar subscription.activated y collection.paid → integrar el portal del cliente para que actualice su tarjeta.sk_test_. Todo lo que crees queda is_test: true, en paralelo a lo real.incomplete antes de active — si tu código asume active al recibir la respuesta del POST, falla en producción con cualquier método asíncrono.billing_period: "day" hace el ciclo visible en minutos).past_due → reintentos.| Síntoma | Causa |
|---|---|
"Creé la suscripción pero está incomplete" | Correcto y esperado con charge: se activa cuando se paga el primer cobro. Escucha subscription.activated. |
days_until_due is only allowed for collection_method charge | days_until_due va solo con collect, donde además es obligatorio. |
"No puedo mandar payment_method y payment_information" | Son excluyentes: uno u otro. |
Todos los precios deben tener la misma frecuencia | En un mismo enlace/tienda/suscripción los precios recurrentes deben compartir billing_period + billing_interval. |
La pasarela de pago X no se encuentra configurada en tu cuenta | payment_methods referencia una pasarela que no tienes activa. |
La suscripción quedó expired sin explicación | Nació con charge y el primer pago nunca se completó dentro de ~23 h (típico de PSE abandonado). |
Error al usar first_payment_invoicing: "create" con charge | Con cobro automático la primera factura solo puede ser "after". |
| El monto no cuadra en monedas distintas a COP | COP es la moneda de liquidación; el resto se guarda convertido con la tasa del momento. Compara siempre en la moneda de la suscripción. |
| Los medios de pago no se guardan para renovar | Solo card, nequi y daviplata se tokenizan. Con pse/efectivo usa collect (+ switch_to_charge). |
| Acción | Endpoint |
|---|---|
| Crear suscripción | POST /v1/subscriptions |
| Migrar suscripción existente | POST /v1/subscriptions/migrate |
| Ver / listar | GET /v1/subscriptions/{id} · GET /v1/subscriptions |
| Actualizar | POST /v1/subscriptions/{id}/update |
| Ítems | POST /v1/subscription_items · `POST |
| Cancelar / pausar / reanudar | POST /v1/subscriptions/{id}/cancel · /pause · /resume |
| Envío | POST /v1/subscriptions/{id}/shipping · /shipping_item |
| Sesión de checkout | POST /v1/checkout_session · GET /v1/checkout_session/{id} |
| Enlaces de pago | POST /v1/payment_links · POST /v1/payment_links/{id}/update |
| Tiendas | POST /v1/storefronts · POST /v1/storefronts/{id}/update |
| Catálogo | POST /v1/products · POST /v1/prices |
| Clientes | POST /v1/customers · GET /v1/customers/{id}/payment_methods |
| Cobros | GET /v1/collections/{id} · POST /v1/collections/{id}/pay · /void · /refund |
| Medios de pago | POST /v1/payment_methods/{id}/update · /delete · POST /v1/payment_methods/migrate |