Webhooks

Webhooks

Webhooks notify your application in real-time when events happen — payments, subscription changes, refunds, and more.

Setting Up Webhooks

Via Dashboard

To activate webhooks for your account, within your Recurrente account, go to:

SettingsDevelopers and API.

There click on “Webhooks”, and continue to add the endpoint where you want the requests to be sent.

Via API

$curl -X POST https://app.recurrente.com/api/webhook_endpoints \
> -H "X-PUBLIC-KEY: ..." \
> -H "X-SECRET-KEY: ..." \
> -H "Content-Type: application/json" \
> -d '{
> "url": "https://yoursite.com/webhooks/recurrente",
> "description": "Production webhook"
> }'

Webhook Event Types

Recurrente sends webhooks for the following events:

payment_intent.succeeded

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

Example response:

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": null,
15 "address": null,
16 "phone_number": null
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 },
42 "product": {
43 "id": "prod_id123"
44 },
45 "invoice": {
46 "id": "inv_123",
47 "tax_invoice_url": null
48 }
49}

payment_intent.failed

Failed card charge.

Example response:

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

subscription.create

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

Example response:

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": "Terms and conditions",
25 "description": "Test subscription",
26 "has_dynamic_pricing": false,
27 "id": "prod_123",
28 "metadata": {},
29 "name": "Test Plan",
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/test-plan",
46 "success_url": ""
47 }
48}

subscription.past_due

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

Note: In a subscription, when a payment fails, Recurrente attempts to charge it again 3 and 5 days later. If both retry attempts fail, the subscription is canceled at that time.

subscription.paused

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

subscription.cancel

Emitted when a subscription’s automatic charge fails for the third time.

Note: In a subscription, when a payment fails, Recurrente attempts to charge it again 3 and 5 days later. If both retry attempts fail, the subscription is canceled at that time.

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.

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.

Webhook Payload

Each webhook POST includes a JSON body with the event data. The structure varies by event type.

Best Practices

  • Return 2xx quickly — Acknowledge receipt before doing heavy processing
  • Handle duplicates — Webhooks may be delivered more than once; use the event ID for idempotency
  • Verify the source — Validate that requests come from Recurrente’s servers
  • Process asynchronously — Use a queue for heavy processing after acknowledging receipt

Retries

If your endpoint doesn’t respond with a 2xx code, Recurrente will retry sending the webhook:

  • Immediately after the first failure
  • 1 minute later
  • 5 minutes later
  • 30 minutes later
  • 2 hours later
  • 6 hours later