Eventos legacy (referencia)

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.*. Si ya integraste con el formato clásico, mirá la guía Migrar a Webhooks Unificados.

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:

1{
2 "id": "pa_id123",
3 "event_type": "payment_intent.succeeded",
4 "api_version": "2024-04-24",
5 "checkout": {
6 "id": "ch_id123",
7 "status": "paid",
8 "payment": {
9 "id": "pa_laybj3zw",
10 "paymentable": {
11 "type": "OneTimePayment",
12 "id": "on_arognqni",
13 "tax_name": null,
14 "tax_id": "12345678",
15 "address": null,
16 "phone_number": "+50255551234"
17 }
18 },
19 "payment_method": {
20 "id": "pay_m_7v5ie3pw",
21 "type": "card",
22 "card": {
23 "last4": "4242",
24 "network": "visa"
25 }
26 },
27 "transfer_setups": [],
28 "metadata": {}
29 },
30 "created_at": "2024-02-16T03:01:13.260Z",
31 "failure_reason": null,
32 "amount_in_cents": 10000,
33 "currency": "GTQ",
34 "fee": 450,
35 "vat_withheld": 160,
36 "vat_withheld_currency": "GTQ",
37 "customer": {
38 "email": "hello@example.com",
39 "full_name": "Max Rodriguez",
40 "id": "us_id123",
41 "nit": "12345678",
42 "phone": "+50255551234"
43 },
44 "product": {
45 "id": "prod_id123"
46 },
47 "invoice": {
48 "id": "inv_123",
49 "tax_invoice_url": null
50 }
51}

payment_intent.failed

Cobro fallido con tarjeta.

Ejemplo de respuesta:

1{
2 "id": "pa_id123",
3 "event_type": "payment_intent.failed",
4 "api_version": "2024-03-13",
5 "checkout": {
6 "id": "ch_id123"
7 },
8 "created_at": "2024-02-16T03:01:13.260Z",
9 "failure_reason": "Tu banco ha rechazado la transacción. Llama a tu banco y pide que autoricen esta transacción.",
10 "amount_in_cents": 10000,
11 "currency": "GTQ",
12 "fee": 0,
13 "vat_withheld": 0,
14 "vat_withheld_currency": "GTQ",
15 "customer": {
16 "email": "hello@example.com",
17 "full_name": "Max Rodriguez",
18 "id": "us_id123"
19 },
20 "product": {
21 "id": "prod_id123"
22 }
23}

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.

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.

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).

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:

1{
2 "api_version": "2024-04-24",
3 "created_at": "2025-10-13T13:59:27.931Z",
4 "customer_email": "example@example.com",
5 "customer_id": "us_1234",
6 "customer_name": "Pedro Pérez",
7 "event_type": "subscription.create",
8 "id": "su_123",
9 "payment": {
10 "id": "pa_123",
11 "paymentable": {
12 "address": null,
13 "id": "su_123",
14 "phone_number": "+50255555555",
15 "tax_id": "",
16 "tax_name": null,
17 "type": "Subscription"
18 }
19 },
20 "product": {
21 "address_requirement": "none",
22 "billing_info_requirement": "optional",
23 "cancel_url": "",
24 "custom_terms_and_conditions": "Términos y condiciones",
25 "description": "Suscripción de prueba",
26 "has_dynamic_pricing": false,
27 "id": "prod_123",
28 "metadata": {},
29 "name": "Plan de Prueba",
30 "phone_requirement": "required",
31 "prices": [
32 {
33 "amount_in_cents": 999,
34 "billing_interval": "month",
35 "billing_interval_count": 1,
36 "charge_type": "recurring",
37 "currency": "GTQ",
38 "free_trial_interval": "month",
39 "free_trial_interval_count": 0,
40 "id": "price_123",
41 "periods_before_automatic_cancellation": null
42 }
43 ],
44 "status": "active",
45 "storefront_link": "https://app.recurrente.com/s/recurrente/plan-de-prueba",
46 "success_url": ""
47 }
48}

subscription.past_due

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

Nota: En una suscripción, cuando un pago falla, Recurrente intenta cobrarlo de nuevo 3 y 5 días después. Si ambos re-intentos son fallidos, en ese momento se cancela la suscripción.

subscription.paused

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 el cobro automático de una suscripción falla por tercera vez.

Nota: En una suscripción, cuando un pago falla, Recurrente intenta cobrarlo de nuevo 3 y 5 días después. Si ambos re-intentos son fallidos, en ese momento se cancela la suscripción.

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.