Lists

Create, read, update, and delete the lists that group records inside a workspace, using the RecordList queries and mutations.


Lists are the columns that organize records within a workspace — the lanes of a board, the sections of a table. In the API they are RecordList objects, and the records they hold are Record objects. Use the queries and mutations on this page to read lists, create and rename them, reorder them, mark every record in a list done or undone, and delete a list.

A workspace can hold at most 50 lists. Lists are ordered by their rank (ascending) and are scoped to the workspace they belong to. Workspace and organization arguments accept either an ID or a slug.

Request

Read a single list

Use the recordList query to fetch one list by ID.

query GetRecordList {
  recordList(id: "list_123") {
    id
    uid
    title
    rank
    isLocked
    todosCount
    project {
      id
      name
    }
  }
}

Read every list in a workspace

Use the recordLists query to fetch all lists in a workspace, ordered by rank.

query GetWorkspaceLists {
  recordLists(projectId: "project_123") {
    id
    title
    rank
    isLocked
    todosCount
  }
}

Search lists across an organization

recordListQueries.todoLists is the filtered, sorted, paginated reader. It returns a RecordListsPagination object (items + pageInfo). companyIds is required; everything else is optional.

query SearchRecordLists(
  $filter: RecordListsFilterInput!
  $sort: [RecordListsSort!]
  $skip: Int
  $take: Int
) {
  recordListQueries {
    todoLists(filter: $filter, sort: $sort, skip: $skip, take: $take) {
      items {
        id
        title
        rank
        project {
          id
          name
        }
      }
      pageInfo {
        totalItems
        hasNextPage
        hasPreviousPage
      }
    }
  }
}
{
  "filter": {
    "companyIds": ["company_123"],
    "projectIds": ["project_123"],
    "search": "sprint"
  },
  "sort": ["rank_ASC"],
  "skip": 0,
  "take": 20
}

Create a list

Use the createRecordList mutation. Send previousId/nextId to place the new list between two existing lists; without them it lands at the far right end.

mutation CreateRecordList {
  createRecordList(input: { projectId: "project_123", title: "Sprint 1" }) {
    id
    title
    rank
  }
}

Rename or reorder a list

Use the editRecordList mutation to change a list’s title or locked state, or to reorder it with previousId/nextId. Only todoListId is required; omitted fields are left unchanged. A reorder without anchors keeps the list where it is.

mutation EditRecordList {
  editRecordList(
    input: { todoListId: "list_123", title: "Sprint 1 — In Progress", isLocked: true }
  ) {
    id
    title
    rank
    isLocked
  }
}

Delete a list

Use the deleteRecordList mutation. The list and its records are moved to Trash together; both projectId and todoListId are required. Deletion is reversible — a workspace OWNER/ADMIN can restore the list (and exactly the records that went down with it) with restoreRecordList until it is purged.

mutation DeleteRecordList {
  deleteRecordList(input: { projectId: "project_123", todoListId: "list_123" }) {
    success
    operationId
  }
}

Restore a deleted list with restoreTodoList, which returns the restored TodoList:

mutation RestoreTodoList {
  restoreTodoList(id: "list_123") {
    id
    title
  }
}

Mark every record in a list done or undone

markRecordListAsDone and markRecordListAsUndone set the done state on every record in a list. Pass an optional filter (a TodosFilter) to scope the change to a subset of records — for example, only records carrying a given tag. Both return a nullable Boolean.

mutation MarkListDone {
  markRecordListAsDone(todoListId: "list_123")
}

mutation MarkListUndone {
  markRecordListAsUndone(
    todoListId: "list_123"
    filter: { companyIds: ["company_123"], tagIds: ["tag_123"] }
  )
}

Parameters

CreateRecordListInput

FieldTypeRequiredDescription
projectIdString!YesWorkspace the list is created in (ID or slug).
titleString!YesDisplay name of the list.
previousIdStringNoPlace the new list directly right of this list. Omit both anchors to land at the far right end.
nextIdStringNoPlace the new list directly left of this list.

EditRecordListInput

FieldTypeRequiredDescription
todoListIdString!YesThe list to update.
titleStringNoNew display name.
previousIdStringNoMove the list to directly right of this list.
nextIdStringNoMove the list to directly left of this list.
isLockedBooleanNoLock the list to prevent further changes to it.

DeleteRecordListInput

FieldTypeRequiredDescription
projectIdString!YesWorkspace the list belongs to (used to verify scope).
todoListIdString!YesThe list to delete.

markRecordListAsDone / markRecordListAsUndone arguments

ArgumentTypeRequiredDescription
todoListIdString!YesThe list whose records are updated.
filterTodosFilterNoRestrict the operation to records matching this filter. When omitted, every record in the list is updated.

TodosFilter is the same record-filter input used to query records — it supports companyIds (required when supplied), projectIds, tagIds, assigneeIds, done, search, duedAt, and more. See List records for the full field set.

RecordListsFilterInput

Used by recordListQueries.todoLists.

FieldTypeRequiredDescription
companyIds[String!]!YesOrganizations to search within.
projectIds[String!]NoRestrict to specific workspaces.
ids[String!]NoRestrict to specific list IDs.
titles[String!]NoMatch exact list titles.
searchStringNoCase-insensitive title search.

