Skip to content

Recurring invoices

What the recurring flag configures, what generates the next one, and what does not.

A recurring invoice is not a subscription. It is an ordinary invoice marked as a template: Wajub copies it into a new document each cycle, overnight, and every copy still has to be opened for payment and settled by the customer. Nothing is debited automatically, because nothing is stored that could be debited.

Marking an invoice recurring

There is no separate endpoint and no subscription resource. Two fields on the ordinary create call are the whole surface.

POSThttps://api.wajub.com/invoices
is_recurringbooleanoptionaldefault : false
Marks this invoice as the one Wajub copies each cycle. The first copy is due one interval after invoice_date. Only an invoice can recur: on a quote or an estimate, true answers 422.
recurring_intervalenumoptional
daily, weekly, monthly, quarterly or yearly. The gap between copies.
recurring_frequencyenumoptional
Accepted on creation as a second spelling of recurring_interval, same five values.
customer_idstringoptional
Not optional here. A recurring invoice without a customer record never generates anything.

Everything else on the invoice, the lines, the totals, the notes, behaves exactly as on a one-off.

curl https://api.wajub.com/invoices \
  -H "Authorization: sk.xxxxxxxxxxxxxxxx…" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "cus_7Kq2mX9vL4tRb3nP8sZcWd1e",
    "customer_name": "Amina Traoré",
    "invoice_date": "2026-09-11",
    "currency": "XAF",
    "items": [
      { "name": "Retainer", "quantity": 1, "unit_price": 250000 }
    ],
    "is_recurring": true,
    "recurring_interval": "monthly"
  }'

The response is the same 201 Created as any other invoice, status: "draft" included, carrying two recurring fields and no more.

Response · 201 Created, abridged
{
"invoice": {
"id": "inv_LRQqYvlhrgUOE225KMKU",
"invoice_number": null,
"status": "draft",
"currency": "XAF",
"total": 250000,
"is_recurring": true,
"recurring_interval": "monthly"
}
}

What the API cannot set

The recurrence has more settings, and none of them is on the API. An end after N occurrences, or an interval of every N months, cannot be set through the API.

SettingWhat it doesWhere
A start datePuts the first copy on a date you choose, instead of one interval after the invoiceThe Dashboard form
An end dateThe last day a cycle is generated forThe Dashboard form
An end after a number of copiesStop after this many copiesNot available
A multiple of the intervalEvery two months, every three weeksNot available

An end date entered in the Dashboard is applied: the cycle that falls on it is the last one generated, and the series then stops for good. A recurrence created through the API has no end rule at all: it runs until you stop it.

What comes back, and what does not

Four recurring fields come back on the invoice object.

FieldOn a recurring invoiceOn a generated copy
is_recurringtrue while the series runs, false once it is stoppedfalse: a copy generates nothing
recurring_intervaldaily, weekly, monthly, quarterly or yearlyThe template's, copied
next_invoice_dateThe date of the next copy, YYYY-MM-DD. null once the series is stopped or the invoice cancelled. It stays set while generation is skipped for want of a plan, and past an end date until the next nightly runnull
recurring_parentnullThe id of the recurring invoice it was generated from

So a copy is the invoice whose recurring_parent is set. The end rule is not in the response, and GET /invoices has no recurring filter, though the Dashboard list does.

How a cycle runs

The next date is set when the invoice is created recurring, or made recurring by an update: one interval after its invoice_date. It is never set in the past, so a backdated invoice does not produce the cycles that went by before it was recurring, and an update that turns the flag off clears it. A series switched off and on again resumes after its latest copy: a cycle already generated is never generated twice. A copy cannot be made recurring itself (422), and a duplicate of a recurring invoice is a plain draft that recurs only if you set it to.

Every night at 02:00 UTC, Wajub generates the copies that have come due: for every invoice that is flagged recurring, whose next date has come, and that is not cancelled, it checks the plan, then the end rule, then copies.

The copy inheritsThe copy has of its own
The lines, with their quantities, prices and taxesNo invoice_number until it is sent, like any draft
The currency and the whole-invoice discountinvoice_date, set to the cycle that just came due
The notes, terms, footer and payment instructionsdue_date, thirty days later
The template, the language and the display settingsThe customer block, re-read from the customer record
The payment methods it acceptsis_recurring: false. A copy is an ordinary invoice and never generates copies of its own

Then the original's next date moves forward by one interval, and the cycle is armed again. Each cycle produces exactly one copy.

Three details of the calendar. A run generates every cycle that has come due, not only the latest. A monthly, quarterly or yearly series never skips a month: one month after 31 January is 28 February, and the series goes on from the 28th. And the dates are UTC: a cycle dated the 11th is generated at 02:00 UTC on the 11th.

Two of those deserve a second look. The customer block is re-snapshotted from the live customer each time, so an address or a company name corrected on the record flows into the next document and leaves the earlier ones untouched. And due_date is always thirty days after the copy's date, whatever terms the original carried.

Stopping a recurrence

An end date, where the Dashboard set one, ends the series on its own. Otherwise you stop it, at any point and whatever the invoice's status, paid included.

POSThttps://api.wajub.com/invoices/{id}/stop-recurring
End the series, keep the document
curl -X POST https://api.wajub.com/invoices/inv_LRQqYvlhrgUOE225KMKU/stop-recurring \
  -H "Authorization: sk.xxxxxxxxxxxxxxxx…"

The call takes no body. The invoice comes back with is_recurring: false and next_invoice_date: null, nothing else about it changes, and invoice.updated is sent. No copy is generated after this, and the copies already generated stay as they are: each one is an invoice of its own, to send, cancel or delete like any other. Stopping a series already stopped answers 200 and changes nothing. In the Dashboard the same action is Stop recurring, in the invoice's actions menu.

Call it on the recurring invoice, not on a copy. A copy has no series of its own, so the call answers 400 on it, with the template's id in recurring_parent:

Response · 400 on a generated copy
{
"code": 400,
"status": "Bad Request",
"message": "This invoice was generated by a recurring invoice. Stop the series on that one.",
"recurring_parent": "inv_LRQqYvlhrgUOE225KMKU"
}

Two other calls touch the series, and both are narrower. PUT /invoices/{id} with is_recurring: false stops it too, but only while the invoice is a draft, since only a draft can be edited. Cancelling the invoice stops generation as well, and clears next_invoice_date, but cancelling is refused once it is paid.

What it costs in plan

Recurrence needs the Recurring billing feature, which starts at Growth.

The Dashboard refuses to save a recurring invoice without it. Without the plan, generation is skipped and the document is left untouched, so a downgraded account resumes on its own if it upgrades again, with the cycles that came due in the meantime. POST /invoices does not check the plan, so creating a recurring invoice through the API succeeds on any plan and simply never generates.

What did you think of this content?