HTTPS webhooks for SaaS subscription lifecycle

For Software / SaaS products, Zenofy POSTs JSON to the webhook URL configured on the product. Each request includes an "event" string and subscription fields your backend can use to sync access.

Enter the endpoint on the product edit/create form (Webhook URL for SaaS). Optionally set a webhook secret; when present, Zenofy sends it as the X-Webhook-Secret header, same idea as the order webhook integration.

Events are separate from the Integrations → Webhook payloads: here the names are subscription.created, subscription.activated, subscription.renewed, subscription.suspended, subscription.canceled, and subscription.expired.

Use Content-Type: application/json; respond with HTTP 2xx quickly and process asynchronously if needed. Delivery is best-effort. Failed deliveries may be recorded for operators—check Zenofy webhook logs when troubleshooting.

Fields such as dates and nested order may vary with serialization; always treat payloads as backward-compatible — new fields may appear over time.

HTTP request

POST · Content-Type: application/json · optional X-Webhook-Secret

POST /your-endpoint HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-Webhook-Secret: your-shared-secret

{ ... }

Events and "event" values

eventWhen (typical)
subscription.createdSubscription row created with the originating order
subscription.activatedFirst successful payment completed; access period active
subscription.renewedRenewal payment succeeded; period extended (see renewal object)
subscription.suspendedRecurring product schedule: unpaid after billing period crosses the configured “suspend after period end” threshold
subscription.canceledMerchant canceled the subscription from the dashboard (or related refund/cancel flows)
subscription.expiredPaid period lapsed without renewal — immediately if no suspend/expire schedule, or when “expire after period end” days elapse after suspend

Payload shape (fields)

  • event — one of the subscription.* values above
  • subscriptionId, productId, productName, merchantId
  • status — subscription status (e.g. PENDING, ACTIVE, SUSPENDED, CANCELED, EXPIRED)
  • billingCycle — snapshot at subscription time (e.g. WEEKLY, MONTHLY, YEARLY)
  • currentPeriodStart, currentPeriodEnd — nullable dates for the billed period where applicable
  • customerEmail — normalized/lowercase email for matching renewals
  • customerNameSnapshot
  • isRenewal — boolean; true when event is subscription.renewed
  • renewal — object for renewed events: renewalOrderId, previousPeriodEnd, newPeriodEnd (ISO 8601 strings); otherwise often null
  • initialOrderId, lastPaidOrderId, pendingOrderId
  • orderId — id associated with this notification context
  • order — when an order snapshot is included: status, totalAmount, currency, paidAt, customer (name, email, phoneNumber); may be null

Sample JSON bodies

subscription.activated (illustrative)

{
  "event": "subscription.activated",
  "subscriptionId": "683a1b2c3d4e5f6789012345",
  "productId": "507f1f77bcf86cd799439011",
  "productName": "My SaaS plan",
  "merchantId": "merchantUserIdExample",
  "status": "ACTIVE",
  "billingCycle": "MONTHLY",
  "currentPeriodStart": "2026-05-01T10:00:00+02:00",
  "currentPeriodEnd": "2026-06-01T10:00:00+02:00",
  "customerEmail": "buyer@example.com",
  "customerNameSnapshot": "Ada Buyer",
  "isRenewal": false,
  "renewal": null,
  "initialOrderId": "673f92b2c3d94a0012abcd01",
  "lastPaidOrderId": "673f92b2c3d94a0012abcd01",
  "pendingOrderId": null,
  "orderId": "673f92b2c3d94a0012abcd01",
  "order": {
    "status": "PAID",
    "totalAmount": 99.99,
    "currency": "MZN",
    "paidAt": "2026-05-01T10:42:18+02:00",
    "customer": {
      "name": "Ada Buyer",
      "email": "buyer@example.com",
      "phoneNumber": "+258840000000"
    }
  }
}

subscription.renewed — note renewal.previousPeriodEnd and renewal.newPeriodEnd

{
  "event": "subscription.renewed",
  "subscriptionId": "683a1b2c3d4e5f6789012345",
  "productId": "507f1f77bcf86cd799439011",
  "productName": "My SaaS plan",
  "merchantId": "merchantUserIdExample",
  "status": "ACTIVE",
  "billingCycle": "MONTHLY",
  "currentPeriodStart": "2026-05-01T10:00:00+02:00",
  "currentPeriodEnd": "2026-07-01T10:00:00+02:00",
  "customerEmail": "buyer@example.com",
  "customerNameSnapshot": "Ada Buyer",
  "isRenewal": true,
  "renewal": {
    "renewalOrderId": "673f92b2c3d94a0012abcd99",
    "previousPeriodEnd": "2026-06-01T10:00:00+02:00",
    "newPeriodEnd": "2026-07-01T10:00:00+02:00"
  },
  "initialOrderId": "673f92b2c3d94a0012abcd01",
  "lastPaidOrderId": "673f92b2c3d94a0012abcd99",
  "pendingOrderId": null,
  "orderId": "673f92b2c3d94a0012abcd99",
  "order": {
    "status": "PAID",
    "totalAmount": 99.99,
    "currency": "MZN",
    "paidAt": "2026-06-05T14:20:00+02:00",
    "customer": {
      "name": "Ada Buyer",
      "email": "buyer@example.com",
      "phoneNumber": "+258840000000"
    }
  }
}

Merchant overview — product setup, renewals, and Catalog → SaaS Subscriptions

All tutorials