Recurring Records
Attach a repeating schedule to a record so Blue automatically generates copies on a defined cadence.
Use the createRepeatingRecord, updateRepeatingRecord, and deleteRepeatingRecord mutations to manage a repeating schedule on a record. The schedule is attached to an existing record, which acts as the template: each time the schedule fires, Blue copies the template into a target list. Records are Record objects in the API; lists are RecordList objects.
You control the cadence with a preset (DAILY, WEEKLY, MONTHLY, …) or a fully custom interval, choose when the schedule ends, and pick which elements (assignees, tags, custom fields, and more) carry over to each copy. All three mutations return Boolean.
Send these headers with every request. Company and project accept either an ID or a slug, and header names are case-insensitive.
blue-token-id: YOUR_TOKEN_ID
blue-token-secret: YOUR_TOKEN_SECRET
blue-org-id: YOUR_ORG_ID
blue-workspace-id: project_123Request
Attach a daily repeating schedule to an existing record, copying assignees and tags to each new occurrence:
mutation CreateRecurringRecord {
createRepeatingRecord(
input: {
todoId: "todo_123"
todoListId: "list_123"
type: DAILY
fields: [ASSIGNEES, TAGS]
from: "2026-06-01T09:00:00Z"
}
)
}Parameters
CreateRepeatingRecordInput
| Parameter | Type | Required | Description |
|---|---|---|---|
todoId | String! | Yes | The existing record to turn into a recurring template. |
todoListId | String! | Yes | The list where each new copy is created. |
type | RepeatingTodoRepeatType! | Yes | The repeat cadence. Use a preset, or CUSTOM with interval. |
fields | [RepeatingTodoAllowedField]! | Yes | Which elements to copy to each occurrence. |
from | DateTime! | Yes | The first occurrence date/time the schedule starts from. |
interval | RepeatingTodoIntervalInput | No | Custom interval. Required when type is CUSTOM. |
end | RepeatingTodoEndInput | No | When the schedule stops. Omit to repeat indefinitely. |
time | RepeatingTodoTimeInput | No | Time of day each occurrence is created at. Omit to keep the legacy default (midnight UTC). |
dueDateMode | RepeatingTodoDueDateMode | No | How each occurrence gets its due date. Omit for NONE. |
dueOffsetDays | Int | No | Days to add to the occurrence date. Only read when dueDateMode is OCCURRENCE_DATE. |
UpdateRepeatingRecordInput
Same shape as CreateRepeatingRecordInput, plus repeatCounts.
| Parameter | Type | Required | Description |
|---|---|---|---|
todoId | String! | Yes | The record whose schedule is being updated. |
todoListId | String! | Yes | The list where each new copy is created. |
type | RepeatingTodoRepeatType! | Yes | The repeat cadence. |
fields | [RepeatingTodoAllowedField]! | Yes | Which elements to copy to each occurrence. |
from | DateTime! | Yes | The occurrence date/time the schedule runs from. |
interval | RepeatingTodoIntervalInput | No | Custom interval. Required when type is CUSTOM. |
end | RepeatingTodoEndInput | No | When the schedule stops. |
repeatCounts | Int | No | How many times the record has already repeated. |
time | RepeatingTodoTimeInput | No | Time of day each occurrence is created at. |
dueDateMode | RepeatingTodoDueDateMode | No | How each occurrence gets its due date. |
dueOffsetDays | Int | No | Days to add to the occurrence date. |
RepeatingTodoTimeInput
| Parameter | Type | Required | Description |
|---|---|---|---|
hour | Int! | Yes | Hour of day, 24-hour format (0-23). |
minute | Int! | Yes | Minute of the hour (0-59). |
timezone | String! | Yes | IANA timezone name (e.g. "America/New_York") the hour/minute are interpreted in. |
RepeatingTodoIntervalInput
| Parameter | Type | Required | Description |
|---|---|---|---|
count | Int! | Yes | How many units between occurrences (e.g. 2 for “every 2 weeks”). |
type | RepeatingTodoIntervalType! | Yes | The unit of time: DAYS, WEEKS, MONTHS, or YEARS. |
days | [RepeatingTodoDayType] | No | Days of the week for WEEKS intervals (Sun, Mon, Tue, Wed, Thu, Fri, Sat). |
month | RepeatingTodoMonthType | No | How to anchor MONTHS intervals: BY_DD or BY_DDDD. |
RepeatingTodoEndInput
| Parameter | Type | Required | Description |
|---|---|---|---|
type | RepeatingTodoEndType! | Yes | How the schedule ends: NEVER, ON, or AFTER. |
on | DateTime | No | End date. Required when type is ON. |
after | Int | No | Number of occurrences. Required when type is AFTER. |
RepeatingTodoRepeatType
| Value | Description |
|---|---|
DAILY | Repeats every day. |
WEEKDAYS | Repeats Monday through Friday. |
WEEKLY | Repeats every week on the same day. |
MONTHLY | Repeats every month on the same date. |
YEARLY | Repeats every year on the same date. |
CUSTOM | Cadence defined by the interval field. |
RepeatingTodoAllowedField
| Value | Description |
|---|---|
ASSIGNEES | Copy assigned users to the new record. |
TAGS | Copy tags to the new record. |
CUSTOM_FIELDS | Copy custom field values to the new record. |
DESCRIPTION | Copy the description to the new record. |
CHECKLISTS | Copy checklists to the new record. |
COMMENTS | Copy comments to the new record. |
RepeatingTodoAllowedField has no DUE_DATE member on purpose. These values copy the template’s own stored values, and a template never moves, so a copied due date would give every occurrence in the series the same fixed day. Use dueDateMode instead — it derives a date from each occurrence.
RepeatingTodoDueDateMode
| Value | Description |
|---|---|
NONE | Occurrences are created with no due date. The default when dueDateMode is omitted. |
OCCURRENCE_DATE | Due on the day the occurrence is created, plus dueOffsetDays. |
OCCURRENCE_DATE reads the day the occurrence is created in the schedule’s own timezone (time.timezone), not in UTC. An evening schedule in a timezone behind UTC would otherwise be dated a day late.
dueOffsetDays must be a positive whole number. Any other value — zero, a negative, a fraction, or omitted — is read as no offset, so the occurrence is due on the day it is created. The date is always stored as an all-day date; the schedule’s time of day is when the work appears, not when it is due.
Existing schedules created before these fields were added carry no dueDateMode, which reads as NONE. Their behavior does not change.
updateRepeatingRecord creates a copy as soon as it succeeds, and that copy is dated by the same rule as every later occurrence. Send dueDateMode on an update as well as on a create, or the first record of the reconfigured series is the only undated one.
RepeatingTodoIntervalType
| Value | Description |
|---|---|
DAYS | Interval measured in days. |
WEEKS | Interval measured in weeks. |
MONTHS | Interval measured in months. |
YEARS | Interval measured in years. |
RepeatingTodoMonthType
| Value | Description |
|---|---|
BY_DD | Repeat on the same date of the month (e.g. the 15th). |
BY_DDDD | Repeat on the same weekday position (e.g. the 2nd Monday). |
RepeatingTodoEndType
| Value | Description |
|---|---|
NEVER | Repeats indefinitely. |
ON | Ends on a specific date (set on). |
AFTER | Ends after a number of occurrences (set after). |
Response
Each mutation returns a Boolean under the operation name.
{
"data": {
"createRepeatingRecord": true
}
}Returns
| Field | Type | Description |
|---|---|---|
createRepeatingRecord | Boolean | true when the schedule is attached. |
updateRepeatingRecord | Boolean | true when the schedule is updated and the next copy is created; false if creating the copy failed (see Errors). |
deleteRepeatingRecord | Boolean | true when the schedule is removed. |
To read the active schedule’s target list back, select repeatingTodoList on the record. It is null when no schedule is set.
query RecurringTarget {
recordQueries {
todos(filter: { companyIds: ["company_123"], todoIds: ["todo_123"] }) {
items {
id
title
repeatingTodoList {
id
title
}
}
}
}
}Full example
Repeat every 2 weeks on Monday and Wednesday, end after 10 occurrences, and copy every supported element:
mutation CreateRecurringRecordCustom {
createRepeatingRecord(
input: {
todoId: "todo_123"
todoListId: "list_123"
type: CUSTOM
fields: [ASSIGNEES, TAGS, CUSTOM_FIELDS, DESCRIPTION, CHECKLISTS, COMMENTS]
from: "2026-06-01T09:00:00Z"
interval: { count: 2, type: WEEKS, days: [Mon, Wed] }
end: { type: AFTER, after: 10 }
}
)
}Update a record’s schedule to repeat monthly by date, ending on a fixed date:
mutation UpdateRecurringRecord {
updateRepeatingRecord(
input: {
todoId: "todo_123"
todoListId: "list_123"
type: CUSTOM
fields: [ASSIGNEES, TAGS, DESCRIPTION]
from: "2026-07-01T09:00:00Z"
interval: { count: 1, type: MONTHS, month: BY_DD }
end: { type: ON, on: "2026-12-31T23:59:59Z" }
repeatCounts: 5
}
)
}Remove a schedule from a record (the id is the record’s todoId):
mutation DeleteRecurringRecord {
deleteRepeatingRecord(id: "todo_123")
}How it works
- The schedule lives on the template record; the template itself is never altered when a copy is generated.
- Each occurrence is a fresh copy created in
todoListIdvia the same mechanism as copying a record. The target list can be in the same workspace or a different one. fieldscontrols exactly what carries over. Anything not listed is left off the copy.- Preset cadences (
DAILY,WEEKDAYS,WEEKLY,MONTHLY,YEARLY) need nointerval.CUSTOMrequires one — useinterval.daysto pin specific weekdays onWEEKSintervals, andinterval.monthto anchorMONTHSintervals to a date (BY_DD) or a weekday position (BY_DDDD). timeapplies uniformly across every cadence and interval type. Omit it to keep the legacy default of creating each occurrence at midnight UTC.timeonly controls when the copy is created (itscreatedAt) — it does not set a due date on the copy.fieldshas no due-date option today, so recurring copies are created without one.- When
updateRepeatingRecordgenerates a copy, it logs aREPEAT_TODOactivity, records a todo action, notifies the copy’s assignees, and publishes the new record in real time. If creating the copy fails, the mutation clears the schedule to avoid a stuck state and returnsfalseinstead of throwing — always check the return value.
Errors
| Code | When |
|---|---|
TODO_NOT_FOUND | todoId (or id on delete) does not exist, or the caller cannot access the record. |
FORBIDDEN | The caller lacks edit-level access to the record (see Permissions). |
UNAUTHENTICATED | The request carries no valid token. |
Permissions
Managing a recurring schedule requires edit-level access to the record. Only OWNER, ADMIN, and MEMBER access levels qualify; CLIENT, COMMENT_ONLY, and VIEW_ONLY cannot. A custom role with records disabled (isRecordsEnabled: false) is also denied, and the record’s workspace must be active (not archived).