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_123

Request

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

ParameterTypeRequiredDescription
todoIdString!YesThe existing record to turn into a recurring template.
todoListIdString!YesThe list where each new copy is created.
typeRepeatingTodoRepeatType!YesThe repeat cadence. Use a preset, or CUSTOM with interval.
fields[RepeatingTodoAllowedField]!YesWhich elements to copy to each occurrence.
fromDateTime!YesThe first occurrence date/time the schedule starts from.
intervalRepeatingTodoIntervalInputNoCustom interval. Required when type is CUSTOM.
endRepeatingTodoEndInputNoWhen the schedule stops. Omit to repeat indefinitely.
timeRepeatingTodoTimeInputNoTime of day each occurrence is created at. Omit to keep the legacy default (midnight UTC).
dueDateModeRepeatingTodoDueDateModeNoHow each occurrence gets its due date. Omit for NONE.
dueOffsetDaysIntNoDays to add to the occurrence date. Only read when dueDateMode is OCCURRENCE_DATE.

UpdateRepeatingRecordInput

Same shape as CreateRepeatingRecordInput, plus repeatCounts.

ParameterTypeRequiredDescription
todoIdString!YesThe record whose schedule is being updated.
todoListIdString!YesThe list where each new copy is created.
typeRepeatingTodoRepeatType!YesThe repeat cadence.
fields[RepeatingTodoAllowedField]!YesWhich elements to copy to each occurrence.
fromDateTime!YesThe occurrence date/time the schedule runs from.
intervalRepeatingTodoIntervalInputNoCustom interval. Required when type is CUSTOM.
endRepeatingTodoEndInputNoWhen the schedule stops.
repeatCountsIntNoHow many times the record has already repeated.
timeRepeatingTodoTimeInputNoTime of day each occurrence is created at.
dueDateModeRepeatingTodoDueDateModeNoHow each occurrence gets its due date.
dueOffsetDaysIntNoDays to add to the occurrence date.

RepeatingTodoTimeInput

ParameterTypeRequiredDescription
hourInt!YesHour of day, 24-hour format (0-23).
minuteInt!YesMinute of the hour (0-59).
timezoneString!YesIANA timezone name (e.g. "America/New_York") the hour/minute are interpreted in.

RepeatingTodoIntervalInput

ParameterTypeRequiredDescription
countInt!YesHow many units between occurrences (e.g. 2 for “every 2 weeks”).
typeRepeatingTodoIntervalType!YesThe unit of time: DAYS, WEEKS, MONTHS, or YEARS.
days[RepeatingTodoDayType]NoDays of the week for WEEKS intervals (Sun, Mon, Tue, Wed, Thu, Fri, Sat).
monthRepeatingTodoMonthTypeNoHow to anchor MONTHS intervals: BY_DD or BY_DDDD.

RepeatingTodoEndInput

ParameterTypeRequiredDescription
typeRepeatingTodoEndType!YesHow the schedule ends: NEVER, ON, or AFTER.
onDateTimeNoEnd date. Required when type is ON.
afterIntNoNumber of occurrences. Required when type is AFTER.

RepeatingTodoRepeatType

ValueDescription
DAILYRepeats every day.
WEEKDAYSRepeats Monday through Friday.
WEEKLYRepeats every week on the same day.
MONTHLYRepeats every month on the same date.
YEARLYRepeats every year on the same date.
CUSTOMCadence defined by the interval field.

RepeatingTodoAllowedField

ValueDescription
ASSIGNEESCopy assigned users to the new record.
TAGSCopy tags to the new record.
CUSTOM_FIELDSCopy custom field values to the new record.
DESCRIPTIONCopy the description to the new record.
CHECKLISTSCopy checklists to the new record.
COMMENTSCopy 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

ValueDescription
NONEOccurrences are created with no due date. The default when dueDateMode is omitted.
OCCURRENCE_DATEDue 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

ValueDescription
DAYSInterval measured in days.
WEEKSInterval measured in weeks.
MONTHSInterval measured in months.
YEARSInterval measured in years.

RepeatingTodoMonthType

ValueDescription
BY_DDRepeat on the same date of the month (e.g. the 15th).
BY_DDDDRepeat on the same weekday position (e.g. the 2nd Monday).

RepeatingTodoEndType

ValueDescription
NEVERRepeats indefinitely.
ONEnds on a specific date (set on).
AFTEREnds after a number of occurrences (set after).

Response

Each mutation returns a Boolean under the operation name.

{
  "data": {
    "createRepeatingRecord": true
  }
}

Returns

FieldTypeDescription
createRepeatingRecordBooleantrue when the schedule is attached.
updateRepeatingRecordBooleantrue when the schedule is updated and the next copy is created; false if creating the copy failed (see Errors).
deleteRepeatingRecordBooleantrue 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 todoListId via the same mechanism as copying a record. The target list can be in the same workspace or a different one.
  • fields controls exactly what carries over. Anything not listed is left off the copy.
  • Preset cadences (DAILY, WEEKDAYS, WEEKLY, MONTHLY, YEARLY) need no interval. CUSTOM requires one — use interval.days to pin specific weekdays on WEEKS intervals, and interval.month to anchor MONTHS intervals to a date (BY_DD) or a weekday position (BY_DDDD).
  • time applies uniformly across every cadence and interval type. Omit it to keep the legacy default of creating each occurrence at midnight UTC.
  • time only controls when the copy is created (its createdAt) — it does not set a due date on the copy. fields has no due-date option today, so recurring copies are created without one.
  • When updateRepeatingRecord generates a copy, it logs a REPEAT_TODO activity, 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 returns false instead of throwing — always check the return value.

Errors

CodeWhen
TODO_NOT_FOUNDtodoId (or id on delete) does not exist, or the caller cannot access the record.
FORBIDDENThe caller lacks edit-level access to the record (see Permissions).
UNAUTHENTICATEDThe 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).