> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.recurrente.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.recurrente.com/_mcp/server.

# Eventos legacy (referencia)

> Formato clásico de webhooks por tipo de pago

> **Warning**
>
> Este es el **formato clásico por tipo** de los webhooks (`payment_intent.*`, `bank_transfer_intent.*`, etc.). Sigue funcionando sin cambios para integraciones existentes, pero para integraciones nuevas usá el [formato unificado `intent.*`](/guias-espanol/comenzar/webhooks). Si ya integraste con el formato clásico, mirá la guía [Migrar a Webhooks Unificados](/guias-espanol/guias/migrar-a-webhooks-unificados).
>
> Las cuentas nuevas no reciben los duplicados legacy que tienen reemplazo unificado. Los eventos sin reemplazo siguen llegando. La compatibilidad se conserva por cuenta receptora, no por fecha de creación del endpoint.

En el formato clásico, cada método de pago emite su propio evento con una estructura distinta. Tu handler tiene que ramificar por el nombre del evento (`event_type`) y parsear una forma diferente por tipo.

## Eventos de pago por tipo

### payment_intent.succeeded

Se emite con un cobro exitoso con tarjeta (crédito o débito). Los fondos ya están en tu balance de Recurrente.

Para **pagos presenciales** (POS, mobile POS y stablecoins), este webhook se envía después de que el cajero completa el paso de captura de datos del cliente (NIT, teléfono, email), para que el payload incluya la información completa del cliente. Esto suele agregar unos segundos de delay después del pago.

*Ejemplo de respuesta:*

```json
{
  "id": "pa_id123",
  "event_type": "payment_intent.succeeded",
  "api_version": "2024-04-24",
  "checkout": {
    "id": "ch_id123",
    "status": "paid",
    "payment": {
      "id": "pa_laybj3zw",
      "paymentable": {
        "type": "OneTimePayment",
        "id": "on_arognqni",
        "tax_name": null,
        "tax_id": "12345678",
        "address": null,
        "phone_number": "+50255551234"
      }
    },
    "payment_method": {
      "id": "pay_m_7v5ie3pw",
      "type": "card",
      "card": {
        "last4": "4242",
        "network": "visa"
      }
    },
    "transfer_setups": [],
    "metadata": {}
  },
  "created_at": "2024-02-16T03:01:13.260Z",
  "failure_reason": null,
  "amount_in_cents": 10000,
  "currency": "GTQ",
  "fee": 450,
  "vat_withheld": 160,
  "vat_withheld_currency": "GTQ",
  "customer": {
    "email": "hello@example.com",
    "full_name": "Max Rodriguez",
    "id": "us_id123",
    "nit": "12345678",
    "phone": "+50255551234"
  },
  "product": {
    "id": "prod_id123"
  },
  "invoice": {
    "id": "inv_123",
    "tax_invoice_url": null
  }
}
```

### payment_intent.failed

Cobro fallido con tarjeta.

*Ejemplo de respuesta:*

```json
{
  "id": "pa_id123",
  "event_type": "payment_intent.failed",
  "api_version": "2024-03-13",
  "checkout": {
    "id": "ch_id123"
  },
  "created_at": "2024-02-16T03:01:13.260Z",
  "failure_reason": "Tu banco ha rechazado la transacción. Llama a tu banco y pide que autoricen esta transacción.",
  "amount_in_cents": 10000,
  "currency": "GTQ",
  "fee": 0,
  "vat_withheld": 0,
  "vat_withheld_currency": "GTQ",
  "customer": {
    "email": "hello@example.com",
    "full_name": "Max Rodriguez",
    "id": "us_id123"
  },
  "product": {
    "id": "prod_id123"
  }
}
```

### bank_transfer_intent.pending

Se emite cuando se inicia un cobro con transferencia bancaria. En cuanto se reciba el dinero en la cuenta, se emitirá `bank_transfer_intent.succeeded`. De lo contrario, se emitirá `bank_transfer_intent.failed`.

### bank_transfer_intent.succeeded

Se emite con un cobro exitoso con transferencia bancaria. Los fondos ya están en tu balance de Recurrente.

El payload incluye `bank_reference` (referencia de la transferencia asignada por el banco o la red de pago) y `sender_comment` (comentario libre que el pagador escribió en la transferencia), útiles para conciliar contra tu estado de cuenta.

### bank_transfer_intent.failed

Se emite con un cobro fallido con transferencia bancaria. Esto sucede cuando no se reciben los fondos en la cuenta de banco, o se recibe el monto incorrecto.

### Pagos en efectivo con referencia

