Sandbox mode — Use https://wallet.e-mazad.store/api/v1 as your base URL
SubscriptionsLifecycle

Subscription Lifecycle

Detailed documentation on billing cycles, retry schedules, state transitions, and how to handle each stage of a subscription.

Billing cycle

Each subscription tracks a cycle counter that increments after every successful charge. The billing date is anchored to the subscription start date.

Example: Monthly subscription started January 15

#1
Jan 15
Charged 15,000 IQD
#2
Feb 15
Charged 15,000 IQD
#3
Mar 15
Failed - insufficient funds
Mar 16
Retry #1 - failed
Mar 18
Retry #2 - succeeded
#4
Apr 15
Charged 15,000 IQD

Anchor date preservation

Even when a retry succeeds mid-cycle, the next billing date remains anchored to the original day of the month. In the example above, cycle 4 still bills on the 15th, not on the 18th when the retry succeeded.

Retry schedule

When a payment fails, Mazad automatically retries using an exponential backoff schedule. The number of retries depends on the plan's grace_period_days.

AttemptDelay after failureAction
#11 dayCharge wallet, send webhook subscription.payment_retry
#23 daysCharge wallet, send webhook subscription.payment_retry
#37 daysCharge wallet, send webhook subscription.payment_retry
#414 daysFinal attempt before grace expiry evaluation

Grace period limits retries

If grace_period_days is shorter than the retry schedule (e.g., 3 days), only retries within that window will be attempted. The subscription is canceled once the grace period expires regardless of remaining retries.

State transitions

Complete reference of all possible subscription state transitions.

FromToTrigger
trialingactiveTrial period ends and first charge succeeds
trialingpast_dueTrial ends and first charge fails
trialingcanceledMerchant or subscriber cancels during trial
activepast_dueRecurring payment fails
activepausedMerchant or subscriber pauses
activecanceledMerchant or subscriber cancels, or max_cycles reached
past_dueactiveRetry payment succeeds
past_duecanceledGrace period expires with no successful retry
pausedactiveMerchant or subscriber resumes
pausedcanceledMerchant cancels while paused

Handling lifecycle in your app

Use webhooks to keep your application in sync with subscription state changes. Here is a typical webhook handler.

app.post('/webhooks/mazad', (req, res) => {
  const event = req.body;

  switch (event.type) {
    case 'subscription.activated':
      // Grant access to the subscriber
      grantAccess(event.data.customer_id);
      break;

    case 'subscription.past_due':
      // Show a warning banner to the user
      showPaymentWarning(event.data.customer_id);
      break;

    case 'subscription.canceled':
      // Revoke access immediately
      revokeAccess(event.data.customer_id);
      break;

    case 'subscription.paused':
      // Optionally restrict features
      restrictFeatures(event.data.customer_id);
      break;

    case 'subscription.resumed':
      // Restore full access
      grantAccess(event.data.customer_id);
      break;
  }

  res.status(200).json({ received: true });
});

Fixed-term subscriptions

Set max_cycles on a plan to automatically cancel the subscription after a specific number of billing cycles.

Example: 12-month commitment

Plan interval

monthly

Max cycles

12

Result

Auto-cancels after 12 months

Unlimited subscriptions

Set max_cycles to null (the default) for subscriptions that renew indefinitely until explicitly canceled.