Ir al contenido

Planes (Prices)

Ver .md

Un plan es la plantilla que usará cada suscripción para determinar cuánto y cada cuánto se cobra: precio, moneda, frecuencia de la recurrencia (invoice_period

  • invoice_interval), días de prueba (trial_*) y período de gracia (grace_*). Un plan puede pertenecer a un grupo.

No necesitas construir un formulario de suscripción. Cada plan trae una página de checkout alojada por Efipay, lista para usar. Al crear el plan la respuesta te devuelve:

Campo Qué es
checkoutUrl La URL de la página donde tu cliente se suscribe: ingresa sus datos, su tarjeta y queda suscrito
qrCodeSvg Esa misma URL como código QR, ya renderizado en SVG. Sirve para imprimirlo o mostrarlo en pantalla

Es la ruta de integración más corta: creas el plan una vez, publicas el enlace y no escribes una sola línea de código de cobro. Efipay se encarga del formulario, la tokenización de la tarjeta y el cobro recurrente.

Desde ese mismo enlace tu suscriptor tiene un portal de autogestión donde puede consultar sus cobros y facturas, actualizar la tarjeta con la que paga, renovar y cancelar su suscripción. Se identifica con un código de verificación que le llega por correo, así que no tienes que darle usuario ni contraseña.

Descripción: Crea un plan que servirá como guía para las suscripciones recurrentes (precio, moneda, frecuencia, prueba y gracia).

POST /api/v1/subscriptions/plan

Nombre del campo Descripción Reglas
name Nombre del plan. Lo ve el suscriptor ['required', 'string', 'max:150']
description Qué incluye el plan ['required', 'string', 'max:500']
price Valor que se cobra en cada renovación. El máximo depende de la moneda: 999999999999 en COP y 200000000 en USD/EUR ['required', 'numeric', 'min:1', 'max:999999999999']
currency_type Moneda del cobro. Ver enumeraciones ['required', 'in:COP,USD,EUR']
tax Valor del IVA a aplicar. Debe ser uno de tus impuestos activos; consúltalos en GET /api/v1/resources/get-taxes ['nullable', 'exists:taxes,value']
invoice_period Cada cuántos invoice_interval se cobra. Junto con el intervalo define la frecuencia ['required', 'integer', 'min:1', 'max:30']
invoice_interval Unidad de la frecuencia de cobro ['required', 'in:day,week,month,year']
trial_period Períodos de prueba antes del primer cobro. 0 = sin prueba ['sometimes', 'integer', 'min:0', 'max:30']
trial_interval Unidad del período de prueba ['sometimes', 'in:day,week,month,year']
grace_period Tiempo tras el vencimiento en el que se sigue reintentando el cobro antes de dar la suscripción por inactiva ['sometimes', 'integer', 'min:0', 'max:7']
grace_interval Unidad del período de gracia ['sometimes', 'in:day,week,month,year']
max_recurrences Número máximo de cobros aprobados. Al alcanzarlo la suscripción se cancela sola ['nullable', 'integer', 'min:1', 'max:100']
deadline Fecha tope de la suscripción. Al pasarla se cancela sola ['nullable', 'date', 'date_format:Y-m-d H:i:s']
active_subscribers_limit Máximo de suscriptores activos que admite el plan ['nullable', 'integer', 'max:100000']
allow_multiple_subscriptions Permite que un mismo suscriptor tenga más de una suscripción a este plan ['sometimes', 'boolean']
sort_order Orden en que se listan los planes ['nullable', 'integer', 'max:100000']
subscription_group_id Grupo al que pertenece el plan ['nullable', 'exists:subscription_groups,id']
office Sucursal a la que pertenece el plan. Debe ser una de tus sucursales ['required', 'exists:offices,id']
advanced_options Opciones avanzadas del cobro ['nullable', 'array']
advanced_options.result_urls URLs de retorno y webhook para los cobros del plan ['nullable', 'array']
metadata Tus pares clave-valor. Ver Metadata ['sometimes', 'nullable', 'metadata']

Descuento del plan — se mantiene por compatibilidad. Para descuentos nuevos usa Cupones, que son reutilizables entre planes.

