Skip to content

Export

User Guide

For a user-facing walkthrough, see Import & Export.

Export location data as JSON, ZIP, or CSV; import V1/V2 format data.


GET /api/locations/{id}/export

Exports the entire location as a V2 JSON document, streamed to the response (the server uses res.write() to avoid buffering very large exports in memory). Photos are base64-encoded and embedded within each bin's photos array.

Filename: openbin-export-<locationId>.json

Limits (enforced server-side):

LimitValue
Max bins per export (active + trashed)5,000
Max total photos per export1,000
Max photos per bin50

Beyond the bin/photo cap the request returns 422 VALIDATION_ERROR. Use search filters or split the export into multiple location-scoped runs.

Path parameters: id (location UUID)

Response (200)

json
{
  "version": 2,
  "exportedAt": "2024-01-01T00:00:00Z",
  "locationName": "My Workshop",
  "locationSettings": {
    "activityRetentionDays": 90,
    "trashRetentionDays": 30,
    "appName": "OpenBin",
    "termBin": "",
    "termLocation": "",
    "termArea": "",
    "defaultJoinRole": "member"
  },
  "bins": [
    {
      "id": "uuid",
      "shortCode": "BINXHM",
      "name": "Screws",
      "items": [
        { "name": "M3x8", "quantity": 50 },
        { "name": "M4x10", "quantity": 25 }
      ],
      "notes": "Sorted by size",
      "tags": ["hardware"],
      "icon": "Wrench",
      "color": "blue-500",
      "createdAt": "...",
      "updatedAt": "...",
      "photos": [
        {
          "id": "uuid",
          "filename": "photo.jpg",
          "mimeType": "image/jpeg",
          "data": "<base64>"
        }
      ]
    }
  ],
  "trashedBins": [ /* same shape as bins, only present when location has trash */ ],
  "areas": [{ "path": "Garage / Workbench" }],
  "tagColors": [{ "tag": "hardware", "color": "blue-500" }],
  "customFieldDefinitions": [{ "name": "Purchase Date", "position": 0 }],
  "pinnedBins": [{ "userId": "uuid", "binId": "uuid", "position": 0 }],
  "savedViews": [{ "userId": "uuid", "name": "Garage hardware", "searchQuery": "screws", "sort": "name", "filters": "{}" }],
  "members": [{ "userId": "uuid", "email": "alice@…", "role": "admin", "joinedAt": "…" }]
}

GET /api/locations/{id}/export/zip

Exports the location as a ZIP file. The archive contains:

EntryContents
manifest.json{ format: "openbin-zip", exportedAt, locationName, locationSettings, areas, customFieldDefinitions, tagColors, pinnedBins, savedViews, members, binCount, trashedBinCount }
bins.jsonArray of all active bins (without photo blobs)
trashed-bins.jsonSoft-deleted bins (only present when there are any)
photos/Original photo files in their native format, organized by bin ID

Filename: openbin-export-YYYY-MM-DD.zip

Path parameters: id (location UUID)

Response (200): Binary ZIP file (application/zip) as a download. Same export caps as the JSON endpoint.


GET /api/locations/{id}/export/csv

Exports the location as a CSV spreadsheet with one row per item. Columns:

ColumnDescription
Bin NameThe bin's name
AreaFull hierarchical area path (e.g. Garage / Workbench)
ItemItem name. Empty when the bin has no items (one row per bin still emitted).
QuantityItem quantity. Empty when no quantity is tracked.
TagsSemicolon-separated list of tags

Filename: openbin-inventory-YYYY-MM-DD.csv

Path parameters: id (location UUID)

Response (200): CSV text (text/csv; charset=utf-8) as a download.


POST /api/locations/{id}/import

Imports bins and photos from a V1 or V2 export document. Supports merge (add to existing) and replace (clear all bins first) modes. Creates areas from path strings on import. JSON body limit: 50 MB. For larger archives, use the ZIP endpoint.

Path parameters: id (location UUID)

Request body

FieldTypeRequiredDescription
version1 or 2YesExport format version
binsarrayYesBin objects matching the format version
exportedAtstring (date-time)No
locationNamestringNo
photosarrayNoPhoto objects
mode"merge" or "replace"NoDefault: "merge"
dryRunbooleanNoWhen true, returns a preview of what would be imported without creating anything. See Dry-Run Preview.

Response (200)

json
{
  "imported": 42,
  "photos": 15
}

POST /api/locations/{id}/import/csv

Imports bins from a CSV file upload. Uses multipart/form-data with a file field. The CSV must have columns matching the export format (Bin Name, Area, Item, Quantity, Tags). Multiple rows with the same bin name and area are grouped into a single bin. File size limit: 10 MB.

Path parameters: id (location UUID)

Form fields

FieldTypeRequiredDescription
filefileYesCSV file
mode"merge" or "replace"NoDefault: "merge"
dryRun"true" or trueNoWhen set, returns a preview without importing. See Dry-Run Preview.

Response (200): { "imported": number }


POST /api/locations/{id}/import/zip

Imports bins and photos from a ZIP backup file. The ZIP must contain manifest.json (with "format": "openbin-zip"), a bins.json file, an optional trashed-bins.json, and an optional photos/ directory. Uses multipart/form-data with a file field. File size limit: 25 MB.

Path parameters: id (location UUID)

Form fields

FieldTypeRequiredDescription
filefileYesZIP file
mode"merge" or "replace"NoDefault: "merge"
dryRun"true" or trueNoWhen set, returns a preview without importing. See Dry-Run Preview.

Response (200): { "imported": number, "photos": number }


Dry-Run Preview

All three import endpoints (JSON, CSV, and ZIP) support a dry-run mode. When you set dryRun to true, the server validates the input and returns a summary of what would happen without actually creating any bins or photos.

Dry-run response (200)

json
{
  "preview": true,
  "toCreate": [
    { "name": "Screws", "itemCount": 3, "tags": ["hardware"] }
  ],
  "toSkip": [
    { "name": "Bolts", "reason": "already exists" }
  ],
  "totalBins": 2,
  "totalItems": 5
}
FieldTypeDescription
previewtrueAlways true in a dry-run response
toCreatearrayBins that would be created, with name, item count, and tags
toSkiparrayBins that would be skipped (e.g. duplicates in merge mode), with the reason
totalBinsnumberTotal number of bins in the import payload
totalItemsnumberTotal number of items across all bins

In merge mode, bins whose IDs already exist in the database are skipped. In replace mode, all bins are treated as new creates.