Three surfaces move raw bytes rather than JSON-RPC. They are plain HTTP because they stream binary data.

## Upload — `POST /api/v1/images`

Multipart form upload of an original. Requires a bearer token (an access token or a personal access token).

- `file` (required) — the image file (png, jpg, or webp).
- `meta` (optional) — a JSON string, `{"title":"…","description":"…"}`.

On success returns `201` with the created image (the same shape as [`image.get`](/docs/methods/image.get)). The original is stored privately and its renders are enqueued; the image starts in a non-ready state and becomes `ready` once its renders are generated.

```bash
curl -s https://peinture.gumeniuk.com/api/v1/images \
  -H "Authorization: Bearer $TOKEN" \
  -F 'file=@sunset.jpg' \
  -F 'meta={"title":"Sunset","description":"From the pier"}'
```

Errors: `400` (missing/empty/unsupported image), `401` (bad token), `413` (too large).

## Archive — `GET /api/v1/images/{id}/archive?token=…`

Downloads a zip of every render plus the original. The `token` comes from [`image.archiveToken`](/docs/methods/image.archiveToken) — a 5-minute, owner-scoped link. Ready images only. Returns `application/zip`.

## Render serve — `GET /i/{id}/{crop}.{ext}`

Streams a single public render through the app (see [serving modes](/docs/serving-modes)). Never serves originals. Public — no token required.