Nombre del campo Descripción Reglas
discount_type_amount Tipo de descuento. Ver enumeraciones ['sometimes', 'nullable', 'in:value,percentage']
discount_amount Valor del descuento, según el tipo ['sometimes', 'nullable', 'numeric']
discount_period Duración del descuento, en discount_interval ['sometimes', 'integer', 'min:0', 'max:30']
discount_interval Unidad de la duración del descuento ['sometimes', 'in:day,week,month,year']
discount_subscribers_limit Cuántos suscriptores alcanzan el descuento ['sometimes', 'nullable', 'integer', 'min:1', 'max:100000']
POSThttps://sag.efipay.co/api/v1/subscriptions/plan
Ventana de terminal
curl -X POST \
'/api/v1/subscriptions/plan' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-type: application/json' \
-H 'Idempotency-Key: 9b1f0e34-6b2a-4a7e-9d0a-000000000002' \
-d '{
"name": "Newsletter mensual",
"description": "Suscripción general a newsletters, 15 envíos por mes",
"price": 15000,
"currency_type": "COP",
"tax": 19,
"invoice_period": 1,
"invoice_interval": "month",
"grace_period": 3,
"grace_interval": "day",
"office": 1
}'
200OK
{
"saved": true,
"plan": {
"id": "9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f",
"name": "Newsletter mensual",
"description": "Suscripción general a newsletters, 15 envíos por mes",
"price": 15000,
"currencyType": "COP",
"production": false,
"trialInterval": "day",
"trialPeriod": 0,
"invoiceInterval": "month",
"invoicePeriod": 1,
"graceInterval": "day",
"gracePeriod": 3,
"discountInterval": "day",
"discountPeriod": 0,
"discountTypeAmount": null,
"discountSubscribersLimit": null,
"activeSubscribersLimit": null,
"allowMultipleSubscriptions": false,
"subscriptionGroupId": null,
"groupName": null,
"maxRecurrences": null,
"deadline": null,
"resultUrls": null,
"createdAt": "2026-07-31 10:15:00",
"active": true,
"checkoutUrl": "https://sag.efipay.co/checkout/subscription-gateway/9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f",
"qrCodeSvg": "<svg xmlns=\"http://www.w3.org/2000/svg\" ...></svg>"
}
}
422Unprocessable Entity
{
"message": "El tax seleccionado no es válido.",
"errors": {
"tax": ["El tax seleccionado no es válido."],
"office": ["El office seleccionado no es válido."]
}
}
403Forbidden

Descripción: Actualiza los campos de un plan existente. Envía solo lo que quieras cambiar.

PUT /api/v1/subscriptions/plan/{plan-id}

Nombre del campo Descripción Reglas
name Nuevo nombre ['sometimes', 'required', 'string', 'max:150']
description Nueva descripción ['sometimes', 'required', 'string', 'max:500']
price Nuevo precio ['sometimes', 'numeric', 'min:1']
currency_type Nueva moneda ['sometimes', 'in:COP,USD,EUR']
tax Nuevo IVA, entre tus impuestos activos ['sometimes', 'nullable', 'exists:taxes,value']
invoice_period Cada cuántos invoice_interval se cobra ['sometimes', 'integer', 'min:1', 'max:30']
invoice_interval Unidad de la frecuencia de cobro ['sometimes', 'in:day,week,month,year']
trial_period Períodos de prueba ['sometimes', 'integer', 'min:0', 'max:30']
trial_interval Unidad del período de prueba ['sometimes', 'in:day,week,month,year']
grace_period Períodos de gracia ['sometimes', 'integer', 'min:0', 'max:7']
grace_interval Unidad del período de gracia ['sometimes', 'in:day,week,month,year']
discount_type_amount Tipo de descuento ['sometimes', 'nullable', 'in:value,percentage']
discount_amount Valor del descuento ['sometimes', 'nullable', 'numeric']
discount_period Duración del descuento. Aquí el máximo es 100000, no 30 ['sometimes', 'integer', 'min:0', 'max:100000']
discount_interval Unidad de la duración del descuento ['sometimes', 'in:day,week,month,year']
discount_subscribers_limit Cuántos suscriptores alcanzan el descuento. Aquí no hay min:1 ['sometimes', 'nullable', 'integer', 'max:100000']
sort_order Orden en que se listan los planes ['sometimes', 'nullable', 'integer', 'max:100000']
active_subscribers_limit Máximo de suscriptores activos ['sometimes', 'nullable', 'integer', 'max:100000']
max_recurrences Máximo de cobros aprobados ['sometimes', 'nullable', 'integer', 'min:1', 'max:100']
deadline Fecha tope de la suscripción ['sometimes', 'nullable', 'date_format:Y-m-d H:i:s']
allow_multiple_subscriptions Permitir varias suscripciones del mismo suscriptor ['sometimes', 'boolean']
subscription_group_id Grupo al que pertenece el plan ['sometimes', 'nullable', 'exists:subscription_groups,id']
advanced_options Opciones avanzadas. Envía null para borrarlas ['nullable', 'array']
advanced_options.result_urls URLs de retorno y webhook ['nullable', 'array']
metadata Se combina con la existente. Una clave con "" o null se borra; metadata: null borra todo. Ver Metadata ['sometimes', 'nullable', 'metadata']
PUThttps://sag.efipay.co/api/v1/subscriptions/plan/your-plan-id
Ventana de terminal
curl -X PUT \
'/api/v1/subscriptions/plan/9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-type: application/json' \
-d '{
"price": 30000,
"description": "Suscripción básica a newsletter, 40 envíos por mes"
}'
200OK
{
"saved": true,
"plan": {
"id": "9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f",
"name": "Newsletter mensual",
"description": "Suscripción básica a newsletter, 40 envíos por mes",
"price": 30000,
"currencyType": "COP",
"production": false,
"trialInterval": "day",
"trialPeriod": 0,
"invoiceInterval": "month",
"invoicePeriod": 1,
"graceInterval": "day",
"gracePeriod": 3,
"discountInterval": "day",
"discountPeriod": 0,
"discountTypeAmount": null,
"discountSubscribersLimit": null,
"activeSubscribersLimit": null,
"allowMultipleSubscriptions": false,
"subscriptionGroupId": null,
"groupName": null,
"maxRecurrences": null,
"deadline": null,
"resultUrls": null,
"createdAt": "2026-07-31 10:15:00",
"active": true,
"checkoutUrl": "https://sag.efipay.co/checkout/subscription-gateway/9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f",
"qrCodeSvg": "<svg xmlns=\"http://www.w3.org/2000/svg\" ...></svg>"
}
}

