# Cupones --- - [Cupones](#cupones) - [¿Qué es un cupón?](#overview) - [Listar cupones](#get-all) - [Obtener un cupón](#get) - [Crear cupón](#create) - [Actualizar cupón](#update) - [Activar / desactivar cupón](#change-active) - [Eliminar cupón](#delete) - [Aplicar a una suscripción](#aplicar) ## ¿Qué es un cupón? [#overview] Los cupones te permiten definir descuentos reutilizables que luego puedes aplicar a las suscripciones. Un cupón puede ser por **porcentaje** (`percent_off`) o por **monto fijo** (`amount_off`), y su **duración** determina por cuánto tiempo se aplica el descuento a la suscripción: | duration | Significado | |-------------|-----------------------------------------------------------------------------| | `once` | Se aplica al ciclo vigente (una vez). | | `repeating` | Se aplica durante `duration_in_months` meses. | | `forever` | Se aplica a todos los cobros mientras la suscripción tenga el cupón. | El campo opcional `code` funciona como un código promocional público que el suscriptor o el comercio usa para redimir el cupón. Reemplaza a los campos `discount_*` del plan (que se mantienen solo por compatibilidad). ## Listar cupones [#get-all] **Descripción:** Lista todos los cupones del comercio. `GET /api/v1/subscriptions/coupon` :::tip Respuesta satisfactoria ::: Código de respuesta: 200 ```json [ { "id": "9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f", "code": "WELCOME10", "name": "Bienvenida", "percent_off": 10, "amount_off": null, "currency": null, "duration": "forever", "duration_in_months": null, "max_redemptions": null, "times_redeemed": 3, "redeem_by": null, "active": true } ] ``` ## Obtener un cupón [#get] **Descripción:** Devuelve un cupón por su `id`. `GET /api/v1/subscriptions/coupon/your-coupon-id` ## Crear cupón [#create] **Descripción:** Crea un cupón. Debes enviar `percent_off` **o** `amount_off` (no ambos). | Nombre del campo | Descripción | Reglas | | - | - | - | | code | Código público que teclea el cliente. Si lo omites, lo generamos. Único dentro de tu comercio | `['nullable', 'string', 'max:64', 'unique:coupons,code']` | | name | Nombre descriptivo, solo para que lo identifiques tú | `['nullable', 'string', 'max:255']` | | percent_off | Descuento porcentual, de 0 a 100. Obligatorio si no envías `amount_off` | `['nullable', 'numeric', 'min:0', 'max:100', 'required_without:amount_off']` | | amount_off | Descuento de monto fijo. Obligatorio si no envías `percent_off` | `['nullable', 'numeric', 'min:0', 'required_without:percent_off']` | | currency | Moneda del `amount_off`, en 3 letras (`COP`) | `['nullable', 'string', 'size:3']` | | duration | Cuánto dura el descuento: `once` un solo cobro, `repeating` durante N meses, `forever` siempre | `['required', 'in:once,repeating,forever']` | | duration_in_months | Meses que dura el descuento. Obligatorio cuando `duration` es `repeating` | `['nullable', 'integer', 'min:1', 'required_if:duration,repeating']` | | max_redemptions | Cuántas veces se puede redimir en total | `['nullable', 'integer', 'min:1']` | | redeem_by | Fecha límite para redimirlo | `['nullable', 'date']` | | active | Si el cupón queda activo al crearse | `['sometimes', 'boolean']` | | office | Sucursal a la que pertenece. Debe ser una de [tus sucursales](/commercio) | `['required', 'exists:offices,id']` | `POST /api/v1/subscriptions/coupon` Cuerpo de ejemplo: ```json { "code": "WELCOME10", "name": "Bienvenida", "percent_off": 10, "duration": "forever", "office": 1 } ``` ```bash curl -X POST\ "/api/v1/subscriptions/coupon"\ -H 'Authorization: Bearer ACCESS_TOKEN' \ -H "Content-type: application/json" \ -d '{ "code": "WELCOME10", "name": "Bienvenida", "percent_off": 10, "duration": "forever", "office": 1 }' ``` :::tip Respuesta satisfactoria ::: Código de respuesta: 200 ```json { "saved": true, "coupon": { "id": "9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f", "code": "WELCOME10", "name": "Bienvenida", "percent_off": 10, "duration": "forever", "active": true, "times_redeemed": 0 } } ``` ## Actualizar cupón [#update] **Descripción:** Actualiza un cupón. Los campos son los mismos que en **Crear cupón**, y `office` también es obligatorio, aunque no se puede cambiar: el cupón se queda en la sucursal donde se creó. `PUT /api/v1/subscriptions/coupon/your-coupon-id` Cuerpo de ejemplo: ```json { "name": "Bienvenida 15%", "percent_off": 15, "duration": "forever" } ``` ## Activar / desactivar cupón [#change-active] **Descripción:** Activa o desactiva un cupón. Un cupón inactivo no puede redimirse. `PUT /api/v1/subscriptions/coupon/changeActive/your-coupon-id` Cuerpo de ejemplo: ```json { "active": false } ``` :::tip Respuesta satisfactoria ::: Código de respuesta: 200 ```json { "updated": true, "coupon": { "id": "9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f", "code": "WELCOME10", "active": false } } ``` ## Eliminar cupón [#delete] **Descripción:** Elimina un cupón. `DELETE /api/v1/subscriptions/coupon/your-coupon-id` :::tip Respuesta satisfactoria ::: Código de respuesta: 200 ```json { "deleted": true } ``` ## Aplicar a una suscripción [#aplicar] `POST /api/v1/subscriptions/subscription/{subscription}/apply-coupon` Aplica un cupón a una suscripción que ya existe. El descuento entra en los cobros recurrentes según la duración del cupón. | Nombre del campo | Descripción | Reglas | | - | - | - | | code | Código del cupón a redimir. Debe existir en tu comercio, estar activo y no haber alcanzado su límite de redenciones ni su `redeem_by` | `['required', 'string']` | `POST /api/v1/subscriptions/subscription/9da5903d-3d1a-4f60-b487-b6b6cd7d9d1b/apply-coupon` Cuerpo de ejemplo: ```json { "code": "WELCOME10" } ``` :::tip Respuesta satisfactoria ::: Código de respuesta: 200 ```json { "applied": true, "coupon_id": "9b0f2a13-2c44-4a1a-9f2e-1d3b4c5d6e7f", "discount_ends_at": "2027-01-31T00:00:00.000000Z" } ``` :::danger Cupón inválido, vencido, agotado o de otro comercio ::: Código de respuesta: 400 ```json { "applied": false, "message": "Cupón inválido o no disponible." } ``` :::note `discount_ends_at` viene en `null` cuando la duración es `forever`: el descuento no expira mientras la suscripción conserve el cupón. :::