DevelopersAPI reference

Settings API

REST endpoints for settings in ServFlo: 12 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 lead sourcesGET /organizations/{organizationId}/lead-sourcesread
Create a lead sourcePOST /organizations/{organizationId}/lead-sourceswrite
Rename or (de)activate a lead sourcePATCH /organizations/{organizationId}/lead-sources/{leadSourceId}write
Delete a lead sourceDELETE /organizations/{organizationId}/lead-sources/{leadSourceId}sensitive
List custom field definitionsGET /organizations/{organizationId}/custom-fieldsread
Define a custom fieldPOST /organizations/{organizationId}/custom-fieldswrite
Update a custom fieldPATCH /organizations/{organizationId}/custom-fields/{fieldId}write
Delete a custom fieldDELETE /organizations/{organizationId}/custom-fields/{fieldId}sensitive
Show a custom field to customers, or mark it sensitivePOST /organizations/{organizationId}/custom-fields/{fieldId}/flagssensitive
Reveal a sensitive custom field valuePOST /organizations/{organizationId}/custom-fields/revealsensitive
What customers agree to when they signGET /organizations/{organizationId}/signing-termsread
Change what customers agree to when they signPATCH /organizations/{organizationId}/signing-termssensitive

List lead sources

GET /organizations/{organizationId}/lead-sources

Where customers hear about the business (Google, referral …), active and hidden, with customer counts. Read by anyone who can read customers, since customers point at them. Read-only.

