# Subscription Status Webhooks

Receive real-time updates about subscription lifecycle events

The **Subscription Status Webhook** notifies your server whenever a subscriber’s status changes, including new subscriptions, renewals, grace transitions, cancellations, reactivations, and quantity/package updates.

Use this webhook to keep your internal user access logic, CRM, analytics systems, and billing dashboards fully synchronized with Zotlo lifecycle events.

## **When This Is Triggered**

You will receive a callback when any of the following events occur:

| Event Type          | Description                                         |
| ------------------- | --------------------------------------------------- |
| **newSubscriber**   | A new subscription has been created (trial or paid) |
| **renewal**         | A subscription has successfully renewed             |
| **activeToGrace**   | Renewal failed → subscriber moved to grace period   |
| **graceToActive**   | A retry succeeded → subscriber returned to active   |
| **graceToPassive**  | All retries failed → subscription became passive    |
| **cancel**          | Subscription canceled by user, merchant, or system  |
| **reactivate**      | A canceled subscription was reactivated             |
| **package\_update** | The subscriber upgraded or downgraded their plan    |

## **Webhook Structure**

Every Subscription Status webhook contains two main sections:

* **queue** → event metadata
* **parameters** → full subscription profile and changes

## Example Payload

{% code overflow="wrap" %}

```json
{
  "queue": {
    "type": "SubscriberUpdate",
    "eventType": "newSubscriber",
    "requestID": "5a33b022-b877-4888-9eed-89a294640a3c",
    "createDate": {
      "date": "2024-05-13 08:18:22.978000",
      "timezone_type": 3,
      "timezone": "UTC"
    },
    "appId": 1651
  },
  "parameters": {
    "profile": {
      "status": "active",
      "realStatus": "active",
      "subscriberId": "testwebhook@mail.com",
      "subscriptionId": 10414,
      "subscriptionType": "trial",
      "startDate": "2024-05-13 08:18:22",
      "expireDate": "2024-05-16 08:18:22",
      "renewalDate": "2024-05-16 08:18:22",
      "package": "paypal_test",
      "country": "US",
      "phoneNumber": null,
      "language": "en",
      "originalTransactionId": "bfe87fcd-72f7-4902-88ba-b2695c829590",
      "lastTransactionId": "bfe87fcd-72f7-4902-88b2695c829590",
      "subscriptionPackageType": "single",
      "cancellation": null,
      "customParameters": {
        "clientUuid": "5adf7031-34f3-402b-88fc-2fe8cc87d0af"
      },
      "quantity": 1,
      "pendingQuantity": 0,
      "renewalFetchCount": 0
    },
    "package": {
      "packageId": "pro_test",
      "price": 1,
      "currency": "USD",
      "packageType": "subscription",
      "name": "pro_test",
      "subscriptionPackageType": "single",
      "bundlePackages": []
    },
    "newPackage": null,
    "card": {
      "cardNumber": "41111111****1111",
      "expireDate": "06/2024",
      "tokenId": 11082
    },
    "customer": null,
    "package_update": 0
  }
}
```

{% endcode %}

## **Field Reference**

#### **queue**

Metadata describing the event:

| Field                | Description                                                       |
| -------------------- | ----------------------------------------------------------------- |
| **queue.type**       | Always `SubscriberUpdate`                                         |
| **queue.eventType**  | Type of subscription event (renewal, cancel, newSubscriber, etc.) |
| **queue.requestID**  | Unique identifier for this webhook call                           |
| **queue.createDate** | Timestamp of the event                                            |
| **queue.appId**      | ID of the project where the transaction occurred                  |

#### **parameters.profile**

Current subscription profile and lifecycle state:

| Field                     | Description                                                                          |
| ------------------------- | ------------------------------------------------------------------------------------ |
| **status**                | Current status → `active`, `grace`, or `passive`                                     |
| **realStatus**            | The true state (canceled users return `passive` immediately even if cycle not ended) |
| **subscriptionType**      | `trial` or `paid`                                                                    |
| **subscriberId**          | Unique identifier sent during purchase (email or phone)                              |
| **subscriptionId**        | Internal Zotlo subscription record ID                                                |
| **startDate**             | Subscription start date                                                              |
| **expireDate**            | Access expiration date                                                               |
| **renewalDate**           | Scheduled next billing attempt                                                       |
| **package**               | Current packageId                                                                    |
| **originalTransactionId** | First purchase transactionId                                                         |
| **lastTransactionId**     | Latest successful payment transactionId                                              |
| **country**               | Subscriber’s country                                                                 |
| **language**              | Subscriber’s preferred language                                                      |
| **cancellation**          | Cancellation details if subscription was canceled                                    |
| **quantity**              | Current billable quantity                                                            |
| **pendingQuantity**       | Quantity change that will apply on next renewal                                      |
| **customParameters**      | Custom metadata sent during purchase                                                 |

#### **parameters.package**

Information about the package currently active or last used.

| Field           | Description             |
| --------------- | ----------------------- |
| **packageId**   | ID of the package       |
| **price**       | Base price              |
| **currency**    | Currency                |
| **packageType** | subscription / one-time |
| **name**        | Display name            |

#### **parameters.newPackage**

Returned when a **downgrade** has occurred.\
`null` if no plan change happened.

#### **parameters.card**

Masked card details, if a card is used.

| Field          | Description       |
| -------------- | ----------------- |
| **cardNumber** | Masked card       |
| **expireDate** | Expiry date       |
| **tokenId**    | Tokenized card ID |

#### **parameters.customer**

Customer details (if applicable).\
May return `null`.

#### **parameters.package\_update**

Indicates whether this event was triggered after a plan change:

* `1` → package was updated
* `0` → no change

## **How to Use This Webhook**

Typical use cases:

* Update subscription status in your backend
* Grant or revoke access based on `status` or `realStatus`
* Trigger email notifications (trial ending, renewal success, cancellation)
* Update CRM / marketing automation
* Sync billing data to analytics systems
* Automate upgrade/downgrade flows

## **Logic for Access Control**

Use **realStatus** for determining true access logic when cancellations are involved:

* `status = active` but `realStatus = passive` → user canceled; access decision depends on your rules
* `status = grace` → payment failed; retry active; your app decides access
* `status = passive` → subscription ended
