DevelopersAPI reference

Forms API

REST endpoints for forms in ServFlo: 10 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 job's forms with their answersGET /organizations/{organizationId}/jobs/{jobId}/formsread
Add a form template to a jobPOST /organizations/{organizationId}/jobs/{jobId}/formswrite
Save a job form's answersPATCH /organizations/{organizationId}/jobs/{jobId}/forms/{formId}write
Remove a form from a jobDELETE /organizations/{organizationId}/jobs/{jobId}/forms/{formId}sensitive
Submit a job formPOST /organizations/{organizationId}/jobs/{jobId}/forms/{formId}/submitwrite
List job form templatesGET /organizations/{organizationId}/form-templatesread
Create a job form templatePOST /organizations/{organizationId}/form-templateswrite
Get a job form templateGET /organizations/{organizationId}/form-templates/{templateId}read
Update a job form templatePATCH /organizations/{organizationId}/form-templates/{templateId}write
Delete a job form templateDELETE /organizations/{organizationId}/form-templates/{templateId}sensitive

A job's forms with their answers

GET /organizations/{organizationId}/jobs/{jobId}/forms

The forms attached to the job (from templates matching its service type, 'always attach' templates, or added by hand): field snapshot, answers, status and missing required fields. Read-only. Also included in GET /jobs/{jobId}.

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

Permissionjobs.read
Riskread, OAuth scope servflo.read. Read: reads only.
MCP tooljobForms_list (toolset scheduling)

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Example

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

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstring
jobIdstring
templateIdstring or null
namestring
descriptionstring or null
fieldsarray of objectUp to 100 items.
fields[].idstringStable id of the field within the template; answers are keyed by it. Up to 64 characters.
fields[].typeenumWhat kind of answer the field takes. One of heading, checkbox, text, textarea, number, select, multiselect, date, photo, signature.
fields[].labelstringUp to 200 characters.
fields[].requiredbooleanA required field must be answered before the job can be completed. Default false.
fields[].helpstring or nullHelp text shown under the field. Up to 500 characters.
fields[].optionsarray of stringChoices for select and multiselect fields. Up to 50 items.
fields[].minnumber or nullSmallest allowed value (number fields).
fields[].maxnumber or nullLargest allowed value (number fields).
fields[].unitstring or nullUnit shown after a number, e.g. psi. Up to 20 characters.
answersobject
statusenumOne of DRAFT, SUBMITTED.
submittedByUserIdstring or null
submittedAtstring (date-time) or null
createdAtstring (date-time)
updatedAtstring (date-time)
missingarray of stringIds of required fields still unanswered.

Add a form template to a job

POST /organizations/{organizationId}/jobs/{jobId}/forms

Attaches a template (GET /form-templates) to the job as a new draft form with a snapshot of its fields; adding one already on the job returns that form. Its required fields then block completing the job.

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

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Request body

FieldTypeRequiredDescription
templateIdstringYes

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/forms" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"templateId":"template_id"}'

Response

201: the answer's fields
FieldTypeDescription
idstring
jobIdstring
templateIdstring or null
namestring
descriptionstring or null
fieldsarray of objectUp to 100 items.
fields[].idstringStable id of the field within the template; answers are keyed by it. Up to 64 characters.
fields[].typeenumWhat kind of answer the field takes. One of heading, checkbox, text, textarea, number, select, multiselect, date, photo, signature.
fields[].labelstringUp to 200 characters.
fields[].requiredbooleanA required field must be answered before the job can be completed. Default false.
fields[].helpstring or nullHelp text shown under the field. Up to 500 characters.
fields[].optionsarray of stringChoices for select and multiselect fields. Up to 50 items.
fields[].minnumber or nullSmallest allowed value (number fields).
fields[].maxnumber or nullLargest allowed value (number fields).
fields[].unitstring or nullUnit shown after a number, e.g. psi. Up to 20 characters.
answersobject
statusenumOne of DRAFT, SUBMITTED.
submittedByUserIdstring or null
submittedAtstring (date-time) or null
createdAtstring (date-time)
updatedAtstring (date-time)
missingarray of stringIds of required fields still unanswered.

Save a job form's answers

PATCH /organizations/{organizationId}/jobs/{jobId}/forms/{formId}

Replaces the form's answers with answers, keyed by field id: checkbox → boolean, text/textarea/select/date → string, number → number, multiselect → string[], photo → ids of this job's photos (POST …/photos first), signature → { name, dataUrl (PNG data URL), signedAt }. Wrong types are refused (400); missing required answers are allowed until submit or completion. A submitted form goes back to DRAFT.

Permissionjobs.work (Owner, Admin, Dispatcher, Technician)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP tooljobForms_save (toolset scheduling)

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes
formIdpathstringYes

Request body

FieldTypeRequiredDescription
answersobjectYesAnswers keyed by field id; see the description for each type.

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/forms/{formId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"answers":{}}'

Response

