DevelopersAPI reference

Jobs API

REST endpoints for jobs in ServFlo: 16 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 jobsGET /organizations/{organizationId}/jobsread
Create a jobPOST /organizations/{organizationId}/jobswrite
Get a job with notes, checklist, materials and invoicesGET /organizations/{organizationId}/jobs/{jobId}read
Update a jobPATCH /organizations/{organizationId}/jobs/{jobId}write
Delete a jobDELETE /organizations/{organizationId}/jobs/{jobId}sensitive
Set a job's status or completion notes (field work)POST /organizations/{organizationId}/jobs/{jobId}/statuswrite
Assign a job to a technicianPOST /organizations/{organizationId}/jobs/{jobId}/assignwrite
Jobs between two dates, for the calendarGET /organizations/{organizationId}/scheduleread
Add a note to a jobPOST /organizations/{organizationId}/jobs/{jobId}/noteswrite
Delete a job noteDELETE /organizations/{organizationId}/jobs/{jobId}/notes/{noteId}sensitive
Add a checklist itemPOST /organizations/{organizationId}/jobs/{jobId}/checklistwrite
Tick, untick or rename a checklist itemPATCH /organizations/{organizationId}/jobs/{jobId}/checklist/{itemId}write
Delete a checklist itemDELETE /organizations/{organizationId}/jobs/{jobId}/checklist/{itemId}sensitive
Record material used on a jobPOST /organizations/{organizationId}/jobs/{jobId}/materialswrite
Remove material usedDELETE /organizations/{organizationId}/jobs/{jobId}/materials/{lineId}sensitive
Draft an invoice from a jobPOST /organizations/{organizationId}/jobs/{jobId}/invoicewrite

List jobs

GET /organizations/{organizationId}/jobs

Jobs, by scheduled date, filtered by text, status, date, technician (the lead or anyone on a visit's crew), customer or property, paged with limit/offset and a total. Each job carries its field status times (onMyWayAt, arrivedAt, startedAt, completedAt). A job's date, time, technician and status are its next open visit's. A technician sees only the jobs they are on a visit's crew of. Read-only. Use GET /schedule for a date range on the calendar.

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 tooljobs_list (toolset scheduling, in the default set)

Parameters

NameInTypeRequiredDescription
queryquerystringNoFree-text search over the list's names, numbers and contact details. Up to 200 characters.
statusqueryenumNoOne of SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED.
datequerystringNoOnly jobs scheduled on this day.
technicianIdquerystringNo
customerIdquerystringNo
propertyIdquerystringNo
businessUnitIdquerystringNoOnly this business unit (GET /business-units), or "none" for records without one. Up to 100 characters.
includeMarginqueryboolean or enumNoAdd each job's margin (revenue, cost, gross profit, margin %) for roles with costing.read; ignored otherwise.
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/jobs" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields
FieldTypeDescription
itemsarray of object
items[].idstringJob id.
items[].organizationIdstring
items[].identifierstringJOB-n, unique per organization.
items[].customerIdstring
items[].propertyIdstring or null
items[].assetIdstring or nullThe equipment worked on.
items[].technicianIdstring or nullThe lead technician of the next open visit.
items[].serviceTypeIdstring or null
items[].statusenumSCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED or CANCELLED. A job's status is its next open visit's. One of SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED.
items[].priorityenumOne of LOW, NORMAL, HIGH, URGENT.
items[].scheduledDatestringThe next open visit's day, YYYY-MM-DD.
items[].scheduledTimestring or nullHh: MM
items[].durationMinutesinteger
items[].priceCentsintegerJob price before tax, in integer cents.
items[].addressstring or null
items[].notesstring or null
items[].completionNotesstring or nullWhat was done.
items[].recurrenceIntervalenum or nullOne of WEEKLY, BIWEEKLY, MONTHLY, QUARTERLY, YEARLY.
items[].recurrenceParentIdstring or null
items[].onMyWayAtstring (date-time) or null
items[].arrivedAtstring (date-time) or null
items[].startedAtstring (date-time) or null
items[].completedAtstring (date-time) or null
items[].signedBystring or nullWho signed the work off on site.
items[].signedAtstring (date-time) or null
items[].businessUnitIdstring or null
items[].customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=JOB).
items[].weatherSensitiveboolean or nullPlans around the weather: overrides the service type; null follows it.
items[].createdAtstring (date-time)
items[].updatedAtstring (date-time)
items[].customerobject
items[].customer.idstringCustomer id.
items[].customer.namestring
items[].customer.phonestring or null
items[].technicianobject or null
items[].technician.idstringTechnician id (GET /technicians).
items[].technician.namestring
items[].technician.colorstringCalendar colour, #rrggbb.
items[].serviceTypeobject or null
items[].serviceType.idstring
items[].serviceType.namestring
items[].serviceType.colorstring
items[].businessUnitobject or nullThe business unit.
items[].businessUnit.idstring
items[].businessUnit.namestring
items[].assetobject or null
items[].asset.idstring
items[].asset.namestring
items[].asset.serialNumberstring
items[].propertyobject or null
items[].property.idstringProperty id.
items[].property.namestring or null
items[].property.addressstring or null
items[].property.citystring or null
items[].property.taxRatenumber or null
items[].nextJobIdstring or nullAfter an update: the next occurrence booked when a recurring job completed.
items[].marginobject or nullWith includeMargin and costing.read only: the job's margin.
items[].margin.revenueCentsinteger
items[].margin.totalCostCentsinteger
items[].margin.grossProfitCentsinteger
items[].margin.marginPercentnumber or null
totalintegerHow many match the filters, across all pages.