Permissioncustomers.read (Owner, Admin, Dispatcher, Technician, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolleadSources_list (toolset settings)

Example

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

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstringLead source id (a customer's leadSourceId).
organizationIdstring
namestring
activeboolean
createdAtstring (date-time)
_countobjectCustomers from this source.
_count.customersinteger

Create a lead source

POST /organizations/{organizationId}/lead-sources

Adds a lead source to pick on customers (PATCH /customers leadSourceId). Names are unique (409). Returns it.

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

Request body

FieldTypeRequiredDescription
namestringYesUp to 200 characters.
activebooleanNo

Example

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

Response

201: the answer's fields
FieldTypeDescription
idstringLead source id (a customer's leadSourceId).
organizationIdstring
namestring
activeboolean
createdAtstring (date-time)

Rename or (de)activate a lead source

PATCH /organizations/{organizationId}/lead-sources/{leadSourceId}

Renames it and/or hides it from forms (active: false) while customers keep the link. Returns it.

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

Parameters

NameInTypeRequiredDescription
leadSourceIdpathstringYes

Request body

FieldTypeRequiredDescription
namestringNoUp to 200 characters.
activebooleanNo

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/lead-sources/{leadSourceId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Dana Whitfield","active":true}'

Response

200: the answer's fields
FieldTypeDescription
idstringLead source id (a customer's leadSourceId).
organizationIdstring
namestring
activeboolean
createdAtstring (date-time)

Delete a lead source

DELETE /organizations/{organizationId}/lead-sources/{leadSourceId}

Destructive: deletes the lead source; customers keep existing with their lead source cleared. Deactivate instead to keep the link.

Permissionsettings.manage (Owner, Admin)
Risksensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolleadSources_delete (toolset settings)
ApprovalOver MCP, this tool always waits for your approval in ServFlo. See Approvals.

Parameters

NameInTypeRequiredDescription
leadSourceIdpathstringYes

Example

curl -X DELETE "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/lead-sources/{leadSourceId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
oktrue

List custom field definitions

GET /organizations/{organizationId}/custom-fields

The extra fields the business defined (key, label, type, options, required, visibleToCustomer, sensitive) for customers, properties, equipment, jobs, visits, quotes, invoices or technicians; archived ones with includeArchived. For equipment, equipmentTypeId gives the fields for every type plus that type's own (what a piece of that type carries); allEquipmentTypes lists every type's. Needed to read and write customFields on those records. Values of sensitive fields read as •••• without customFields.sensitive.read (POST /custom-fields/reveal for one). Read-only.

Permissioncustomers.read (Owner, Admin, Dispatcher, Technician, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolcustomFields_list (toolset settings)

Parameters

NameInTypeRequiredDescription
entityqueryenumNoThe record type: CUSTOMER, PROPERTY, EQUIPMENT (all types or one, equipmentTypeId), JOB, VISIT, QUOTE, INVOICE or TECHNICIAN. One of CUSTOMER, PROPERTY, EQUIPMENT, JOB, VISIT, QUOTE, INVOICE, TECHNICIAN.
includeArchivedquerybooleanNo
equipmentTypeIdquerystringNoEquipment: the fields for every type plus this type's own.
allEquipmentTypesquerybooleanNoEquipment: every type's fields too (Settings).

Example

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

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstringCustom field id.
organizationIdstring
entityenumThe record type the field is on. One of CUSTOMER, PROPERTY, EQUIPMENT, JOB, VISIT, QUOTE, INVOICE, TECHNICIAN.
keystringThe key its values are stored under in the record's customFields; fixed. Two equipment types may share a key.
labelstring
typeenumOne of TEXT, TEXTAREA, NUMBER, DATE, CHECKBOX, SELECT, MULTI_SELECT, URL, EMAIL, PHONE.
optionsarray of stringThe choices of a SELECT or MULTI_SELECT field.
requiredboolean
sortOrderinteger
archivedboolean
equipmentTypeIdstring or nullEQUIPMENT only: the equipment type the field belongs to; null = every type.
sensitivebooleanSensitive (gate codes, medical notes): values read as •••• without customFields.sensitive.read; POST /custom-fields/reveal for one.
visibleToCustomerbooleanShown to the customer: printed on quote/invoice documents, their emails and pages, and in the customer portal.
createdAtstring (date-time)

Define a custom field

POST /organizations/{organizationId}/custom-fields

Defines a custom field on customers, properties, equipment (every type, or one with equipmentTypeId), jobs, visits, quotes, invoices or technicians. Its key is derived from the label once and never changes; SELECT and MULTI_SELECT need options. visibleToCustomer prints it on quote and invoice documents and their emails and shows it in the customer portal (customer-visible); sensitive (gate, alarm or lockbox codes, medical notes) masks its values for anyone without customFields.sensitive.read and can't be combined with visibleToCustomer. A new field has no values yet, so both flags may be set here; change them later with POST /custom-fields/{fieldId}/flags. Returns the definition.

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

Request body

FieldTypeRequiredDescription
entityenumYesThe record type: CUSTOMER, PROPERTY, EQUIPMENT (all types or one, equipmentTypeId), JOB, VISIT, QUOTE, INVOICE or TECHNICIAN. One of CUSTOMER, PROPERTY, EQUIPMENT, JOB, VISIT, QUOTE, INVOICE, TECHNICIAN.
labelstringYesUp to 200 characters.
typeenumYesOne of TEXT, TEXTAREA, NUMBER, DATE, CHECKBOX, SELECT, MULTI_SELECT, URL, EMAIL, PHONE.
optionsarray of stringNoUp to 200 items.
requiredbooleanNo
sortOrderintegerNo
equipmentTypeIdstring or nullNoEQUIPMENT only: the type the field belongs to; unset = every type.
visibleToCustomerbooleanNoShow it to the customer (documents, emails, portal). Default false.
sensitivebooleanNoSensitive (gate codes, medical notes): values masked as •••• for callers without customFields.sensitive.read. Default false.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/custom-fields" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"entity":"CUSTOMER","label":"string","type":"TEXT"}'

Response

201: the answer's fields
FieldTypeDescription
idstringCustom field id.
organizationIdstring
entityenumThe record type the field is on. One of CUSTOMER, PROPERTY, EQUIPMENT, JOB, VISIT, QUOTE, INVOICE, TECHNICIAN.
keystringThe key its values are stored under in the record's customFields; fixed. Two equipment types may share a key.
labelstring
typeenumOne of TEXT, TEXTAREA, NUMBER, DATE, CHECKBOX, SELECT, MULTI_SELECT, URL, EMAIL, PHONE.
optionsarray of stringThe choices of a SELECT or MULTI_SELECT field.
requiredboolean
sortOrderinteger
archivedboolean
equipmentTypeIdstring or nullEQUIPMENT only: the equipment type the field belongs to; null = every type.
sensitivebooleanSensitive (gate codes, medical notes): values read as •••• without customFields.sensitive.read; POST /custom-fields/reveal for one.
visibleToCustomerbooleanShown to the customer: printed on quote/invoice documents, their emails and pages, and in the customer portal.
createdAtstring (date-time)

Update a custom field

PATCH /organizations/{organizationId}/custom-fields/{fieldId}

Changes label, options, required or order, or archives it. The type and the equipment type cannot change. Archived fields keep their saved values but leave forms. Whether customers see it or it is sensitive: POST /custom-fields/{fieldId}/flags.

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

Parameters

NameInTypeRequiredDescription
fieldIdpathstringYes

Request body

FieldTypeRequiredDescription
labelstringNoUp to 200 characters.
optionsarray of stringNoUp to 200 items.
requiredbooleanNo
sortOrderintegerNo
archivedbooleanNo

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/custom-fields/{fieldId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"label":"string","options":["string"],"required":true}'

Response

200: the answer's fields
FieldTypeDescription
idstringCustom field id.
organizationIdstring
entityenumThe record type the field is on. One of CUSTOMER, PROPERTY, EQUIPMENT, JOB, VISIT, QUOTE, INVOICE, TECHNICIAN.
keystringThe key its values are stored under in the record's customFields; fixed. Two equipment types may share a key.
labelstring
typeenumOne of TEXT, TEXTAREA, NUMBER, DATE, CHECKBOX, SELECT, MULTI_SELECT, URL, EMAIL, PHONE.
optionsarray of stringThe choices of a SELECT or MULTI_SELECT field.
requiredboolean
sortOrderinteger
archivedboolean
equipmentTypeIdstring or nullEQUIPMENT only: the equipment type the field belongs to; null = every type.
sensitivebooleanSensitive (gate codes, medical notes): values read as •••• without customFields.sensitive.read; POST /custom-fields/reveal for one.
visibleToCustomerbooleanShown to the customer: printed on quote/invoice documents, their emails and pages, and in the customer portal.
createdAtstring (date-time)

Delete a custom field

DELETE /organizations/{organizationId}/custom-fields/{fieldId}

Destructive: deletes the definition; saved values can no longer be seen. Archive instead to keep them.

Permissionsettings.manage (Owner, Admin)
Risksensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolcustomFields_delete (toolset settings)
ApprovalOver MCP, this tool always waits for your approval in ServFlo. See Approvals.

Parameters

NameInTypeRequiredDescription
fieldIdpathstringYes

Example

curl -X DELETE "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/custom-fields/{fieldId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
oktrue

Show a custom field to customers, or mark it sensitive

POST /organizations/{organizationId}/custom-fields/{fieldId}/flags

EXPOSES TO CUSTOMERS / CHANGES WHO SEES IT: visibleToCustomer: true prints the field's saved values on quotes and invoices, their emails and the customer portal; sensitive: true masks its values (••••) for everyone without customFields.sensitive.read, false shows them to every role that reads the record. A field can't be both (400). Returns the definition.

Permissionsettings.manage (Owner, Admin)
Risksensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolcustomFields_setFlags (toolset settings)
ApprovalOver MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals.

Parameters

NameInTypeRequiredDescription
fieldIdpathstringYes

Request body

FieldTypeRequiredDescription
visibleToCustomerbooleanNo
sensitivebooleanNo

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/custom-fields/{fieldId}/flags" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"visibleToCustomer":true,"sensitive":true}'

Response

200: the answer's fields
FieldTypeDescription
idstringCustom field id.
organizationIdstring
entityenumThe record type the field is on. One of CUSTOMER, PROPERTY, EQUIPMENT, JOB, VISIT, QUOTE, INVOICE, TECHNICIAN.
keystringThe key its values are stored under in the record's customFields; fixed. Two equipment types may share a key.
labelstring
typeenumOne of TEXT, TEXTAREA, NUMBER, DATE, CHECKBOX, SELECT, MULTI_SELECT, URL, EMAIL, PHONE.
optionsarray of stringThe choices of a SELECT or MULTI_SELECT field.
requiredboolean
sortOrderinteger
archivedboolean
equipmentTypeIdstring or nullEQUIPMENT only: the equipment type the field belongs to; null = every type.
sensitivebooleanSensitive (gate codes, medical notes): values read as •••• without customFields.sensitive.read; POST /custom-fields/reveal for one.
visibleToCustomerbooleanShown to the customer: printed on quote/invoice documents, their emails and pages, and in the customer portal.
createdAtstring (date-time)

Reveal a sensitive custom field value

POST /organizations/{organizationId}/custom-fields/reveal

Exposes a secret: one sensitive value (a gate or lockbox code, a medical note) of one record, which other answers show as ••••. Recorded in the activity log. Technicians: only the customers, properties, equipment, jobs and visits of their own jobs (404 otherwise). Get the field's key from GET /custom-fields.

Permission: customFields.sensitive.read (Owner, Admin, Dispatcher, Technician (own jobs)); risk sensitive (OAuth scope servflo.sensitive).

PermissioncustomFields.sensitive.read
Risksensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolcustomFields_reveal (toolset settings)
ApprovalOver MCP, this tool always waits for your approval in ServFlo. See Approvals.

Request body

FieldTypeRequiredDescription
entityenumYesThe record type: CUSTOMER, PROPERTY, EQUIPMENT (all types or one, equipmentTypeId), JOB, VISIT, QUOTE, INVOICE or TECHNICIAN. One of CUSTOMER, PROPERTY, EQUIPMENT, JOB, VISIT, QUOTE, INVOICE, TECHNICIAN.
recordIdstringYesThe customer, property, equipment, job, visit, quote, invoice or technician id.
keystringYesThe sensitive field's key. Up to 200 characters.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/custom-fields/reveal" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"entity":"CUSTOMER","recordId":"record_id","key":"string"}'

Response

200: the answer's fields
FieldTypeDescription
keystring
labelstring
typestring
valueanyThe stored value; null when empty.

What customers agree to when they sign

GET /organizations/{organizationId}/signing-terms

The job sign-off statement, the quote terms and the membership agreement: the business's wording (null = ServFlo's default), the defaults, and the resolved text customers see ({business} replaced by the business's name). Read-only.

Permissionorganization.read (Owner, Admin, Dispatcher, Technician, Member)
Riskread, OAuth scope servflo.read. Read: reads only.
MCP toolsigningTerms_get (toolset settings)

Example

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

Response

200: the answer's fields
FieldTypeDescription
signOffTermsstring or nullThe business's sign-off statement; null = the default.
quoteTermsstring or nullThe business's quote terms; null = the default.
membershipTermsstring or nullThe membership agreement signed on a technician's phone; null = the default.
defaultsobject
defaults.signOffTermsstring
defaults.quoteTermsstring
defaults.membershipTermsstring
resolvedobjectWhat customers see now, {business} filled in.
resolved.signOffTermsstring
resolved.quoteTermsstring
resolved.membershipTermsstring

Change what customers agree to when they sign

PATCH /organizations/{organizationId}/signing-terms

Changes what customers agree to: sets the job sign-off statement, the quote terms and/or the membership agreement (up to 5000 characters each; {business} is replaced by the business's name). Null or empty restores the default. Signatures already given keep the text they were shown.

Permissionsettings.manage (Owner, Admin)
Risksensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.
MCP toolsigningTerms_update (toolset settings)
ApprovalOver MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals.

Request body

FieldTypeRequiredDescription
signOffTermsstring or nullNoUp to 5000 characters.
quoteTermsstring or nullNoUp to 5000 characters.
membershipTermsstring or nullNoUp to 5000 characters.

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/signing-terms" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"signOffTerms":"string","quoteTerms":"string","membershipTerms":"string"}'

Response

200: the answer's fields
FieldTypeDescription
signOffTermsstring or nullThe business's sign-off statement; null = the default.
quoteTermsstring or nullThe business's quote terms; null = the default.
membershipTermsstring or nullThe membership agreement signed on a technician's phone; null = the default.
defaultsobject
defaults.signOffTermsstring
defaults.quoteTermsstring
defaults.membershipTermsstring
resolvedobjectWhat customers see now, {business} filled in.
resolved.signOffTermsstring
resolved.quoteTermsstring
resolved.membershipTermsstring

On this page