# 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.

```json
{ "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 duplicate weekday, a fractional `count`, or a `count` outside 1 to 999 all make the whole rule invalid.

> ⚠ Today an invalid rule raises no error. The row is accepted and simply treated as non-recurring, which you will only notice when the next occurrence never appears. Validate the JSON yourself, then read the to-do back and check `recurrenceRule` came back as you sent it.

## 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.

```bash
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` sets `status: "done"`, stamps `completedAt`, and for a recurring to-do also advances the series.

**The response is the to-do you completed**, as a [Todo](/objects#todo). The next occurrence is a separate row, and you will see it in a later list rather than in this response. A `count` is decremented on each completion.

So a client that wants the next occurrence immediately has to go and read it:

```bash
curl -s "https://api.inittasks.com/v1/todos?limit=5" \
  -H "Authorization: Bearer $INITTASKS_TOKEN"
```

## Parked recurring to-dos

Parking a plain to-do in someday strips its dates. A recurring one instead keeps its date and its rule, dormant. Setting `status: "open"` again re-aligns a dormant `schedule` rule to today or later, and leaves an `afterCompletion` rule where it is.

## Next

- [The data model](/data-model)
- [Reference for /todos](/reference/todos)