Create a job

POST /organizations/{organizationId}/jobs

Books a job (JOB-n) for a customer. Address defaults to the equipment's property, then the customer's address; duration and price default to the service type's. With requestId, that request becomes CONVERTED and points at the job. Nothing is sent to the customer. Call GET /customers, /service-types and /technicians/options first for the ids.

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

Request body

FieldTypeRequiredDescription
customerIdstringYesThe customer the job is for. Find one with GET /customers.
customFieldsobjectNoJob custom field values (GET /custom-fields?entity=JOB); required ones are checked when the job is created here.
propertyIdstring or nullNoWhere the work is: one of the customer's properties. Defaults from the equipment.
assetIdstring or nullNoEquipment worked on; must belong to the job's customer.
technicianIdstring or nullNoAssigned technician (GET /technicians/options).
serviceTypeIdstring or nullNoService type (GET /service-types); its duration and price are the defaults.
statusenumNoOne of SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED.
priorityenumNoOne of LOW, NORMAL, HIGH, URGENT.
scheduledDatestringYesA calendar date in the business's own calendar, YYYY-MM-DD.
scheduledTimestring or nullNoA local time of day, HH:MM (24-hour). Blank means 09:00 on new jobs.
durationMinutesintegerNoMinutes; 0 or omitted takes the service type's default. -100000–100000.
priceCentsintegerNoPrice in cents; 0 or omitted takes the service type's. -100000000–100000000.
addressstring or nullNoDefaults to the equipment's property, then the customer's address.
notesstring or nullNo
completionNotesstring or nullNoWhat was done; shown on the job and in the equipment history.
recurrenceIntervalenum or nullNoRepeat the job: completing it books the next occurrence once. One of WEEKLY, BIWEEKLY, MONTHLY, QUARTERLY, YEARLY.
businessUnitIdstring or nullNoBusiness unit (GET /business-units); null = none. Omitted on create: the default (service type, then technician). Up to 100 characters.
weatherSensitiveboolean or nullNoPlans around the weather: true or false override the service type's setting; null follows it.
requestIdstring or nullNoBooked from this request: it becomes CONVERTED and points at the job.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customerId":"customer_id","scheduledDate":"2026-11-03"}'

Response

201: the answer's fields
FieldTypeDescription
idstringJob id.
organizationIdstring
identifierstringJOB-n, unique per organization.
customerIdstring
propertyIdstring or null
assetIdstring or nullThe equipment worked on.
technicianIdstring or nullThe lead technician of the next open visit.
serviceTypeIdstring or null
statusenumSCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED or CANCELLED. A job's status is its next open visit's. One of SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED.
priorityenumOne of LOW, NORMAL, HIGH, URGENT.
scheduledDatestringThe next open visit's day, YYYY-MM-DD.
scheduledTimestring or nullHh: MM
durationMinutesinteger
priceCentsintegerJob price before tax, in integer cents.
addressstring or null
notesstring or null
completionNotesstring or nullWhat was done.
recurrenceIntervalenum or nullOne of WEEKLY, BIWEEKLY, MONTHLY, QUARTERLY, YEARLY.
recurrenceParentIdstring or null
onMyWayAtstring (date-time) or null
arrivedAtstring (date-time) or null
startedAtstring (date-time) or null
completedAtstring (date-time) or null
signedBystring or nullWho signed the work off on site.
signedAtstring (date-time) or null
businessUnitIdstring or null
customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=JOB).
weatherSensitiveboolean or nullPlans around the weather: overrides the service type; null follows it.
createdAtstring (date-time)
updatedAtstring (date-time)
customerobject
customer.idstringCustomer id.
customer.namestring
customer.phonestring or null
technicianobject or null
technician.idstringTechnician id (GET /technicians).
technician.namestring
technician.colorstringCalendar colour, #rrggbb.
serviceTypeobject or null
serviceType.idstring
serviceType.namestring
serviceType.colorstring
businessUnitobject or nullThe business unit.
businessUnit.idstring
businessUnit.namestring
assetobject or null
asset.idstring
asset.namestring
asset.serialNumberstring
propertyobject or null
property.idstringProperty id.
property.namestring or null
property.addressstring or null
property.citystring or null
property.taxRatenumber or null
nextJobIdstring or nullAfter an update: the next occurrence booked when a recurring job completed.

