---
title: "Update items, many in one call"
method: PATCH
path: "/api/v1/items"
tags: ["Items"]
---

# Update items, many in one call

`PATCH /api/v1/items`

## Request

- Base URL: `https://api.roma.app`
- URL: `https://api.roma.app/api/v1/items`
- Auth: HTTP bearer

Update items, many in one call, each with its own title, body edits and values; the status, due date, archive and favorite flags apply to every item in the call. Only the fields passed change; null leaves a field as it is. The body is edited with `edits` against the handles get_item returns in `body` — replace, insert, delete, setChecked, move, replaceText, or rewrite pinned to `bodyVersion` — applied in order, all or nothing; a refused call writes nothing on that item and returns the current body with fresh handles. The older way, `body` with the call's merge `mode` (append by default, prepend, insertAfter with `anchor`, replace with confirmReplace: true), still works; an item uses one or the other. `values` MERGE into the item (only the properties sent change; "" clears one; an unknown property is an error naming the valid ones). `imageUrls` add images (clearImages: true drops the old ones first). taskStatus, dueAt, reminderAt and muteReminder apply only on a list that keeps them: a due date is a day, or a local time when one was stated, which also arms a reminder at that moment; reminderAt arms a reminder on a day without touching the date; muteReminder turns it off; dueAt "none" clears the due date and its reminder. Items are written in order; a refusal stops the batch and names the items already written, so re-send only the rest. Returns each item, with `body`, `bodyVersion` and `applied` after a body write.

## Request body

