Recurring Templates
Recurring templates automatically generate invoices, bills or journal entries on a schedule. Set up a template once and DayZero creates the documents at the configured frequency.
Create a Recurring Template
A template has a schedule (top-level fields) and the document to generate (template_data):
curl -X POST "https://api.ondayzero.com/api/v1/recurring" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme monthly retainer",
"recurrence_type": "invoice",
"customer_id": "CUSTOMER_UUID",
"frequency": "monthly",
"day_of_month": 1,
"start_date": "2026-11-01",
"days_until_due": 30,
"auto_send": false,
"template_data": {
"description": "Monthly retainer",
"line_items": [
{
"description": "Monthly retainer",
"quantity": 1,
"unit_price": 250000
}
]
}
}'
unit_priceis in cents.250000= $2,500.00 per month.
The response is the template (status 201), trimmed here:
{
"success": true,
"data": {
"id": "0198a2c4-0000-7d3a-9a51-3f6f0c1d2e50",
"name": "Acme monthly retainer",
"recurrence_type": "invoice",
"status": "active",
"frequency": "monthly",
"start_date": "2026-11-01",
"next_occurrence": "2026-11-01",
"last_generated": null,
"occurrences_generated": 0,
"days_until_due": 30,
"auto_send": false,
"customer": { "id": "0198a2c4-0000-7d3a-9a51-3f6f0c1d2e20", "name": "Acme Corp" },
"frequency_display": "Monthly",
"days_until_next": 18
}
}start_date and end_date cannot be in the past. You can also create a template as part of an invoice or bill: send a recurring object (frequency, start_date, and optional name, day_of_month, day_of_week, days_until_due, end_date, max_occurrences) on POST /api/v1/invoices or POST /api/v1/bills (or the matching PUT). On invoice create, the invoice you are creating counts as the schedule's first occurrence, so the template generates the next one a period later.
A recurring bill:
curl -X POST "https://api.ondayzero.com/api/v1/recurring" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "Office rent",
"recurrence_type": "bill",
"vendor_id": "VENDOR_UUID",
"frequency": "monthly",
"day_of_month": 1,
"days_until_due": 15,
"start_date": "2026-11-01",
"template_data": {
"description": "Office rent for 123 Main St",
"amount": 350000
}
}'Schedule fields
| Field | Required | Description |
|---|---|---|
name |
Yes | Template name |
recurrence_type |
Yes | invoice, bill or journal_entry |
frequency |
Yes | daily, weekly, biweekly, monthly, quarterly, annually |
start_date |
Yes | First generation date |
customer_id |
For invoices | Customer to bill |
vendor_id |
For bills | Vendor the bill is from |
day_of_month |
No | 1–31 for monthly/quarterly/annually; clamps to the last day of shorter months. Defaults to the day in start_date |
day_of_week |
No | 0 = Monday … 6 = Sunday for weekly/biweekly. Defaults to the weekday of start_date |
days_until_due |
No | Days from generation to due date, 0-365 (default 30) |
end_date / max_occurrences |
No | Stop after a date or a count — whichever comes first. Both null = indefinite |
auto_send |
No | Invoice templates only. Stored on the template (default false). Generated invoices are always created as draft; see the note under template_data |
currency |
No | USD (default), CAD, AUD, EUR, GBP |
notes |
No | Free-text notes, up to 1,000 characters |
contract_id |
No | Invoice templates only — routes generated invoices into the contract's billing tallies |
template_data by type
| Type | Keys |
|---|---|
invoice |
Either line_items (same shape as invoice line items; the total is calculated) or total (cents), plus optional description and project_id. Generated invoices are created as draft with the next invoice number, and are not finalized or emailed automatically |
bill |
amount (cents, required) and optional description. Generated bills are created as forecasted, type: recurring, with expected_amount set from amount |
journal_entry |
line_entries (at least two balanced debit/credit lines, same shape as journal entry lines) and description, both required |
Customers and vendors are validated when the template is created, and again at generation time: if the customer or vendor has since been removed, that occurrence fails.
List Templates
curl "https://api.ondayzero.com/api/v1/recurring?recurrence_type=invoice&status=active" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID"Filter Parameters
| Parameter | Type | Description |
|---|---|---|
recurrence_type |
string | invoice, bill or journal_entry |
status |
string | active, paused, completed, cancelled |
customer_id |
UUID | Filter invoice templates by customer |
vendor_id |
UUID | Filter bill templates by vendor |
search |
string | Match on name, description, frequency, status or counterparty |
Plus the standard pagination parameters. Shortcut endpoints are also available (each takes status and its counterparty filter plus pagination):
GET /api/v1/recurring/invoices— only invoice templates (customer_id)GET /api/v1/recurring/bills— only bill templates (vendor_id)
GET /api/v1/recurring/{template_id} returns one template. Each template includes status, next_occurrence, last_generated, occurrences_generated, customer / vendor summaries, contract_id, and computed fields such as frequency_display and days_until_next.
POST /api/v1/recurring/suggest-templates asks the AI to find repeating invoices and bills that could become templates.
Manage Template Lifecycle
Status rules: a template starts active. Only an active template can be paused or skipped, only a paused one can be resumed, and a completed or cancelled template can no longer be cancelled or updated (each returns 400). A template becomes completed when it reaches end_date or max_occurrences.
Pause
curl -X POST "https://api.ondayzero.com/api/v1/recurring/{template_id}/pause" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID"Resume
Resuming recalculates the next occurrence.
curl -X POST "https://api.ondayzero.com/api/v1/recurring/{template_id}/resume" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID"Cancel
curl -X POST "https://api.ondayzero.com/api/v1/recurring/{template_id}/cancel" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID"Cancelling is permanent (status cancelled); use pause if you may want to resume. DELETE /api/v1/recurring/{template_id} removes the template entirely; documents it already generated are kept.
Skip Next Occurrence
Advances next_occurrence to the following scheduled date without generating a document (active templates only). The response has skipped_date, next_occurrence and message. If the following date falls after end_date, the template becomes completed.
curl -X POST "https://api.ondayzero.com/api/v1/recurring/{template_id}/skip" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID"Update
PUT /api/v1/recurring/{template_id} changes name, currency, frequency, days_until_due, day_of_month, day_of_week, end_date, max_occurrences, notes, template_data, auto_send, customer_id (invoice templates only), vendor_id (bill templates only) and contract_id (invoice templates only); changes apply from the next generation onward. template_data.amount and template_data.total must be positive. recurrence_type and start_date cannot be changed — clone instead. Completed and cancelled templates cannot be updated.
View Generation History
See the documents generated from a template (limit is 1-100, default 50). The response has template_id, template_name, document_type, total_generated and items; each item has id, document_type, status, number, description, amount (cents), due_date and created_at, plus customer_name (invoices) or vendor_name (bills):
curl "https://api.ondayzero.com/api/v1/recurring/{template_id}/history?limit=10" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID"Clone a Template
Copy a template, optionally pointing it at a different customer or vendor and a new start date. name defaults to the original name plus (Copy) and start_date defaults to today. The clone starts active with 0 occurrences generated:
curl -X POST "https://api.ondayzero.com/api/v1/recurring/{template_id}/clone" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID" \
-H "Content-Type: application/json" \
-d '{"name": "Globex monthly retainer", "customer_id": "OTHER_CUSTOMER_UUID", "start_date": "2026-12-01"}'Upcoming Scheduled Invoices
GET /api/v1/invoices/scheduled?days=90 projects the invoices that will auto-draft, from active recurring invoice templates and upcoming contract billing periods. It is read-only: nothing is created and no template or contract changes. days is 1-730 (default 90) and only bounds items with no end date; a template with an end_date is projected in full through that date. The response is {"items": [...]} sorted by date, each with scheduled_date, amount_cents, customer_name, source (recurring_template or contract), source_id, description, and, when they resolve, project_id, project_name, contract_id and contract_number. The Scheduled tab in the app asks for 400 days.
Common errors
| Status | Cause | Fix |
|---|---|---|
422 |
start_date or end_date in the past, day_of_month outside 1-31, day_of_week outside 0-6, days_until_due outside 0-365 |
Fix the field named in errors |
400 |
Pausing or skipping a template that is not active, resuming one that is not paused, or cancelling or updating a completed / cancelled one |
Check status first |
404 |
Template id wrong or from another business | List with GET /api/v1/recurring |