Get a job with notes, checklist, materials and invoices

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

One job with its customer, property (with access notes and hazards), equipment, technician, notes, checklist, materials used, invoices, forms (with answers and what is still missing), field status times, the customer's sign-off (signedBy, signedAt) and photoCount. A technician gets 404 for a job not assigned to them. Read-only. Get job ids from GET /jobs or GET /schedule.

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 tooljobs_get (toolset scheduling, in the default set)

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Example

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

Response

200: the answer's fields
FieldTypeDescription
idstringJob id.
organizationIdstring
identifierstringJOB-n, unique per organization.
customerIdstring
propertyIdstring or null
assetIdstring or nullThe equipment worked on.
technicianIdstring or nullThe lead technician of the next open visit.
serviceTypeIdstring or null
statusenumSCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED or CANCELLED. A job's status is its next open visit's. One of SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED.
priorityenumOne of LOW, NORMAL, HIGH, URGENT.
scheduledDatestringThe next open visit's day, YYYY-MM-DD.
scheduledTimestring or nullHh: MM
durationMinutesinteger
priceCentsintegerJob price before tax, in integer cents.
addressstring or null
notesstring or null
completionNotesstring or nullWhat was done.
recurrenceIntervalenum or nullOne of WEEKLY, BIWEEKLY, MONTHLY, QUARTERLY, YEARLY.
recurrenceParentIdstring or null
onMyWayAtstring (date-time) or null
arrivedAtstring (date-time) or null
startedAtstring (date-time) or null
completedAtstring (date-time) or null
signedBystring or nullWho signed the work off on site.
signedAtstring (date-time) or null
businessUnitIdstring or null
customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=JOB).
weatherSensitiveboolean or nullPlans around the weather: overrides the service type; null follows it.
createdAtstring (date-time)
updatedAtstring (date-time)
customerobject
customer.idstringCustomer id.
customer.namestring
customer.phonestring or null
technicianobject or null
technician.idstringTechnician id (GET /technicians).
technician.namestring
technician.colorstringCalendar colour, #rrggbb.
serviceTypeobject or null
serviceType.idstring
serviceType.namestring
serviceType.colorstring
businessUnitobject or nullThe business unit.
businessUnit.idstring
businessUnit.namestring
assetobject or null
asset.idstring
asset.namestring
asset.serialNumberstring
propertyobject or null
property.idstringProperty id.
property.namestring or null
property.addressstring or null
property.citystring or null
property.taxRatenumber or null
property.gateCodestring or null
property.accessInstructionsstring or null
property.safetyNotesstring or null
property.petsOnSiteboolean
property.petNotesstring or null
property.contactNamestring or null
property.contactPhonestring or null
property.latitudenumber or null
property.longitudenumber or null
nextJobIdstring or nullAfter an update: the next occurrence booked when a recurring job completed.
notesLogarray of objectInternal notes, newest first.
notesLog[].idstringJob note id.
notesLog[].jobIdstring
notesLog[].contentstring
notesLog[].authorUserIdstring or null
notesLog[].createdAtstring (date-time)
checklistarray of object
checklist[].idstringChecklist item id.
checklist[].jobIdstring
checklist[].labelstring
checklist[].checkedboolean
checklist[].sortOrderinteger
materialsarray of object
materials[].idstringMaterial line id.
materials[].jobIdstring
materials[].materialIdstring or null
materials[].pricebookItemIdstring or null
materials[].descriptionstring or null
materials[].unitstring or null
materials[].quantitynumber
materials[].unitCostCentsintegerThe unit PRICE billed for this line (the original API's name), in integer cents.
materials[].costCentsinteger or nullOur unit cost in cents (costing.read only).
materials[].locationIdstring or nullThe stock location it was drawn from.
materials[].createdAtstring (date-time)
materials[].materialobjectThe original API's material shape; id null for a pricebook-only line.
materials[].material.idstring or null
materials[].material.namestring
materials[].material.unitstring
materials[].pricebookItemobject or null
materials[].pricebookItem.idstring
materials[].pricebookItem.codestring or null
materials[].pricebookItem.kindenumOne of SERVICE, MATERIAL, EQUIPMENT, FEE.
materials[].locationobject or null
materials[].location.idstring
materials[].location.namestring
materials[].location.kindenumOne of WAREHOUSE, TRUCK.
invoicesarray of objectInvoices for the job (INV-n).
invoices[].idstring
invoices[].identifierstringINV-n
invoices[].statusenumDRAFT (not issued), SENT (issued, money due), PAID, OVERDUE (past dueDate) or CANCELLED. One of DRAFT, SENT, PAID, OVERDUE, CANCELLED.
invoices[].totalCentsinteger
quotesarray of objectQuotes the job came from (Q-n).
quotes[].idstring
quotes[].identifierstringQ-n
quotes[].statusenumDRAFT → SENT (customer can answer at /q/{publicToken}) → APPROVED / CHANGES_REQUESTED / DECLINED; APPROVED → CONVERTED (job or invoice made). SENT past validUntil becomes EXPIRED. One of DRAFT, SENT, APPROVED, CHANGES_REQUESTED, DECLINED, CONVERTED, EXPIRED, ARCHIVED.
requestsarray of object
requests[].idstring
requests[].identifierstring
assessmentRequestsarray of object
assessmentRequests[].idstring
assessmentRequests[].identifierstring
visitsarray of objectThe job's visits in order.
visits[].idstringVisit id (for /jobs/{jobId}/visits/{visitId}/…).
visits[].jobIdstring
visits[].scheduledDatestring or nullYYYY-MM-DD; null = not scheduled yet.
visits[].scheduledTimestring or nullHh: MM
visits[].durationMinutesinteger
visits[].statusenumSCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED or CANCELLED. A job's status is its next open visit's. One of SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED.
visits[].notesstring or null
visits[].sortOrderinteger
visits[].routeOrderinteger or null
visits[].onMyWayAtstring (date-time) or null
visits[].trackingTokenstring or nullThe customer's tracking link token (/t/{token}), made on On my way.
visits[].arrivedAtstring (date-time) or null
visits[].startedAtstring (date-time) or null
visits[].completedAtstring (date-time) or null
visits[].createdAtstring (date-time)
visits[].updatedAtstring (date-time)
visits[].crewarray of objectTechnicians on the visit, lead first.
visits[].crew[].technicianIdstring
visits[].crew[].isLeadboolean
visits[].crew[].namestring
visits[].crew[].colorstring
formsanyThe job's forms with their fields, answers, status and missing required fields (as GET /jobs/{jobId}/forms).
photoCountinteger
membershipobject or nullThe Member badge: the customer's membership that covers the job.
membership.membershipIdstring
membership.identifierstringMEM-n
membership.planNamestring
membership.prioritybooleanThe plan flags its members' work as priority on the board.
membership.dueMonthstring or nullYYYY-MM when the job is an included member visit; null for other work for a member.
membership.dueDatestring or nullYYYY-MM-DD when the member visit is on a week cadence (every N weeks); null for month-based visits.

Update a job

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

Changes any job field (only those sent): reschedule, re-price, change customer, equipment or status. Date, time, duration, technician and status apply to the visit the job mirrors (its next open visit); COMPLETED closes the job (its other open visits are cancelled) and CANCELLED cancels every open visit. Completing a recurring job books its next occurrence once; nextJobId names it. Field staff use POST /jobs/{jobId}/status and dispatchers POST /jobs/{jobId}/assign for the narrower changes.

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

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Request body

FieldTypeRequiredDescription
customerIdstringNoThe customer the job is for. Find one with GET /customers.
customFieldsobjectNoJob custom field values (GET /custom-fields?entity=JOB); required ones are checked when the job is created here.
propertyIdstring or nullNoWhere the work is: one of the customer's properties. Defaults from the equipment.
assetIdstring or nullNoEquipment worked on; must belong to the job's customer.
technicianIdstring or nullNoAssigned technician (GET /technicians/options).
serviceTypeIdstring or nullNoService type (GET /service-types); its duration and price are the defaults.
statusenumNoOne of SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED.
priorityenumNoOne of LOW, NORMAL, HIGH, URGENT.
scheduledDatestringNoA calendar date in the business's own calendar, YYYY-MM-DD.
scheduledTimestring or nullNoA local time of day, HH:MM (24-hour). Blank means 09:00 on new jobs.
durationMinutesintegerNoMinutes; 0 or omitted takes the service type's default. -100000–100000.
priceCentsintegerNoPrice in cents; 0 or omitted takes the service type's. -100000000–100000000.
addressstring or nullNoDefaults to the equipment's property, then the customer's address.
notesstring or nullNo
completionNotesstring or nullNoWhat was done; shown on the job and in the equipment history.
recurrenceIntervalenum or nullNoRepeat the job: completing it books the next occurrence once. One of WEEKLY, BIWEEKLY, MONTHLY, QUARTERLY, YEARLY.
businessUnitIdstring or nullNoBusiness unit (GET /business-units); null = none. Omitted on create: the default (service type, then technician). Up to 100 characters.
weatherSensitiveboolean or nullNoPlans around the weather: true or false override the service type's setting; null follows it.

Example

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

Response

200: the answer's fields
FieldTypeDescription
idstringJob id.
organizationIdstring
identifierstringJOB-n, unique per organization.
customerIdstring
propertyIdstring or null
assetIdstring or nullThe equipment worked on.
technicianIdstring or nullThe lead technician of the next open visit.
serviceTypeIdstring or null
statusenumSCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED or CANCELLED. A job's status is its next open visit's. One of SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED.
priorityenumOne of LOW, NORMAL, HIGH, URGENT.
scheduledDatestringThe next open visit's day, YYYY-MM-DD.
scheduledTimestring or nullHh: MM
durationMinutesinteger
priceCentsintegerJob price before tax, in integer cents.
addressstring or null
notesstring or null
completionNotesstring or nullWhat was done.
recurrenceIntervalenum or nullOne of WEEKLY, BIWEEKLY, MONTHLY, QUARTERLY, YEARLY.
recurrenceParentIdstring or null
onMyWayAtstring (date-time) or null
arrivedAtstring (date-time) or null
startedAtstring (date-time) or null
completedAtstring (date-time) or null
signedBystring or nullWho signed the work off on site.
signedAtstring (date-time) or null
businessUnitIdstring or null
customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=JOB).
weatherSensitiveboolean or nullPlans around the weather: overrides the service type; null follows it.
createdAtstring (date-time)
updatedAtstring (date-time)
customerobject
customer.idstringCustomer id.
customer.namestring
customer.phonestring or null
technicianobject or null
technician.idstringTechnician id (GET /technicians).
technician.namestring
technician.colorstringCalendar colour, #rrggbb.
serviceTypeobject or null
serviceType.idstring
serviceType.namestring
serviceType.colorstring
businessUnitobject or nullThe business unit.
businessUnit.idstring
businessUnit.namestring
assetobject or null
asset.idstring
asset.namestring
asset.serialNumberstring
propertyobject or null
property.idstringProperty id.
property.namestring or null
property.addressstring or null
property.citystring or null
property.taxRatenumber or null
nextJobIdstring or nullAfter an update: the next occurrence booked when a recurring job completed.

