-
Notifications
You must be signed in to change notification settings - Fork 1
Bulk CSV Import
There are two CSV importers in Roomer:
- Global import — Admin → Import. Creates buildings, floors, zones and assets from one flat sheet. Use this for initial seeding or moving in a whole floorplan from a spreadsheet.
- Per-floor import — inside the floor editor. Creates assets on an existing floor and places them into existing zones.
They have different column names and different semantics. Pick the one that matches what you already have.
Use when you have a single sheet that describes the whole layout: "Building Sydney HQ has two floors, each with a Window zone and an Open zone, and here are the 200 desks."
POST /api/v1/import/bulk — SUPER_ADMIN only. Max 2000 rows per request.
| Column | Required? | Accepted values |
|---|---|---|
building_name |
✓ | Any non-empty string. Buildings are looked up by name; if a building with that name exists it's reused. |
building_address |
Free text. Only applied when the building is created; ignored on reuse. | |
floor_name |
✓ | Any non-empty string. Scoped to the building — two floors with the same name in different buildings are OK. |
floor_level |
Integer. Controls sort order in the sidebar (lower first). Blank → 0. |
|
zone_name |
✓ | Any non-empty string. Scoped to the floor. |
zone_colour |
6-digit hex like #6366f1. Blank → palette is auto-assigned from a rotating 10-colour list, so you can leave it out entirely. |
|
asset_name |
✓ | Display name on the marker. |
asset_category |
✓ | Any string. If the category doesn't exist it's created on the fly with defaultIsBookable inferred from the row. |
asset_status |
OPEN (default), RESTRICTED, ASSIGNED, or DISABLED. See Zones and Assets. |
|
asset_amenities |
Semicolon-separated list: monitor;docking-station;adjustable-desk. |
|
is_bookable |
true (default) or false/0 to create an inventory-only asset. |
|
serial_number |
Free text. | |
asset_tag |
Free text. Must be unique across all assets. |
One row creates one asset. Buildings / floors / zones / categories are upserted by name — the importer tracks what it has already created within the same request so repeating a building/floor/zone across rows is fine:
building_name,floor_name,zone_name,asset_name,asset_category,asset_status
Sydney HQ,Level 1,Window Row,A-01,Desk,OPEN
Sydney HQ,Level 1,Window Row,A-02,Desk,OPEN
Sydney HQ,Level 1,Open Plan,B-01,Desk,OPEN
Sydney HQ,Level 2,Window Row,C-01,Desk,OPENResult: 1 building, 2 floors, 3 zones (Window Row on L1, Open Plan on L1, Window Row on L2), 4 assets.
Every imported asset is dropped at (x=50, y=50) with width=3, height=2, rotation=0. After import, open the floor editor to drag assets into
position. (Keeping layout information in CSV is deliberately out-of-scope —
you end up in a GIS-y rabbit hole. Use the canvas once, not a spreadsheet.)
Rows are validated individually. Valid rows are imported in a transaction;
invalid rows are returned to the UI with row numbers (offset by +2 so row 1
is the header, row 2 is the first data row). If all rows are invalid the
endpoint returns 422 with no changes applied.
The import dialog in Admin → Import shows the success/error count and lists every error, making it easy to fix the sheet and re-upload. Re-running with partial overlap is safe — existing buildings/floors/zones/categories get reused.
building_name,building_address,floor_name,floor_level,zone_name,zone_colour,asset_name,asset_category,asset_status,asset_amenities,is_bookable,serial_number,asset_tag
Sydney HQ,1 Example St Sydney,Level 1,1,Window Row,#6366f1,A-01,Desk,OPEN,monitor;docking-station,true,,A-01
Sydney HQ,,Level 1,1,Window Row,,A-02,Desk,OPEN,,true,,A-02
Sydney HQ,,Level 1,1,Open Plan,#10b981,B-01,Desk,OPEN,,true,,B-01
Sydney HQ,,Level 1,1,Open Plan,,B-02,Desk,DISABLED,,true,,
Sydney HQ,,Level 2,2,Window Row,,C-01,Desk,RESTRICTED,,true,,C-01You can download this template from Admin → Import → Template CSV.
Use when the building, floor and zones already exist and you just want to populate (or add to) a floor with assets.
POST /api/v1/assets/bulk-import — body { floorId, assets: [...] },
SUPER_ADMIN only. Max 500 rows per request.
| Column | Required? | Accepted values |
|---|---|---|
name |
✓ | Display name. |
category |
✓ | Category name. Auto-created if missing, with defaultIsBookable=true. |
bookingStatus |
OPEN (default), RESTRICTED, ASSIGNED, DISABLED. |
|
bookingLabel |
Defaults to Desk. Shown in the booking dialog and email subject. |
|
amenities |
Semicolon-separated list. | |
serialNumber |
Free text. | |
assetTag |
Free text. Must be unique. | |
notes |
Free text. | |
zoneName |
Name of an existing zone on this floor (case-insensitive). If no match or omitted, the asset is placed in the floor's first zone — create zones before importing. |
name,category,bookingStatus,bookingLabel,amenities,serialNumber,assetTag,notes,zoneName
A-01,Desk,OPEN,Desk,monitor;docking-station,,,,Window Row
A-02,Desk,OPEN,Desk,,,,,Window Row
MR-Jupiter,Meeting Room,OPEN,Room,whiteboard;tv,,,,RoomsEach row is attempted independently; failures are returned with the row number and an error message. Successful rows are not rolled back when others fail — fix the broken rows and re-run.
Use this when you want to bulk-assign users to existing bookable assets without editing each one individually.
Where to find it:
- Admin → Buildings → [building] → Bulk assign users — pre-loaded with the building's assets; download a pre-populated CSV to start.
- Admin → Assets → Bulk assign users — no building filter; download the blank template and fill in asset IDs.
POST /api/v1/assets/user-assignments/bulk — body
{ rows: [{ assetId, userEmail, isPrimary? }] }, SUPER_ADMIN only.
Max 5000 rows per request.
| Column | Required | Accepted values |
|---|---|---|
ASSET_ID |
✓ | UUID of an existing Roomer asset. |
USER_EMAIL |
✓ | Email of an existing Roomer user. |
IS_PRIMARY |
true / false / 1 / yes. Defaults to false. Setting a new primary clears the previous one for that asset. |
ASSET_ID,USER_EMAIL,IS_PRIMARY
<asset-uuid>,jane.smith@example.com,true
<asset-uuid>,john.doe@example.com,falseDownload [building] assets in the dialog to get a pre-populated version with asset IDs and current assignments already filled in.
- Each row is attempted independently; rows that fail (unknown asset, unknown user) are returned with a row number and reason.
- Successful rows upsert — running the same assignment twice is safe.
- Removing a user is not supported via this CSV; use the per-asset UI or the
DELETE /api/v1/assets/:id/user-assignments/:userIdendpoint.
To wipe a floor's assignments in bulk, use the Clear assignments button
(user-minus icon) on each floor card in Admin → Buildings → [building].
This calls DELETE /api/v1/assets/user-assignments/by-floor/:floorId.
- Excel will mangle leading zeros (
001,02-A) — if you use those, save the sheet as CSV with quoted fields or use Google Sheets / LibreOffice. - Both importers treat the first CSV row as headers — case-insensitive, but the exact names listed above must be used (no synonyms).
- Use UTF-8. Non-ASCII zone/asset names work fine.
- If you need to re-upload after fixing errors, you can — duplicate rows
with the same name will hit uniqueness on
asset_tag(if set) or create a second asset (if not). Clean up first, or only include the missing rows.
Install & Run
- Getting Started
- Development Setup
- Production Deployment
- Kubernetes Deployment
- Backup and Recovery
- TLS Configuration
- Configuration Reference
Using Roomer
- Buildings and Floors
- Zones and Assets
- Users, Groups and Permissions
- Booking and Queue
- Bulk CSV Import
- Enterprise Auth
- Email Notifications
- Webhooks
- Reports and Leases
Developer