Pagos Recurrentes
Cobra a tus clientes de forma periodica (mensual, semanal, cada N dias, anual, un dia concreto de cada mes, con o sin fecha de fin) y gestiona todo el ciclo de vida desde tu sistema: alta, consulta, cambios, pausa, reactivacion, cambio de tarjeta y cancelacion.
Nombre tecnico: en la API cada pago recurrente es un recurso
subscription(rutas/subscriptions, idsWEBCODE-SB-xxxxxxxx). En el panel aparecen en Transacciones > Pagos Recurrentes.
| Live | Test | |
|---|---|---|
| URL base | /external/v1/subscriptions | /external/v1/test/subscriptions |
| API key | Key Live | Key Test |
| Pago inicial | Pagina segura real (/pay/...) | Pagina simulada (/pay-subscription-test/...) |
| Cobros recurrentes | Reales, en su fecha | Simulados (en su fecha o al momento con simulate-renewal) |
| Webhooks | URL Live | URL Test (con environment: "test") |
| Visible en el panel | Si (Pagos Recurrentes) | No |
Reglas generales
webcodeobligatorio: en el body en POST/PATCH y en la query en GET. Debe coincidir con el de tu API key.- Solo veras y modificaras los pagos recurrentes de tu webcode y de ese entorno. Cualquier recurso ajeno o del otro entorno responde
404. - Importes siempre en centimos (
2990= 29,90 EUR). Monedas: EUR, USD, GBP. Idempotency-Keyrecomendada en todos los POST y PATCH (ver Autenticacion).
Flujo
POST /subscriptionscrea un link de pago recurrente y devuelvepaymentUrl.- Rediriges a tu cliente a
paymentUrl. Paga el primer importe y se guarda su tarjeta. - Se crea el pago recurrente (
subscriptionId) y recibesSUBSCRIPTION_CREATED. Tambien puedes consultarlo enGET /subscriptions/links/{linkId}(camposubscriptionId). - Avirato cobra cada periodo. Si un cobro falla se reintenta 3 veces (5 h, 8 h y 11 h despues); si sigue fallando el pago recurrente queda pausado (
SUBSCRIPTION_ERROR).
Si el primer pago se rechaza
Se crea igualmente el pago recurrente en estado error (statusReason: initial_payment_failed) y recibes SUBSCRIPTION_FAILED. El link sigue pending y tu cliente puede reintentar con el mismo paymentUrl: cada intento crea un pago recurrente nuevo. El anterior queda en error, nunca se cobra y puedes ignorarlo. El valido es el del webhook SUBSCRIPTION_CREATED, que es tambien el que devuelve el detalle del link. El motivo del rechazo esta en refusalReason de GET /subscriptions/{id}/payments. Igual en Live y en Test.
Intervalos
| Quieres | intervalUnit | intervalCount | Extra |
|---|---|---|---|
| Mensual | month | 1 | — |
| Cada 15 dias | day | 15 | — |
| Cada 2 semanas | week | 2 | — |
| Trimestral | month | 3 | — |
| Anual | year | 1 | — |
| El dia 5 de cada mes | month | 1 | billingDay: 5 |
| Mensual hasta el 31/12/2027 | month | 1 | endAt: "2027-12-31" |
intervalCountminimo 1.billingDay(1-31) solo conmonth. En meses mas cortos se cobra el ultimo dia del mes.endAtfutura (Y-m-doY-m-d H:i:s): el dia de fin ya no se cobra; esa noche el pago recurrente se cancela (statusReason: end_date_reached).initialAmount: primer pago distinto al recurrente (puede ser 0 para solo guardar la tarjeta).
Crear un pago recurrente
POST /external/v1/subscriptions → 201
{
"webcode": "SHOP01",
"amount": { "value": 2990, "currency": "EUR" },
"intervalUnit": "month",
"intervalCount": 1,
"billingDay": 5,
"endAt": "2027-06-30",
"initialAmount": { "value": 990 },
"returnUrl": "https://tu-web.com/pago-recurrente/ok",
"description": "Plan Gold",
"customReference": "PEDIDO-123",
"planCode": "GOLD",
"customerInternalId": "CLI-42",
"customerInternalFolder": "EXP-2026-7",
"customerExtraInfo": "Juan Perez",
"metadata": { "contrato": "C-99" },
"expiresAt": "2026-11-30 23:59:59",
"countryCode": "ES",
"shopperLocale": "es-ES"
}Obligatorios: webcode, amount, intervalUnit, intervalCount, returnUrl (http/https). description maximo 255 caracteres; metadata debe ser un objeto JSON.
{
"success": true,
"data": {
"linkId": "SHOP01-LK-1792068995050",
"environment": "live",
"status": "pending",
"paymentUrl": "https://aviratopayments.com/pay/eyJ0eXAi...",
"subscriptionId": null,
"amount": { "value": 2990, "currency": "EUR" },
"initialAmount": { "value": 990, "currency": "EUR" },
"intervalUnit": "month",
"intervalCount": 1,
"billingDay": 5,
"endAt": "2027-06-30 23:59:59",
"planCode": "GOLD",
"returnUrl": "https://tu-web.com/pago-recurrente/ok",
"expiresAt": "2026-11-30 23:59:59",
"createdAt": "2026-10-15 14:56:35"
}
}Al terminar el pago el cliente vuelve a returnUrl con ?linkId=...&subscriptionId=...&status=success|refused|error. No te fies solo del redirect: confirma con el webhook o consultando el link.
Endpoints
Consultas
| Metodo | Ruta | Descripcion |
|---|---|---|
| GET | /subscriptions?webcode= | Listado. Filtros: status, plan_code, customer_internal_id, customer_internal_folder, created_at_start, created_at_end. Paginacion: take (1-100, def. 20), cursor, order |
| GET | /subscriptions/{id}?webcode= | Detalle. Incluye paymentRetryInfo si hay reintentos en curso y failedPaymentInfo si se pauso por cobro fallido |
| GET | /subscriptions/{id}/payments?webcode= | Historial de pagos (inicial, cambios de tarjeta y recurrentes) con refusalReason si fallaron |
| GET | /subscriptions/{id}/charges?webcode=&status= | Cola de cobros: pendientes, realizados, fallidos, reintentos |
| GET | /subscriptions/links?webcode=&status= | Links de pago recurrente (pending, redeemed, expired, cancelled) |
| GET | /subscriptions/links/{linkId}?webcode= | Detalle del link (tras el pago incluye subscriptionId) |
Ciclo de vida (body siempre con webcode)
| Metodo | Ruta | Body | Reglas |
|---|---|---|---|
| PATCH | /subscriptions/{id} | amount, intervalUnit, intervalCount, billingDay, endAt (null = sin fin), nextChargeDate, planCode, customerExtraInfo, customerInternalId, customerInternalFolder, autoRenew, metadata | No se puede modificar uno cancelado. Al cambiar importe o fechas se ajusta el siguiente cobro y la baja programada |
| POST | /subscriptions/{id}/pause | — | Solo activos. Anula el cobro pendiente |
| POST | /subscriptions/{id}/reactivate | chargeImmediately (bool, def. true) | Desde paused o error. Uno cancelado no se reactiva |
| POST | /subscriptions/{id}/update-card | returnUrl, countryCode? (def. ES), shopperLocale? (def. es-ES) | Desde paused, error o pendingNewCard. Devuelve paymentUrl para que el cliente pague con su nueva tarjeta; al pagar se reactiva |
| POST | /subscriptions/{id}/cancel | reason? (a-z, 0-9 y _; def. cancelled_by_client) | Definitivo: anula cobros pendientes y no se puede reactivar |
| POST | /subscriptions/links/{linkId}/cancel | — | Solo links no pagados |
Estados y acciones permitidas
| Estado | Significado | Puedes |
|---|---|---|
active | Cobrando con normalidad | Modificar, pausar, cancelar |
paused | Pausado por ti (paused_by_client) o tras agotar los reintentos (payment_failed_max_retries) | Reactivar (tarjeta actual), cambiar tarjeta, modificar, cancelar |
error | Fallo el primer pago o el pago con la nueva tarjeta | Reactivar, cambiar tarjeta, cancelar |
pendingNewCard | Esperando a que el cliente pague con su nueva tarjeta | Generar otro link (update-card), cancelar |
cancelled | Cancelado por ti o fin por endAt (end_date_reached) | Nada (definitivo) |
Entorno Test
Todo funciona igual que en Live pero sin dinero real. Los pagos recurrentes de test no aparecen en el panel; consultalos con la API.
Pago inicial: abre paymentUrl (/pay-subscription-test/...) y usa cualquier tarjeta valida (p. ej. 4111 1111 1111 1111, fecha futura en formato MM/AA, CVC 737). El titular decide el resultado:
| Titular | Resultado |
|---|---|
| Cualquier nombre | Pago correcto |
DECLINED, CARD_EXPIRED, NOT_ENOUGH_BALANCE, CVC_DECLINED, FRAUD, INVALID_CARD | Rechazado |
ERROR | Error del procesador |
Simuladores (solo /external/v1/test/...), body { "webcode", "result" } con result: success (def.), declined, not_enough_balance, card_expired, error:
| Metodo | Ruta | Que hace |
|---|---|---|
| POST | /test/subscriptions/links/{linkId}/simulate-checkout | Completa el pago inicial (o el de cambio de tarjeta) sin abrir la pagina |
| POST | /test/subscriptions/{id}/simulate-renewal | Ejecuta ya el siguiente cobro con ese resultado (reintentos, pausa tras 3 fallos, siguiente ciclo y webhooks como en Live) |
| POST | /test/subscriptions/{id}/simulate-end | Da de baja el pago recurrente como si hubiera llegado su endAt |
Webhooks
Eventos SUBSCRIPTION_CREATED, SUBSCRIPTION_RENEWED, SUBSCRIPTION_FAILED, SUBSCRIPTION_ERROR, SUBSCRIPTION_PAUSED, SUBSCRIPTION_REACTIVATED, SUBSCRIPTION_CANCELLED y SUBSCRIPTION_CARD_UPDATED. Formato y ejemplos en Webhooks.
Errores habituales
Ver Errores > Pagos recurrentes. Resumen: 400 validacion o accion no permitida en el estado actual, 403 key/webcode/entorno, 404 no existe para tu webcode y entorno, 409 Idempotency-Key reutilizada.