Delete a job

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

Destructive: deletes the job with its notes, checklist and materials; invoices made from it stay, unlinked. Its equipment history keeps a 'job deleted' entry. Cannot be undone; to stop a visit without losing it, set its status to CANCELLED instead.

Permissionjobs.delete (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 tooljobs_delete (toolset scheduling)
ApprovalOver MCP, this tool always waits for your approval in ServFlo. See Approvals.

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Example

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

Response

200: the answer's fields
FieldTypeDescription
oktrue

Set a job's status or completion notes (field work)

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

The field technician's update: move the job to SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED or CANCELLED (any to any) and/or save completion notes. IN_PROGRESS stamps startedAt and starts the technician's job clock (stopping travel); COMPLETED is refused (400) while a form on the job lacks required answers, stamps completedAt, stops the job clock and books a recurring job's next occurrence once (nextJobId). Technicians may only change their own jobs (404 otherwise). Equipment history records the change. Nothing is sent to the customer. POST …/start and …/complete are the same with a clearer name.

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

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Request body

FieldTypeRequiredDescription
statusenumNoOne of SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED.
completionNotesstring or nullNoWhat was done; shown on the job and in the equipment history.

Example

curl -X POST "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/status" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"SCHEDULED","completionNotes":"string"}'

Response

