DevelopersAPI reference

Equipment API

REST endpoints for equipment in ServFlo: 20 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
A customer's sites (the properties they currently occupy)GET /organizations/{organizationId}/customers/{customerId}/sitesread
Create a site (a property the customer owns)POST /organizations/{organizationId}/customers/{customerId}/siteswrite
Update a sitePATCH /organizations/{organizationId}/sites/{siteId}write
A customer's equipmentGET /organizations/{organizationId}/customers/{customerId}/assetsread
Register equipment for a customerPOST /organizations/{organizationId}/customers/{customerId}/assetswrite
All equipmentGET /organizations/{organizationId}/assetsread
Equipment at a propertyGET /organizations/{organizationId}/properties/{propertyId}/assetsread
Register equipment at a propertyPOST /organizations/{organizationId}/properties/{propertyId}/assetswrite
Equipment a job for this customer can be linked toGET /organizations/{organizationId}/customers/{customerId}/assets/optionsread
Get equipment with its type, property and ownerGET /organizations/{organizationId}/assets/{assetId}read
Update equipmentPATCH /organizations/{organizationId}/assets/{assetId}write
Equipment history, newest firstGET /organizations/{organizationId}/assets/{assetId}/historyread
Photos from jobs on this equipmentGET /organizations/{organizationId}/assets/{assetId}/photosread
List equipment typesGET /organizations/{organizationId}/equipment-typesread
Add an equipment typePOST /organizations/{organizationId}/equipment-typeswrite
Get an equipment typeGET /organizations/{organizationId}/equipment-types/{equipmentTypeId}read
Rename, change or archive an equipment typePATCH /organizations/{organizationId}/equipment-types/{equipmentTypeId}write
Add a trade's preset equipment typesPOST /organizations/{organizationId}/equipment-types/presetswrite
What equipment is called hereGET /organizations/{organizationId}/equipment-labelsread
Change what equipment is calledPATCH /organizations/{organizationId}/equipment-labelswrite

A customer's sites (the properties they currently occupy)

GET /organizations/{organizationId}/customers/{customerId}/sites

The original API's sites: the properties the customer currently occupies. Read-only. Prefer GET /properties?customerId=… for the full property records.

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

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes

Example

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

Response

200: the answer's fields

An array of objects:

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)

Create a site (a property the customer owns)

POST /organizations/{organizationId}/customers/{customerId}/sites

The original API's site create: creates a property and links the customer as its owner from today. Returns the site.

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

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes

Request body

FieldTypeRequiredDescription
namestringYesUp to 500 characters.
addressstring or nullNoUp to 500 characters.
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.

Example

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

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)

Update a site

PATCH /organizations/{organizationId}/sites/{siteId}

The original API's site update: changes the property's fields sent. Same as PATCH /properties/{propertyId}.

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

Parameters

NameInTypeRequiredDescription
siteIdpathstringYes

Request body

FieldTypeRequiredDescription
namestringNoUp to 500 characters.
addressstring or nullNoUp to 500 characters.
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.

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/sites/{siteId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Dana Whitfield","address":"string","contactName":"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)

A customer's equipment

GET /organizations/{organizationId}/customers/{customerId}/assets

The customer's own equipment (customer-owned: vehicles, boats …) and the equipment at the properties they currently occupy, filtered by text (name, serial, make, model), type, ownership and status, paged with a total. Read-only.

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

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes
queryquerystringNoFree-text search over the list's names, numbers and contact details. Up to 200 characters.
equipmentTypeIdquerystringNoOnly this equipment type.
ownershipqueryenumNoWho owns it: PROPERTY (stays with the property when it changes hands; propertyId required) or CUSTOMER (a car, a boat: linkable to that customer's jobs at any address; propertyId optional, where it is kept). Unset: CUSTOMER when customerId is given or the type is customer-owned and a customer is known, else PROPERTY. One of PROPERTY, CUSTOMER.
statusqueryenumNoOne of IN_SERVICE, OUT_OF_SERVICE, RETIRED.
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/customers/{customerId}/assets" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
itemsarray of object
items[].idstringEquipment (asset) id.
items[].organizationIdstring
items[].propertyIdstring or nullThe property it belongs to (property-owned) or is kept at (customer-owned); null = a customer's, kept nowhere in particular.
items[].customerIdstring or nullSet = customer-owned (a car, a boat): it goes wherever that customer's jobs are.
items[].ownershipenumWho owns it: the property (stays on a transfer) or the customer. One of PROPERTY, CUSTOMER.
items[].equipmentTypeIdstring or nullIts equipment type.
items[].typeobject or null
items[].type.idstring
items[].type.namestring
items[].type.iconstring
items[].type.customerOwnedboolean
items[].type.builtInFieldsarray of string
items[].type.builtInLabelsany
items[].type.archivedboolean
items[].namestring
items[].serialNumberstringSerial number or VIN; "" when not recorded. Unique per property and per owning customer.
items[].manufacturerstring or null
items[].modelstring or null
items[].statusenumRETIRED equipment is kept for history instead of being deleted. One of IN_SERVICE, OUT_OF_SERVICE, RETIRED.
items[].installationDatestring or nullYYYY-MM-DD
items[].commissioningDatestring or nullYYYY-MM-DD
items[].warrantyStartstring or nullYYYY-MM-DD
items[].warrantyEndstring or nullYYYY-MM-DD
items[].notesstring or null
items[].equipmentTypestring or nullCustomer 360 lifespan key (AC, FURNACE …).
items[].installYearinteger or null
items[].expectedLifespanYearsinteger or null
items[].refrigerantTypestring or null
items[].conditionenum or nullOne of GOOD, FAIR, POOR, FAILED.
items[].customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=EQUIPMENT).
items[].createdAtstring (date-time)
items[].updatedAtstring (date-time)
items[].propertyobject or nullThe property (all its fields on get and update); null for customer-owned equipment kept nowhere in particular.
items[].property.idstringProperty id.
items[].property.namestring or null
items[].property.addressstring or null
items[].property.citystring or null
items[].customerobject or nullThe owner: the owning customer, else the property's current primary customer; null when vacant.
items[].customer.idstring
items[].customer.namestring
totalintegerHow many match the filters, across all pages.

Register equipment for a customer

POST /organizations/{organizationId}/customers/{customerId}/assets

Registers equipment for the customer: customer-owned (ownership CUSTOMER, e.g. a car; propertyId optional, where it is kept) or at one of the customer's current properties (ownership PROPERTY, propertyId or siteId required). Type from equipmentTypeId (GET /equipment-types), else matched from the name; its required custom fields must be given. Serial numbers are unique per property and per owning customer (409). Written to the equipment history. Returns the equipment.

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

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes

