DevelopersAPI reference

Properties API

REST endpoints for properties in ServFlo: 9 operations with parameters, request and response fields, permissions and curl examples.

Base URL: https://app.servflo.ai/api. Every call needs Authorization: Bearer sfk_… (Authentication); {organizationId} ($ORGANIZATION_ID in the examples) is your business's id.

OperationEndpointRisk
List propertiesGET /organizations/{organizationId}/propertiesread
Create a propertyPOST /organizations/{organizationId}/propertieswrite
Get a property with its occupancy historyGET /organizations/{organizationId}/properties/{propertyId}read
Update a propertyPATCH /organizations/{organizationId}/properties/{propertyId}write
Link a customer to a propertyPOST /organizations/{organizationId}/properties/{propertyId}/occupancieswrite
Change a current occupant's role or make them primaryPATCH /organizations/{organizationId}/properties/{propertyId}/occupancies/{occupancyId}write
End a customer's link to a propertyPOST /organizations/{organizationId}/properties/{propertyId}/occupancies/{occupancyId}/endwrite
Transfer a property (sale or move)POST /organizations/{organizationId}/properties/{propertyId}/transferwrite
Re-geocode a propertyPOST /organizations/{organizationId}/properties/{propertyId}/geocodewrite

List properties

GET /organizations/{organizationId}/properties