200: the answer's fields
FieldTypeDescription
idstringJob id.
organizationIdstring
identifierstringJOB-n, unique per organization.
customerIdstring
propertyIdstring or null
assetIdstring or nullThe equipment worked on.
technicianIdstring or nullThe lead technician of the next open visit.
serviceTypeIdstring or null
statusenumSCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED or CANCELLED. A job's status is its next open visit's. One of SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED.
priorityenumOne of LOW, NORMAL, HIGH, URGENT.
scheduledDatestringThe next open visit's day, YYYY-MM-DD.
scheduledTimestring or nullHh: MM
durationMinutesinteger
priceCentsintegerJob price before tax, in integer cents.
addressstring or null
notesstring or null
completionNotesstring or nullWhat was done.
recurrenceIntervalenum or nullOne of WEEKLY, BIWEEKLY, MONTHLY, QUARTERLY, YEARLY.
recurrenceParentIdstring or null
onMyWayAtstring (date-time) or null
arrivedAtstring (date-time) or null
startedAtstring (date-time) or null
completedAtstring (date-time) or null
signedBystring or nullWho signed the work off on site.
signedAtstring (date-time) or null
businessUnitIdstring or null
customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=JOB).
weatherSensitiveboolean or nullPlans around the weather: overrides the service type; null follows it.
createdAtstring (date-time)
updatedAtstring (date-time)
customerobject
customer.idstringCustomer id.
customer.namestring
customer.phonestring or null
technicianobject or null
technician.idstringTechnician id (GET /technicians).
technician.namestring
technician.colorstringCalendar colour, #rrggbb.
serviceTypeobject or null
serviceType.idstring
serviceType.namestring
serviceType.colorstring
businessUnitobject or nullThe business unit.
businessUnit.idstring
businessUnit.namestring
assetobject or null
asset.idstring
asset.namestring
asset.serialNumberstring
propertyobject or null
property.idstringProperty id.
property.namestring or null
property.addressstring or null
property.citystring or null
property.taxRatenumber or null
nextJobIdstring or nullAfter an update: the next occurrence booked when a recurring job completed.

