CSV Import Wizard
The Import page (/import) is the fastest way to get a new agency live.
A typical 150-door portfolio finishes all three imports in 10-15 minutes.
How it works
Three cards, one per entity type. Each card:
- Has a Download sample CSV button that produces a valid header + one example row
- Has a Choose file picker accepting
.csvortext/csv - Parses row-by-row; a bad row is skipped with an error line, the rest still land
- Returns
{ createdCount, errors: [{ row, message }] }on completion
Properties (+ owners)
street,suburb,state,postcode,property_type,owner_approval_threshold,owner_name,owner_email,owner_mobile
45 Bourke St,Melbourne,VIC,3000,APARTMENT,50000,Jane Montgomery,jane@example.com,0400 111 222
state— VIC / NSW / QLD / WA / SA / TAS / ACT / NTproperty_type—APARTMENT/HOUSE/TOWNHOUSE/UNIT/STUDIOowner_approval_threshold— dollars × 100 (cents).50000= $500.owner_email— find-or-create. If an owner with that email exists in your agency, the property links to them. If not, a new owner is created.- All owner fields are optional except
owner_email. A blank email creates a no-owner property (edge case — use sparingly).
Endpoint: POST /api/v1/properties/import-csv (multipart).
Tenants
full_name,email,mobile
Alex Nguyen,alex@example.com,0411 100 001
- Either
emailormobilerequired. - Leases are not part of this CSV — we'll add that in a second pass once tenants are loaded. Today, link leases via the property detail page or API.
Endpoint: POST /api/v1/tenants/import-csv.
Contractors
business_name,abn,trades,email,mobile,insurance_expires_on
Harbour Plumbing,53 004 085 616,PLUMBER;GAS_FITTER,ops@harbour.example,0411 222 333,2027-06-30
trades— semicolon-separated. See Trade enum.insurance_expires_on— ISO date (YYYY-MM-DD). Drives theCONTRACTOR_INSURANCE_EXPIRINGscanner + ranked-picker score.abn— free text, no validation today. Future: ABN lookup.
Endpoint: POST /api/v1/contractors/import-csv.
Common errors you'll see
| Error | Fix |
|---|---|
row 4: invalid state 'Victoria', expected VIC | Use the 2-3 letter code, not full name |
row 7: trades field empty | Contractor must have at least one trade |
row 12: mobile and email both missing | Tenant / contractor needs one reachable contact |
row 15: owner_approval_threshold must be integer cents | 50000 not 500.00 |
The errors panel in the UI shows the first 20; the rest are available in the response payload.
Atomicity
Each row is processed in its own transaction. A bad row does not rollback earlier good rows. This is intentional — a 500-row CSV with 3 bad rows should leave you with 497 loaded rows and a list of the 3 to fix and re-upload.
Safe to re-upload: properties dedupe on (agency, street, suburb, state, postcode);
tenants dedupe on (agency, email); contractors dedupe on
(agency, business_name).
See also
- Getting Started — where the wizard sits in the first-run flow
- PropertyMe One-Way Sync (planned)