Recurring & repeating tasks
Bordio has two different ways a task can repeat. They are mutually exclusive — pick one:
- On a schedule (
recurrence) — the task/event repeats on fixed dates, e.g. every Monday. Uses an iCalendarRRULE. Works for tasks and events. Covered first, below. - After completion (
repeat_on_completion) — a fresh copy is created only when you close the task, with dates shifted forward. Good for “do this again N days after I finish it”. Tasks only. See Repeat after completion.
On a schedule (recurrence)
Section titled “On a schedule (recurrence)”A task or event can repeat on a schedule — a daily task, a weekly standup, a monthly review. You create a repeating series by adding a recurrence object to the normal create request. The result is a series (one template you address by its id), not a pile of copies.
Recurrence uses the iCalendar RRULE format (RFC 5545) — the same rule syntax as Google Calendar and CalDAV. If you have ever built a recurrence with a calendar library, you already know it.
Creating a recurring event
Section titled “Creating a recurring event”Add recurrence to POST /scheduled-events. The series is anchored at start_at.
curl -X POST "https://api.bordio.com/public/v1/scheduled-events" \ -H "Authorization: Bearer brd_sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "title": "Team standup", "start_at": "2026-07-06T09:00:00Z", "end_at": "2026-07-06T09:15:00Z", "recurrence": { "rule": "RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR", "until": "2026-12-31" } }'This creates a standup every Monday, Wednesday and Friday from 06 Jul 2026 until the end of the year.
Creating a recurring task
Section titled “Creating a recurring task”Add recurrence to POST /tasks. The series is anchored by the task’s date (the day the task is scheduled) — you must include date, otherwise the request is rejected with 422.
curl -X POST "https://api.bordio.com/public/v1/tasks" \ -H "Authorization: Bearer brd_sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "title": "Water the plants", "project_id": "proj_6594a1b2c3d4e5f6a7b8c9d0", "date": "2026-07-06", "recurrence": { "rule": "RRULE:FREQ=DAILY", "until": "2026-08-31" } }'The recurrence object
Section titled “The recurrence object”| Field | Required | Description |
|---|---|---|
rule |
yes | A bare iCalendar RRULE string, e.g. RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR. |
until |
no | ISO-8601 date/datetime — the inclusive end of the series. |
Writing the rule
Section titled “Writing the rule”The rule is a standard RRULE line. The most common parts:
FREQ=— how often:DAILY,WEEKLY,MONTHLYorYEARLY.INTERVAL=— every N periods (e.g.INTERVAL=2withFREQ=WEEKLY= every two weeks). Defaults to1.BYDAY=— days of the week:MO,TU,WE,TH,FR,SA,SU(use withFREQ=WEEKLY).BYMONTHDAY=— day of the month, e.g.BYMONTHDAY=1(use withFREQ=MONTHLY).
Examples:
| Goal | rule |
|---|---|
| Every day | RRULE:FREQ=DAILY |
| Every weekday | RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR |
| Every other Monday | RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=MO |
| First of every month | RRULE:FREQ=MONTHLY;BYMONTHDAY=1 |
| Every year | RRULE:FREQ=YEARLY |
Rules and limits
Section titled “Rules and limits”To keep series valid and safe, the API is strict about the rule:
FREQis required and must be one ofDAILY,WEEKLY,MONTHLY,YEARLY. Sub-daily frequencies (HOURLY,MINUTELY,SECONDLY) are rejected.- Do not include
DTSTART. The start is derived from the resource (start_atfor events,datefor tasks). ADTSTARTin theruleis rejected. - Do not use
COUNT. Bound the series with theuntilfield instead. INTERVAL, if present, must be a positive integer (≤ 1000).- The
rulemust be a singleRRULE:line (noRDATE/EXDATE, no line breaks).
Anything else returns 422 validation_error with code invalid_recurrence_rule.
When does it end?
Section titled “When does it end?”Use the until field for the end date. If you omit until, the series is open-ended and repeats indefinitely.
Reading a series back
Section titled “Reading a series back”Recurring resources include a recurrence object in responses; single (non-recurring) ones return recurrence: null.
{ "data": { "id": "event_6594a1b2c3d4e5f6a7b8c9d0", "title": "Team standup", "start_at": "2026-07-06T09:00:00.000Z", "recurrence": { "rule": "RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR", "until": "2026-12-31T00:00:00.000Z" } }}The returned rule is normalized to the RRULE: line — the internal DTSTART is not exposed.
Repeat after completion (tasks only)
Section titled “Repeat after completion (tasks only)”Instead of a fixed schedule, a task can spawn a new copy of itself when you complete it (move it to a closed status). This is a different mechanism from recurrence above — there is no RRULE, and nothing is created until the task is actually closed. Add repeat_on_completion to POST /tasks:
curl -X POST "https://api.bordio.com/public/v1/tasks" \ -H "Authorization: Bearer brd_sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "title": "Change the water filter", "project_id": "proj_6594a1b2c3d4e5f6a7b8c9d0", "estimated_time_seconds": 1800, "repeat_on_completion": { "start_date_shift_days": 30, "due_date_shift_days": 2, "until": "2027-12-31" } }'When this task is closed, Bordio creates a fresh copy: same title, project, assignees, priority and subtasks, with its start date set 30 days after the completion date and its due date 2 days after that. The copy repeats the same way, until until passes.
| Field | Required | Description |
|---|---|---|
start_date_shift_days |
yes | Days after completion the next copy starts. 0 = same day. |
due_date_shift_days |
no | Days after the copy’s start that its due date falls. Omit for no due date. |
until |
no | Stop repeating after this date (ISO-8601). Omit to repeat indefinitely. |
Notes:
- Only when closed. The copy is created when the task moves to a status whose state is closed — not on every edit.
- Fields are inherited. Title, description, project, assignees, reporters, priority, subtasks and the time estimate carry over to each copy automatically; you only specify the date shifts.
- Mutually exclusive with
recurrence. Sending both on the same task returns422.
Responses include a repeat_on_completion object (or null):
{ "data": { "id": "task_6594a1b2c3d4e5f6a7b8c9d0", "repeat_on_completion": { "start_date_shift_days": 30, "due_date_shift_days": 2, "until": "2027-12-31T00:00:00.000Z" } }}Series vs. occurrences
Section titled “Series vs. occurrences”- The series (the template) has a plain id —
task_<id>/event_<id>— the id you get back from create. Reading, updating or deleting it applies to the whole series. - An individual occurrence has its own id that carries the occurrence date, e.g.
task_<id>_20260113T090000Z(see Identifiers). Read it back from the API and use it verbatim to address that single occurrence — never build it yourself.
What is supported today
Section titled “What is supported today”- Create a recurring task or event.
- Read, update and delete both a series and an individual occurrence by its id.
Not yet available:
- Scoped edits — “this and following” / “all” semantics. An update currently affects the single id you address (the series, or one occurrence), not a chosen span of the series.
This page will be updated as scoped edits land.