Export, Import & Clone
Synchronous export / import
Section titled “Synchronous export / import”POST /api/rooms/:roomId/export (token permission: read) # empty body {} = full room → .gpkgPOST /api/rooms/:roomId/import (token permission: write) # multipart file=@room.gpkg, ≤ 2 GiBcurl -X POST "$API/api/rooms/$ROOM/export" -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" -d '{}' -o room.gpkgcurl -X POST "$API/api/rooms/$ROOM/import" -H "Authorization: Bearer $TOKEN" -F "file=@room.gpkg"The export body/query mirror the app options (?include_tiffs=&include_tiles=).
Size probe
Section titled “Size probe”GET /api/rooms/:roomId/export-size (token permission: read)→ { "bytes", "thresholdBytes", "recommended": "sync" | "async" }. Use it to decide between the sync
route and async jobs (the app switches automatically above ~2 GiB).
Asynchronous export jobs
Section titled “Asynchronous export jobs”POST /api/rooms/:roomId/export-jobs (read) → 202 { "jobId": "<uuid>" }GET /api/rooms/:roomId/export-jobs/:jobId (read) → { status, bytes, error?, startedAt, finishedAt }GET /api/rooms/:roomId/export-jobs/:jobId/artifact (read) → .gpkg streamJob ids are room-bound (polling another room’s job → 404). Artifacts expire after 24 hours.
Clone a large room (reconnect manifest)
Section titled “Clone a large room (reconnect manifest)”Very large rooms exceed the 2 GiB import cap, so they’re cloned instead of re-uploaded — the server copies the underlying data in place.
GET /api/rooms/:roomId/export-manifest (read) # small .json — no bulk data insidePOST /api/rooms/:roomId/clone-jobs (write) → 202 { "jobId": "job-<uuid>" }GET /api/layers/jobs/:jobId # poll: { stage, progress, layersCloned, ... }The manifest carries markers, icons, drawn shapes, and layer configs; bulky layer data is referenced by source room id only and copied server-side into the target room. Copied bytes count against the target owner’s storage quota.

