Property Management
The Property Management API provides offline-first access to property data with comprehensive filtering, sorting, and pagination capabilities.
Table of contents
Fetch Properties (Paginated)
Retrieves a paginated list of properties with advanced filtering and sorting options.
import zync.api.property.models.GetPropertiesResult
import zync.api.property.models.ZyncPropertySortAndFilter
import zync.api.property.models.ZyncPropertySortBy
import zync.api.common.filter.ZyncSortType
val sortAndFilter = ZyncPropertySortAndFilter(
sortType = ZyncSortType.Descending,
sortBy = ZyncPropertySortBy.PropertyName,
keyword = "warehouse",
isActive = true
)
when (val result = zync.properties.fetchProperties(
sortAndFilter = sortAndFilter,
page = 1,
pageSize = 20
)) {
is GetPropertiesResult.Success -> {
val properties = result.data
val currentPage = result.currentPage
val totalPages = result.totalPages
val totalRecords = result.totalRecords
val isPartialData = result.isPartialData
println("Fetched ${properties.size} properties (page $currentPage of $totalPages)")
if (isPartialData) {
println("Data from cache - may be incomplete")
}
}
is GetPropertiesResult.Failure -> {
println("Error: ${result.error.message}")
}
}
import ZuperSync
let sortAndFilter = ZyncPropertySortAndFilter(
sortType: .descending,
sortBy: .propertyName,
keyword: "warehouse",
isActive: true
)
switch onEnum(of: await zync.properties.fetchProperties(
sortAndFilter: sortAndFilter,
page: 1,
pageSize: 20
)) {
case .success(let success):
let properties = success.data
let currentPage = success.currentPage
let totalPages = success.totalPages
let isPartialData = success.isPartialData
print("Fetched \(properties.count) properties (page \(currentPage) of \(totalPages))")
if isPartialData {
print("Data from cache - may be incomplete")
}
case .failure(let failure):
print("Error: \(failure.error.message)")
}
Parameters
| Parameter | Type | Description |
|---|---|---|
sortAndFilter | ZyncPropertySortAndFilter | Comprehensive filter and sort options |
page | Int | Page number (1-based) |
pageSize | Int | Number of properties per page |
ZyncPropertySortAndFilter Options
| Property | Type | Description |
|---|---|---|
sortType | ZyncSortType | Sort direction (Ascending/Descending/DEFAULT) |
sortBy | ZyncPropertySortBy | Field to sort by (PropertyName, CreatedDate) |
keyword | String? | Search keyword for property name |
customer | ZyncFilterModule? | Filter by customer UID |
organization | ZyncFilterModule? | Filter by organization UID |
createdByUser | ZyncFilterModule? | Filter by creator user UID |
createdDateRange | ZyncFilterDateRange? | Filter by creation date range |
customField | ZyncFilterByCustomField? | Filter by custom field values |
jobRange | ZyncFilterJobRange? | Filter by number of jobs (min/max) |
isActive | Boolean? | Filter by active status |
Return Value: GetPropertiesResult
Success Case:
data: List ofZyncPropertyobjectscurrentPage: Current page numbertotalPages: Total number of pages availabletotalRecords: Total number of properties across all pagesisPartialData:trueif data is from cache (may be incomplete),falseif from API
Failure Case:
error:ZyncErrorwith error details
Get Property Detail
Retrieves comprehensive details for a specific property, including related data like customers, organization, attachments, custom fields, and pricing information.
import zync.api.property.models.GetPropertyResult
when (val result = zync.properties.getPropertyDetail(
propertyUid = "550e8400-e29b-41d4-a716-446655440000"
)) {
is GetPropertyResult.Success -> {
val property = result.data
val lastSynced = result.lastSyncedAt
val syncStatus = result.syncStatus
println("Property: ${property.propertyName}")
println("Address: ${property.propertyAddress?.street}")
println("Organization: ${property.organization?.organizationName}")
println("Jobs: ${property.noOfJobs}")
println("Customers: ${property.customers.size}")
println("Custom Fields: ${property.customFields.size}")
println("Attachments: ${property.attachments.size}")
println("Tax Exempt: ${property.isTaxExempted}")
if (syncStatus == ZyncDataSyncStatus.AGED) {
println("Note: Data is older than 5 minutes. Last synced: $lastSynced")
}
}
is GetPropertyResult.Failure -> {
println("Error: ${result.error.message}")
}
}
import ZuperSync
switch onEnum(of: await zync.properties.getPropertyDetail(
propertyUid: "550e8400-e29b-41d4-a716-446655440000"
)) {
case .success(let success):
let property = success.data
let lastSynced = success.lastSyncedAt
let syncStatus = success.syncStatus
print("Property: \(property.propertyName)")
print("Address: \(property.propertyAddress?.street ?? "N/A")")
print("Organization: \(property.organization?.organizationName ?? "N/A")")
print("Jobs: \(property.noOfJobs ?? 0)")
print("Customers: \(property.customers.count)")
print("Custom Fields: \(property.customFields.count)")
print("Attachments: \(property.attachments.count)")
print("Tax Exempt: \(property.isTaxExempted)")
if syncStatus == .aged {
print("Note: Data is older than 5 minutes. Last synced: \(lastSynced)")
}
case .failure(let failure):
print("Error: \(failure.error.message)")
}
Parameters
| Parameter | Type | Description |
|---|---|---|
propertyUid | String | Unique identifier of the property |
Return Value: GetPropertyResult
Success Case:
data:ZyncPropertyDetailobject with comprehensive property informationsyncStatus:ZyncDataSyncStatus- Indicates data freshness (NONEfor fresh data,AGEDfor data older than 5 minutes,OUTDATED_RECORDfor stale data)lastSyncedAt:String- ISO-8601 formatted timestamp of when this record was last synced from the server
Failure Case:
error:ZyncErrorwith error details
Property Data Models
ZyncProperty (List Item)
Basic property information returned in paginated lists:
| Property | Type | Description |
|---|---|---|
propertyUid | String | Unique identifier |
propertyName | String | Property name |
propertyImage | String? | Property image URL |
propertyAddress | ZyncAddress? | Property address |
noOfJobs | Int? | Number of jobs associated |
isActive | Boolean | Active status |
description | String? | Property description |
ZyncPropertyDetail (Full Detail)
Comprehensive property information including all related data:
| Property | Type | Description |
|---|---|---|
propertyUid | String | Unique identifier |
propertyName | String | Property name |
propertyImage | String? | Property image URL |
propertyAddress | ZyncAddress? | Property address |
isActive | Boolean | Active status |
description | String? | Property description |
noOfJobs | Int? | Number of jobs |
customers | List<ZyncCustomer> | Associated customers |
organization | ZyncOrganization? | Associated organization |
parentProperty | ZyncProperty? | Parent property reference |
createdBy | ZyncCreatedByUser? | User who created the property |
customFields | List<ZyncFormField> | Custom field values |
attachments | List<ZyncAttachment> | Property attachments |
taxGroup | ZyncTaxGroup? | Associated tax group |
isTaxExempted | Boolean | Tax exemption status |
priceList | ZyncPriceList? | Associated price list |
createdAt | String | Creation timestamp |
updatedAt | String? | Last update timestamp |
Best Practices
Pagination
Start with page 1 and use consistent page sizes across requests for predictable behavior. Monitor the isPartialData flag to determine if data is from cache.
suspend fun loadAllProperties() {
val filter = ZyncPropertySortAndFilter(isActive = true)
var currentPage = 1
val pageSize = 50
do {
when (val result = zync.properties.fetchProperties(filter, currentPage, pageSize)) {
is GetPropertiesResult.Success -> {
processProperties(result.data)
currentPage++
if (result.isPartialData) {
println("Warning: Showing cached data")
}
if (currentPage > result.totalPages) break
}
is GetPropertiesResult.Failure -> {
println("Error loading page $currentPage: ${result.error.message}")
break
}
}
} while (true)
}
func loadAllProperties() async {
let filter = ZyncPropertySortAndFilter(isActive: true)
var currentPage = 1
let pageSize = 50
while true {
switch onEnum(of: await zync.properties.fetchProperties(
sortAndFilter: filter,
page: currentPage,
pageSize: pageSize
)) {
case .success(let success):
processProperties(success.data)
currentPage += 1
if success.isPartialData {
print("Warning: Showing cached data")
}
if currentPage > success.totalPages { break }
case .failure(let failure):
print("Error loading page \(currentPage): \(failure.error.message)")
break
}
}
}
Filtering & Sorting
Combine multiple filter properties together for precise results. Use keyword to search property names.
val filter = ZyncPropertySortAndFilter(
sortType = ZyncSortType.Descending,
sortBy = ZyncPropertySortBy.CreatedDate,
keyword = "office",
isActive = true,
createdDateRange = ZyncFilterDateRange(
fromDate = "2024-01-01",
toDate = "2024-12-31"
),
organization = ZyncFilterModule(uid = "org-uid-123")
)
val result = zync.properties.fetchProperties(filter, 1, 50)
let filter = ZyncPropertySortAndFilter(
sortType: .descending,
sortBy: .createdDate,
keyword: "office",
isActive: true,
createdDateRange: ZyncFilterDateRange(
fromDate: "2024-01-01",
toDate: "2024-12-31"
),
organization: ZyncFilterModule(uid: "org-uid-123")
)
let result = await zync.properties.fetchProperties(
sortAndFilter: filter,
page: 1,
pageSize: 50
)
Offline-First Behavior
The Property Management API follows an offline-first approach. Data is immediately available from cache, with background synchronization when online. Always check the
isPartialDataflag to determine data freshness.
The SDK returns cached data when offline and syncs in the background when online.
Error Handling
Always handle both Success and Failure cases. Use error.message for user-friendly messages and error.httpStatusCode for specific error handling.
when (val result = zync.properties.getPropertyDetail(propertyUid)) {
is GetPropertyResult.Success -> {
// Handle success
}
is GetPropertyResult.Failure -> {
when (result.error.httpStatusCode) {
404 -> println("Property not found")
401 -> println("Authentication required")
else -> println("Error: ${result.error.message}")
}
}
}
switch onEnum(of: await zync.properties.getPropertyDetail(propertyUid: propertyUid)) {
case .success(let success):
// Handle success
case .failure(let failure):
switch failure.error.httpStatusCode {
case 404:
print("Property not found")
case 401:
print("Authentication required")
default:
print("Error: \(failure.error.message)")
}
}
Common Use Cases
Search Properties by Keyword
val searchFilter = ZyncPropertySortAndFilter(
keyword = "downtown office",
isActive = true
)
when (val result = zync.properties.fetchProperties(searchFilter, 1, 20)) {
is GetPropertiesResult.Success -> {
println("Found ${result.totalRecords} properties matching 'downtown office'")
result.data.forEach { property ->
println("${property.propertyName} - ${property.propertyAddress?.street}")
}
}
is GetPropertiesResult.Failure -> {
println("Search failed: ${result.error.message}")
}
}
let searchFilter = ZyncPropertySortAndFilter(
keyword: "downtown office",
isActive: true
)
switch onEnum(of: await zync.properties.fetchProperties(
sortAndFilter: searchFilter,
page: 1,
pageSize: 20
)) {
case .success(let success):
print("Found \(success.totalRecords) properties matching 'downtown office'")
success.data.forEach { property in
print("\(property.propertyName) - \(property.propertyAddress?.street ?? "N/A")")
}
case .failure(let failure):
print("Search failed: \(failure.error.message)")
}
Filter by Organization
val orgFilter = ZyncPropertySortAndFilter(
organization = ZyncFilterModule(uid = "org-uid-123"),
isActive = true,
sortBy = ZyncPropertySortBy.PropertyName
)
val result = zync.properties.fetchProperties(orgFilter, 1, 50)
let orgFilter = ZyncPropertySortAndFilter(
organization: ZyncFilterModule(uid: "org-uid-123"),
isActive: true,
sortBy: .propertyName
)
let result = await zync.properties.fetchProperties(
sortAndFilter: orgFilter,
page: 1,
pageSize: 50
)
Get Property with Related Data
when (val result = zync.properties.getPropertyDetail(propertyUid)) {
is GetPropertyResult.Success -> {
val property = result.data
// Access related data
println("Customers: ${property.customers.size}")
property.customers.forEach { customer ->
println(" - ${customer.fullName} (${customer.email})")
}
// Access organization
property.organization?.let { org ->
println("Organization: ${org.organizationName}")
}
// Access parent property
property.parentProperty?.let { parent ->
println("Parent Property: ${parent.propertyName}")
}
// Access custom fields
property.customFields.forEach { field ->
println("${field.fieldName}: ${field.fieldValue}")
}
// Access attachments
property.attachments.forEach { attachment ->
println("Attachment: ${attachment.fileName}")
}
// Access pricing information
property.priceList?.let { priceList ->
println("Price List: ${priceList.name}")
println("Discount: ${priceList.discount}%")
}
// Access tax information
if (property.isTaxExempted) {
println("Tax Status: Exempt")
} else {
property.taxGroup?.let { taxGroup ->
println("Tax Group: ${taxGroup.name}")
println("Tax Rate: ${taxGroup.totalTax}%")
}
}
}
is GetPropertyResult.Failure -> {
println("Error: ${result.error.message}")
}
}
switch onEnum(of: await zync.properties.getPropertyDetail(propertyUid: propertyUid)) {
case .success(let success):
let property = success.data
// Access related data
print("Customers: \(property.customers.count)")
property.customers.forEach { customer in
print(" - \(customer.fullName) (\(customer.email ?? "N/A"))")
}
// Access organization
if let org = property.organization {
print("Organization: \(org.organizationName)")
}
// Access parent property
if let parent = property.parentProperty {
print("Parent Property: \(parent.propertyName)")
}
// Access custom fields
property.customFields.forEach { field in
print("\(field.fieldName): \(field.fieldValue ?? "N/A")")
}
// Access attachments
property.attachments.forEach { attachment in
print("Attachment: \(attachment.fileName)")
}
// Access pricing information
if let priceList = property.priceList {
print("Price List: \(priceList.name)")
print("Discount: \(priceList.discount ?? 0)%")
}
// Access tax information
if property.isTaxExempted {
print("Tax Status: Exempt")
} else if let taxGroup = property.taxGroup {
print("Tax Group: \(taxGroup.name)")
print("Tax Rate: \(taxGroup.totalTax ?? 0)%")
}
case .failure(let failure):
print("Error: \(failure.error.message)")
}
Filter by Job Count
val jobRangeFilter = ZyncPropertySortAndFilter(
jobRange = ZyncFilterJobRange(
minJobs = 5,
maxJobs = 20
),
isActive = true
)
when (val result = zync.properties.fetchProperties(jobRangeFilter, 1, 50)) {
is GetPropertiesResult.Success -> {
println("Properties with 5-20 jobs: ${result.totalRecords}")
result.data.forEach { property ->
println("${property.propertyName} - ${property.noOfJobs} jobs")
}
}
is GetPropertiesResult.Failure -> {
println("Error: ${result.error.message}")
}
}
let jobRangeFilter = ZyncPropertySortAndFilter(
jobRange: ZyncFilterJobRange(
minJobs: 5,
maxJobs: 20
),
isActive: true
)
switch onEnum(of: await zync.properties.fetchProperties(
sortAndFilter: jobRangeFilter,
page: 1,
pageSize: 50
)) {
case .success(let success):
print("Properties with 5-20 jobs: \(success.totalRecords)")
success.data.forEach { property in
print("\(property.propertyName) - \(property.noOfJobs ?? 0) jobs")
}
case .failure(let failure):
print("Error: \(failure.error.message)")
}