- object
  - `items` object[], required: Every item to update, in one call.
    - `itemId` string, required: The item's id.
    - `title` string, nullable: New title. Omit, or pass null, to leave it unchanged.
    - `edits` object[], nullable: Body edits by block handle, applied in order, all or nothing. The handles come from `body` on the item as read with get_item (`[b7k2] - [ ] milk`; the handle is how a block is pointed at and is never written into Markdown an edit authors). Ops: `replace` a block's Markdown; `insert` Markdown at a `position` relative to a block (after, before, child of a list item, sectionEnd of a heading) or at start / end of the body with no block; `delete` a block; `setChecked` a checklist item; `move` a block to a `position` relative to `to`; `replaceText` one exact phrase (`find` → `replace`) inside a block; `rewrite` the whole body with `baseVersion` set to the `bodyVersion` that was read, refused when the body moved on since. Lists: an item is authored with its marker (`- `, `1. `, `- [ ] `) and joins the list it is placed in; a plain paragraph placed `after` or `before` an item lands outside the list, which splits around it. An item replaced by plain lines stays an item; replaced by Markdown that opens with a heading, quote or code block, it leaves the list and the new blocks stand in its place (list lines at the start replace it in place, the rest follows after the list). A block replaced earlier in the same call keeps its handle for the edits after it. A refused call writes nothing and returns the current body with fresh handles. Omit for no body change; not combined with the legacy body field and `mode`.
      - `op` 'replace' | 'insert' | 'delete' | 'setChecked' | 'move' | 'replaceText' | 'rewrite', required: What this edit does: replace | insert | delete | setChecked | move | replaceText | rewrite.
      - `block` string, nullable, required: Handle of the target block, e.g. "b7k2", as shown in front of the block in `body` (for move: the block that moves). null for insert at start/end and for rewrite.
      - `position` 'before' | 'after' | 'child' | 'sectionEnd' | 'start' | 'end', nullable, required: insert/move only: before | after | child (under a list item) | sectionEnd (end of a heading's section) | start | end (of the body, with block null). null otherwise.
      - `to` string, nullable, required: move only: handle of the block to move next to. null for start/end.
      - `markdown` string, nullable, required: replace/insert/rewrite: the Markdown to write (checklists `- [ ] item`, headings, lists, links). Never contains a handle. null otherwise.
      - `checked` boolean, nullable, required: setChecked only: true to tick, false to untick. null otherwise.
      - `find` string, nullable, required: replaceText only: the exact phrase to change; it must appear once in the block (or once in the body when block is null).
      - `replace` string, nullable, required: replaceText only: the new phrase ("" deletes it). null otherwise.
      - `isDeletionIntended` boolean, nullable, required: rewrite only: true when the person asked to remove a large part of the body. null otherwise.
      - `baseVersion` string, nullable, required: rewrite only: the `bodyVersion` returned with the body the rewrite was written from (e.g. "v3k9x2"). null otherwise.
    - `body` string, nullable: Legacy body write: Markdown to merge in per the call's `mode`. Omit, or pass null, to leave the body unchanged (or pass `edits`). To empty the body, send "" with mode 'replace' and confirmReplace: true.
    - `values` object[], nullable: Values for the list's own properties to set, as {propertyId, value} pairs — MERGED into the item's values. "" clears a property.
      - `propertyId` string, required: The property's stable id (from list_lists) or its name.
      - `value` union, required: The value for this property: text, a number, an option label or id, or an array of them for a multiSelect property. "" clears it on an update.
        - string
        - number
        - boolean
        - string[]
    - `expertId` string, nullable: The item's standing expert: one of the user's experts by id or name (list_experts), or "none" to clear it. That expert answers by default in the item's chat in Roma. Omit, or pass null, to leave it unchanged. Refused on an item shared with the user: its expert is its owner's.
    - `imageUrls` string[], nullable: Images to add (the same sources as create_items). Max 5 per item, 30 per call.
    - `clearImages` boolean, nullable: true removes the item's existing images first; any imageUrls then attach fresh.
    - `taskStatus` string, nullable: This item's status, on a list that keeps one: a status id of the list's Status property (todo, inProgress, completed on every list that keeps one; backlog, inReview, canceled and the list's own ids where list_lists shows them). A done-stage status completes the item. Wins over the call's taskStatus for this item.
  - `mode` 'prepend' | 'append' | 'replace' | 'insertAfter', nullable: Legacy: how each item's `body` merges: 'append' (default, at the bottom), 'prepend' (at the top), 'insertAfter' (right after the line named in `anchor`), or 'replace' (swap the whole body — only when the user explicitly asked to rewrite it; requires confirmReplace: true).
  - `anchor` string, nullable: For mode 'insertAfter' only: a verbatim snippet of the existing line to insert after. Errors if not found.
  - `confirmReplace` boolean, nullable: Required (true) for mode 'replace': confirms the user explicitly asked to swap the WHOLE body, deleting everything in it. Never pass it on the user's behalf without that explicit ask.
  - `taskStatus` string, nullable: On a list that keeps a status: a status id of the list's Status property (todo, inProgress, completed on every list that keeps one; backlog, inReview, canceled and the list's own ids where list_lists shows them). A done-stage status completes the item. Applies to every item in the call. Status transitions report progress.
  - `dueAt` string, nullable: On a list that keeps a due date, for every item in the call: `YYYY-MM-DD` for a day the person named with no time (the usual case; nothing rings); `YYYY-MM-DDTHH:MM` in their local time when they stated a time, which also arms a push reminder at that moment. An instant with a zone (`2026-10-28T09:00:00Z`) is read as the day it falls on in their zone unless hasDueTime is true. A reminder already armed follows a moved day. "none" removes the due date with its time and reminder.
  - `hasDueTime` boolean, nullable: With a dueAt that carries a zone: true when its time of day is meant (the due is that moment and the reminder is armed), false to keep the day alone. Not needed for the two plain shapes.
  - `reminderAt` string, nullable: Arms a reminder without changing the visible due date, for every item in the call: `YYYY-MM-DD` (that day at the person's default reminder hour) or `YYYY-MM-DDTHH:MM` in their local time. An undated item is dated that day. A moment already passed arms nothing. Not beside dueAt "none" or muteReminder.
  - `muteReminder` boolean, nullable: true turns the reminder off and leaves the due date and its time as they are, for every item in the call. Not beside reminderAt.
  - `archived` boolean, nullable: true sets the item(s) aside (hidden from every list, kept and reversible); false brings them back.
  - `favorited` boolean, nullable: true pins the item(s) in the app's Favorites; false unpins them.

## Response `200`

The tool's result.

- object
  - `updated` number, required
  - `items` object[], required
    - `id` string, required
    - `identifier` string, nullable: The item's fixed ID — its list's prefix and a number, TASK-1601 — which every item tool takes as its id too.
    - `title` string, nullable
    - `body` string, nullable: The body as Markdown; with a short handle in front of every block on a read made for editing.
    - `bodyVersion` string: A fingerprint of the body as read; a whole-body `rewrite` names it as `baseVersion`.
    - `taskStatus` string, nullable: On a list that keeps a status.
    - `dueAt` string, nullable: On a list that keeps a due date: the instant stored; a day when hasDueTime is false.
    - `hasDueTime` boolean, nullable: Whether dueAt's time of day is meant; false for a day.
    - `reminderAt` string, nullable: When the reminder rings, as an instant; null for none.
    - `completedAt` string, nullable
    - `values` object: The item's values keyed by property id; a select value is an option id.
    - `cells` object: The item's values by property NAME, as text, where its list has properties of its own.
    - `isSharedWithMe` boolean: Shared with the person by its owner; `editable` says what update_items admits on it.
    - `editable` 'all' | 'titleAndBody': On a row shared with the person: `titleAndBody` for an item shared with them one by one (its status, due date, values and images are its owner's; update_items refuses them by name), `all` for an item on a list shared with them (every field but the owner's favorite).
    - `listId` string, nullable
    - `listName` string, nullable
    - `listIcon` string, nullable: The list's own icon, an emoji, when it has one.
    - `expertId` string, nullable: The id of the item's standing expert (one of the user's experts, list_experts), when the user's own item carries one: that expert answers by default in the item's chat in Roma. Absent on a row shared with the user.
    - `createdAt` string, nullable
    - `updatedAt` string, nullable
    - `editedAt` string, nullable
    - `archivedAt` string, nullable
    - `recordingStatus` string
    - `attachments` object[]
      - `bucketPath` string, required
      - `mimeType` string, required
      - `sizeBytes` number, required
      - `url` string
    - `bodyImages` object[]: The pictures the body shows (`![…](roma://attachment/<bucketPath>)`), whether or not they are attachments, with the size each was stored at (null when unknown) and its alt text; with includeImageUrls, a short-lived signed url on each; with includeImages on get_item, the pictures themselves as image content blocks.
      - `bucketPath` string, required
      - `width` number, nullable, required
      - `height` number, nullable, required
      - `alt` string, required
      - `url` string
    - `properties` object[]: The list's own properties.
      - `id` string, required
      - `name` string, required
      - `type` string, required
      - `kind` string: What the property IS: "status" / "dueDate" for the reserved pair a list binds to the task columns, else its type. A select named Status on any other list is a plain select.
      - `options` object[]
        - `id` string, required
        - `label` string, required
      - `optionCount` number
    - `applied` string[]: The edits that were applied, in order.
    - `warning` string: The body was written and a row field was not; the sentence says which.
  - `imagesAttached` number, required
  - `imageFailures` object[], required
    - `item` string, nullable, required
    - `source` string, required
    - `reason` string, required
  - `links` object, required: The roots of a row's links: `<webOrigin>/artifacts/<id>` is the item's page in Roma, `<appScheme>://artifacts/<id>` the same item in the Roma Mac app.
    - `webOrigin` string, required
    - `appScheme` string, required

## Other responses

- `400`: The request was understood and refused; the error says what to change.
- `401`: No usable bearer token.
- `404`: No such item for this account.
- `405`: The path exists but not with this method; Allow lists the ones that work.
- `429`: Over the rate limit; wait for Retry-After.

---

[API](https://skmtc.dev/roma/apis/roma-api.md) - [All operations](https://skmtc.dev/roma/apis/roma-api/llms.txt) - [OpenAPI document](https://skmtc.dev/roma/apis/roma-api/revisions/3dd91459b0fb?raw)
