Subscription businesses do not invoice in a stream — they invoice in a spike. On the 1st of the month, thousands of renewals need to become GST-compliant invoices within a narrow window, each with a valid number, a ledger posting, and (for B2B customers above the threshold) an IRN. Recurring invoice automation at this scale is an architecture problem before it is an accounting problem, and getting the architecture wrong shows up as the worst kind of bug: revenue that silently never got invoiced. Here is how to design the billing run properly.
The billing-day spike problem
Say you have 10,000 active subscriptions renewing on the 1st. At 00:05, your billing job wakes up and starts creating invoices. The load profile is brutal by design: an entire month's invoicing compressed into minutes. And unlike a web-traffic spike, every single unit of this workload is a statutory financial document — you cannot shed load, sample, or "eventually" get to some of them. Every renewal must produce exactly one invoice, and you must be able to prove it did.
Why synchronous APIs fail under burst
The naive design — loop over subscriptions, call a create-invoice API synchronously for each — fails in predictable ways at spike volume:
- Rate limiting — the API starts returning "too many requests". If your loop skips and moves on, those invoices are silently missing; you discover the gap weeks later during reconciliation, as unexplained revenue leakage.
- Ambiguous timeouts — a call times out after the invoice was actually created. Retry it naively and you have issued a duplicate invoice to a real customer: a GSTR-1 overstatement that can only be unwound with a credit note.
- Numbering collisions — invoice numbers generated under high concurrency, without a properly serialised series, produce gaps or duplicates. Both are direct GST compliance exposures, since an invoice series must be consecutive and unique.
- No end-state — with ten thousand independent calls, "did the billing run finish, and did everything succeed?" has no authoritative answer. Your finance team finds out tomorrow, one support ticket at a time.
The pattern that works: acknowledge fast, process async, confirm by webhook
High-volume invoicing platforms solve this with an asynchronous batch pattern, and it is worth understanding even if you never build one — because it is what you should demand from any API you integrate:
- Submit a batch. Your billing job sends the renewals as one or a few batch payloads — hundreds or thousands of invoice requests per call — each request carrying its own idempotency key (the subscription ID plus billing period is a natural choice).
- Get acknowledged instantly. The platform validates the envelope and returns an acceptance with a batch ID in milliseconds. Your job's responsibility is now over except for listening.
- The queue absorbs the burst. Behind the acknowledgement, the platform drains the batch through workers at a database-safe rate. Invoice numbers are assigned from a serialised, gapless series — concurrency is the platform's problem, solved once, centrally.
- Webhooks confirm everything. Each invoice confirms individually (with its number, document link, and IRN where applicable), and the batch itself emits a completion event with succeeded/failed counts. Failures arrive with reasons, not silence.
The finance-facing consequence is the one that matters: at 09:00 on the 1st, someone can ask "did all 10,000 generate?" and get a definitive answer from the batch report — not a shrug. The retry and idempotency mechanics that make step 1 safe are covered in depth in idempotency, retries and webhooks.
GST specifics for subscription billing
Recurring revenue has its own compliance texture:
- SAC codes — subscriptions are services; every plan needs the correct SAC code and rate on its line items, held once in your plan catalogue.
- B2B renewals need IRNs — if e-invoicing applies to you (confirm the current turnover threshold on gst.gov.in), every B2B renewal invoice must obtain an IRN. At spike volume this multiplies the burst — one more reason the platform, not your job, should own IRP submission. See generating IRNs from your own app for the failure handling involved.
- Place of supply per customer — a national subscriber base means every renewal individually resolves to CGST+SGST or IGST based on the customer's state. This is master data, resolved at signup, not at billing time.
- Mid-cycle changes — upgrades, downgrades, and cancellations produce prorated charges and credit notes. Model these as first-class flows; a subscription business without an automated credit-note path does not stay compliant for long.
Reconciliation: proving the run was complete
Design the reconciliation before the first real billing run. The invariant to enforce: active subscriptions due for renewal = invoice requests submitted = invoices confirmed + failures explained. Concretely:
- Your billing job records what it submitted (count and idempotency keys) per batch.
- The batch completion webhook gives you the platform's count of created and failed.
- A scheduled job diffs the two and alerts on any mismatch — the same day, not at month-end.
Because the platform posts each invoice to the customer ledger and receivables position as it is created, the accounting side needs no separate sync: the books are the same records the batch produced. That post-invoice chain is its own topic — see who keeps the books when your app creates invoices.
What to ask any vendor before you integrate
If you are evaluating platforms for subscription invoicing, these five questions separate accounting-grade APIs from document generators:
- What happens at 10x our normal request rate — queuing, or errors?
- Are idempotency keys supported natively, and what is the dedupe window?
- How are invoice numbers serialised under concurrency — can you guarantee a gapless series per GSTIN?
- Is there a per-batch completion event with authoritative counts?
- Does invoice creation atomically include ledger posting, AR, and IRN generation — or are those separate systems to reconcile?
The broader evaluation framework is in our complete invoicing API integration guide.
Built for the spike
Invodo's recurring invoicing engine and API are designed around exactly this pattern: batches acknowledged instantly, drained through a controlled queue, numbered gaplessly per GSTIN, posted atomically to ledger and receivables, with IRNs generated in-flow and webhooks confirming every invoice and every batch. If billing day currently ends with your team hoping everything generated, see how Invodo handles recurring invoicing or view pricing to start a conversation about your volume.
Put this into practice with Invodo
GST-compliant invoicing, e-invoicing, and purchase management built for Indian businesses.
Invodo Editorial
Reviewed by a Chartered Accountant
The Invodo editorial team writes practical, India-specific guides on GST and business finance. Compliance content is reviewed by a practising Chartered Accountant.