Skip to content

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 iCalendar RRULE. 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.

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.

Add recurrence to POST /scheduled-events. The series is anchored at start_at.

Terminal window
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.

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.

Terminal window
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"
}
}'
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.

The rule is a standard RRULE line. The most common parts:

  • FREQ= — how often: DAILY, WEEKLY, MONTHLY or YEARLY.
  • INTERVAL= — every N periods (e.g. INTERVAL=2 with FREQ=WEEKLY = every two weeks). Defaults to 1.
  • BYDAY= — days of the week: MO,TU,WE,TH,FR,SA,SU (use with FREQ=WEEKLY).
  • BYMONTHDAY= — day of the month, e.g. BYMONTHDAY=1 (use with FREQ=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

To keep series valid and safe, the API is strict about the rule:

  • FREQ is required and must be one of DAILY, WEEKLY, MONTHLY, YEARLY. Sub-daily frequencies (HOURLY, MINUTELY, SECONDLY) are rejected.
  • Do not include DTSTART. The start is derived from the resource (start_at for events, date for tasks). A DTSTART in the rule is rejected.
  • Do not use COUNT. Bound the series with the until field instead.
  • INTERVAL, if present, must be a positive integer (≤ 1000).
  • The rule must be a single RRULE: line (no RDATE/EXDATE, no line breaks).

Anything else returns 422 validation_error with code invalid_recurrence_rule.

Use the until field for the end date. If you omit until, the series is open-ended and repeats indefinitely.

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.

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:

Terminal window
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 returns 422.

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"
}
}
}
  • 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.
  • 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.