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). 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.
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 — 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). Never serves originals. Public — no token required.