metadata guarda tus propias referencias del plan (SKU, nivel, id en tu catálogo…), al estilo de Stripe. Mismas reglas que en suscripciones:

Límite Valor
Claves Hasta 50, de 1 a 40 caracteres [A-Za-z0-9_-]
Valor Texto o número, hasta 500 caracteres. Se guarda como texto
Al actualizar Las claves se combinan; "" o null borra una clave; metadata: null borra todo

Llega en los GET y listados y en los webhooks de suscripción, dentro de subscription.plan.metadata. Filtra los listados con filter[metadata][clave]=valor. Un valor inválido responde 422 con error.code: "validation_failed" y error.param: "metadata".

Descripción: Devuelve tus planes, paginados.

GET /api/v1/subscriptions/plan

Estos parámetros de consulta no se validan en el servidor: un valor inesperado no produce un 422, simplemente no filtra.

Nombre del campo Descripción
active Envía exactamente la cadena true para traer solo los planes activos. Cualquier otro valor no filtra
fields Columnas a devolver, separadas por coma. Útil para respuestas ligeras
per_page Planes por página. Por defecto 2, así que casi siempre querrás enviarlo
filter[metadata][clave] Coincidencia exacta con un par de tu metadata, por ejemplo filter[metadata][tier]=gold

La respuesta son los modelos crudos en snake_case dentro del sobre de paginación de Laravel, no el objeto camelCase que devuelven crear y actualizar.

GEThttps://sag.efipay.co/api/v1/subscriptions/plan
Ventana de terminal
curl -X GET \
'/api/v1/subscriptions/plan?active=true&per_page=50' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Accept: application/json'
200OK
{
"current_page": 1,
"data": [
{
"id": "9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f",
"name": "Newsletter mensual",
"description": "Suscripción general a newsletters, 15 envíos por mes",
"price": 15000,
"currency_type": "COP",
"advanced_option_id": null,
"tax": 19,
"trial_period": 0,
"trial_interval": "day",
"invoice_period": 1,
"invoice_interval": "month",
"grace_period": 3,
"grace_interval": "day",
"discount_period": 0,
"discount_interval": "day",
"discount_subscribers_limit": null,
"discount_type_amount": null,
"discount_amount": null,
"sort_order": 0,
"active_subscribers_limit": null,
"max_recurrences": null,
"deadline": null,
"production": false,
"active": true,
"subscription_group_id": null,
"user_id": 42,
"office_id": 1,
"commerce_id": 315,
"allow_multiple_subscriptions": false,
"metadata": { "tier": "gold" },
"created_at": "2026-07-31 10:15:00",
"checkout_url": "https://sag.efipay.co/checkout/subscription-gateway/9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f",
"checkout_url_commerce_assign": "https://sag.efipay.co/checkout/subscription-gateway/9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f?commerce_assign=true"
}
],
"first_page_url": "https://sag.efipay.co/api/v1/subscriptions/plan?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "https://sag.efipay.co/api/v1/subscriptions/plan?page=1",
"next_page_url": null,
"path": "https://sag.efipay.co/api/v1/subscriptions/plan",
"per_page": 50,
"prev_page_url": null,
"to": 1,
"total": 1
}

Descripción: Devuelve un plan por su id, como modelo crudo en snake_case.

GET /api/v1/subscriptions/plan/{plan-id}

