the rule format, and what completing a recurring to-do does
Recurrence
A recurring to-do carries a rule. Over MCP you pass it as a repeat object; over REST you pass that same object serialised to a JSON string in recurrenceRule, up to 512 characters. The server reads it with the same engine the apps run, so a string it cannot parse (an iCalendar FREQ=DAILY, say) is validation_failed at /recurrenceRule rather than a stored rule nothing can use.
{ "freq": "weekly", "interval": 1, "byday": [1, 3, 5], "until": "2026-12-31" }The rule
| field | required | values |
|---|---|---|
freq |
always | daily, weekly, monthly, yearly |
interval |
always | 1 to 999 |
byday |
weekly only |
ISO weekdays, Monday 1 through Sunday 7. Non-empty and unique |
bymonthday |
monthly, and yearly |
1 to 31, clamped to the month end when it overflows |
bymonth |
yearly only |
1 to 12 |
mode |
optional | schedule (the default) or afterCompletion |
until |
optional | yyyy-MM-dd, the last date an occurrence may fall on, inclusive |
count |
optional | occurrences remaining including the active one, 1 to 999 |
schedule repeats on a fixed grid. afterCompletion counts the next date from when you complete it, and in that mode the rule carries only freq, interval and the end conditions. A grid field there makes the rule invalid.
The grammar is closed
An unknown field, an unknown mode, a grid field under afterCompletion, a missing byday on a weekly rule, a duplicate weekday, a fractional count, or a count outside 1 to 999 all make the whole rule invalid. POST and PATCH refuse an invalid rule with validation_failed at /recurrenceRule, and nothing is written.
Setting one
Sending a rule clears deadline and stamps whenDate as the anchor. In schedule mode with no whenDate, the first occurrence date is seeded for you. In afterCompletion mode it is seeded to today. A rule whose until falls before that first date would never happen, so it is refused with validation_failed at /recurrenceRule.
A parked to-do (status: "someday") given a rule comes out of someday: it is dated the same way, its status becomes open, and it lists on planned (on today, in afterCompletion mode).
curl -s "https://api.inittasks.com/v1/todos/$ID" -X PATCH \
-H "Authorization: Bearer $INITTASKS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"recurrenceRule":"{\"freq\":\"weekly\",\"interval\":1,\"byday\":[1]}"}'Send "recurrenceRule": null to clear the rule and leave an ordinary to-do.
Completing one
POST /v1/todos/{id}/complete on a plain to-do sets status: "done" and stamps completedAt.
A recurring to-do works the other way round. The row you complete is the series, and it stays open: it moves to its next occurrence (whenDate advances, a count is decremented, and a reminder on the occurrence's day moves with it; recurrenceAnchor stays). The completion is recorded as a new done row: a copy with completedAt and no rule. That copy is what the completed view lists.
So the response, a Todo, is the series at its next occurrence, still open. Keep using the same id for the series. The done copy has an id of its own; find it in /v1/views/completed.
The last occurrence (a count of 1, or the next date past until) is different: there is no next one, so the row itself becomes done, rule and date kept.
Parked recurring to-dos
Parking a to-do in someday (POST /v1/todos/{id}/someday) strips its dates, a recurring one included. A recurring one keeps its rule, dormant: nothing rolls while it is parked.
To bring it back with its series running, either:
- move it:
POST /v1/todos/{id}/move, to its own project or any other place, un-parks it and gives it a new first date, the rule's first day from today on, or today itself inafterCompletionmode. On MCP,update_todowithstatus: "open"does the same. - give it a date:
PATCHwith awhenDateun-parks it on that day, and the series restarts from it. AwhenTimewith no date does the same on today.
POST /v1/todos/{id}/anytime un-parks it too, but the way the apps' anytime does: open, undated, rule kept. With no date there is nothing to roll from, so completing it finishes it like a plain to-do. Give it a whenDate and it rolls again from that date.