---
url: /api/recurring-tasks.md
description: Create, manage, and edit recurring task series via the API.
---

# Recurring Tasks API

All endpoints require a Bearer JWT token. Recurring tasks are scoped to a workspace.

**Base URL:** `https://api.hule-do.com/api`

***

## `POST /workspaces/:workspaceId/recurring-tasks`

Create a new recurring task series.

**Request:**

```json
{
  "title": "Weekly standup notes",
  "description": "What I worked on, what's blocking me, next steps",
  "listId": "667f...",
  "spaceId": "667f...",
  "interval": {
    "frequency": "week",
    "every": 1,
    "daysOfWeek": ["mon", "wed", "fri"],
    "timeOfDay": "09:00",
    "timezone": "Europe/Moscow"
  },
  "endCondition": {
    "type": "after_n",
    "count": 50
  },
  "spawnStatusId": "667f...",
  "priority": "medium",
  "tagIds": ["667f..."]
}
```

**`interval` fields:**

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `frequency` | string | yes | `day`, `week`, `month`, `year` |
| `every` | number | yes | Step: every N days/weeks/months/years |
| `daysOfWeek` | string\[] | for `week` | `mon`, `tue`, `wed`, `thu`, `fri`, `sat`, `sun` |
| `monthDay` | number | for `month` | Day of month (1–31) |
| `monthOfYear` | number | for `year` | Month (1–12) |
| `timeOfDay` | string | yes | HH:MM in 24h format |
| `timezone` | string | yes | IANA timezone, e.g. `America/New_York` |

**`endCondition` fields:**

| Type | Additional fields |
|------|-------------------|
| `never` | — |
| `on_date` | `date` (ISO 8601) |
| `after_n` | `count` (number) |

**Response:** `201`

```json
{
  "id": "667f...",
  "title": "Weekly standup notes",
  "interval": { /* ... */ },
  "nextRunAt": "2026-06-02T06:00:00.000Z",
  "spawnCount": 0,
  "active": true,
  "createdAt": "2026-05-28T10:00:00.000Z"
}
```

***

## `GET /workspaces/:workspaceId/recurring-tasks`

List all recurring task series in the workspace.

**Response:** `200` — array of recurring job objects.

***

## `GET /workspaces/:workspaceId/recurring-tasks/:id`

Get a single recurring job.

**Response:** `200` — recurring job object.

***

## `PATCH /workspaces/:workspaceId/recurring-tasks/:id`

Update a recurring job. Omitted fields are not changed.

**Request:**

```json
{
  "active": false,
  "title": "Updated meeting title"
}
```

**Response:** `200` — updated recurring job.

***

## `DELETE /workspaces/:workspaceId/recurring-tasks/:id`

Delete the recurring series. Existing spawned task instances are preserved.

**Response:** `204 No Content`

***

## `POST /workspaces/:workspaceId/recurring-tasks/:id/skip`

Skip the next occurrence. The job's `nextRunAt` is advanced past the current candidate by adding it to `skipDates[]`.

**Request:** (no body)

**Response:** `204 No Content`

***

## `POST /workspaces/:workspaceId/recurring-tasks/:id/skip-until`

Skip all occurrences until a specific date. Pass `null` to clear.

**Request:**

```json
{
  "skipUntil": "2026-06-15T00:00:00.000Z"
}
```

**Response:** `204 No Content`

***

## `POST /workspaces/:workspaceId/recurring-tasks/:jobId/instances/:taskId/edit-mode`

Edit a spawned task instance with control over how the change propagates.

**Request:**

```json
{
  "mode": "this",
  "updates": {
    "title": "Updated standup topic",
    "priority": "high"
  }
}
```

**`mode` values:**

| Mode | Behaviour |
|------|-----------|
| `this` | Update only this instance. The occurrence date is added to the series' skip list. |
| `this_and_following` | Split the series. End the current series before this date and create a new one with the changes. |
| `all` | Update this instance + the template + all past instances (title, description, priority, tags). |

**Response:** `200` — updated `TaskDto`.

***

## `GET /workspaces/:workspaceId/recurring-tasks/:id/instances`

List all task instances spawned from this recurring job.

**Query parameters:** `page`, `limit`.

**Response:** `200`

```json
{
  "items": [ /* TaskDto[] */ ],
  "total": 12,
  "page": 1,
  "limit": 20
}
```

***

## Errors

| Code | Meaning |
|------|---------|
| `400` | Invalid interval or end condition |
| `404` | Recurring job not found |

## Related

* [API Examples](/api/examples) — full walkthroughs.
* [Set up a recurring task](/guides/set-up-recurring-tasks) — the same feature in the app.