GEThttps://sag.efipay.co/api/v1/subscriptions/plan/your-plan-id
Ventana de terminal
curl -X GET \
'/api/v1/subscriptions/plan/9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Accept: application/json'
200OK
{
"id": "9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f",
"name": "Newsletter mensual",
"description": "Suscripción general a newsletters, 15 envíos por mes",
"price": 15000,
"currency_type": "COP",
"tax": 19,
"trial_period": 0,
"trial_interval": "day",
"invoice_period": 1,
"invoice_interval": "month",
"grace_period": 3,
"grace_interval": "day",
"production": false,
"active": true,
"subscription_group_id": null,
"office_id": 1,
"commerce_id": 315,
"allow_multiple_subscriptions": false,
"created_at": "2026-07-31 10:15:00",
"checkout_url": "https://sag.efipay.co/checkout/subscription-gateway/9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f",
"checkout_url_commerce_assign": "https://sag.efipay.co/checkout/subscription-gateway/9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f?commerce_assign=true"
}
404Not Found

Descripción: A partir del ID de un grupo, devuelve los planes de ese grupo.

GET /api/v1/subscriptions/plan/group/{group}/{all?}

Los dos segmentos son opcionales y cambian el resultado:

Ruta Devuelve
/plan/group/{group} Solo los planes activos del grupo
/plan/group/{group}/all Todos los planes del grupo, activos e inactivos
/plan/group Los planes activos del comercio, sin filtrar por grupo

Acepta también filter[metadata][clave]=valor para quedarte con los planes cuya metadata coincide exactamente.

GEThttps://sag.efipay.co/api/v1/subscriptions/plan/group/%7Byour-group-id%7D/all
Ventana de terminal
curl -X GET \
'/api/v1/subscriptions/plan/group/9ae9a2e0-bf16-43c7-a052-f448c447c33e/all' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Accept: application/json'
200OK
[
{
"id": "9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f",
"name": "Newsletter mensual",
"price": 15000,
"currency_type": "COP",
"invoice_period": 1,
"invoice_interval": "month",
"production": false,
"active": true,
"subscription_group_id": "9ae9a2e0-bf16-43c7-a052-f448c447c33e",
"created_at": "2026-07-31 10:15:00"
}
]

Descripción: Activa o desactiva un plan. Un plan inactivo no puede usarse para crear nuevas suscripciones, pero las suscripciones existentes siguen cobrándose.

PUT /api/v1/subscriptions/plan/changeActive/{plan-id}

Nombre del campo Descripción Reglas
active Nuevo estado del plan ['required', 'boolean']
PUThttps://sag.efipay.co/api/v1/subscriptions/plan/changeActive/your-plan-id
Ventana de terminal
curl -X PUT \
'/api/v1/subscriptions/plan/changeActive/9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-type: application/json' \
-d '{ "active": false }'
200OK
{
"active": false,
"plan": {
"id": "9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f",
"name": "Newsletter mensual",
"price": 15000,
"currencyType": "COP",
"active": false,
"createdAt": "2026-07-31 10:15:00",
"checkoutUrl": "https://sag.efipay.co/checkout/subscription-gateway/9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f",
"qrCodeSvg": "<svg xmlns=\"http://www.w3.org/2000/svg\" ...></svg>"
}
}

Descripción: Elimina un plan por su id.

DELETE /api/v1/subscriptions/plan/{plan-id}

DELETEhttps://sag.efipay.co/api/v1/subscriptions/plan/your-plan-id
Ventana de terminal
curl -X DELETE \
'/api/v1/subscriptions/plan/9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Accept: application/json'
200OK
{
"deleted": true
}
400Bad Request
{
"message": "El plan tiene suscripciones activas y no puede eliminarse."
}

Las mismas operaciones, con el nombre de Stripe. Comportamiento, parámetros y respuestas son idénticos a los de arriba. Fíjate en que el filtro por grupo usa product en lugar de group.

Listar — GET /api/v1/subscriptions/price (recuerda per_page, que por defecto es 2)

GEThttps://sag.efipay.co/api/v1/subscriptions/price

Obtener uno — GET /api/v1/subscriptions/price/{price-id}

GEThttps://sag.efipay.co/api/v1/subscriptions/price/your-plan-id

Por grupo — GET /api/v1/subscriptions/price/product/{product-id}/{all?}

GEThttps://sag.efipay.co/api/v1/subscriptions/price/product/%7Byour-group-id%7D/all

Crear — POST /api/v1/subscriptions/price

POSThttps://sag.efipay.co/api/v1/subscriptions/price

Actualizar — PUT /api/v1/subscriptions/price/{price-id}

PUThttps://sag.efipay.co/api/v1/subscriptions/price/your-plan-id

Activar / desactivar — PUT /api/v1/subscriptions/price/changeActive/{price-id}

PUThttps://sag.efipay.co/api/v1/subscriptions/price/changeActive/your-plan-id

Eliminar — DELETE /api/v1/subscriptions/price/{price-id}

DELETEhttps://sag.efipay.co/api/v1/subscriptions/price/your-plan-id

Última actualización: