This guide shows you how to implement subscription billing using Simiz recurring payments.

Scenario: SaaS monthly subscription

You’re building a SaaS product and want to charge customers 10,000 XAF/month via Mobile Money.

Step 1: Create the subscription

curl -X POST /api/v1/projects/{projectId}/recurring \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 10000,
    "currency": "XAF",
    "interval": "MONTHLY",
    "intervalCount": 1,
    "paymentMethod": "ORANGE_MONEY",
    "payerPhone": "237690000001",
    "payerName": "Jane Doe",
    "startDate": "2026-04-01T00:00:00Z",
    "description": "Pro Plan - Monthly",
    "metadata": {
      "plan": "pro",
      "customerId": "cust_456"
    }
  }'

Step 2: Handle webhook events

Set up webhook listeners for recurring payment events:
app.post('/webhooks/simiz', (req, res) => {
  const event = req.body;

  switch (event.type) {
    case 'recurring.executed':
      // Payment successful — extend subscription
      extendSubscription(event.data.metadata.customerId);
      break;

    case 'recurring.failed':
      // Payment failed — notify customer
      notifyCustomer(event.data.metadata.customerId, {
        reason: event.data.failureReason,
      });
      break;

    case 'recurring.paused':
      // Auto-paused after too many failures
      notifyCustomer(event.data.metadata.customerId, {
        message: 'Subscription paused due to payment failures',
      });
      break;

    case 'recurring.cancelled':
      // Subscription cancelled — downgrade access
      downgradeAccess(event.data.metadata.customerId);
      break;
  }

  res.sendStatus(200);
});

Step 3: Handle payment failures

When a customer’s Mobile Money balance is insufficient:
  1. Receive recurring.failed webhook
  2. Send the customer a notification (SMS, email, or in-app)
  3. Optionally pause the subscription:
curl -X POST /api/v1/projects/{projectId}/recurring/{recurringId}/pause \
  -H "Authorization: Bearer sk_live_xxx"
  1. When the customer tops up, resume:
curl -X POST /api/v1/projects/{projectId}/recurring/{recurringId}/resume \
  -H "Authorization: Bearer sk_live_xxx"

Common patterns

Grace period

Give customers a few days after a failed payment before revoking access:
case 'recurring.failed':
  const GRACE_DAYS = 3;
  setGracePeriod(customerId, GRACE_DAYS);
  notifyCustomer(customerId, `Payment failed. You have ${GRACE_DAYS} days to top up.`);
  break;

Plan upgrades

To upgrade a customer from a 10,000 XAF plan to 25,000 XAF:
  1. Cancel the current recurring payment
  2. Create a new one with the higher amount
  3. Update your internal records
Store the recurring payment id in your database alongside the customer record so you can easily manage upgrades and cancellations.

Installment plans

For selling high-value items in installments (e.g., a 120,000 XAF laptop in 12 payments):
curl -X POST /api/v1/projects/{projectId}/recurring \
  -H "Authorization: Bearer sk_live_xxx" \
  -d '{
    "amount": 10000,
    "currency": "XAF",
    "interval": "MONTHLY",
    "paymentMethod": "MTN_MOMO",
    "payerPhone": "237670000001",
    "payerName": "Paul K.",
    "startDate": "2026-04-01T00:00:00Z",
    "description": "Laptop installment 1/12",
    "maxCycles": 12
  }'
The recurring payment will automatically stop after 12 cycles.