Docs
PTENES Website Sign up

WebhooksRecurrence

Recurrence webhook

This page describes the format of the webhook sent by the platform whenever there is an update to a recurrence or to one of its charges.

Description

The recurrence webhook is sent automatically whenever the status of the recurrence or of a charge changes, letting the integrator's system follow the whole cycle, from creation to cancellation.

It goes to the Subscriptions webhooks registered in the panel and to the notificationUrl you provided at creation.

Timezone Standard

All date and time fields sent in webhooks use the standard ISO 8601 in the timezone UTC (UTC+00:00), ensuring consistency regardless of the integrator's timezone. To avoid discrepancies caused by local time or daylight saving time, it is recommended to keep values in UTC for storage and processing, converting to the local timezone only at the presentation layer.

Optional Webhook Validation

To increase security, webhooks registered directly in the dashboard may include a signature sent in the header X-Signature: <base64-signature>, allowing validation of the authenticity of the received notification. This signature is generated by the platform using HMAC with SHA-256 over the webhook body, in JSON format, using a shared secret WEBHOOK_SECRET and encoded in Base64. The integrator can reproduce the same calculation in their system using the same secret and the received payload. If the generated signature matches the one sent in the header, the webhook is considered legitimate and intact. If they differ, the request may have been altered or not sent by the platform.

This validation is available only for webhooks registered in the dashboard. Webhooks sent to a URL provided dynamically through notificationUrl do not include the X-Signature.

Signature validation is optional, but strongly recommended whenever the webhook is configured through the dashboard to ensure greater communication security.

Notification Endpoint

When provided, the webhook is sent to the URL set in the notificationUrl field at the time the recurrence is created.

The endpoint must be publicly reachable and respond with HTTP 200 to confirm receipt of the notification.

Recurrence notifications can also arrive via in-bound webhook, registered in the panel with the Subscriptions type. A webhook registered as Payments receives no recurrence event.

Recurrence status

The possible values for the status field are:

  • PENDING – Recurrence created, awaiting the payer's authorization or the first charge.
  • ACTIVE – First charge paid. With card it may happen right at creation; with Pix Automático, on the first cycle.
  • CANCELLED – Recurrence ended. No new charge is generated.
  • FAILED – The acquirer declined the card at creation. The recurrence never comes to exist for them.

Charge status

The possible values for the invoice.status field are:

  • SCHEDULED – Charge scheduled for the cycle, not charged yet.
  • PAID – Charge paid. The amount goes into your balance.
  • REJECTED – Charge definitively refused. The recurrence is cancelled with it.

How the two relate

The body has no event field. When the invoice field is null, the notice is about the recurrence. When it is filled, it is about a charge.

The recurrence status follows from the charges:

The charge arrives asThe recurrence becomes
SCHEDULEDNo change
PAID (the first one)ACTIVE
PAID (the following ones)Stays ACTIVE
REJECTEDCANCELLED

To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel.

The recurrence is also cancelled with no charge involved: when the payer declines the authorization, when you call the cancel route, and when the contract is cancelled or paused in the acquirer's panel. In all three the notice arrives with a null invoice, and the charge that was scheduled ends with it, without a notice of its own.

The same notice may arrive more than once, and the scheduling and the payment of a cycle share the same invoice.id. To avoid processing twice, use id + status + invoice.id + invoice.status.

Payload format

The body is the same in every event. What changes are the status and invoice fields.

Pix Automático · JSON
{
  "id": "recr_01HXYZ123ABC456DEF789",
  "amount": 9900,
  "currency": "BRL",
  "method": "PIXAUTOMATIC",
  "status": "ACTIVE",
  "description": "Assinatura mensal",
  "options": {
    "frequency": "MONTHLY",
    "freqInterval": 1,
    "maxPeriods": null
  },
  "customer": {
    "name": "John Doe",
    "taxId": "12345678900",
    "email": "john.doe@example.com",
    "phone": "11999990000"
  },
  "pix": {
    "emv": "00020101021226850014br.gov.bcb.pix2563api.gateway.test/pix/123e4567-e89b-12d3-a456-4266141740005204000053039865802BR6304ABCD",
    "retryPolicy": "THREE_RETRIES_7_DAYS"
  },
  "card": null,
  "invoice": {
    "id": "rinv_01HXYZ987ZYX654",
    "amount": 9900,
    "status": "PAID",
    "e2e": "E1234567890123456789012345678901",
    "refusedMsg": null,
    "periodNumber": 1,
    "periodStart": "2026-01-05",
    "periodEnd": "2026-02-05",
    "paidAt": "2026-01-05T10:15:10.000Z",
    "cancelledAt": null,
    "lastTryAt": "2026-01-05T10:15:08.000Z",
    "createdAt": "2026-01-05T10:12:33.120Z",
    "updatedAt": "2026-01-05T10:15:10.000Z"
  },
  "orderId": null,
  "cancelledAt": null,
  "externalRef": "order_123456",
  "notificationUrl": "https://example.com/webhook/recurrency",
  "metadata": null,
  "createdAt": "2026-01-05T10:12:33.120Z",
  "updatedAt": "2026-01-05T10:15:10.000Z"
}
Recurring card · JSON
{
  "id": "recr_01HXYZ123ABC456DEF789",
  "amount": 4990,
  "currency": "BRL",
  "method": "CREDIT_CARD",
  "status": "CANCELLED",
  "description": "Assinatura mensal",
  "options": {
    "frequency": "MONTHLY",
    "freqInterval": 1,
    "maxPeriods": null
  },
  "customer": {
    "name": "John Doe",
    "taxId": "12345678900",
    "email": "john.doe@example.com",
    "phone": "11999990000"
  },
  "pix": null,
  "card": {
    "brand": "VISA",
    "holder": "JOHN DOE",
    "number": "411111******1111",
    "refusedMsg": null
  },
  "invoice": {
    "id": "rinv_01HXYZ987ZYX654",
    "amount": 4990,
    "status": "REJECTED",
    "e2e": null,
    "refusedMsg": "Cartão sem limite disponível.",
    "periodNumber": 4,
    "periodStart": "2026-04-05",
    "periodEnd": "2026-05-05",
    "paidAt": null,
    "cancelledAt": "2026-04-12T18:45:10.532Z",
    "lastTryAt": "2026-04-12T18:45:10.000Z",
    "createdAt": "2026-01-05T10:12:33.120Z",
    "updatedAt": "2026-04-12T18:45:10.532Z"
  },
  "orderId": null,
  "cancelledAt": "2026-04-12T18:45:10.532Z",
  "externalRef": "order_123456",
  "notificationUrl": "https://example.com/webhook/recurrency",
  "metadata": null,
  "createdAt": "2026-01-05T10:12:33.120Z",
  "updatedAt": "2026-04-12T18:45:10.532Z"
}

Something wrong on this page? Talk to us