---
title: Batches and reasons
description: Several writes as one transaction, with a reason kept for each change.
section: Data
order: 4
---

# Batches and reasons

<p class="lead">A batch makes several writes as one: either all of them happen or none do. A reason can go with them, and it is kept with every change in collections that keep history.</p>

```http title="HTTP"
POST /api/batch
X-Sluurp-Reason: Term two timetable

{
  "requests": [
    { "method": "POST",   "url": "/api/collections/lessons/records", "body": { "day": "mon", "slot": 1 } },
    { "method": "PATCH",  "url": "/api/collections/lessons/records/l0000000000001", "body": { "slot": 2 } },
    { "method": "DELETE", "url": "/api/collections/lessons/records/l0000000000002" }
  ]
}
```

- A batch is one transaction. If any request is refused, by a rule or by validation, nothing is written, and the answer says which request failed.
- Each request is checked as the caller, as it would be on its own.
- A batch refuses collections that have a write hook, because a hook runs outside the transaction.
- The reason, given as the header or as `"reason"` in the body, is kept with every change the batch makes.

## One write at a time

```ts title="Browser"
await sluurp.collection("grades").update(id, { value: 7 }, { reason: "Re-marked after appeal" });
await sluurp.collection("grades").delete(id, { reason: "Entered twice" });
```

Reasons show in a record's [history](/docs/history), beside who made the change and when.