200: the answer's fields
FieldTypeDescription
idstring
jobIdstring
templateIdstring or null
namestring
descriptionstring or null
fieldsarray of objectUp to 100 items.
fields[].idstringStable id of the field within the template; answers are keyed by it. Up to 64 characters.
fields[].typeenumWhat kind of answer the field takes. One of heading, checkbox, text, textarea, number, select, multiselect, date, photo, signature.
fields[].labelstringUp to 200 characters.
fields[].requiredbooleanA required field must be answered before the job can be completed. Default false.
fields[].helpstring or nullHelp text shown under the field. Up to 500 characters.
fields[].optionsarray of stringChoices for select and multiselect fields. Up to 50 items.
fields[].minnumber or nullSmallest allowed value (number fields).
fields[].maxnumber or nullLargest allowed value (number fields).
fields[].unitstring or nullUnit shown after a number, e.g. psi. Up to 20 characters.
answersobject
statusenumOne of DRAFT, SUBMITTED.
submittedByUserIdstring or null
submittedAtstring (date-time) or null
createdAtstring (date-time)
updatedAtstring (date-time)
missingarray of stringIds of required fields still unanswered.

Remove a form from a job

DELETE /organizations/{organizationId}/jobs/{jobId}/forms/{formId}

Destructive: removes the form and its answers from the job (the template stays). Cannot be undone.

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

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes
formIdpathstringYes

Example

curl -X DELETE "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/forms/{formId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
oktrue

Submit a job form

POST /organizations/{organizationId}/jobs/{jobId}/forms/{formId}/submit

Marks the form SUBMITTED by the caller. Refused (400, naming the fields) while a required field is unanswered. Emits form.submitted. Completing the job submits complete drafts automatically.

Permissionjobs.work (Owner, Admin, Dispatcher, Technician)
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP tooljobForms_submit (toolset scheduling)

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes
formIdpathstringYes

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/forms/{formId}/submit" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
idstring
jobIdstring
templateIdstring or null
namestring
descriptionstring or null
fieldsarray of objectUp to 100 items.
fields[].idstringStable id of the field within the template; answers are keyed by it. Up to 64 characters.
fields[].typeenumWhat kind of answer the field takes. One of heading, checkbox, text, textarea, number, select, multiselect, date, photo, signature.
fields[].labelstringUp to 200 characters.
fields[].requiredbooleanA required field must be answered before the job can be completed. Default false.
fields[].helpstring or nullHelp text shown under the field. Up to 500 characters.
fields[].optionsarray of stringChoices for select and multiselect fields. Up to 50 items.
fields[].minnumber or nullSmallest allowed value (number fields).
fields[].maxnumber or nullLargest allowed value (number fields).
fields[].unitstring or nullUnit shown after a number, e.g. psi. Up to 20 characters.
answersobject
statusenumOne of DRAFT, SUBMITTED.
submittedByUserIdstring or null
submittedAtstring (date-time) or null
createdAtstring (date-time)
updatedAtstring (date-time)
missingarray of stringIds of required fields still unanswered.

List job form templates

GET /organizations/{organizationId}/form-templates

Every job form template (active first) with its fields, the service types it is assigned to, whether it always attaches, and how many jobs carry it. Read-only.

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

Example

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

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstring
namestring
descriptionstring or null
activeboolean
alwaysAttachboolean
fieldsarray of objectUp to 100 items.
fields[].idstringStable id of the field within the template; answers are keyed by it. Up to 64 characters.
fields[].typeenumWhat kind of answer the field takes. One of heading, checkbox, text, textarea, number, select, multiselect, date, photo, signature.
fields[].labelstringUp to 200 characters.
fields[].requiredbooleanA required field must be answered before the job can be completed. Default false.
fields[].helpstring or nullHelp text shown under the field. Up to 500 characters.
fields[].optionsarray of stringChoices for select and multiselect fields. Up to 50 items.
fields[].minnumber or nullSmallest allowed value (number fields).
fields[].maxnumber or nullLargest allowed value (number fields).
fields[].unitstring or nullUnit shown after a number, e.g. psi. Up to 20 characters.
serviceTypeIdsarray of string
createdAtstring (date-time)
updatedAtstring (date-time)
jobFormCountinteger

Create a job form template

POST /organizations/{organizationId}/form-templates

Creates a template. From now on, new jobs of its service types (or every new job, with alwaysAttach) get a copy to fill in; existing jobs are unchanged (add it by hand with POST /jobs/{jobId}/forms). Fields are validated (unique ids, choices for selects). Returns the template.

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

Request body

FieldTypeRequiredDescription
namestringYesUp to 200 characters.
descriptionstring or nullNoUp to 2000 characters.
activebooleanNoInactive templates attach to no new jobs.
alwaysAttachbooleanNoAttach to every new job, whatever its service type.
fieldsarray of anyYesThe fields, in order: { id, type (heading, checkbox, text, textarea, number, select, multiselect, date, photo, signature), label, required, help?, options? (select/multiselect), min?, max?, unit? }. Up to 100 items.
serviceTypeIdsarray of stringNoService types (GET /service-types) whose new jobs get this form. Up to 100 items.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/form-templates" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Dana Whitfield","fields":[null]}'