Assign a job to a technician

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

Sets the job's technician, or clears it with technicianId: null: the visit the job mirrors (its next open visit) gets that technician as its lead, or no crew. For crews and other visits use PUT /jobs/{jobId}/visits/{visitId}/crew. Get technician ids from GET /technicians/options. Nothing is sent to anyone.

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

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Request body

FieldTypeRequiredDescription
technicianIdstring or nullYesThe technician, or null to unassign.

Example

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

Response

200: the answer's fields
FieldTypeDescription
idstringJob id.
organizationIdstring
identifierstringJOB-n, unique per organization.
customerIdstring
propertyIdstring or null
assetIdstring or nullThe equipment worked on.
technicianIdstring or nullThe lead technician of the next open visit.
serviceTypeIdstring or null
statusenumSCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED or CANCELLED. A job's status is its next open visit's. One of SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED.
priorityenumOne of LOW, NORMAL, HIGH, URGENT.
scheduledDatestringThe next open visit's day, YYYY-MM-DD.
scheduledTimestring or nullHh: MM
durationMinutesinteger
priceCentsintegerJob price before tax, in integer cents.
addressstring or null
notesstring or null
completionNotesstring or nullWhat was done.
recurrenceIntervalenum or nullOne of WEEKLY, BIWEEKLY, MONTHLY, QUARTERLY, YEARLY.
recurrenceParentIdstring or null
onMyWayAtstring (date-time) or null
arrivedAtstring (date-time) or null
startedAtstring (date-time) or null
completedAtstring (date-time) or null
signedBystring or nullWho signed the work off on site.
signedAtstring (date-time) or null
businessUnitIdstring or null
customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=JOB).
weatherSensitiveboolean or nullPlans around the weather: overrides the service type; null follows it.
createdAtstring (date-time)
updatedAtstring (date-time)
customerobject
customer.idstringCustomer id.
customer.namestring
customer.phonestring or null
technicianobject or null
technician.idstringTechnician id (GET /technicians).
technician.namestring
technician.colorstringCalendar colour, #rrggbb.
serviceTypeobject or null
serviceType.idstring
serviceType.namestring
serviceType.colorstring
businessUnitobject or nullThe business unit.
businessUnit.idstring
businessUnit.namestring
assetobject or null
asset.idstring
asset.namestring
asset.serialNumberstring
propertyobject or null
property.idstringProperty id.
property.namestring or null
property.addressstring or null
property.citystring or null
property.taxRatenumber or null
nextJobIdstring or nullAfter an update: the next occurrence booked when a recurring job completed.