Request body

FieldTypeRequiredDescription
propertyIdstring or nullNoThe property it belongs to (property-owned) or is kept at (customer-owned; null clears it).
siteIdstring or nullNoThe original API's name for propertyId.
ownershipenumNoWho owns it: PROPERTY (stays with the property when it changes hands; propertyId required) or CUSTOMER (a car, a boat: linkable to that customer's jobs at any address; propertyId optional, where it is kept). Unset: CUSTOMER when customerId is given or the type is customer-owned and a customer is known, else PROPERTY. One of PROPERTY, CUSTOMER.
equipmentTypeIdstring or nullNoIts equipment type (GET /equipment-types). Unset on create: matched from the name, else Other.
namestringYesUp to 500 characters.
serialNumberstring or nullNoSerial number or VIN; unique per property and per owning customer; blank = not recorded. Up to 500 characters.
manufacturerstring or nullNoUp to 500 characters.
modelstring or nullNoUp to 500 characters.
statusenumNoOne of IN_SERVICE, OUT_OF_SERVICE, RETIRED.
installationDateempty string or string or nullNo
commissioningDateempty string or string or nullNo
warrantyStartempty string or string or nullNo
warrantyEndempty string or string or nullNo
notesstring or nullNoUp to 5000 characters.
equipmentTypeenum or nullNoLifespan key for the replacement outlook; unset: the equipment type's, else read from the name. One of AC, HEAT_PUMP, FURNACE, BOILER, MINI_SPLIT, AIR_HANDLER, PACKAGE_UNIT, WATER_HEATER, TANKLESS_WATER_HEATER, THERMOSTAT, HUMIDIFIER, AIR_PURIFIER, WATER_SOFTENER, SUMP_PUMP, WELL_PUMP, SEPTIC_PUMP, BACKFLOW_PREVENTER, ELECTRICAL_PANEL, GENERATOR, EV_CHARGER, GARAGE_DOOR_OPENER, POOL_PUMP, POOL_HEATER, REFRIGERATION, ICE_MACHINE, OTHER.
installYearinteger or nullNoThe install year when only the year is known (data plate); installationDate wins when set. 1900–2100.
expectedLifespanYearsinteger or nullNoThis unit's expected lifespan in years, overriding the organization's lifespan table. 1–100.
refrigerantTypestring or nullNoe.g. R-22, R-410A, R-454B. R-22 raises the replacement likelihood. Up to 50 characters.
conditionenum or nullNoCondition as last assessed. One of GOOD, FAIR, POOR, FAILED.
customFieldsobjectNoValues of the fields for every type and of its own type's (GET /custom-fields?entity=EQUIPMENT&equipmentTypeId=…). Required ones are checked on create and when the type changes.

Example

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

Response

201: the answer's fields
FieldTypeDescription
idstringEquipment (asset) id.
organizationIdstring
propertyIdstring or nullThe property it belongs to (property-owned) or is kept at (customer-owned); null = a customer's, kept nowhere in particular.
customerIdstring or nullSet = customer-owned (a car, a boat): it goes wherever that customer's jobs are.
ownershipenumWho owns it: the property (stays on a transfer) or the customer. One of PROPERTY, CUSTOMER.
equipmentTypeIdstring or nullIts equipment type.
typeobject or null
type.idstring
type.namestring
type.iconstring
type.customerOwnedboolean
type.builtInFieldsarray of string
type.builtInLabelsany
type.archivedboolean
namestring
serialNumberstringSerial number or VIN; "" when not recorded. Unique per property and per owning customer.
manufacturerstring or null
modelstring or null
statusenumRETIRED equipment is kept for history instead of being deleted. One of IN_SERVICE, OUT_OF_SERVICE, RETIRED.
installationDatestring or nullYYYY-MM-DD
commissioningDatestring or nullYYYY-MM-DD
warrantyStartstring or nullYYYY-MM-DD
warrantyEndstring or nullYYYY-MM-DD
notesstring or null
equipmentTypestring or nullCustomer 360 lifespan key (AC, FURNACE …).
installYearinteger or null
expectedLifespanYearsinteger or null
refrigerantTypestring or null
conditionenum or nullOne of GOOD, FAIR, POOR, FAILED.
customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=EQUIPMENT).
createdAtstring (date-time)
updatedAtstring (date-time)
propertyobject or nullThe property (all its fields on get and update); null for customer-owned equipment kept nowhere in particular.
property.idstringProperty id.
property.namestring or null
property.addressstring or null
property.citystring or null
customerobject or nullThe owner: the owning customer, else the property's current primary customer; null when vacant.
customer.idstring
customer.namestring

All equipment

GET /organizations/{organizationId}/assets

Every piece of equipment in the business (a technician: only that of their jobs), with type, property and owner, filtered by text (name, serial, make, model), type, ownership and status, paged with a total. Read-only.

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

Parameters

NameInTypeRequiredDescription
queryquerystringNoFree-text search over the list's names, numbers and contact details. Up to 200 characters.
equipmentTypeIdquerystringNoOnly this equipment type.
ownershipqueryenumNoWho owns it: PROPERTY (stays with the property when it changes hands; propertyId required) or CUSTOMER (a car, a boat: linkable to that customer's jobs at any address; propertyId optional, where it is kept). Unset: CUSTOMER when customerId is given or the type is customer-owned and a customer is known, else PROPERTY. One of PROPERTY, CUSTOMER.
statusqueryenumNoOne of IN_SERVICE, OUT_OF_SERVICE, RETIRED.
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/assets" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
itemsarray of object
items[].idstringEquipment (asset) id.
items[].organizationIdstring
items[].propertyIdstring or nullThe property it belongs to (property-owned) or is kept at (customer-owned); null = a customer's, kept nowhere in particular.
items[].customerIdstring or nullSet = customer-owned (a car, a boat): it goes wherever that customer's jobs are.
items[].ownershipenumWho owns it: the property (stays on a transfer) or the customer. One of PROPERTY, CUSTOMER.
items[].equipmentTypeIdstring or nullIts equipment type.
items[].typeobject or null
items[].type.idstring
items[].type.namestring
items[].type.iconstring
items[].type.customerOwnedboolean
items[].type.builtInFieldsarray of string
items[].type.builtInLabelsany
items[].type.archivedboolean
items[].namestring
items[].serialNumberstringSerial number or VIN; "" when not recorded. Unique per property and per owning customer.
items[].manufacturerstring or null
items[].modelstring or null
items[].statusenumRETIRED equipment is kept for history instead of being deleted. One of IN_SERVICE, OUT_OF_SERVICE, RETIRED.
items[].installationDatestring or nullYYYY-MM-DD
items[].commissioningDatestring or nullYYYY-MM-DD
items[].warrantyStartstring or nullYYYY-MM-DD
items[].warrantyEndstring or nullYYYY-MM-DD
items[].notesstring or null
items[].equipmentTypestring or nullCustomer 360 lifespan key (AC, FURNACE …).
items[].installYearinteger or null
items[].expectedLifespanYearsinteger or null
items[].refrigerantTypestring or null
items[].conditionenum or nullOne of GOOD, FAIR, POOR, FAILED.
items[].customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=EQUIPMENT).
items[].createdAtstring (date-time)
items[].updatedAtstring (date-time)
items[].propertyobject or nullThe property (all its fields on get and update); null for customer-owned equipment kept nowhere in particular.
items[].property.idstringProperty id.
items[].property.namestring or null
items[].property.addressstring or null
items[].property.citystring or null
items[].customerobject or nullThe owner: the owning customer, else the property's current primary customer; null when vacant.
items[].customer.idstring
items[].customer.namestring
totalintegerHow many match the filters, across all pages.