Response

201: the answer's fields
FieldTypeDescription
idstring
namestring
descriptionstring or null
activeboolean
alwaysAttachboolean
fieldsarray of objectUp to 100 items.
fields[].idstringStable id of the field within the template; answers are keyed by it. Up to 64 characters.
fields[].typeenumWhat kind of answer the field takes. One of heading, checkbox, text, textarea, number, select, multiselect, date, photo, signature.
fields[].labelstringUp to 200 characters.
fields[].requiredbooleanA required field must be answered before the job can be completed. Default false.
fields[].helpstring or nullHelp text shown under the field. Up to 500 characters.
fields[].optionsarray of stringChoices for select and multiselect fields. Up to 50 items.
fields[].minnumber or nullSmallest allowed value (number fields).
fields[].maxnumber or nullLargest allowed value (number fields).
fields[].unitstring or nullUnit shown after a number, e.g. psi. Up to 20 characters.
serviceTypeIdsarray of string
createdAtstring (date-time)
updatedAtstring (date-time)
jobFormCountinteger

Get a job form template

GET /organizations/{organizationId}/form-templates/{templateId}

One template with its fields and assigned service types. Read-only.

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

Parameters

NameInTypeRequiredDescription
templateIdpathstringYes

Example

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

Response

200: the answer's fields
FieldTypeDescription
idstring
namestring
descriptionstring or null
activeboolean
alwaysAttachboolean
fieldsarray of objectUp to 100 items.
fields[].idstringStable id of the field within the template; answers are keyed by it. Up to 64 characters.
fields[].typeenumWhat kind of answer the field takes. One of heading, checkbox, text, textarea, number, select, multiselect, date, photo, signature.
fields[].labelstringUp to 200 characters.
fields[].requiredbooleanA required field must be answered before the job can be completed. Default false.
fields[].helpstring or nullHelp text shown under the field. Up to 500 characters.
fields[].optionsarray of stringChoices for select and multiselect fields. Up to 50 items.
fields[].minnumber or nullSmallest allowed value (number fields).
fields[].maxnumber or nullLargest allowed value (number fields).
fields[].unitstring or nullUnit shown after a number, e.g. psi. Up to 20 characters.
serviceTypeIdsarray of string
createdAtstring (date-time)
updatedAtstring (date-time)
jobFormCountinteger

Update a job form template

PATCH /organizations/{organizationId}/form-templates/{templateId}

Changes the fields sent. serviceTypeIds replaces the assignment. Forms already on jobs keep their own copy of the fields. Returns the template.

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

Parameters

NameInTypeRequiredDescription
templateIdpathstringYes

Request body

FieldTypeRequiredDescription
namestringNoUp to 200 characters.
descriptionstring or nullNoUp to 2000 characters.
activebooleanNoInactive templates attach to no new jobs.
alwaysAttachbooleanNoAttach to every new job, whatever its service type.
fieldsarray of anyNoThe fields, in order: { id, type (heading, checkbox, text, textarea, number, select, multiselect, date, photo, signature), label, required, help?, options? (select/multiselect), min?, max?, unit? }. Up to 100 items.
serviceTypeIdsarray of stringNoService types (GET /service-types) whose new jobs get this form. Up to 100 items.

Example

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

Response

200: the answer's fields
FieldTypeDescription
idstring
namestring
descriptionstring or null
activeboolean
alwaysAttachboolean
fieldsarray of objectUp to 100 items.
fields[].idstringStable id of the field within the template; answers are keyed by it. Up to 64 characters.
fields[].typeenumWhat kind of answer the field takes. One of heading, checkbox, text, textarea, number, select, multiselect, date, photo, signature.
fields[].labelstringUp to 200 characters.
fields[].requiredbooleanA required field must be answered before the job can be completed. Default false.
fields[].helpstring or nullHelp text shown under the field. Up to 500 characters.
fields[].optionsarray of stringChoices for select and multiselect fields. Up to 50 items.
fields[].minnumber or nullSmallest allowed value (number fields).
fields[].maxnumber or nullLargest allowed value (number fields).
fields[].unitstring or nullUnit shown after a number, e.g. psi. Up to 20 characters.
serviceTypeIdsarray of string
createdAtstring (date-time)
updatedAtstring (date-time)
jobFormCountinteger

Delete a job form template

DELETE /organizations/{organizationId}/form-templates/{templateId}

Destructive: deletes the template; forms already filled in on jobs keep their copy. Prefer active: false to stop attaching it.

Permissionforms.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 toolformTemplates_delete (toolset settings)
ApprovalOver MCP, this tool always waits for your approval in ServFlo. See Approvals.

Parameters

NameInTypeRequiredDescription
templateIdpathstringYes

Example

curl -X DELETE "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/form-templates/{templateId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
oktrue

On this page