---
title: "Create items on a list, many in one call"
method: POST
path: "/api/v1/items"
tags: ["Items"]
---

# Create items on a list, many in one call

`POST /api/v1/items`

## Request

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

Create items on one list, many in one call (1 to 100): a to-do or a dictated list of them on the Tasks list, a note on the Notes list, rows of a reading list or a CRM. Each entry carries a title, a body as Markdown, and `values` for the list's own properties as {propertyId, value} pairs (ids or names from list_lists; a select value may be its label or option id, a multiSelect value an array of them; an unknown label becomes a new option). On a list that keeps a status and a due date an entry may set taskStatus, dueAt (a day, or a local time when one was stated, which also arms a reminder at that moment) and reminderAt (a reminder on a day, at the person's default reminder hour). The items are stored as written and indexed for search; no AI pass runs unless `enrich` is true, which on a tasks list derives the title and due date from the words. An entry's `externalId` (the caller's own id) makes re-sending safe: the same externalId returns the item already made, under `existing`. With `matchOn`, an entry whose named values match an existing item fills that item's empty values, body and images and overwrites nothing (changing a filled value is update_items' job); without it every entry is inserted. Images come as `imageUrls` (a Roma storage path from create_image_upload, or a public https image URL the server downloads); failures come back in `imageFailures`. One bad entry never fails the batch; it is reported under `failed` with its reason.

## Request body

- object
  - `listId` string: The list every item lands on: a list id (from list_lists or get_context), or the word "tasks" (the Tasks list, the unsorted pool) or "notes" (the Notes list, made afresh when the user deleted theirs). Omit for the Tasks list.
  - `items` object[], required: Every item to create, in one call.
    - `title` string, nullable: The item's title — the one name every item has: a short, clear task title on a list that keeps the task columns; the thing's name on every other list, where it is required (no cell stands in for it); optional on the Notes list.
    - `body` string, nullable: The item's body, as Markdown (headings, lists, task lists `- [ ]`, bold, links).
    - `values` object[], nullable: Values for the list's own properties, as {propertyId, value} pairs.
      - `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[]
    - `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. Defaults to 'todo'. Refused on a list without one, or with an id the list does not carry.
    - `dueAt` string, nullable: On a list that keeps a due date: `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. Refused on a list without one.
    - `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: A reminder without a time on the due date, for "remind me about it tomorrow" on a day: `YYYY-MM-DD` (that day at the person's default reminder hour) or `YYYY-MM-DDTHH:MM` in their local time. The visible due date stays a day; an entry with no dueAt is dated that day. A stated due time arms its own reminder, so this is not needed beside one. A moment already passed arms nothing. Refused on a list without a due date.
    - `expertId` string, nullable: The item's standing expert: one of the user's experts by id or name (list_experts). That expert answers by default in the item's chat in Roma, the way a hand-off from the main chat sets one. Only on the user's own lists.
    - `externalId` string, nullable: The caller's own id for this item. The same externalId sent again returns the item already made instead of creating a second one.
    - `imageUrls` string[], nullable: Images for this item: a Roma storage path (from create_image_upload) or a public https image URL the server downloads (images only, ≤10 MB). Max 5 per entry, 30 per call.
  - `matchOn` string[], nullable: Property ids or names that identify an existing item. When given, an entry whose listed values all match an existing item is not added again: the existing item gains the entry's values for its empty cells, its body if it had none, and its images, and keeps every cell it already had; matching is exact. Omit to always insert — no property is a natural key, so there is no default dedup.
  - `enrich` boolean, nullable: Run Roma's background AI pass on each item of a tasks list (title cleanup, due date and list suggestions). Default false: the items are stored as written.

## Response `201`

Created; the body is the new item.

- object
  - `listId` string, required
  - `listName` string, required
  - `listIcon` string, nullable: The list's own icon, an emoji, when it has one.
  - `properties` object[]: The list's own properties, when it has some.
    - `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
  - `items` object[], required
    - `index` number, 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
    - `merged` boolean
  - `added` number, required: Items inserted by this call.
  - `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
  - `mergedIds` string[], required: Existing items an entry was merged into through matchOn.
  - `existing` object[], required
    - `index` number, required
    - `id` string, required
    - `title` string, nullable, required
  - `failed` object[], required
    - `index` number, required
    - `title` string, nullable, required
    - `reason` string, required
  - `unknownKeys` string[], required
  - `imagesAttached` number, required
  - `imageFailures` object[], required
    - `item` string, nullable, required
    - `source` string, required
    - `reason` 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)