Equipment at a property

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

Equipment registered at the property (its own, and customers' equipment kept there), filtered by text, type, ownership and status, paged with a total. Read-only. 404 for an unknown property.

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

Parameters

NameInTypeRequiredDescription
propertyIdpathstringYes
queryquerystringNoFree-text search over the list's names, numbers and contact details. Up to 200 characters.
equipmentTypeIdquerystringNoOnly this equipment type.
ownershipqueryenumNoWho owns it: PROPERTY (stays with the property when it changes hands; propertyId required) or CUSTOMER (a car, a boat: linkable to that customer's jobs at any address; propertyId optional, where it is kept). Unset: CUSTOMER when customerId is given or the type is customer-owned and a customer is known, else PROPERTY. One of PROPERTY, CUSTOMER.
statusqueryenumNoOne of IN_SERVICE, OUT_OF_SERVICE, RETIRED.
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/{propertyId}/assets" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
itemsarray of object
items[].idstringEquipment (asset) id.
items[].organizationIdstring
items[].propertyIdstring or nullThe property it belongs to (property-owned) or is kept at (customer-owned); null = a customer's, kept nowhere in particular.
items[].customerIdstring or nullSet = customer-owned (a car, a boat): it goes wherever that customer's jobs are.
items[].ownershipenumWho owns it: the property (stays on a transfer) or the customer. One of PROPERTY, CUSTOMER.
items[].equipmentTypeIdstring or nullIts equipment type.
items[].typeobject or null
items[].type.idstring
items[].type.namestring
items[].type.iconstring
items[].type.customerOwnedboolean
items[].type.builtInFieldsarray of string
items[].type.builtInLabelsany
items[].type.archivedboolean
items[].namestring
items[].serialNumberstringSerial number or VIN; "" when not recorded. Unique per property and per owning customer.
items[].manufacturerstring or null
items[].modelstring or null
items[].statusenumRETIRED equipment is kept for history instead of being deleted. One of IN_SERVICE, OUT_OF_SERVICE, RETIRED.
items[].installationDatestring or nullYYYY-MM-DD
items[].commissioningDatestring or nullYYYY-MM-DD
items[].warrantyStartstring or nullYYYY-MM-DD
items[].warrantyEndstring or nullYYYY-MM-DD
items[].notesstring or null
items[].equipmentTypestring or nullCustomer 360 lifespan key (AC, FURNACE …).
items[].installYearinteger or null
items[].expectedLifespanYearsinteger or null
items[].refrigerantTypestring or null
items[].conditionenum or nullOne of GOOD, FAIR, POOR, FAILED.
items[].customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=EQUIPMENT).
items[].createdAtstring (date-time)
items[].updatedAtstring (date-time)
items[].propertyobject or nullThe property (all its fields on get and update); null for customer-owned equipment kept nowhere in particular.
items[].property.idstringProperty id.
items[].property.namestring or null
items[].property.addressstring or null
items[].property.citystring or null
items[].customerobject or nullThe owner: the owning customer, else the property's current primary customer; null when vacant.
items[].customer.idstring
items[].customer.namestring
totalintegerHow many match the filters, across all pages.

Register equipment at a property

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

Registers equipment at the property: owned by the property, or, with customerId (ownership CUSTOMER), a customer's own equipment kept there. Type from equipmentTypeId, else matched from the name. Serial numbers are unique per property and per owning customer (409). Written to the equipment history. Returns the equipment.

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

Parameters

NameInTypeRequiredDescription
propertyIdpathstringYes

Request body

FieldTypeRequiredDescription
customerIdstring or nullNoThe owning customer for customer-owned equipment (on an update, null makes it property-owned).
ownershipenumNoWho owns it: PROPERTY (stays with the property when it changes hands; propertyId required) or CUSTOMER (a car, a boat: linkable to that customer's jobs at any address; propertyId optional, where it is kept). Unset: CUSTOMER when customerId is given or the type is customer-owned and a customer is known, else PROPERTY. One of PROPERTY, CUSTOMER.
equipmentTypeIdstring or nullNoIts equipment type (GET /equipment-types). Unset on create: matched from the name, else Other.
namestringYesUp to 500 characters.
serialNumberstring or nullNoSerial number or VIN; unique per property and per owning customer; blank = not recorded. Up to 500 characters.
manufacturerstring or nullNoUp to 500 characters.
modelstring or nullNoUp to 500 characters.
statusenumNoOne of IN_SERVICE, OUT_OF_SERVICE, RETIRED.
installationDateempty string or string or nullNo
commissioningDateempty string or string or nullNo
warrantyStartempty string or string or nullNo
warrantyEndempty string or string or nullNo
notesstring or nullNoUp to 5000 characters.
equipmentTypeenum or nullNoLifespan key for the replacement outlook; unset: the equipment type's, else read from the name. One of AC, HEAT_PUMP, FURNACE, BOILER, MINI_SPLIT, AIR_HANDLER, PACKAGE_UNIT, WATER_HEATER, TANKLESS_WATER_HEATER, THERMOSTAT, HUMIDIFIER, AIR_PURIFIER, WATER_SOFTENER, SUMP_PUMP, WELL_PUMP, SEPTIC_PUMP, BACKFLOW_PREVENTER, ELECTRICAL_PANEL, GENERATOR, EV_CHARGER, GARAGE_DOOR_OPENER, POOL_PUMP, POOL_HEATER, REFRIGERATION, ICE_MACHINE, OTHER.
installYearinteger or nullNoThe install year when only the year is known (data plate); installationDate wins when set. 1900–2100.
expectedLifespanYearsinteger or nullNoThis unit's expected lifespan in years, overriding the organization's lifespan table. 1–100.
refrigerantTypestring or nullNoe.g. R-22, R-410A, R-454B. R-22 raises the replacement likelihood. Up to 50 characters.
conditionenum or nullNoCondition as last assessed. One of GOOD, FAIR, POOR, FAILED.
customFieldsobjectNoValues of the fields for every type and of its own type's (GET /custom-fields?entity=EQUIPMENT&equipmentTypeId=…). Required ones are checked on create and when the type changes.

Example

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

Response

201: the answer's fields
FieldTypeDescription
idstringEquipment (asset) id.
organizationIdstring
propertyIdstring or nullThe property it belongs to (property-owned) or is kept at (customer-owned); null = a customer's, kept nowhere in particular.
customerIdstring or nullSet = customer-owned (a car, a boat): it goes wherever that customer's jobs are.
ownershipenumWho owns it: the property (stays on a transfer) or the customer. One of PROPERTY, CUSTOMER.
equipmentTypeIdstring or nullIts equipment type.
typeobject or null
type.idstring
type.namestring
type.iconstring
type.customerOwnedboolean
type.builtInFieldsarray of string
type.builtInLabelsany
type.archivedboolean
namestring
serialNumberstringSerial number or VIN; "" when not recorded. Unique per property and per owning customer.
manufacturerstring or null
modelstring or null
statusenumRETIRED equipment is kept for history instead of being deleted. One of IN_SERVICE, OUT_OF_SERVICE, RETIRED.
installationDatestring or nullYYYY-MM-DD
commissioningDatestring or nullYYYY-MM-DD
warrantyStartstring or nullYYYY-MM-DD
warrantyEndstring or nullYYYY-MM-DD
notesstring or null
equipmentTypestring or nullCustomer 360 lifespan key (AC, FURNACE …).
installYearinteger or null
expectedLifespanYearsinteger or null
refrigerantTypestring or null
conditionenum or nullOne of GOOD, FAIR, POOR, FAILED.
customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=EQUIPMENT).
createdAtstring (date-time)
updatedAtstring (date-time)
propertyobject or nullThe property (all its fields on get and update); null for customer-owned equipment kept nowhere in particular.
property.idstringProperty id.
property.namestring or null
property.addressstring or null
property.citystring or null
customerobject or nullThe owner: the owning customer, else the property's current primary customer; null when vacant.
customer.idstring
customer.namestring

Equipment a job for this customer can be linked to

GET /organizations/{organizationId}/customers/{customerId}/assets/options

Id, name, type and ownership of the equipment a job for this customer may link (not retired): their own equipment, linkable at any address, and the equipment at their current properties. For the job form's picker. Read-only.

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

Parameters

NameInTypeRequiredDescription
customerIdpathstringYes

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/customers/{customerId}/assets/options" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstringEquipment id (a job's assetId).
namestring
serialNumberstring
ownershipenumOne of PROPERTY, CUSTOMER.
typeobject or null
type.idstring
type.namestring
type.iconstring
type.customerOwnedboolean
type.builtInFieldsarray of string
type.builtInLabelsany
type.archivedboolean
propertyobject or null
property.idstringProperty id.
property.namestring or null
property.addressstring or null
property.citystring or null

Get equipment with its type, property and owner

GET /organizations/{organizationId}/assets/{assetId}

One piece of equipment with its type, its property (if any) and the customer it belongs to (the owning customer, else the property's current primary customer). Read-only.

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

Parameters

NameInTypeRequiredDescription
assetIdpathstringYes

Example

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

Response

200: the answer's fields
FieldTypeDescription
idstringEquipment (asset) id.
organizationIdstring
propertyIdstring or nullThe property it belongs to (property-owned) or is kept at (customer-owned); null = a customer's, kept nowhere in particular.
customerIdstring or nullSet = customer-owned (a car, a boat): it goes wherever that customer's jobs are.
ownershipenumWho owns it: the property (stays on a transfer) or the customer. One of PROPERTY, CUSTOMER.
equipmentTypeIdstring or nullIts equipment type.
typeobject or null
type.idstring
type.namestring
type.iconstring
type.customerOwnedboolean
type.builtInFieldsarray of string
type.builtInLabelsany
type.archivedboolean
namestring
serialNumberstringSerial number or VIN; "" when not recorded. Unique per property and per owning customer.
manufacturerstring or null
modelstring or null
statusenumRETIRED equipment is kept for history instead of being deleted. One of IN_SERVICE, OUT_OF_SERVICE, RETIRED.
installationDatestring or nullYYYY-MM-DD
commissioningDatestring or nullYYYY-MM-DD
warrantyStartstring or nullYYYY-MM-DD
warrantyEndstring or nullYYYY-MM-DD
notesstring or null
equipmentTypestring or nullCustomer 360 lifespan key (AC, FURNACE …).
installYearinteger or null
expectedLifespanYearsinteger or null
refrigerantTypestring or null
conditionenum or nullOne of GOOD, FAIR, POOR, FAILED.
customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=EQUIPMENT).
createdAtstring (date-time)
updatedAtstring (date-time)
propertyobject or null
property.idstringProperty id.
property.organizationIdstring
property.namestring or null
property.addressstring or null
property.address2string or null
property.citystring or null
property.statestring or null
property.zipstring or null
property.countrystring or null
property.propertyTypeenumOne of RESIDENTIAL, COMMERCIAL, MULTI_FAMILY, INDUSTRIAL.
property.contactNamestring or nullWho to ask for on site.
property.contactPhonestring or null
property.contactEmailstring or null
property.timezonestringIANA timezone of the property.
property.accessInstructionsstring or null
property.safetyNotesstring or null
property.gateCodestring or null
property.petsOnSiteboolean
property.petNotesstring or null
property.yearBuiltinteger or null
property.squareFeetinteger or null
property.tagsarray of string
property.latitudenumber or null
property.longitudenumber or null
property.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).
property.geocodedAtstring (date-time) or null
property.taxRatenumber or nullTax rate in percent for work here; null = the business default.
property.customFieldsanyCustom field values by key (definitions: GET /custom-fields).
property.createdAtstring (date-time)
property.updatedAtstring (date-time)
customerobject or nullThe owner: the owning customer, else the property's current primary customer; null when vacant.
customer.idstring
customer.namestring
siteobject or nullThe property again, under the original API's name.
site.idstringProperty id.
site.organizationIdstring
site.namestring or null
site.addressstring or null
site.address2string or null
site.citystring or null
site.statestring or null
site.zipstring or null
site.countrystring or null
site.propertyTypeenumOne of RESIDENTIAL, COMMERCIAL, MULTI_FAMILY, INDUSTRIAL.
site.contactNamestring or nullWho to ask for on site.
site.contactPhonestring or null
site.contactEmailstring or null
site.timezonestringIANA timezone of the property.
site.accessInstructionsstring or null
site.safetyNotesstring or null
site.gateCodestring or null
site.petsOnSiteboolean
site.petNotesstring or null
site.yearBuiltinteger or null
site.squareFeetinteger or null
site.tagsarray of string
site.latitudenumber or null
site.longitudenumber or null
site.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).
site.geocodedAtstring (date-time) or null
site.taxRatenumber or nullTax rate in percent for work here; null = the business default.
site.customFieldsanyCustom field values by key (definitions: GET /custom-fields).
site.createdAtstring (date-time)
site.updatedAtstring (date-time)

