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

# Legacy events (reference)

> Classic per-payment-type webhook format

> **Warning**
>
> This is the **classic per-type** webhook format (`payment_intent.*`, `bank_transfer_intent.*`, etc.). It keeps working unchanged for existing integrations, but for new integrations use the [unified `intent.*` format](/guides-english/getting-started/webhooks). If you already integrated with the classic format, see the [Migrate to Unified Webhooks](/guides-english/guides/migrate-to-unified-webhooks) guide.
>
> New accounts do not receive legacy duplicates that have a unified replacement. Events without a replacement are still delivered. Compatibility follows the receiving account, not the endpoint creation date.

In the classic format, each payment method emits its own event with a different structure. Your handler has to branch on the event name (`event_type`) and parse a different shape per type.

## Per-type payment events

### payment_intent.succeeded

Emitted with a successful card charge (credit or debit). The funds are already in your Recurrente balance.

For **in-person payments** (POS, mobile POS, and stablecoins), this webhook is sent after the cashier completes the customer data collection step (NIT, phone, email), so that the payload includes the full customer information. This typically adds a few seconds of delay after the payment itself.

*Example response:*

```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

Failed card charge.

*Example response:*

```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": "Your bank has rejected the transaction. Call your bank and ask them to authorize this transaction.",
  "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

Emitted when a bank transfer charge is initiated. As soon as the money is received in the account, `bank_transfer_intent.succeeded` will be emitted. Otherwise, `bank_transfer_intent.failed` will be emitted.

### bank_transfer_intent.succeeded

Emitted with a successful bank transfer charge. The funds are already in your Recurrente balance.

### bank_transfer_intent.failed

Emitted with a failed bank transfer charge. This happens when the funds are not received in the bank account, or the wrong amount is received.

### Cash reference payments

Eligible accounts may receive `akisi_intent.pending` when a one-time GTQ cash reference is generated, `akisi_intent.succeeded` when the counter confirms payment, `akisi_intent.canceled` when the counter reverses a confirmed payment, and `akisi_intent.failed` when the reference expires unpaid. Every one carries the 12-digit `reference` and its `expires_at`. `akisi_intent.update` is emitted when the intent is updated and is not payment confirmation. A pending reference is not a completed payment.

These events have no unified `intent.*` replacement and are delivered to both new and existing accounts. They use the standard legacy intent payload, including `checkout`, `payment`, `customer`, `amount_in_cents`, `currency`, `product`, and `tax_invoice_url`. The reference and expiration time are not included in the webhook payload.

The Sandbox webhook helper can emit these events as fixtures only. It does not generate cash references, confirm payments, or change balances; counter payments are unavailable in Sandbox.

### balance_intent.succeeded

Emitted with a successful charge paid using the customer's Recurrente balance. The funds are already in your Recurrente balance. This event is delivered to the merchant account (the account that received the payment).

### balance_intent.paid

Emitted to the payer account (the account whose balance was debited) when it successfully pays a checkout using its Recurrente balance. You only receive it if the payer account has a webhook endpoint configured.

*Note: a single balance-paid charge triggers two independent webhook deliveries: `balance_intent.succeeded` to the merchant and `balance_intent.paid` to the payer. The payload follows the same shape as `bank_transfer_intent.succeeded` (includes `checkout`, `payment`, `customer`, `amount_in_cents`, `currency`, `product`, `tax_invoice_url`).*

## Subscription events

### subscription.create

If the product is recurring, this event is emitted in addition to payment.succeeded with the subscription information.

*Example response:*

```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": "Terms and conditions",
    "description": "Test subscription",
    "has_dynamic_pricing": false,
    "id": "prod_123",
    "metadata": {},
    "name": "Test Plan",
    "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/test-plan",
    "success_url": ""
  }
}
```

### subscription.past_due

Emitted when a subscription's automatic charge fails for the first time.

Payment retries run daily, up to **15 total attempts per billing period: the initial attempt and up to 14 retries**. Each next attempt is scheduled one day after the previous failure. A successful payment stops retries for that period; if attempt 15 fails, the subscription is automatically canceled.

Read `next_payment_attempt_at` in `GET /api/subscriptions/{id}` for the next scheduled attempt, rather than assuming an exact execution time.

### subscription.pause

Emitted when a subscription is paused. A paused subscription will not be charged again until it is reactivated.

### subscription.cancel

Emitted when a subscription is canceled. This includes automatic cancellation after all 15 payment attempts for the period fail, following the schedule described under `subscription.past_due`.

## Other events

### setup_intent.succeeded

Emitted when a subscription with a trial period is successfully initiated. Also emitted when a card is tokenized without charging it.

### setup_intent.cancelled

Emitted when a card cannot be tokenized without charging it. This happens when the first payment of a subscription with a trial period fails.