> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cativa.digital/llms.txt
> Use this file to discover all available pages before exploring further.

# paywall_payment_completed

> Fired when the gateway confirms a paywall payment — the right moment to grant access in external systems.

This event fires **as soon as the payment gateway (Asaas, Stripe, etc.) confirms a paywall payment**. It's the canonical moment to sync access in external systems (legacy member area, course platform, ERP), since internally Cativa also uses this same event to grant the user a badge/group/course.

<Note>
  The internal event name (used when subscribing webhooks in the Console) is `paywall_payment_completed`.
</Note>

## When it fires

* Payment gateway (Asaas, Stripe) sends the confirmation callback to Cativa
* A PIX payment clears
* A boleto charge clears
* A credit-card charge is captured successfully
* A manual payment is marked as confirmed in the admin

## When it does NOT fire

* Payment created but still **pending** (PIX generated and not paid, boleto not yet due, etc.)
* Payment **failed** or **cancelled** by the gateway
* Payment refunded after it had been confirmed
* Payment without a resolved `UserId` (e.g. PIX where the payer hasn't been associated with a tenant user yet) — delivery is skipped
* Paywall or payment not found while enriching the payload (delivery is skipped)

## Payload

The payload is serialized in **PascalCase** and delivered in the body of the `POST` with `Content-Type: application/json`. The payload has three nested objects — `User`, `Paywall` and `Payment`:

```json theme={null}
{
  "CustomerId": "01HQ0ABCDEF1234567890XYZ",
  "User": {
    "Id": "01HQ7Z3X4Y5Z6A7B8C9D0E1F2G",
    "Email": "mary@example.com",
    "FirstName": "Mary",
    "LastName": "Smith",
    "DisplayName": "Mary Smith",
    "Username": "mary.smith",
    "CreatedAt": "2026-04-12T14:32:01Z"
  },
  "Paywall": {
    "Id": "01HQ5PAYWALL1234567890ABC",
    "Name": "Premium Mentorship 2026",
    "Description": "12 months of access to mentorship, exclusive courses and the VIP group.",
    "CustomLink": "premium-mentorship-2026",
    "FullUrl": "https://community.example.com/pagamento/premium-mentorship-2026",
    "Price": 1497.00,
    "DiscountPercentage": 10,
    "MaxInstallments": 12,
    "AccessMonths": 12,
    "RemoveAfterExpiration": true,
    "ActionType": 5,
    "ActionPayload": "01HQ4ABCDEF1234567890XYZ",
    "ImageUrl": "https://cdn.cativalab.digital/paywall/01HQ5.../cover.jpg",
    "OpeningLink": "https://community.example.com/welcome-mentorship"
  },
  "Payment": {
    "PaymentId": "01HQ9PAYMENT1234567890XYZ",
    "ValorPago": 1347.30,
    "ValorOriginal": 1497.00,
    "Desconto": 10,
    "Installments": 12,
    "TipoPagamento": "CREDIT_CARD",
    "Gateway": "Asaas",
    "IdTransacao": "pay_5478392a01b2c3d4e5f6",
    "CompletedAt": "2026-05-08T14:32:01Z"
  }
}
```

### Payload fields

#### Root

| Field        | Type   | Description                                 |
| ------------ | ------ | ------------------------------------------- |
| `CustomerId` | GUID   | ID of the tenant that emitted the event.    |
| `User`       | object | Buyer information.                          |
| `Paywall`    | object | Configuration of the paywall that was paid. |
| `Payment`    | object | Details of the confirmed payment.           |

#### `User`

| Field              | Type     | Description                              |
| ------------------ | -------- | ---------------------------------------- |
| `User.Id`          | GUID     | ID of the buyer.                         |
| `User.Email`       | string   | Buyer email.                             |
| `User.FirstName`   | string   | First name.                              |
| `User.LastName`    | string   | Last name.                               |
| `User.DisplayName` | string   | Display name.                            |
| `User.Username`    | string   | Username.                                |
| `User.CreatedAt`   | ISO 8601 | When the user was created in the tenant. |

#### `Paywall`

| Field                           | Type           | Description                                                                                                           |
| ------------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------- |
| `Paywall.Id`                    | GUID           | Paywall ID.                                                                                                           |
| `Paywall.Name`                  | string         | Configured name of the paywall.                                                                                       |
| `Paywall.Description`           | string \| null | Free-text description, when provided.                                                                                 |
| `Paywall.CustomLink`            | string         | Slug used in the public paywall URL.                                                                                  |
| `Paywall.FullUrl`               | string \| null | Full public checkout URL (`{tenant-origin}/pagamento/{CustomLink}`). `null` when the tenant has no origin configured. |
| `Paywall.Price`                 | decimal        | Configured full price (in the tenant's currency — usually BRL).                                                       |
| `Paywall.DiscountPercentage`    | int            | Discount percentage active on the paywall (0-100).                                                                    |
| `Paywall.MaxInstallments`       | int            | Maximum number of installments allowed by the paywall.                                                                |
| `Paywall.AccessMonths`          | int \| null    | Number of months of access granted by the purchase. `null` for lifetime access.                                       |
| `Paywall.RemoveAfterExpiration` | bool           | If `true`, access is automatically removed when `AccessMonths` expires.                                               |
| `Paywall.ActionType`            | int            | Action executed after payment (see table below).                                                                      |
| `Paywall.ActionPayload`         | string \| null | Payload tied to `ActionType` — typically an ID (badge, course or group) or JSON, depending on the type.               |
| `Paywall.ImageUrl`              | string \| null | Cover image of the paywall, when configured.                                                                          |
| `Paywall.OpeningLink`           | string \| null | Link the user is redirected to after purchase, when configured.                                                       |

`Paywall.ActionType` follows the enum:

| Value | Meaning                                                       | `ActionPayload`                  |
| ----- | ------------------------------------------------------------- | -------------------------------- |
| `0`   | `CreateUserOnly` — only registers the user, no access granted | empty                            |
| `1`   | `AddToCourse` — enrolls in a course                           | `CourseId` (GUID)                |
| `2`   | `GrantBadge` — assigns a badge                                | `BadgeId` (GUID)                 |
| `3`   | `AddToGroup` — adds to a group                                | `GroupId` (GUID)                 |
| `4`   | `AddToCourseAndGrantBadge`                                    | JSON with `CourseId` + `BadgeId` |
| `5`   | `AddToGroupAndGrantBadge`                                     | JSON with `GroupId` + `BadgeId`  |
| `6`   | `None` — no automatic action                                  | empty                            |

#### `Payment`

| Field                   | Type     | Description                                                                                       |
| ----------------------- | -------- | ------------------------------------------------------------------------------------------------- |
| `Payment.PaymentId`     | GUID     | ID of the confirmed payment.                                                                      |
| `Payment.ValorPago`     | decimal  | Amount actually paid after discounts.                                                             |
| `Payment.ValorOriginal` | decimal  | Full paywall price before discounts.                                                              |
| `Payment.Desconto`      | int      | Discount percentage applied to this payment (0-100).                                              |
| `Payment.Installments`  | int      | Number of installments chosen by the buyer.                                                       |
| `Payment.TipoPagamento` | string   | Payment method — typical values: `PIX`, `CREDIT_CARD`, `BOLETO`. Normalized to uppercase.         |
| `Payment.Gateway`       | string   | Gateway that processed the payment (e.g. `Asaas`, `Stripe`). Empty string if not provided.        |
| `Payment.IdTransacao`   | string   | External transaction ID at the gateway (use it for reconciliation). Empty string if not provided. |
| `Payment.CompletedAt`   | ISO 8601 | Moment when the payment was confirmed.                                                            |

<Note>
  The Portuguese-named fields (`ValorPago`, `ValorOriginal`, `Desconto`, `TipoPagamento`, `IdTransacao`) are inherited from v1 of the platform and kept for compatibility with existing Make/Zapier integrations. They will not be renamed.
</Note>

## Request headers

| Header                   | Description                                                                                                            |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `X-Cativa-Signature`     | HMAC-SHA256 signature of the delivery, in the format `t=<unixTs>,v1=<hex>`. **Verify it before processing the event.** |
| `X-Cativa-Execution-Id`  | Unique ID of this event. Stable across retries — use it as your idempotency key.                                       |
| `X-Cativa-Automation-Id` | ID of the listener configured in the Console (same value across all deliveries from the same subscription).            |

The full explanation of how to verify `X-Cativa-Signature`, handle retries and ensure idempotency (with examples in Node, Python, Go and C#) lives in [Subscribing and verifying webhooks](/en/webhooks/subscribing-and-verifying).

## Use cases

* **Grant access in an external platform** — if you still host part of the content outside Cativa (legacy member area, Hotmart, Memberkit), use `Payment.PaymentId` + `User.Id` to provision access there as soon as the payment is confirmed.
* **Financial reconciliation** — record `Payment.IdTransacao` + `Payment.Gateway` + `Payment.ValorPago` in your ERP/accounting to close the books per gateway.
* **Send a transactional email** — fire a receipt, invoice or "purchase confirmed" welcome message using `User.Email`, `Paywall.Name`, `Payment.ValorPago` and `Payment.Installments`.

<Warning>
  This event fires **once per confirmed payment** — it does **not** fire on automatic subscription renewal (recurring billing is not yet in production). Don't treat this event as a renewal trigger.
</Warning>

## Related events

<CardGroup cols={2}>
  <Card title="user_received_badge" icon="shield-check" href="/en/webhooks/events/user-received-badge">
    Fired when the paywall grants a badge — useful to pair the granted permission with the payment.
  </Card>

  <Card title="user_joined_group" icon="users" href="/en/webhooks/events/user-joined-group">
    Fired when the paywall adds the buyer to a group (ActionType 3 or 5).
  </Card>

  <Card title="Subscribing to webhooks" icon="webhook" href="/en/webhooks/subscribing-and-verifying">
    How to register listeners, verify HMAC and handle retries.
  </Card>

  <Card title="Webhooks (overview)" icon="rectangle-history" href="/en/concepts/webhooks">
    Why webhooks, delivery guarantees and payload format.
  </Card>
</CardGroup>
