# Update tasks in place — one, or several

`PATCH /api/v1/tasks/batch`

MCP tool: `update-tasks`

The only way to change a task: 1 to 100 items, each an `id` plus the fields to change, all written or none. Each changes only the fields sent. A status move outside the table answers `409` with `from`, `to` and `allowed`, and nothing lands; an id given twice answers `400`. Send `basis` with the move itself: resending the status a task already has records no change, so a cause left off is given only through `reconcile-task`.
`wait: null` clears the wait; omitting `wait` leaves it. Clearing a wait never changes the status: the task then answers `get-next?slice=hold_cleared` (or `date_came`) until somebody moves it.
Send `if_unmodified_since` with the `updated_at` you read to have a concurrent write reported. The answer is one acknowledgement per item, in order.

## Responses

- `200` — Every item was written; one acknowledgement each, in order
- `400` — The request body or query string does not match the operation's schema, or a `calendar` task names no date (`calendar_requires_date`)
- `404` — No such task
- `409` — The status change is not one the GTD state table allows. The body's `error.code` is `invalid_transition` and `error.meta` carries `from`, `to` and `allowed` — the statuses this task can actually move to.
