# Batch

For imports and bulk edits, send up to **100 operations** in one call.

```
POST /v1/publisher/calendars/{calendar_id}/events/batch
```

```bash
curl https://api.kalender-sync.de/v1/publisher/calendars/$KS_CAL/events/batch \
  -H "Authorization: Bearer $KS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operations": [
      { "method": "PUT", "external_id": "wp-1482", "event": { "title": "Sunset Yoga", "start": "2026-11-12T18:00:00" } },
      { "method": "PUT", "external_id": "wp-1490", "event": { "title": "", "start": "2026-11-13T18:00:00" } },
      { "method": "DELETE", "external_id": "wp-1311" }
    ]
  }'
```

| Field | Rules |
|---|---|
| `operations` | 1 to 100 entries |
| `operations[].method` | `PUT` (create or update) or `DELETE` |
| `operations[].external_id` | as with the [single PUT](https://docs.kalender-sync.de/en/api/events/) |
| `operations[].event` | for `PUT`: the event, with the same fields as the single PUT |
| `sync_id` | optional: assigns the operations to a [full sync](https://docs.kalender-sync.de/en/api/full-sync/) |

The request body may be up to 1 MB.

## Response

Always `200 OK` as long as the call itself is valid. The result of each operation is in `results`, in the same order:

```json
{
  "results": [
    { "external_id": "wp-1482", "status": 201, "changed": true, "sequence": 0 },
    {
      "external_id": "wp-1490",
      "status": 400,
      "error": {
        "code": "invalid_request",
        "errors": [{ "field": "title", "code": "too_small", "message": "String must contain at least 1 character(s)" }]
      }
    },
    { "external_id": "wp-1311", "status": 204 }
  ]
}
```

| `status` | Meaning |
|---|---|
| `201` | Event created |
| `200` | Event updated or unchanged (`changed: false`) |
| `204` | Event deleted (or already gone) |
| `4xx` | This operation failed; details in `error.code`, `error.message`, `error.errors` |

Possible error codes per operation: [`invalid_request`](https://docs.kalender-sync.de/en/api/errors/invalid_request/), [`invalid_external_id`](https://docs.kalender-sync.de/en/api/errors/invalid_external_id/), [`event_limit_reached`](https://docs.kalender-sync.de/en/api/errors/event_limit_reached/).

## Behavior

- Operations run **in order**. A failing operation does not stop the others, so check every result.
- A batch is **not a transaction**. If the connection drops, some operations may already be done. Just send the batch again: `PUT` and `DELETE` are idempotent.
- The feed is updated once after the batch, not per operation.
- Each batch counts as **one** request for the [rate limit](https://docs.kalender-sync.de/en/api/limits/). That makes batch the right tool for imports.

Errors that affect the whole call (key, calendar, more than 100 operations, body too large, sync expired) come as a normal problem response with an HTTP status. → [Errors](https://docs.kalender-sync.de/en/api/errors/)