Skip to main content

When it fires

At the start of each new billing cycle for an active subscriber. Settlx creates a renewal invoice and transitions the subscriber to past_due until payment is confirmed. This also fires when a first invoice is created for a new pending subscriber (if no trial period is configured).

What to do

  • Send a payment reminder email to the subscriber
  • Optionally restrict non-critical features while the invoice is outstanding
  • Do not revoke access immediately — the subscriber still has the full grace period to pay
The grace period is configured per plan (gracePeriodDays). The subscriber’s gracePeriodEndsAt in the payload tells you exactly when access should be revoked if no payment arrives.

Payload

{
  "event": "subscriber.past_due",
  "subscriberId": "9f1e2d3c-4b5a-6789-abcd-ef0123456789",
  "merchantId": "f9e8d7c6-b5a4-3210-9876-543210fedcba",
  "planId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "email": "customer@example.com",
  "status": "past_due",
  "currentPeriodEnd": "2026-06-19T00:00:00.000Z",
  "gracePeriodEndsAt": "2026-05-26T00:00:00.000Z",
  "timestamp": "2026-05-19T00:00:00.000Z"
}
FieldTypeDescription
eventstringAlways subscriber.past_due
subscriberIdstringUUID of the subscriber record
merchantIdstringYour merchant account UUID
planIdstringUUID of the plan
emailstringSubscriber email address
statusstringAlways past_due
currentPeriodEndstringISO 8601 — end of the billing period
gracePeriodEndsAtstringISO 8601 — deadline to pay before the subscription expires
timestampstringISO 8601 — when the event was generated

Handler example

Node.js
app.post('/webhooks/settlx', express.raw({ type: 'application/json' }), async (req, res) => {
  verifySignature(req); // see Webhook Integration for verification code

  const event = JSON.parse(req.body);

  if (event.event === 'subscriber.past_due') {
    const { subscriberId, email, gracePeriodEndsAt } = event;

    await db.subscriptions.update(subscriberId, { status: 'past_due' });

    // Send payment reminder with deadline
    await sendEmail(email, 'payment-due', {
      payBy: gracePeriodEndsAt,
    });

    // Optional: show a banner in your UI but keep access active
    await db.users.setFlag(email, 'show_payment_banner', true);
  }

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