Las cuentas habilitadas pueden recibir `akisi_intent.pending` cuando se genera una referencia para un cobro único en GTQ, `akisi_intent.succeeded` cuando el punto confirma el pago, `akisi_intent.canceled` cuando el punto anula un pago confirmado y `akisi_intent.failed` cuando la referencia vence sin pago. Todos incluyen la `reference` de 12 dígitos y su `expires_at`. `akisi_intent.update` se emite al actualizar el intento y no equivale a una confirmación de pago. Una referencia pendiente no equivale a un pago completado.

Estos eventos no tienen reemplazo unificado `intent.*` y se entregan tanto a cuentas nuevas como existentes. Usan el payload estándar de intents legacy, con `checkout`, `payment`, `customer`, `amount_in_cents`, `currency`, `product` y `tax_invoice_url`. El payload del webhook no incluye la referencia ni su vencimiento.

### balance_intent.succeeded

Se emite con un cobro exitoso pagado con el balance de Recurrente del cliente. Los fondos ya están en tu balance. Este evento llega a la cuenta del comercio (la que cobró).

### balance_intent.paid

Se emite a la cuenta del pagador (la cuenta cuyo balance fue debitado) cuando paga exitosamente un checkout usando su balance de Recurrente. Solo lo recibes si configuraste un endpoint de webhook en la cuenta pagadora.

*Nota: un mismo cobro con balance dispara dos webhooks independientes: `balance_intent.succeeded` al comercio y `balance_intent.paid` al pagador. El payload sigue la misma estructura que `bank_transfer_intent.succeeded` (incluye `checkout`, `payment`, `customer`, `amount_in_cents`, `currency`, `product`, `tax_invoice_url`).*

Los eventos `akisi_intent.pending`, `akisi_intent.succeeded`, `akisi_intent.canceled`, `akisi_intent.failed` y `akisi_intent.update` pueden probarse como fixtures. Eso no genera una referencia de efectivo, no confirma un pago ni modifica el balance; el flujo de pago en puntos no está disponible en Sandbox.

## Eventos de suscripción

### subscription.create

Si el producto es recurrente, se emite además del payment.succeeded este evento con la información de la suscripción.

*Ejemplo de respuesta:*

```json
{
  "api_version": "2024-04-24",
  "created_at": "2025-10-13T13:59:27.931Z",
  "customer_email": "example@example.com",
  "customer_id": "us_1234",
  "customer_name": "Pedro Pérez",
  "event_type": "subscription.create",
  "id": "su_123",
  "payment": {
    "id": "pa_123",
    "paymentable": {
      "address": null,
      "id": "su_123",
      "phone_number": "+50255555555",
      "tax_id": "",
      "tax_name": null,
      "type": "Subscription"
    }
  },
  "product": {
    "address_requirement": "none",
    "billing_info_requirement": "optional",
    "cancel_url": "",
    "custom_terms_and_conditions": "Términos y condiciones",
    "description": "Suscripción de prueba",
    "has_dynamic_pricing": false,
    "id": "prod_123",
    "metadata": {},
    "name": "Plan de Prueba",
    "phone_requirement": "required",
    "prices": [
      {
        "amount_in_cents": 999,
        "billing_interval": "month",
        "billing_interval_count": 1,
        "charge_type": "recurring",
        "currency": "GTQ",
        "free_trial_interval": "month",
        "free_trial_interval_count": 0,
        "id": "price_123",
        "periods_before_automatic_cancellation": null
      }
    ],
    "status": "active",
    "storefront_link": "https://app.recurrente.com/s/recurrente/plan-de-prueba",
    "success_url": ""
  }
}
```

### subscription.past_due

Se emite cuando el cobro automático de una suscripción falla por primera vez.

Los reintentos de cobro son diarios, hasta un máximo de **15 intentos totales por período: el intento inicial y hasta 14 reintentos**. Cada siguiente intento se programa un día después del fallo anterior. Si un intento tiene éxito, se detienen los reintentos de ese período; si falla el intento número 15, la suscripción se cancela automáticamente.

Consulta `next_payment_attempt_at` en `GET /api/subscriptions/{id}` para conocer la próxima fecha programada, sin asumir una hora exacta de ejecución.

### subscription.pause

Se emite cuando se pausa la suscripción. Una suscripción pausada no se volverá a cobrar hasta que sea reactivada.

### subscription.cancel

Se emite cuando se cancela una suscripción. Esto incluye la cancelación automática cuando fallan los 15 intentos de cobro del período, según el calendario descrito en `subscription.past_due`.

## Otros eventos

### setup_intent.succeeded

Se emite cuando se inicia exitosamente una suscripción con un período de prueba. También se emite cuando se tokeniza una tarjeta sin cobrarla.

### setup_intent.cancelled

Se emite cuando no se logra tokenizar una tarjeta sin cobrarla. Esto sucede cuando el primer pago de una suscripción con período de prueba, falla.