Automated Subscription Billing with Inngest Crons
Automated Subscription Billing with Inngest Crons
Calmony Pay v1.0.11
Subscription billing is one of the hardest parts of running a SaaS — not because charging a card is complicated, but because doing it reliably at scale is. Network blips, card declines, and thundering-herd renewal spikes can all turn a simple recurring charge into a support nightmare. In v1.0.11, Calmony Pay ships a production-grade subscription billing cron built on Inngest that handles all of this out of the box.
What shipped
An hourly Inngest cron function now powers the entire subscription renewal lifecycle:
- Automatic detection — every hour, the function finds all active subscriptions where
currentPeriodEnd <= now, so no subscription renewal is ever missed regardless of when it was created. - Payment Intent charging — the customer's default payment method is charged via a Payment Intent, keeping Calmony Pay's payment flow consistent with one-off charges.
- Period extension + invoice creation — on a successful charge, the billing period advances and an invoice is generated immediately, giving both the platform and the end customer a paper trail.
- Retry logic with
past_duefallback — failures are retried up to 3 times over 3 days. If all attempts fail, the subscription moves topast_duerather than silently dropping. NonRetriableErrorfor hard failures — if a card is permanently declined or the payment method is invalid, Inngest is told not to retry, saving time and preventing unnecessary noise.- Concurrency limiting — the function caps parallel executions so a large renewal batch doesn't spike load across the stack.
Why Inngest?
Inngest gives Calmony Pay durable, observable, retryable background functions without managing queues or workers. The billing cron is defined as code, versioned alongside the API, and visible in the Inngest dashboard — including full execution history, retry state, and failure reasons. This means the team can see exactly which subscriptions failed to renew and why, without digging through logs.
The renewal flow in detail
[Hourly cron trigger]
│
▼
Query: active subscriptions where currentPeriodEnd <= now
│
▼
For each subscription (concurrency-limited):
│
├─ Create Payment Intent for default payment method
│
├─ SUCCESS
│ ├─ Extend currentPeriodEnd
│ └─ Create invoice
│
└─ FAILURE
├─ Retryable error → retry up to 3x over 3 days
├─ NonRetriableError → stop immediately
└─ Retries exhausted → mark subscription past_due
What's next
The past_due status is intentionally the end of the automated flow — it's a hook for dunning emails, grace periods, or cancellation logic to be layered on top. Future releases will build on this foundation.
Full technical details are in the Subscription Billing Cron feature guide.