# Images

The [subscribe page](https://docs.kalender-sync.de/en/abo-kalender/abo-seite/) shows a **logo** next to the name and a **banner** at the top. You upload both as a raw image, meaning the image itself is the request body, not JSON or a form.

```
PUT    /v1/publisher/calendars/{calendar_id}/images/logo
PUT    /v1/publisher/calendars/{calendar_id}/images/banner
DELETE /v1/publisher/calendars/{calendar_id}/images/logo
DELETE /v1/publisher/calendars/{calendar_id}/images/banner
```

## Upload

```bash
curl -X PUT https://api.kalender-sync.de/v1/publisher/calendars/$KS_CAL/images/logo \
  -H "Authorization: Bearer $KS_KEY" \
  -H "Content-Type: image/png" \
  --data-binary @logo.png
```

`--data-binary` matters, so curl sends the image unchanged. The response is `200 OK` with the full [calendar](https://docs.kalender-sync.de/en/api/calendars/#the-response), including the new `logo_url` or `banner_url`. A new image replaces the old one.

| | Logo | Banner |
|---|---|---|
| Formats | PNG, JPEG, WebP | PNG, JPEG, WebP |
| Size | up to 512 KB | up to 2 MB |
| Recommended | square, at least 192 × 192 px | about 3:1, at least 1200 px wide |

- **Content-Type:** `image/png`, `image/jpeg`, `image/webp` or `application/octet-stream`. We check whether it really is PNG, JPEG or WebP by the file's content, not by the header.
- **No SVG.** SVG can carry scripts and is refused.
- Aspect ratios and minimum sizes are recommendations for a good look. The API only checks format and file size.

## Remove

```bash
curl -X DELETE https://api.kalender-sync.de/v1/publisher/calendars/$KS_CAL/images/banner \
  -H "Authorization: Bearer $KS_KEY"
```

Response `204 No Content`.

## Image URLs

`logo_url` and `banner_url` point to our own domain, for example

```
https://app.kalender-sync.de/api/public/subscribe/cal_XXXXXXXXXXXX/images/logo?v=…
```

The `v` parameter changes with every new image. Browsers can cache the images for a long time and still show the new one after an upload. Visitors of the subscribe page load nothing from third-party servers.

## Errors

| Code | Status | When |
|---|---|---|
| [`invalid_image`](https://docs.kalender-sync.de/en/api/errors/invalid_image/) | 400 | Empty body |
| [`image_too_large`](https://docs.kalender-sync.de/en/api/errors/image_too_large/) | 413 | Logo over 512 KB, banner over 2 MB |
| [`unsupported_image_type`](https://docs.kalender-sync.de/en/api/errors/unsupported_image_type/) | 415 | Content is not PNG, JPEG or WebP (e.g. SVG, GIF) |
| [`unsupported_media_type`](https://docs.kalender-sync.de/en/api/errors/unsupported_media_type/) | 415 | The Content-Type is not accepted |
| [`payload_too_large`](https://docs.kalender-sync.de/en/api/errors/payload_too_large/) | 413 | Body well over 2 MB |