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: a nightly job copies it into a new document each cycle, 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 the job copies.
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_idstring (uuid)optional
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.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i…" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "9d1f0c7a-4b2e-4f61-9d3a-7c8e5b21a940",
    "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": "INV-202609-0001",
"status": "draft",
"currency": "XAF",
"total": 250000,
"is_recurring": true,
"recurring_interval": "monthly"
}
}

What the API cannot set

The recurrence has four more settings in the database, and none of them is on the API.

SettingWhat it doesWhere
recurring_end_typenever, date or occurrencesDashboard
recurring_end_dateStop generating after this dateDashboard
recurring_occurrencesStop after this many copiesDashboard
A multiplier above 1Every two months, every three weeksNeither

An invoice created through the API therefore has no end rule at all, which matters more than it looks: read the section on stopping one below before you set is_recurring on anything.

What comes back, and what does not

is_recurring and recurring_interval are the only recurring fields on the invoice object. There is no next_invoice_date, no recurring_parent_id and no end rule in the response.

Two consequences worth planning around. The API cannot tell you when the next document is due, and it cannot tell a generated copy from the invoice it was copied from, since the link between them is not exposed. GET /invoices has no recurring filter either, though the Dashboard list does, so keep your own record of which invoice is the recurring one.

How a cycle runs

A job named invoices:generate-recurring runs every night at 02:00 and walks every invoice that is flagged recurring, has a next date in the past, and is not cancelled. For each one it checks the plan, then the end rule, then copies.

The copy inheritsThe copy recomputes
The lines, with their quantities, prices and taxesIts own invoice_number
The currency, the notes, terms and footerinvoice_date, set to the cycle that just came due
The interval and the end ruledue_date, thirty days later
The template and the display settingsThe customer block, re-read from the customer record

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

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, because the field the calculation reads does not exist on the invoice.

Stopping a recurrence

While the original is still unpaid, either of two calls ends it. Cancelling takes it out of the job's reach for good, and an update clearing the flag leaves the document alive but inert.

POSThttps://api.wajub.com/invoices/{id}/cancel
curl -X PUT https://api.wajub.com/invoices/inv_LRQqYvlhrgUOE225KMKU \
  -H "Authorization: sk.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i…" \
  -H "Content-Type: application/json" \
  -d '{ "is_recurring": false }'

What it costs in plan

Recurrence needs recurring_billing, which starts at Growth. The gate is enforced in two of the three places it could be.

The Dashboard refuses to save a recurring invoice without it. The job checks it on every run and skips the invoice, logging a notice and leaving the document untouched, so a downgraded account resumes on its own if it upgrades again. POST /invoices checks neither, so creating a recurring invoice through the API succeeds on any plan and simply never generates.

What did you think of this content?