Update equipment

PATCH /organizations/{organizationId}/assets/{assetId}

Changes the fields sent. Moving it to another property, changing its owner (ownership / customerId), its type and its status (RETIRED instead of deleting) are recorded in the equipment history. Custom field values merge into the saved ones; a new type's required fields are checked. Returns the equipment.

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

Parameters

NameInTypeRequiredDescription
assetIdpathstringYes

Request body

FieldTypeRequiredDescription
propertyIdstring or nullNoThe property it belongs to (property-owned) or is kept at (customer-owned; null clears it).
siteIdstring or nullNoThe original API's name for propertyId.
customerIdstring or nullNoThe owning customer for customer-owned equipment (on an update, null makes it property-owned).
ownershipenumNoWho owns it: PROPERTY (stays with the property when it changes hands; propertyId required) or CUSTOMER (a car, a boat: linkable to that customer's jobs at any address; propertyId optional, where it is kept). Unset: CUSTOMER when customerId is given or the type is customer-owned and a customer is known, else PROPERTY. One of PROPERTY, CUSTOMER.
equipmentTypeIdstring or nullNoIts equipment type (GET /equipment-types). Unset on create: matched from the name, else Other.
namestringNoUp to 500 characters.
serialNumberstring or nullNoSerial number or VIN; unique per property and per owning customer; blank = not recorded. Up to 500 characters.
manufacturerstring or nullNoUp to 500 characters.
modelstring or nullNoUp to 500 characters.
statusenumNoOne of IN_SERVICE, OUT_OF_SERVICE, RETIRED.
installationDateempty string or string or nullNo
commissioningDateempty string or string or nullNo
warrantyStartempty string or string or nullNo
warrantyEndempty string or string or nullNo
notesstring or nullNoUp to 5000 characters.
equipmentTypeenum or nullNoLifespan key for the replacement outlook; unset: the equipment type's, else read from the name. One of AC, HEAT_PUMP, FURNACE, BOILER, MINI_SPLIT, AIR_HANDLER, PACKAGE_UNIT, WATER_HEATER, TANKLESS_WATER_HEATER, THERMOSTAT, HUMIDIFIER, AIR_PURIFIER, WATER_SOFTENER, SUMP_PUMP, WELL_PUMP, SEPTIC_PUMP, BACKFLOW_PREVENTER, ELECTRICAL_PANEL, GENERATOR, EV_CHARGER, GARAGE_DOOR_OPENER, POOL_PUMP, POOL_HEATER, REFRIGERATION, ICE_MACHINE, OTHER.
installYearinteger or nullNoThe install year when only the year is known (data plate); installationDate wins when set. 1900–2100.
expectedLifespanYearsinteger or nullNoThis unit's expected lifespan in years, overriding the organization's lifespan table. 1–100.
refrigerantTypestring or nullNoe.g. R-22, R-410A, R-454B. R-22 raises the replacement likelihood. Up to 50 characters.
conditionenum or nullNoCondition as last assessed. One of GOOD, FAIR, POOR, FAILED.
customFieldsobjectNoValues of the fields for every type and of its own type's (GET /custom-fields?entity=EQUIPMENT&equipmentTypeId=…). Required ones are checked on create and when the type changes.

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/assets/{assetId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"propertyId":"property_id","siteId":"site_id","customerId":"customer_id"}'

Response

200: the answer's fields
FieldTypeDescription
idstringEquipment (asset) id.
organizationIdstring
propertyIdstring or nullThe property it belongs to (property-owned) or is kept at (customer-owned); null = a customer's, kept nowhere in particular.
customerIdstring or nullSet = customer-owned (a car, a boat): it goes wherever that customer's jobs are.
ownershipenumWho owns it: the property (stays on a transfer) or the customer. One of PROPERTY, CUSTOMER.
equipmentTypeIdstring or nullIts equipment type.
typeobject or null
type.idstring
type.namestring
type.iconstring
type.customerOwnedboolean
type.builtInFieldsarray of string
type.builtInLabelsany
type.archivedboolean
namestring
serialNumberstringSerial number or VIN; "" when not recorded. Unique per property and per owning customer.
manufacturerstring or null
modelstring or null
statusenumRETIRED equipment is kept for history instead of being deleted. One of IN_SERVICE, OUT_OF_SERVICE, RETIRED.
installationDatestring or nullYYYY-MM-DD
commissioningDatestring or nullYYYY-MM-DD
warrantyStartstring or nullYYYY-MM-DD
warrantyEndstring or nullYYYY-MM-DD
notesstring or null
equipmentTypestring or nullCustomer 360 lifespan key (AC, FURNACE …).
installYearinteger or null
expectedLifespanYearsinteger or null
refrigerantTypestring or null
conditionenum or nullOne of GOOD, FAIR, POOR, FAILED.
customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=EQUIPMENT).
createdAtstring (date-time)
updatedAtstring (date-time)
propertyobject or null
property.idstringProperty id.
property.organizationIdstring
property.namestring or null
property.addressstring or null
property.address2string or null
property.citystring or null
property.statestring or null
property.zipstring or null
property.countrystring or null
property.propertyTypeenumOne of RESIDENTIAL, COMMERCIAL, MULTI_FAMILY, INDUSTRIAL.
property.contactNamestring or nullWho to ask for on site.
property.contactPhonestring or null
property.contactEmailstring or null
property.timezonestringIANA timezone of the property.
property.accessInstructionsstring or null
property.safetyNotesstring or null
property.gateCodestring or null
property.petsOnSiteboolean
property.petNotesstring or null
property.yearBuiltinteger or null
property.squareFeetinteger or null
property.tagsarray of string
property.latitudenumber or null
property.longitudenumber or null
property.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).
property.geocodedAtstring (date-time) or null
property.taxRatenumber or nullTax rate in percent for work here; null = the business default.
property.customFieldsanyCustom field values by key (definitions: GET /custom-fields).
property.createdAtstring (date-time)
property.updatedAtstring (date-time)
customerobject or nullThe owner: the owning customer, else the property's current primary customer; null when vacant.
customer.idstring
customer.namestring

