Contract Management
The Contract Management API provides offline-first access to service contracts with comprehensive filtering, sorting, and pagination capabilities.
Table of contents
Fetch Contracts (Paginated)
Retrieves a paginated list of service contracts with advanced filtering and sorting options.
import zync.api.contract.models.GetContractsResult
import zync.api.contract.models.ZyncContractSortAndFilter
import zync.api.contract.models.ZyncContractSortBy
import zync.api.common.filter.ZyncSortType
val sortAndFilter = ZyncContractSortAndFilter(
sortType = ZyncSortType.Descending,
sortBy = ZyncContractSortBy.ContractExpiryDate,
keyword = "annual",
isActive = true
)
when (val result = zync.contract.fetchContracts(
sortAndFilter = sortAndFilter,
page = 1,
pageSize = 20
)) {
is GetContractsResult.Success -> {
val contracts = result.data
val currentPage = result.currentPage
val totalPages = result.totalPages
val totalRecords = result.totalRecords
val isPartialData = result.isPartialData
println("Fetched ${contracts.size} contracts (page $currentPage of $totalPages)")
if (isPartialData) {
println("Data from cache - may be incomplete")
}
}
is GetContractsResult.Failure -> {
println("Error: ${result.error.message}")
}
}
import ZuperSync
let sortAndFilter = ZyncContractSortAndFilter(
sortType: .descending,
sortBy: .contractExpiryDate,
keyword: "annual",
isActive: true
)
switch onEnum(of: await zync.contract.fetchContracts(
sortAndFilter: sortAndFilter,
page: 1,
pageSize: 20
)) {
case .success(let success):
let contracts = success.data
let currentPage = success.currentPage
let totalPages = success.totalPages
let isPartialData = success.isPartialData
print("Fetched \(contracts.count) contracts (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 | ZyncContractSortAndFilter | Comprehensive filter and sort options |
page | Int | Page number (1-based) |
pageSize | Int | Number of contracts per page |
ZyncContractSortAndFilter Options
| Property | Type | Description |
|---|---|---|
sortType | ZyncSortType | Sort direction (Ascending/Descending/DEFAULT) |
sortBy | ZyncContractSortBy | Field to sort by (ContractNumber, ContractExpiryDate, CreatedDate) |
keyword | String? | Search keyword for contract name or number |
approvalStatus | String? | Filter by approval status |
asset | ZyncFilterModule? | Filter by asset UID |
approvalBy | ZyncFilterModule? | Filter by approver UID |
customField | ZyncFilterByCustomField? | Filter by custom field values |
customer | ZyncFilterModule? | Filter by customer UID |
organization | ZyncFilterModule? | Filter by organization UID |
property | ZyncFilterModule? | Filter by property UID |
expiryDateRange | ZyncFilterDateRange? | Filter by expiry date range |
isActive | Boolean? | Filter by active status |
isExpired | Boolean? | Filter by expiration status |
uid | List<String>? | Filter by specific contract UIDs |
project | ZyncFilterModule? | Filter by project UID |
Return Value: GetContractsResult
Success Case:
data: List ofZyncContractobjectscurrentPage: Current page numbertotalPages: Total number of pages availabletotalRecords: Total number of contracts across all pagesisPartialData:trueif data is from cache (may be incomplete),falseif from API
Failure Case:
error:ZyncErrorwith error details
Get Contract Detail
Retrieves comprehensive details for a specific contract, including customer information, line items, assets, properties, invoicing, and attachments.
import zync.api.contract.models.ContractResult
when (val result = zync.contract.getContractDetail(
contractUid = "550e8400-e29b-41d4-a716-446655440000"
)) {
is ContractResult.Success -> {
val contract = result.data
val lastSynced = result.lastSyncedAt
val syncStatus = result.syncStatus
println("Contract: ${contract.name}")
println("Number: ${contract.contractNumber}")
println("Status: ${contract.status}")
println("Period: ${contract.startDate} to ${contract.endDate}")
println("Customer: ${contract.customer?.fullName}")
println("Organization: ${contract.organization?.organizationName}")
println("Assets: ${contract.assets.size}")
println("Properties: ${contract.properties.size}")
println("Line Items: ${contract.lineItems.size}")
println("Invoice History: ${contract.contractInvoiceHistory.size}")
if (syncStatus == ZyncDataSyncStatus.AGED) {
println("Note: Data is older than 5 minutes. Last synced: $lastSynced")
}
}
is ContractResult.Failure -> {
println("Error: ${result.error.message}")
}
}
import ZuperSync
switch onEnum(of: await zync.contract.getContractDetail(
contractUid: "550e8400-e29b-41d4-a716-446655440000"
)) {
case .success(let success):
let contract = success.data
let lastSynced = success.lastSyncedAt
let syncStatus = success.syncStatus
print("Contract: \(contract.name)")
print("Number: \(contract.contractNumber)")
print("Status: \(contract.status?.rawValue ?? "N/A")")
print("Period: \(contract.startDate) to \(contract.endDate)")
print("Customer: \(contract.customer?.fullName ?? "N/A")")
print("Organization: \(contract.organization?.organizationName ?? "N/A")")
print("Assets: \(contract.assets.count)")
print("Properties: \(contract.properties.count)")
print("Line Items: \(contract.lineItems.count)")
print("Invoice History: \(contract.contractInvoiceHistory.count)")
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 |
|---|---|---|
contractUid | String | Unique identifier of the contract |
Return Value: ContractResult
Success Case:
data:ZyncContractDetailobject with comprehensive contract 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
Contract Data Models
ZyncContract (List Item)
Basic contract information returned in paginated lists:
| Property | Type | Description |
|---|---|---|
contractUid | String | Unique identifier |
contractNumber | Int | Contract number |
name | String | Contract name |
prefix | String? | Contract prefix |
status | ZyncContractStatus? | Contract status |
startDate | String | Contract start date |
endDate | String | Contract end date |
customer | ZyncCustomer? | Associated customer |
termInMonths | Int? | Contract term duration in months |
isExpired | Boolean? | Expiration status |
isActive | Boolean | Active status |
contractTemplate | ZyncContractTemplate? | Template used |
referenceNumber | String? | Reference number |
description | String? | Contract description |
customFields | List<ZyncFormField> | Custom field values |
createdAt | String | Creation timestamp |
updatedAt | String? | Last update timestamp |
ZyncContractDetail (Full Detail)
Comprehensive contract information including all related data:
| Property | Type | Description |
|---|---|---|
contractUid | String | Unique identifier |
contractNumber | Int | Contract number |
name | String | Contract name |
prefix | String? | Contract prefix |
status | ZyncContractStatus? | Contract status |
startDate | String | Contract start date |
endDate | String | Contract end date |
customer | ZyncCustomer? | Associated customer |
termInMonths | Int? | Contract term duration in months |
isExpired | Boolean? | Expiration status |
isActive | Boolean | Active status |
contractTemplate | ZyncContractTemplate? | Template used |
referenceNumber | String? | Reference number |
description | String? | Contract description |
serviceAddress | ZyncAddress? | Service address |
billingAddress | ZyncAddress? | Billing address |
organization | ZyncOrganization? | Associated organization |
properties | List<ZyncProperty> | Associated properties |
assets | List<ZyncAsset> | Associated assets |
lineItems | List<ZyncLineItem> | Contract line items |
parentContract | ZyncParentContract? | Parent contract reference |
createdBy | User? | User who created the contract |
attachments | List<ZyncAttachment> | Contract attachments |
customFields | List<ZyncFormField> | Custom field values |
invoiceSettings | ZyncContractInvoiceSettings? | Invoice configuration |
contractInvoiceHistory | List<ZyncContractInvoiceHistory> | Invoice history |
priceList | ZyncPriceList? | Associated price list |
createdAt | String | Creation timestamp |
updatedAt | String? | Last update timestamp |
syncedAt | String? | Last sync timestamp |
Best Practices
Pagination
Start with page 1 and use consistent page sizes across requests. Monitor the isPartialData flag to determine if data is from cache.
suspend fun loadAllContracts() {
val filter = ZyncContractSortAndFilter(isActive = true)
var currentPage = 1
val pageSize = 50
do {
when (val result = zync.contract.fetchContracts(filter, currentPage, pageSize)) {
is GetContractsResult.Success -> {
processContracts(result.data)
currentPage++
if (result.isPartialData) {
println("Warning: Showing cached data")
}
if (currentPage > result.totalPages) break
}
is GetContractsResult.Failure -> {
println("Error loading page $currentPage: ${result.error.message}")
break
}
}
} while (true)
}
func loadAllContracts() async {
let filter = ZyncContractSortAndFilter(isActive: true)
var currentPage = 1
let pageSize = 50
while true {
switch onEnum(of: await zync.contract.fetchContracts(
sortAndFilter: filter,
page: currentPage,
pageSize: pageSize
)) {
case .success(let success):
processContracts(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
Use multiple filters to find contracts by customer, organization, expiry dates, or assets. Keyword search works across contract name and number.
val filter = ZyncContractSortAndFilter(
sortType = ZyncSortType.Ascending,
sortBy = ZyncContractSortBy.ContractExpiryDate,
customer = ZyncFilterModule(uid = "customer-uid-123"),
isActive = true,
isExpired = false,
expiryDateRange = ZyncFilterDateRange(
fromDate = "2025-01-01",
toDate = "2025-12-31"
)
)
val result = zync.contract.fetchContracts(filter, 1, 50)
let filter = ZyncContractSortAndFilter(
sortType: .ascending,
sortBy: .contractExpiryDate,
customer: ZyncFilterModule(uid: "customer-uid-123"),
isActive: true,
isExpired: false,
expiryDateRange: ZyncFilterDateRange(
fromDate: "2025-01-01",
toDate: "2025-12-31"
)
)
let result = await zync.contract.fetchContracts(
sortAndFilter: filter,
page: 1,
pageSize: 50
)
Offline-First Behavior
The Contract 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.contract.getContractDetail(contractUid)) {
is ContractResult.Success -> {
// Handle success
}
is ContractResult.Failure -> {
when (result.error.httpStatusCode) {
404 -> println("Contract not found")
401 -> println("Authentication required")
else -> println("Error: ${result.error.message}")
}
}
}
switch onEnum(of: await zync.contract.getContractDetail(contractUid: contractUid)) {
case .success(let success):
// Handle success
case .failure(let failure):
switch failure.error.httpStatusCode {
case 404:
print("Contract not found")
case 401:
print("Authentication required")
default:
print("Error: \(failure.error.message)")
}
}
Common Use Cases
Find Expiring Contracts
val expiringFilter = ZyncContractSortAndFilter(
sortBy = ZyncContractSortBy.ContractExpiryDate,
isActive = true,
isExpired = false,
expiryDateRange = ZyncFilterDateRange(
fromDate = "2025-01-01",
toDate = "2025-03-31"
)
)
when (val result = zync.contract.fetchContracts(expiringFilter, 1, 50)) {
is GetContractsResult.Success -> {
println("Contracts expiring in Q1 2025: ${result.totalRecords}")
result.data.forEach { contract ->
println("${contract.name} - Expires: ${contract.endDate}")
}
}
is GetContractsResult.Failure -> {
println("Error: ${result.error.message}")
}
}
let expiringFilter = ZyncContractSortAndFilter(
sortBy: .contractExpiryDate,
isActive: true,
isExpired: false,
expiryDateRange: ZyncFilterDateRange(
fromDate: "2025-01-01",
toDate: "2025-03-31"
)
)
switch onEnum(of: await zync.contract.fetchContracts(
sortAndFilter: expiringFilter,
page: 1,
pageSize: 50
)) {
case .success(let success):
print("Contracts expiring in Q1 2025: \(success.totalRecords)")
success.data.forEach { contract in
print("\(contract.name) - Expires: \(contract.endDate)")
}
case .failure(let failure):
print("Error: \(failure.error.message)")
}
Filter by Customer
val customerFilter = ZyncContractSortAndFilter(
customer = ZyncFilterModule(uid = "customer-uid-123"),
isActive = true
)
val result = zync.contract.fetchContracts(customerFilter, 1, 50)
let customerFilter = ZyncContractSortAndFilter(
customer: ZyncFilterModule(uid: "customer-uid-123"),
isActive: true
)
let result = await zync.contract.fetchContracts(
sortAndFilter: customerFilter,
page: 1,
pageSize: 50
)
Get Contract with Assets and Invoicing
when (val result = zync.contract.getContractDetail(contractUid)) {
is ContractResult.Success -> {
val contract = result.data
println("Contract: ${contract.name} (#${contract.contractNumber})")
println("Customer: ${contract.customer?.fullName}")
println("Term: ${contract.termInMonths} months")
println("Period: ${contract.startDate} - ${contract.endDate}")
// Access assets
println("\nAssets (${contract.assets.size}):")
contract.assets.forEach { asset ->
println(" - ${asset.assetName} (${asset.assetCode})")
}
// Access properties
println("\nProperties (${contract.properties.size}):")
contract.properties.forEach { property ->
println(" - ${property.propertyName}")
}
// Access line items
println("\nLine Items (${contract.lineItems.size}):")
contract.lineItems.forEach { item ->
println(" - ${item.productName}: ${item.quantity} x ${item.unitPrice}")
}
// Access invoice settings
contract.invoiceSettings?.let { settings ->
println("\nInvoice Frequency: ${settings.frequency}")
}
// Access invoice history
println("\nInvoice History (${contract.contractInvoiceHistory.size}):")
contract.contractInvoiceHistory.forEach { invoice ->
println(" - ${invoice.invoiceDate}: ${invoice.amount}")
}
}
is ContractResult.Failure -> {
println("Error: ${result.error.message}")
}
}
switch onEnum(of: await zync.contract.getContractDetail(contractUid: contractUid)) {
case .success(let success):
let contract = success.data
print("Contract: \(contract.name) (#\(contract.contractNumber))")
print("Customer: \(contract.customer?.fullName ?? "N/A")")
print("Term: \(contract.termInMonths ?? 0) months")
print("Period: \(contract.startDate) - \(contract.endDate)")
// Access assets
print("\nAssets (\(contract.assets.count)):")
contract.assets.forEach { asset in
print(" - \(asset.assetName) (\(asset.assetCode))")
}
// Access properties
print("\nProperties (\(contract.properties.count)):")
contract.properties.forEach { property in
print(" - \(property.propertyName)")
}
// Access line items
print("\nLine Items (\(contract.lineItems.count)):")
contract.lineItems.forEach { item in
print(" - \(item.productName): \(item.quantity) x \(item.unitPrice)")
}
// Access invoice settings
if let settings = contract.invoiceSettings {
print("\nInvoice Frequency: \(settings.frequency ?? "N/A")")
}
// Access invoice history
print("\nInvoice History (\(contract.contractInvoiceHistory.count)):")
contract.contractInvoiceHistory.forEach { invoice in
print(" - \(invoice.invoiceDate): \(invoice.amount)")
}
case .failure(let failure):
print("Error: \(failure.error.message)")
}