Jobs between two dates, for the calendar

GET /organizations/{organizationId}/schedule

Every VISIT scheduled from start to end (inclusive, YYYY-MM-DD), ordered by date and time, shaped like a job (id is the job's) with the visit's date, time, duration, status and field times, plus visitId, crew, visitNumber/visitCount, routeOrder and the job's own jobStatus. technicianId filters to visits whose crew includes that technician; a technician sees only the visits they are on. Read-only.

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

Parameters

NameInTypeRequiredDescription
startquerystringYesFirst day, YYYY-MM-DD.
endquerystringYesLast day (inclusive), YYYY-MM-DD.
technicianIdquerystringNo
businessUnitIdquerystringNoOnly visits of jobs in this business unit.

Example

curl "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/schedule?start=2026-11-03&end=2026-11-03" \
  -H "Authorization: Bearer $SERVFLO_API_KEY"

Response

200: the answer's fields

An array of objects:

FieldTypeDescription
idstringJob id.
organizationIdstring
identifierstringJOB-n, unique per organization.
customerIdstring
propertyIdstring or null
assetIdstring or nullThe equipment worked on.
technicianIdstring or nullThe lead technician of the next open visit.
serviceTypeIdstring or null
statusenumThe visit's status. One of SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED.
priorityenumOne of LOW, NORMAL, HIGH, URGENT.
scheduledDatestringThe next open visit's day, YYYY-MM-DD.
scheduledTimestring or nullHh: MM
durationMinutesinteger
priceCentsintegerJob price before tax, in integer cents.
addressstring or null
notesstring or null
completionNotesstring or nullWhat was done.
recurrenceIntervalenum or nullOne of WEEKLY, BIWEEKLY, MONTHLY, QUARTERLY, YEARLY.
recurrenceParentIdstring or null
onMyWayAtstring (date-time) or null
arrivedAtstring (date-time) or null
startedAtstring (date-time) or null
completedAtstring (date-time) or null
signedBystring or nullWho signed the work off on site.
signedAtstring (date-time) or null
businessUnitIdstring or null
customFieldsanyCustom field values by key (definitions: GET /custom-fields?entity=JOB).
weatherSensitiveboolean or nullPlans around the weather: overrides the service type; null follows it.
createdAtstring (date-time)
updatedAtstring (date-time)
customerobject
customer.idstringCustomer id.
customer.namestring
customer.phonestring or null
technicianobject or null
technician.idstringTechnician id (GET /technicians).
technician.namestring
technician.colorstringCalendar colour, #rrggbb.
serviceTypeobject or null
serviceType.idstring
serviceType.namestring
serviceType.colorstring
businessUnitobject or nullThe business unit.
businessUnit.idstring
businessUnit.namestring
assetobject or null
asset.idstring
asset.namestring
asset.serialNumberstring
propertyobject or null
property.idstringProperty id.
property.namestring or null
property.addressstring or null
property.citystring or null
property.taxRatenumber or null
nextJobIdstring or nullAfter an update: the next occurrence booked when a recurring job completed.
jobStatusenumThe job's rolled-up status. One of SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED.
visitIdstringThe visit (PATCH /visits/{visitId}).
visitNumberinteger1-based position of the visit in the job.
visitCountinteger
routeOrderinteger or null
visitNotesstring or null
crewarray of objectTechnicians on the visit, lead first.
crew[].technicianIdstring
crew[].isLeadboolean
crew[].namestring
crew[].colorstring

Add a note to a job

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

Adds an internal note, authored by the caller; also written to the equipment's history. Never shown to the customer. Returns the note.

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

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Request body

FieldTypeRequiredDescription
contentstringYesThe note text (internal).

Example

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

Response

201: the answer's fields
FieldTypeDescription
idstringJob note id.
jobIdstring
contentstring
authorUserIdstring or null
createdAtstring (date-time)

Delete a job note

DELETE /organizations/{organizationId}/jobs/{jobId}/notes/{noteId}

Destructive: deletes the note. The equipment history keeps a record that a note existed. Note ids come from GET /jobs/{jobId}.

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

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes
noteIdpathstringYes

Example

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

Response

200: the answer's fields
FieldTypeDescription
oktrue

Add a checklist item

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

Adds an unticked item to the end of the job's checklist. Returns the item.

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

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Request body

FieldTypeRequiredDescription
labelstringYesWhat to check or do.

Example

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

Response

201: the answer's fields
FieldTypeDescription
idstringChecklist item id.
jobIdstring
labelstring
checkedboolean
sortOrderinteger

Tick, untick or rename a checklist item

PATCH /organizations/{organizationId}/jobs/{jobId}/checklist/{itemId}

Send checked to tick or untick, label to rename; with neither, the item toggles (the original API's PUT). Item ids come from GET /jobs/{jobId}.

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

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes
itemIdpathstringYes

Request body

FieldTypeRequiredDescription
labelstringNo
checkedbooleanNo

Example

curl -X PATCH "https://app.servflo.ai/api/organizations/$ORGANIZATION_ID/jobs/{jobId}/checklist/{itemId}" \
  -H "Authorization: Bearer $SERVFLO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"label":"string","checked":true}'

Response

200: the answer's fields
FieldTypeDescription
idstringChecklist item id.
jobIdstring
labelstring
checkedboolean
sortOrderinteger

Delete a checklist item

DELETE /organizations/{organizationId}/jobs/{jobId}/checklist/{itemId}

Destructive: removes the item from the job's checklist.

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

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes
itemIdpathstringYes

Example

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

Response

200: the answer's fields
FieldTypeDescription
oktrue

Record material used on a job

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

Adds a material line to the job, by pricebook item (pricebookItemId, GET /pricebook/items) or original material (materialId, GET /materials). The line snapshots the item's name, unit, price (unitCostCents, the unit price billed: the original API's name) and cost, frozen on the job; a negative quantity records a return. STOCK: a MATERIAL or EQUIPMENT item is drawn from the truck of the job's technician, else the default warehouse (negative stock is allowed and flagged in stock.negative). Invoicing the job (POST /jobs/{jobId}/invoice) bills these lines.

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

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Request body

FieldTypeRequiredDescription
materialIdstring or nullNoFrom GET /materials (or name a pricebook item).
pricebookItemIdstring or nullNoFrom GET /pricebook/items (or name an original material).
quantitynumberYesQuantity; may be fractional, negative for returned material, never 0. -1000000–1000000.
unitCostCentsintegerNoThe unit PRICE billed for this line; defaults to the item's price. Ignored for technicians, who bill at the pricebook's price. -100000000–100000000.

Example

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

Response

201: the answer's fields
FieldTypeDescription
idstringMaterial line id.
jobIdstring
materialIdstring or null
pricebookItemIdstring or null
descriptionstring or null
unitstring or null
quantitynumber
unitCostCentsintegerThe unit PRICE billed for this line (the original API's name), in integer cents.
costCentsinteger or nullOur unit cost in cents (costing.read only).
locationIdstring or nullThe stock location it was drawn from.
createdAtstring (date-time)
materialobjectThe original API's material shape; id null for a pricebook-only line.
material.idstring or null
material.namestring
material.unitstring
pricebookItemobject or null
pricebookItem.idstring
pricebookItem.codestring or null
pricebookItem.kindenumOne of SERVICE, MATERIAL, EQUIPMENT, FEE.
locationobject or null
location.idstring
location.namestring
location.kindenumOne of WAREHOUSE, TRUCK.
stockobject or nullThe stock drawn for a stocked item; null when nothing was drawn.
stock.locationIdstring or null
stock.locationNamestring or null
stock.onHandnumber
stock.negativebooleanThe location's stock went below zero.

Remove material used

DELETE /organizations/{organizationId}/jobs/{jobId}/materials/{lineId}

Destructive: removes a material line from the job and puts what it used back where it was drawn from (a RETURN movement). Invoices already made from the job keep their lines.

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

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes
lineIdpathstringYes

Example

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

Response

200: the answer's fields
FieldTypeDescription
oktrue

Draft an invoice from a job

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

Creates a DRAFT invoice (INV-n): one line for the service at the job's price and one per material used; deposits on the quote the job came from move onto it. Nothing is sent; share it with POST /invoices/{invoiceId}/link. Returns the invoice.

Permission: invoices.write (Owner, Admin, Dispatcher, Technician (own jobs' invoices)); risk write (OAuth scope servflo.write).

Permissioninvoices.write
Riskwrite, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.
MCP tooljobs_createInvoice (toolset scheduling, in the default set)

Parameters

NameInTypeRequiredDescription
jobIdpathstringYes

Example

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

Response

201: the answer's fields

A value of type any.

On this page