Equipment history, newest first

GET /organizations/{organizationId}/assets/{assetId}/history

The equipment's history: registered, moved, status changes, jobs linked/updated/unlinked/deleted and job notes; paged with a total. Read-only.

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

Parameters

NameInTypeRequiredDescription
assetIdpathstringYes
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/assets/{assetId}/history" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
itemsarray of object
items[].idstring
items[].assetIdstring
items[].jobIdstring or null
items[].summarystringWhat happened (registered, moved, status changed, job …).
items[].detailsstring
items[].createdAtstring (date-time)
items[].availableJobIdstring or nulljobId while that job still exists.
totalintegerHow many match the filters, across all pages.

Photos from jobs on this equipment

GET /organizations/{organizationId}/assets/{assetId}/photos

Before, after, general and issue photos taken on the jobs linked to this equipment, newest first (up to 60), each with its job and 10-minute view and download URLs. Read-only. A technician gets 404 for equipment they have no job on.

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

Parameters

NameInTypeRequiredDescription
assetIdpathstringYes

Example

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

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstring
jobIdstring or null
tagenum or nullOne of BEFORE, AFTER, GENERAL, ISSUE, SIGNATURE.
fileNamestring
contentTypestring
sizeBytesinteger
uploadedAtstring (date-time) or null
createdAtstring (date-time)
urlstringView URL, valid for 10 minutes.
downloadUrlstringDownload URL, valid for 10 minutes.
jobobject or null
job.idstring
job.identifierstringJOB-n
job.scheduledDatestring

