A new auto-invoice trigger: billing on the last day of the month
Until now, all time-based auto-invoice triggers in ZEIT.IO had one thing in common: they always bill the previous month. The day_of_month trigger creates an invoice for June on 3 July, and day_of_month_range behaves the same way. That is right for many billing models – but not for all of them.
One request kept reaching us: the invoice should be created within the very month it bills. That is exactly what the new trigger is for: last_day_of_month.
What the new trigger does
With last_day_of_month, ZEIT.IO creates the invoice on the last day of the month – and bills the current month, not the previous one.
An example: the trigger fires on 31 August. The billing period of the resulting invoice is then 1 to 31 August. August's work is therefore invoiced while it is still August.
ZEIT.IO works out the end of the month correctly on its own – 28 or 29 February, 30 April, 31 May. There is nothing to configure; this trigger deliberately has no day field.
| Trigger | Billing period | Invoice is created |
|---|---|---|
day_of_month | previous month | on the configured day (day) |
day_of_month_range | previous month | daily within the configured range |
last_day_of_month | current month | on the last day of the month, at 8:00 p.m. |
Setting it up
In the user interface you will find the new trigger where the others are:
- On the project under Auto invoices – there it applies to that one project.
- On the customer under Settings → Auto invoice – there it acts as the default for every newly created project of that customer.
If you select „The last day of the month", the day fields disappear, because the date follows by itself. All six invoice types are available – exactly as with the day_of_month trigger.
Through the REST API it works as usual:
PATCH /api/v1/org/projects/:id/autoinvoices/:aid
apiKey: your-api-key
Content-Type: application/json
{
"trigger": "last_day_of_month",
"language": "en",
"payment_target": 14,
"target_state": "draft"
}
Why 8:00 p.m. and not midnight?
That is the most important design decision behind this trigger – and the reason for the warning in the next section.
The other daily jobs in ZEIT.IO run shortly after midnight. For a trigger that bills the current month, that would be the worst possible time: at 00:05 on 31 August, nobody has booked a single time record for 31 August yet. The entire last day of the month would drop out of the invoice, every month.
So this job deliberately runs at 8:00 p.m. German time – after the working day, but with enough of a buffer before midnight in case something has to be caught up manually.
⚠️ Important: time records after 8:00 p.m. can slip through the cracks
Please read this section before you put the trigger to work in production.
At 8:00 p.m. on the last day of the month, ZEIT.IO takes a snapshot: the invoice contains exactly those time records that exist at that moment and are already approved.
Anything that happens afterwards is too late:
- A time record booked on 31 August at 9:30 p.m. is not part of the invoice dated 31 August.
- A time record booked on 31 August at 2:00 p.m. but only approved on 1 September is not included either. Unapproved records are never billed.
And here is the real catch: those records are not picked up automatically later on either. The following month's run bills the period 1 to 30 September – a record dated 31 August falls outside that period. It therefore stays unbilled indefinitely, until someone invoices it manually.
With the previous triggers this could not happen, because they always billed a month that had already closed. With the new trigger, the month being billed is not over yet at the time the invoice is created – that is precisely the intended effect, but it comes with exactly this flip side.
What you can do about it
- Finish time tracking and approvals before 8:00 p.m. On the last day of the month, every record should be booked and approved before the job runs. A quick look at pending approvals on the afternoon of the last day saves the rework.
- Have the invoice created as a draft (
target_state: "draft"). Then you can check it before sending and add any missing line items. Withsent, the invoice goes to the customer immediately – gap included. - Bill stragglers manually. If a record does get approved too late, it has to be added manually to a separate invoice or to the next one.
- With long approval delays, prefer
day_of_month. If timesheets in your organisation are typically approved days later, billing the previous month is the more robust model.
We are currently looking into whether ZEIT.IO should carry such stragglers over into the following month's invoice automatically. Until then, the note above applies.
One more note on triggering manually
The „Update & trigger" button lets you start an auto-invoice configuration by hand at any time. For the last_day_of_month trigger this means: the billing period is always the full current month, no matter which day you press the button. Trigger it manually on 15 August and you get an invoice covering 1 to 31 August.
To prevent duplicates, ZEIT.IO checks before creating whether an invoice that has not been cancelled already exists for the same configuration and the same period. If so, no second invoice is created.
Questions?
If you have questions about the new trigger, or you are unsure which billing model is the right one for your projects, just write to us at support@zeit.io.