The recordListQueries.todoLists field also accepts sort: [RecordListsSort!], skip: Int (default 0), take: Int (default 20), and distinct: [RecordListsFilterDistinct!] to collapse duplicate rows. RecordListsFilterDistinct has a single value, title.

Omit sort to order by rank_ASC, then by id for equal ranks. This is the board’s left-to-right order when the query targets one workspace. Each workspace has its own rank space, so a multi-workspace result is deterministic but does not represent one shared board order.

Sending rank_ASC or rank_DESC explicitly requires exactly one projectIds entry. A rank sort must be the only sort and cannot be combined with distinct. The retired position_ASC and position_DESC values are no longer part of RecordListsSort.

RecordListsSort

ValueDescription
title_ASCTitle, A→Z.
title_DESCTitle, Z→A.
createdAt_ASCOldest created first.
createdAt_DESCNewest created first.
updatedAt_ASCLeast recently updated first.
updatedAt_DESCMost recently updated first.
rank_ASCBoard order, left to right.
rank_DESCBoard order, right to left.

Response

createRecordList and editRecordList return the RecordList:

{
  "data": {
    "createRecordList": {
      "id": "clm4n8qwx000008l0g4oxdqn7",
      "title": "Sprint 1",
      "rank": "a1"
    }
  }
}

deleteRecordList returns a MutationResult:

{
  "data": {
    "deleteRecordList": {
      "success": true,
      "operationId": "clm4n8qwx000108l0h2pyerz9"
    }
  }
}

markRecordListAsDone and markRecordListAsUndone return a nullable Boolean:

{
  "data": {
    "markRecordListAsDone": true
  }
}

RecordList

FieldTypeDescription
idID!Unique identifier.
uidString!Short human-readable identifier.
titleString!Display name.
rankStringOpaque board-order key. Compare two lists’ ranks as strings; do not parse or generate one.
isDisabledBoolean!Whether the list is disabled.
isLockedBooleanWhether the list is locked against changes.
completedBooleanWhether every record in the list is done.
editableBooleanWhether the current user may edit this list.
deletableBooleanWhether the current user may delete this list.
createdAtDateTime!Creation timestamp.
updatedAtDateTime!Last-update timestamp.
createdByUserUser who created the list.
projectWorkspaceParent workspace.
activityActivityAssociated activity-feed entry.
assignees[User!]!Distinct users assigned to records in this list.
tags[Tag!]!Distinct tags applied to records in this list.
todos[Record!]!Records in this list (see arguments below).
todosCountInt!Count of records in this list (accepts the same filter arguments).

The todos and todosCount fields accept arguments to filter the records they resolve: search: String, tagIds: [String!], assigneeIds: [String!], unassigned: Boolean, done: Boolean, duedAt: DateTime, duedAtStart: DateTime, duedAtEnd: DateTime, startedAt: DateTime, fields: JSON, and op: FilterLogicalOperator. todos additionally accepts first: Int, skip: Int, and orderBy: TodoOrderByInput.

query OpenRecordsInList {
  recordList(id: "list_123") {
    title
    todosCount(done: false)
    todos(done: false, first: 25) {
      id
      title
      duedAt
    }
  }
}

RecordListsPagination

FieldTypeDescription
items[RecordList!]!The page of lists.
pageInfoPageInfo!Pagination metadata.

PageInfo exposes totalItems, totalPages, page, perPage, hasNextPage, and hasPreviousPage. RecordListsPagination has no totalCount sibling field — read the total from pageInfo.totalItems.

MutationResult

FieldTypeDescription
successBoolean!Whether the operation completed.
operationIdStringIdentifier for the operation, echoed by the matching subscription event.

Errors

CodeWhen
TODO_LIST_NOT_FOUNDThe todoListId does not exist. Message: Todo list was not found.
PROJECT_NOT_FOUNDThe projectId does not exist or you are not a member of it. Message: Project was not found.
FORBIDDENThe workspace already has 50 lists (createRecordList), or your role lacks permission for the operation (message: You are not authorized.).
{
  "errors": [
    {
      "message": "You have reached the maximum number of todo lists for this project.",
      "extensions": { "code": "FORBIDDEN" }
    }
  ]
}
{
  "errors": [
    {
      "message": "You are not authorized.",
      "extensions": { "code": "FORBIDDEN" }
    }
  ]
}

Permissions

All list mutations require an active (non-archived) workspace and deny VIEW_ONLY and COMMENT_ONLY roles. Creating and deleting lists additionally deny CLIENT.

OperationAllowed roles
createRecordListOWNER, ADMIN, MEMBER
editRecordListOWNER, ADMIN, MEMBER, CLIENT
deleteRecordListOWNER, ADMIN, MEMBER
markRecordListAsDoneOWNER, ADMIN, MEMBER, CLIENT
markRecordListAsUndoneOWNER, ADMIN, MEMBER, CLIENT

Custom roles refine this further: canCreateLists gates createRecordList, canEditLists gates editRecordList, and per-list deletable flags can override canEditLists for deleteRecordList.