Properties (service addresses) with their current occupants, filtered by text, type, tag, or customerId (that customer's current properties); paged with a total. A technician sees only properties where they have a job. Read-only.

Permissionproperties.read (Owner, Admin, Dispatcher, Technician, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolproperties_list (toolset customers, in the default set)

Parameters

NameInTypeRequiredDescription
queryquerystringNoFree-text search over the list's names, numbers and contact details. Up to 200 characters.
customerIdquerystringNo
propertyTypequeryenumNoOne of RESIDENTIAL, COMMERCIAL, MULTI_FAMILY, INDUSTRIAL.
tagquerystringNoUp to 200 characters.
limitqueryintegerNoPage size, 1–200. Default 50.
offsetqueryintegerNoRows to skip; the answer's total counts every match. Default 0.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/properties" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
itemsarray of object
items[].idstringProperty id.
items[].organizationIdstring
items[].namestring or null
items[].addressstring or null
items[].address2string or null
items[].citystring or null
items[].statestring or null
items[].zipstring or null
items[].countrystring or null
items[].propertyTypeenumOne of RESIDENTIAL, COMMERCIAL, MULTI_FAMILY, INDUSTRIAL.
items[].contactNamestring or nullWho to ask for on site.
items[].contactPhonestring or null
items[].contactEmailstring or null
items[].timezonestringIANA timezone of the property.
items[].accessInstructionsstring or null
items[].safetyNotesstring or null
items[].gateCodestring or null
items[].petsOnSiteboolean
items[].petNotesstring or null
items[].yearBuiltinteger or null
items[].squareFeetinteger or null
items[].tagsarray of string
items[].latitudenumber or null
items[].longitudenumber or null
items[].geocodeSourcestring or nullWhere the coordinates came from: GEOCODER (the address), GEOCODER_STREET / GEOCODER_AREA (approximate: only its street or town is on the map; visit safety then searches the ZIP), MANUAL (pinned by hand).
items[].geocodedAtstring (date-time) or null
items[].taxRatenumber or nullTax rate in percent for work here; null = the business default.
items[].customFieldsanyCustom field values by key (definitions: GET /custom-fields).
items[].createdAtstring (date-time)
items[].updatedAtstring (date-time)
items[].occupanciesarray of objectCurrent occupants, primary first.
items[].occupancies[].idstringOccupancy id (for PATCH …/occupancies/{occupancyId}).
items[].occupancies[].propertyIdstring
items[].occupancies[].customerIdstring
items[].occupancies[].roleenumOne of OWNER, TENANT, LANDLORD, PROPERTY_MANAGER.
items[].occupancies[].isPrimarybooleanThe property's primary current occupant.
items[].occupancies[].startedOnstringFirst day of the link, YYYY-MM-DD.
items[].occupancies[].endedOnstring or nullLast day, YYYY-MM-DD; null = current.
items[].occupancies[].createdAtstring (date-time)
items[].occupancies[].customerobject
items[].assetCountintegerEquipment registered at the property.
totalintegerHow many match the filters, across all pages.

Create a property

POST /organizations/{organizationId}/properties

Creates a property (service address). With customerId it is linked to that customer from startedOn or today (default role OWNER, primary). Returns the property.

Permissionproperties.write (Owner, Admin, Dispatcher)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolproperties_create (toolset customers, in the default set)

Request body

FieldTypeRequiredDescription
namestring or nullNoUp to 500 characters.
addressstring or nullNoUp to 500 characters.
address2string or nullNoUp to 500 characters.
citystring or nullNoUp to 500 characters.
statestring or nullNoUp to 500 characters.
zipstring or nullNoUp to 500 characters.
countrystring or nullNoUp to 500 characters.
propertyTypeenumNoOne of RESIDENTIAL, COMMERCIAL, MULTI_FAMILY, INDUSTRIAL.
contactNamestring or nullNoUp to 500 characters.
contactPhonestring or nullNoUp to 500 characters.
contactEmailempty string or string (email) or nullNo
timezonestringNoAn IANA timezone, e.g. America/Chicago. Up to 100 characters.
accessInstructionsstring or nullNoUp to 5000 characters.
safetyNotesstring or nullNoUp to 5000 characters.
gateCodestring or nullNoUp to 500 characters.
petsOnSitebooleanNo
petNotesstring or nullNoUp to 5000 characters.
yearBuiltinteger or nullNo1000–3000.
squareFeetinteger or nullNo0–100000000.
tagsarray of stringNoUp to 100 items.
taxRatenumber or nullNo-1000–1000.
latitudenumber or nullNoGeocode (WGS84), pinned by hand. Leave out to have the address geocoded after saving; the map, route planning and My day's distances use it. -90–90.
longitudenumber or nullNo-180–180.
customFieldsobjectNo
customerIdstringNo
roleenumNoOne of OWNER, TENANT, LANDLORD, PROPERTY_MANAGER.
startedOnstringNoA calendar date in the business's own calendar, YYYY-MM-DD.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/properties" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Dana Whitfield","address":"string","address2":"string"}'

Response

201: the answer's fields
FieldTypeDescription
idstringProperty id.
organizationIdstring
namestring or null
addressstring or null
address2string or null
citystring or null
statestring or null
zipstring or null
countrystring or null
propertyTypeenumOne of RESIDENTIAL, COMMERCIAL, MULTI_FAMILY, INDUSTRIAL.
contactNamestring or nullWho to ask for on site.
contactPhonestring or null
contactEmailstring or null
timezonestringIANA timezone of the property.
accessInstructionsstring or null
safetyNotesstring or null
gateCodestring or null
petsOnSiteboolean
petNotesstring or null
yearBuiltinteger or null
squareFeetinteger or null
tagsarray of string
latitudenumber or null
longitudenumber or null
geocodeSourcestring or nullWhere the coordinates came from: GEOCODER (the address), GEOCODER_STREET / GEOCODER_AREA (approximate: only its street or town is on the map; visit safety then searches the ZIP), MANUAL (pinned by hand).
geocodedAtstring (date-time) or null
taxRatenumber or nullTax rate in percent for work here; null = the business default.
customFieldsanyCustom field values by key (definitions: GET /custom-fields).
createdAtstring (date-time)
updatedAtstring (date-time)

Get a property with its occupancy history

GET /organizations/{organizationId}/properties/{propertyId}

One property with every occupancy (owner, tenant … with dates), its equipment count and custom fields. A technician gets 404 unless they have a job there. Read-only.

Permissionproperties.read (Owner, Admin, Dispatcher, Technician, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolproperties_get (toolset customers)

Parameters

NameInTypeRequiredDescription
propertyIdpathstringYes

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/properties/{propertyId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
idstringProperty id.
organizationIdstring
namestring or null
addressstring or null
address2string or null
citystring or null
statestring or null
zipstring or null
countrystring or null
propertyTypeenumOne of RESIDENTIAL, COMMERCIAL, MULTI_FAMILY, INDUSTRIAL.
contactNamestring or nullWho to ask for on site.
contactPhonestring or null
contactEmailstring or null
timezonestringIANA timezone of the property.
accessInstructionsstring or null
safetyNotesstring or null
gateCodestring or null
petsOnSiteboolean
petNotesstring or null
yearBuiltinteger or null
squareFeetinteger or null
tagsarray of string
latitudenumber or null
longitudenumber or null
geocodeSourcestring or nullWhere the coordinates came from: GEOCODER (the address), GEOCODER_STREET / GEOCODER_AREA (approximate: only its street or town is on the map; visit safety then searches the ZIP), MANUAL (pinned by hand).
geocodedAtstring (date-time) or null
taxRatenumber or nullTax rate in percent for work here; null = the business default.
customFieldsanyCustom field values by key (definitions: GET /custom-fields).
createdAtstring (date-time)
updatedAtstring (date-time)
occupanciesarray of objectEvery occupancy, current ones first (endedOn null), then past ones.
occupancies[].idstringOccupancy id (for PATCH …/occupancies/{occupancyId}).
occupancies[].propertyIdstring
occupancies[].customerIdstring
occupancies[].roleenumOne of OWNER, TENANT, LANDLORD, PROPERTY_MANAGER.
occupancies[].isPrimarybooleanThe property's primary current occupant.
occupancies[].startedOnstringFirst day of the link, YYYY-MM-DD.
occupancies[].endedOnstring or nullLast day, YYYY-MM-DD; null = current.
occupancies[].createdAtstring (date-time)
occupancies[].customerobject
occupancies[].customer.idstringCustomer id.
occupancies[].customer.namestring
occupancies[].customer.typeenumOne of RESIDENTIAL, COMMERCIAL.
occupancies[].customer.phonestring or null
occupancies[].customer.emailstring or null
_countobjectEquipment and jobs at the property.
_count.assetsinteger
_count.jobsinteger

Update a property

PATCH /organizations/{organizationId}/properties/{propertyId}

Changes the fields sent (address, access notes, gate code, tax rate, custom fields …). Returns the property.

Permissionproperties.write (Owner, Admin, Dispatcher)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolproperties_update (toolset customers)

Parameters

NameInTypeRequiredDescription
propertyIdpathstringYes

Request body

FieldTypeRequiredDescription
namestring or nullNoUp to 500 characters.
addressstring or nullNoUp to 500 characters.
address2string or nullNoUp to 500 characters.
citystring or nullNoUp to 500 characters.
statestring or nullNoUp to 500 characters.
zipstring or nullNoUp to 500 characters.
countrystring or nullNoUp to 500 characters.
propertyTypeenumNoOne of RESIDENTIAL, COMMERCIAL, MULTI_FAMILY, INDUSTRIAL.
contactNamestring or nullNoUp to 500 characters.
contactPhonestring or nullNoUp to 500 characters.
contactEmailempty string or string (email) or nullNo
timezonestringNoAn IANA timezone, e.g. America/Chicago. Up to 100 characters.
accessInstructionsstring or nullNoUp to 5000 characters.
safetyNotesstring or nullNoUp to 5000 characters.
gateCodestring or nullNoUp to 500 characters.
petsOnSitebooleanNo
petNotesstring or nullNoUp to 5000 characters.
yearBuiltinteger or nullNo1000–3000.
squareFeetinteger or nullNo0–100000000.
tagsarray of stringNoUp to 100 items.
taxRatenumber or nullNo-1000–1000.
latitudenumber or nullNoGeocode (WGS84), pinned by hand. Leave out to have the address geocoded after saving; the map, route planning and My day's distances use it. -90–90.
longitudenumber or nullNo-180–180.
customFieldsobjectNo

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/properties/{propertyId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Dana Whitfield","address":"string","address2":"string"}'

Response

200: the answer's fields
FieldTypeDescription
idstringProperty id.
organizationIdstring
namestring or null
addressstring or null
address2string or null
citystring or null
statestring or null
zipstring or null
countrystring or null
propertyTypeenumOne of RESIDENTIAL, COMMERCIAL, MULTI_FAMILY, INDUSTRIAL.
contactNamestring or nullWho to ask for on site.
contactPhonestring or null
contactEmailstring or null
timezonestringIANA timezone of the property.
accessInstructionsstring or null
safetyNotesstring or null
gateCodestring or null
petsOnSiteboolean
petNotesstring or null
yearBuiltinteger or null
squareFeetinteger or null
tagsarray of string
latitudenumber or null
longitudenumber or null
geocodeSourcestring or nullWhere the coordinates came from: GEOCODER (the address), GEOCODER_STREET / GEOCODER_AREA (approximate: only its street or town is on the map; visit safety then searches the ZIP), MANUAL (pinned by hand).
geocodedAtstring (date-time) or null
taxRatenumber or nullTax rate in percent for work here; null = the business default.
customFieldsanyCustom field values by key (definitions: GET /custom-fields).
createdAtstring (date-time)
updatedAtstring (date-time)

Link a customer to a property

POST /organizations/{organizationId}/properties/{propertyId}/occupancies

Links a customer to the property as owner, tenant, landlord or property manager from a date. A new primary demotes the current one. Returns the occupancy.

Permissionproperties.write (Owner, Admin, Dispatcher)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolproperties_addOccupant (toolset customers)

Parameters

NameInTypeRequiredDescription
propertyIdpathstringYes

Request body

FieldTypeRequiredDescription
customerIdstringYes
roleenumNoOne of OWNER, TENANT, LANDLORD, PROPERTY_MANAGER.
isPrimarybooleanNo
startedOnstringNoA calendar date in the business's own calendar, YYYY-MM-DD.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/properties/{propertyId}/occupancies" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customerId":"customer_id"}'

Response

201: the answer's fields
FieldTypeDescription
idstringOccupancy id (for PATCH …/occupancies/{occupancyId}).
propertyIdstring
customerIdstring
roleenumOne of OWNER, TENANT, LANDLORD, PROPERTY_MANAGER.
isPrimarybooleanThe property's primary current occupant.
startedOnstringFirst day of the link, YYYY-MM-DD.
endedOnstring or nullLast day, YYYY-MM-DD; null = current.
createdAtstring (date-time)

Change a current occupant's role or make them primary

PATCH /organizations/{organizationId}/properties/{propertyId}/occupancies/{occupancyId}

Changes an open occupancy's role and/or makes it the primary one. Occupancy ids come from GET /properties/{propertyId}.

Permissionproperties.write (Owner, Admin, Dispatcher)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolproperties_updateOccupancy (toolset customers)

Parameters

NameInTypeRequiredDescription
propertyIdpathstringYes
occupancyIdpathstringYes

Request body

FieldTypeRequiredDescription
roleenumNoOne of OWNER, TENANT, LANDLORD, PROPERTY_MANAGER.
isPrimarybooleanNo

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/properties/{propertyId}/occupancies/{occupancyId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"role":"OWNER","isPrimary":true}'

Response

200: the answer's fields
FieldTypeDescription
idstringOccupancy id (for PATCH …/occupancies/{occupancyId}).
propertyIdstring
customerIdstring
roleenumOne of OWNER, TENANT, LANDLORD, PROPERTY_MANAGER.
isPrimarybooleanThe property's primary current occupant.
startedOnstringFirst day of the link, YYYY-MM-DD.
endedOnstring or nullLast day, YYYY-MM-DD; null = current.
createdAtstring (date-time)

End a customer's link to a property

POST /organizations/{organizationId}/properties/{propertyId}/occupancies/{occupancyId}/end

Ends the customer's link on endedOn (default today). The history row stays; the next current occupant becomes primary.

Permissionproperties.write (Owner, Admin, Dispatcher)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolproperties_endOccupancy (toolset customers)

Parameters

NameInTypeRequiredDescription
propertyIdpathstringYes
occupancyIdpathstringYes

Request body

FieldTypeRequiredDescription
endedOnstringNoA calendar date in the business's own calendar, YYYY-MM-DD.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/properties/{propertyId}/occupancies/{occupancyId}/end" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"endedOn":"2026-11-03"}'

Response

200: the answer's fields
FieldTypeDescription
idstringOccupancy id (for PATCH …/occupancies/{occupancyId}).
propertyIdstring
customerIdstring
roleenumOne of OWNER, TENANT, LANDLORD, PROPERTY_MANAGER.
isPrimarybooleanThe property's primary current occupant.
startedOnstringFirst day of the link, YYYY-MM-DD.
endedOnstring or nullLast day, YYYY-MM-DD; null = current.
createdAtstring (date-time)

Transfer a property (sale or move)

POST /organizations/{organizationId}/properties/{propertyId}/transfer

For a sale or move: ends every current link on onDate (default today) and makes toCustomerId the primary occupant. Equipment and history stay with the property. Returns the new occupancy.

Permissionproperties.write (Owner, Admin, Dispatcher)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolproperties_transfer (toolset customers)

Parameters

NameInTypeRequiredDescription
propertyIdpathstringYes

Request body

FieldTypeRequiredDescription
toCustomerIdstringYes
roleenumNoOne of OWNER, TENANT, LANDLORD, PROPERTY_MANAGER.
onDatestringNoA calendar date in the business's own calendar, YYYY-MM-DD.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/properties/{propertyId}/transfer" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"toCustomerId":"toCustomer_id"}'

Response

200: the answer's fields
FieldTypeDescription
idstringOccupancy id (for PATCH …/occupancies/{occupancyId}).
propertyIdstring
customerIdstring
roleenumOne of OWNER, TENANT, LANDLORD, PROPERTY_MANAGER.
isPrimarybooleanThe property's primary current occupant.
startedOnstringFirst day of the link, YYYY-MM-DD.
endedOnstring or nullLast day, YYYY-MM-DD; null = current.
createdAtstring (date-time)

Re-geocode a property

POST /organizations/{organizationId}/properties/{propertyId}/geocode

Looks the property's address up again now with the configured geocoder (SERVFLO_GEOCODER: OpenStreetMap Nominatim, a self-hosted server or the test fake; answers are cached by address) and stores the coordinates, replacing a hand-placed pin. found: false keeps the old coordinates (nothing found, or geocoding is off). Waits for the answer (Nominatim allows one request a second).

Permissionproperties.write (Owner, Admin, Dispatcher)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP toolproperties_geocode (toolset customers)

Parameters

NameInTypeRequiredDescription
propertyIdpathstringYes

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/properties/{propertyId}/geocode" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
foundboolean
latitudenumber or null
longitudenumber or null
geocodeSourcestring or nullGEOCODER, GEOCODER_STREET or GEOCODER_AREA (approximate), or MANUAL.
geocodedAtstring (date-time) or null

On this page