List equipment types

GET /organizations/{organizationId}/equipment-types

The business's kinds of equipment (seeded once from its trade, e.g. Furnace / Air conditioner for HVAC, Car / Boat for detailing), each with its icon, built-in columns, default ownership and its own custom fields; archived ones with includeArchived. Needed before registering equipment (equipmentTypeId). Read-only.

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

Parameters

NameInTypeRequiredDescription
includeArchivedquerybooleanNo

Example

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

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstringEquipment type id (an asset's equipmentTypeId).
organizationIdstring
namestringe.g. Furnace, Car, Pool. The owner's to rename.
iconstringIcon key.
presetKeystring or nullThe trade preset it was seeded from (e.g. hvac.furnace); null = added by the owner.
lifespanKeystring or nullCustomer 360 lifespan key new equipment of this type gets (AC, FURNACE …).
customerOwnedbooleanNew equipment of this type belongs to the customer by default (vehicles, boats).
builtInFieldsarray of stringBuilt-in columns shown for this type: serialNumber, manufacturer, model, installationDate, warranty, condition, refrigerantType, lifespan.
builtInLabelsanyLabels for built-in columns, e.g. { "serialNumber": "VIN", "manufacturer": "Make" }.
sortOrderinteger
archivedboolean
customFieldsarray of objectThe type's own fields (entity EQUIPMENT); fields for every type are listed separately.
customFields[].idstringCustom field id.
customFields[].organizationIdstring
customFields[].entityenumThe record type the field is on. One of CUSTOMER, PROPERTY, EQUIPMENT, JOB, VISIT, QUOTE, INVOICE, TECHNICIAN.
customFields[].keystringThe key its values are stored under in the record's customFields; fixed. Two equipment types may share a key.
customFields[].labelstring
customFields[].typeenumOne of TEXT, TEXTAREA, NUMBER, DATE, CHECKBOX, SELECT, MULTI_SELECT, URL, EMAIL, PHONE.
customFields[].optionsarray of stringThe choices of a SELECT or MULTI_SELECT field.
customFields[].requiredboolean
customFields[].sortOrderinteger
customFields[].archivedboolean
customFields[].equipmentTypeIdstring or nullEQUIPMENT only: the equipment type the field belongs to; null = every type.
customFields[].sensitivebooleanSensitive (gate codes, medical notes): values read as •••• without customFields.sensitive.read; POST /custom-fields/reveal for one.
customFields[].visibleToCustomerbooleanShown to the customer: printed on quote/invoice documents, their emails and pages, and in the customer portal.
customFields[].createdAtstring (date-time)
_countobject
_count.assetsinteger
createdAtstring (date-time)
updatedAtstring (date-time)

Add an equipment type

POST /organizations/{organizationId}/equipment-types

Adds a kind of equipment (e.g. Generator, Jet ski). Add its own fields after with POST /custom-fields (entity EQUIPMENT, equipmentTypeId). Returns the type.

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

Request body

FieldTypeRequiredDescription
namestringYese.g. Furnace, Car, Pool. Up to 80 characters.
iconenumNoIcon shown beside the type. One of wrench, fan, flame, snowflake, thermometer, droplet, droplets, waves, zap, plug, battery, sun, car, truck, bus, ship, bike, caravan, home, door, bug, tree, sprout, sparkles, spray, lock, refrigerator, washing-machine, box, cog.
customerOwnedbooleanNoNew equipment of this type belongs to the customer (vehicles, boats).
builtInFieldsarray of enumNoBuilt-in columns shown for the type (the rest are hidden): serialNumber, manufacturer, model, installationDate, warranty, condition, refrigerantType, lifespan. Up to 8 items.
builtInLabelsobjectNoOwn labels for built-in columns, e.g. { "serialNumber": "VIN", "manufacturer": "Make" }.
lifespanKeyenum or nullNoCustomer 360 lifespan key new equipment of this type gets (AC, FURNACE …). One of AC, HEAT_PUMP, FURNACE, BOILER, MINI_SPLIT, AIR_HANDLER, PACKAGE_UNIT, WATER_HEATER, TANKLESS_WATER_HEATER, THERMOSTAT, HUMIDIFIER, AIR_PURIFIER, WATER_SOFTENER, SUMP_PUMP, WELL_PUMP, SEPTIC_PUMP, BACKFLOW_PREVENTER, ELECTRICAL_PANEL, GENERATOR, EV_CHARGER, GARAGE_DOOR_OPENER, POOL_PUMP, POOL_HEATER, REFRIGERATION, ICE_MACHINE, OTHER.
sortOrderintegerNo

Example

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

Response

201: the answer's fields
FieldTypeDescription
idstringEquipment type id (an asset's equipmentTypeId).
organizationIdstring
namestringe.g. Furnace, Car, Pool. The owner's to rename.
iconstringIcon key.
presetKeystring or nullThe trade preset it was seeded from (e.g. hvac.furnace); null = added by the owner.
lifespanKeystring or nullCustomer 360 lifespan key new equipment of this type gets (AC, FURNACE …).
customerOwnedbooleanNew equipment of this type belongs to the customer by default (vehicles, boats).
builtInFieldsarray of stringBuilt-in columns shown for this type: serialNumber, manufacturer, model, installationDate, warranty, condition, refrigerantType, lifespan.
builtInLabelsanyLabels for built-in columns, e.g. { "serialNumber": "VIN", "manufacturer": "Make" }.
sortOrderinteger
archivedboolean
customFieldsarray of objectThe type's own fields (entity EQUIPMENT); fields for every type are listed separately.
customFields[].idstringCustom field id.
customFields[].organizationIdstring
customFields[].entityenumThe record type the field is on. One of CUSTOMER, PROPERTY, EQUIPMENT, JOB, VISIT, QUOTE, INVOICE, TECHNICIAN.
customFields[].keystringThe key its values are stored under in the record's customFields; fixed. Two equipment types may share a key.
customFields[].labelstring
customFields[].typeenumOne of TEXT, TEXTAREA, NUMBER, DATE, CHECKBOX, SELECT, MULTI_SELECT, URL, EMAIL, PHONE.
customFields[].optionsarray of stringThe choices of a SELECT or MULTI_SELECT field.
customFields[].requiredboolean
customFields[].sortOrderinteger
customFields[].archivedboolean
customFields[].equipmentTypeIdstring or nullEQUIPMENT only: the equipment type the field belongs to; null = every type.
customFields[].sensitivebooleanSensitive (gate codes, medical notes): values read as •••• without customFields.sensitive.read; POST /custom-fields/reveal for one.
customFields[].visibleToCustomerbooleanShown to the customer: printed on quote/invoice documents, their emails and pages, and in the customer portal.
customFields[].createdAtstring (date-time)
_countobject
_count.assetsinteger
createdAtstring (date-time)
updatedAtstring (date-time)

Get an equipment type

GET /organizations/{organizationId}/equipment-types/{equipmentTypeId}

One equipment type with its own custom fields and equipment count. Read-only.

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

Parameters

NameInTypeRequiredDescription
equipmentTypeIdpathstringYes

Example

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

Response

200: the answer's fields
FieldTypeDescription
idstringEquipment type id (an asset's equipmentTypeId).
organizationIdstring
namestringe.g. Furnace, Car, Pool. The owner's to rename.
iconstringIcon key.
presetKeystring or nullThe trade preset it was seeded from (e.g. hvac.furnace); null = added by the owner.
lifespanKeystring or nullCustomer 360 lifespan key new equipment of this type gets (AC, FURNACE …).
customerOwnedbooleanNew equipment of this type belongs to the customer by default (vehicles, boats).
builtInFieldsarray of stringBuilt-in columns shown for this type: serialNumber, manufacturer, model, installationDate, warranty, condition, refrigerantType, lifespan.
builtInLabelsanyLabels for built-in columns, e.g. { "serialNumber": "VIN", "manufacturer": "Make" }.
sortOrderinteger
archivedboolean
customFieldsarray of objectThe type's own fields (entity EQUIPMENT); fields for every type are listed separately.
customFields[].idstringCustom field id.
customFields[].organizationIdstring
customFields[].entityenumThe record type the field is on. One of CUSTOMER, PROPERTY, EQUIPMENT, JOB, VISIT, QUOTE, INVOICE, TECHNICIAN.
customFields[].keystringThe key its values are stored under in the record's customFields; fixed. Two equipment types may share a key.
customFields[].labelstring
customFields[].typeenumOne of TEXT, TEXTAREA, NUMBER, DATE, CHECKBOX, SELECT, MULTI_SELECT, URL, EMAIL, PHONE.
customFields[].optionsarray of stringThe choices of a SELECT or MULTI_SELECT field.
customFields[].requiredboolean
customFields[].sortOrderinteger
customFields[].archivedboolean
customFields[].equipmentTypeIdstring or nullEQUIPMENT only: the equipment type the field belongs to; null = every type.
customFields[].sensitivebooleanSensitive (gate codes, medical notes): values read as •••• without customFields.sensitive.read; POST /custom-fields/reveal for one.
customFields[].visibleToCustomerbooleanShown to the customer: printed on quote/invoice documents, their emails and pages, and in the customer portal.
customFields[].createdAtstring (date-time)
_countobject
_count.assetsinteger
createdAtstring (date-time)
updatedAtstring (date-time)

Rename, change or archive an equipment type

PATCH /organizations/{organizationId}/equipment-types/{equipmentTypeId}

Changes the fields sent. archived: true removes it from pickers (its equipment keeps it, nothing is deleted); false brings it back. Returns the type.

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

Parameters

NameInTypeRequiredDescription
equipmentTypeIdpathstringYes

Request body

FieldTypeRequiredDescription
namestringNoe.g. Furnace, Car, Pool. Up to 80 characters.
iconenumNoIcon shown beside the type. One of wrench, fan, flame, snowflake, thermometer, droplet, droplets, waves, zap, plug, battery, sun, car, truck, bus, ship, bike, caravan, home, door, bug, tree, sprout, sparkles, spray, lock, refrigerator, washing-machine, box, cog.
customerOwnedbooleanNo
builtInFieldsarray of enumNoBuilt-in columns shown for the type (the rest are hidden): serialNumber, manufacturer, model, installationDate, warranty, condition, refrigerantType, lifespan. Up to 8 items.
builtInLabelsobjectNoOwn labels for built-in columns, e.g. { "serialNumber": "VIN", "manufacturer": "Make" }.
lifespanKeyenum or nullNoCustomer 360 lifespan key new equipment of this type gets (AC, FURNACE …). One of AC, HEAT_PUMP, FURNACE, BOILER, MINI_SPLIT, AIR_HANDLER, PACKAGE_UNIT, WATER_HEATER, TANKLESS_WATER_HEATER, THERMOSTAT, HUMIDIFIER, AIR_PURIFIER, WATER_SOFTENER, SUMP_PUMP, WELL_PUMP, SEPTIC_PUMP, BACKFLOW_PREVENTER, ELECTRICAL_PANEL, GENERATOR, EV_CHARGER, GARAGE_DOOR_OPENER, POOL_PUMP, POOL_HEATER, REFRIGERATION, ICE_MACHINE, OTHER.
sortOrderintegerNo
archivedbooleanNo

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/equipment-types/{equipmentTypeId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Dana Whitfield","icon":"wrench","customerOwned":true}'

Response

200: the answer's fields
FieldTypeDescription
idstringEquipment type id (an asset's equipmentTypeId).
organizationIdstring
namestringe.g. Furnace, Car, Pool. The owner's to rename.
iconstringIcon key.
presetKeystring or nullThe trade preset it was seeded from (e.g. hvac.furnace); null = added by the owner.
lifespanKeystring or nullCustomer 360 lifespan key new equipment of this type gets (AC, FURNACE …).
customerOwnedbooleanNew equipment of this type belongs to the customer by default (vehicles, boats).
builtInFieldsarray of stringBuilt-in columns shown for this type: serialNumber, manufacturer, model, installationDate, warranty, condition, refrigerantType, lifespan.
builtInLabelsanyLabels for built-in columns, e.g. { "serialNumber": "VIN", "manufacturer": "Make" }.
sortOrderinteger
archivedboolean
customFieldsarray of objectThe type's own fields (entity EQUIPMENT); fields for every type are listed separately.
customFields[].idstringCustom field id.
customFields[].organizationIdstring
customFields[].entityenumThe record type the field is on. One of CUSTOMER, PROPERTY, EQUIPMENT, JOB, VISIT, QUOTE, INVOICE, TECHNICIAN.
customFields[].keystringThe key its values are stored under in the record's customFields; fixed. Two equipment types may share a key.
customFields[].labelstring
customFields[].typeenumOne of TEXT, TEXTAREA, NUMBER, DATE, CHECKBOX, SELECT, MULTI_SELECT, URL, EMAIL, PHONE.
customFields[].optionsarray of stringThe choices of a SELECT or MULTI_SELECT field.
customFields[].requiredboolean
customFields[].sortOrderinteger
customFields[].archivedboolean
customFields[].equipmentTypeIdstring or nullEQUIPMENT only: the equipment type the field belongs to; null = every type.
customFields[].sensitivebooleanSensitive (gate codes, medical notes): values read as •••• without customFields.sensitive.read; POST /custom-fields/reveal for one.
customFields[].visibleToCustomerbooleanShown to the customer: printed on quote/invoice documents, their emails and pages, and in the customer portal.
customFields[].createdAtstring (date-time)
_countobject
_count.assetsinteger
createdAtstring (date-time)
updatedAtstring (date-time)

Add a trade's preset equipment types

POST /organizations/{organizationId}/equipment-types/presets

Adds the preset types (with their fields) of a trade the business does not have yet, e.g. pool-spa for a plumber who also services pools. Presets already added, renamed or archived are left alone. Returns how many were added and every type.

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

Request body

FieldTypeRequiredDescription
tradeenumYesTrade key (hvac, plumbing, pool-spa, car-detailing … or other). One of hvac, plumbing, electrical, roofing, lawn-care, landscaping, tree-care, pest-control, house-cleaning, carpet-cleaning, window-cleaning, pressure-washing, pool-spa, painting, handyman, garage-doors, appliance-repair, locksmith, junk-removal, moving, flooring, remodeling, solar, septic-drain, chimney-fireplace, irrigation, car-detailing, other.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/equipment-types/presets" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"trade":"hvac"}'

Response

200: the answer's fields
FieldTypeDescription
addedinteger
typesarray of object
types[].idstringEquipment type id (an asset's equipmentTypeId).
types[].organizationIdstring
types[].namestringe.g. Furnace, Car, Pool. The owner's to rename.
types[].iconstringIcon key.
types[].presetKeystring or nullThe trade preset it was seeded from (e.g. hvac.furnace); null = added by the owner.
types[].lifespanKeystring or nullCustomer 360 lifespan key new equipment of this type gets (AC, FURNACE …).
types[].customerOwnedbooleanNew equipment of this type belongs to the customer by default (vehicles, boats).
types[].builtInFieldsarray of stringBuilt-in columns shown for this type: serialNumber, manufacturer, model, installationDate, warranty, condition, refrigerantType, lifespan.
types[].builtInLabelsanyLabels for built-in columns, e.g. { "serialNumber": "VIN", "manufacturer": "Make" }.
types[].sortOrderinteger
types[].archivedboolean
types[].customFieldsarray of objectThe type's own fields (entity EQUIPMENT); fields for every type are listed separately.
types[].customFields[].idstringCustom field id.
types[].customFields[].organizationIdstring
types[].customFields[].entityenumThe record type the field is on. One of CUSTOMER, PROPERTY, EQUIPMENT, JOB, VISIT, QUOTE, INVOICE, TECHNICIAN.
types[].customFields[].keystringThe key its values are stored under in the record's customFields; fixed. Two equipment types may share a key.
types[].customFields[].labelstring
types[].customFields[].typeenumOne of TEXT, TEXTAREA, NUMBER, DATE, CHECKBOX, SELECT, MULTI_SELECT, URL, EMAIL, PHONE.
types[].customFields[].optionsarray of stringThe choices of a SELECT or MULTI_SELECT field.
types[].customFields[].requiredboolean
types[].customFields[].sortOrderinteger
types[].customFields[].archivedboolean
types[].customFields[].equipmentTypeIdstring or nullEQUIPMENT only: the equipment type the field belongs to; null = every type.
types[].customFields[].sensitivebooleanSensitive (gate codes, medical notes): values read as •••• without customFields.sensitive.read; POST /custom-fields/reveal for one.
types[].customFields[].visibleToCustomerbooleanShown to the customer: printed on quote/invoice documents, their emails and pages, and in the customer portal.
types[].customFields[].createdAtstring (date-time)
types[]._countobject
types[]._count.assetsinteger
types[].createdAtstring (date-time)
types[].updatedAtstring (date-time)

What equipment is called here

GET /organizations/{organizationId}/equipment-labels

The business's word for equipment, singular and plural (e.g. Vehicle / Vehicles for a detailer, Unit / Units for HVAC): the owner's own when set, else the trade's default. Use it when talking to the business about its equipment. Read-only.

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

Example

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

Response

200: the answer's fields
FieldTypeDescription
singularstringWhat one piece of equipment is called here, e.g. Vehicle.
pluralstringe.g. Vehicles.
custombooleanThe owner set their own wording (else the trade's default).
tradeDefaultobject
tradeDefault.singularstring
tradeDefault.pluralstring

Change what equipment is called

PATCH /organizations/{organizationId}/equipment-labels

Sets the word used for equipment across the app, the portal and emails (singular and plural, 1–40 characters each); null goes back to the trade's default. Returns the wording in use.

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

Request body

FieldTypeRequiredDescription
singularstring or nullNoe.g. Vehicle; null = the trade's default. Up to 40 characters.
pluralstring or nullNoe.g. Vehicles; null = the trade's default. Up to 40 characters.

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/equipment-labels" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"singular":"string","plural":"string"}'

Response

200: the answer's fields
FieldTypeDescription
singularstringWhat one piece of equipment is called here, e.g. Vehicle.
pluralstringe.g. Vehicles.
custombooleanThe owner set their own wording (else the trade's default).
tradeDefaultobject
tradeDefault.singularstring
tradeDefault.pluralstring

On this page