REST endpoints for change orders 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 .
GET /organizations/{organizationId}/change-orders
Change orders, newest first, of a project (projectId) or all, optionally by status (DRAFT, SENT, APPROVED, DECLINED). Read-only.
Permission projects.read (Owner, Admin, Dispatcher, Technician, Member)Risk read, OAuth scope servflo.read. Read: reads only.MCP tool changeOrders_list (toolset projects)
Name In Type Required Description projectIdquery string No statusquery enum No One of DRAFT, SENT, APPROVED, DECLINED. limitquery integer No Page size, 1–200. Default 50. offsetquery integer No Rows to skip; the answer's total counts every match. Default 0.
curl "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /change-orders" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description itemsarray of object items[].idstring items[].projectIdstring items[].labelstring CO-n within the project. items[].titlestring items[].statusenum One of DRAFT, SENT, APPROVED, DECLINED. items[].priceChangeCentsinteger Before tax; negative for a credit. items[].scheduleDaysinteger items[].linesarray of object items[].lines[].descriptionstring items[].lines[].quantitynumber items[].lines[].unitPriceCentsinteger items[].urlstring The customer's page to approve it (/co/{token}); works once SENT. totalinteger
GET /organizations/{organizationId}/change-orders/{changeOrderId}
A change order with its lines, status, the customer's decision and its approval link. Read-only.
Permission projects.read (Owner, Admin, Dispatcher, Technician, Member)Risk read, OAuth scope servflo.read. Read: reads only.MCP tool changeOrders_get (toolset projects)
Name In Type Required Description changeOrderIdpath string Yes
curl "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /change-orders/{changeOrderId}" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description idstring projectIdstring labelstring CO-n within the project. titlestring statusenum One of DRAFT, SENT, APPROVED, DECLINED. priceChangeCentsinteger Before tax; negative for a credit. scheduleDaysinteger linesarray of object lines[].descriptionstring lines[].quantitynumber lines[].unitPriceCentsinteger urlstring The customer's page to approve it (/co/{token}); works once SENT.
PATCH /organizations/{organizationId}/change-orders/{changeOrderId}
Changes a DRAFT (its title, description, schedule days or all its lines). 409 once sent; reopen it first.
Permission projects.field (Owner, Admin, Dispatcher, Technician)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool changeOrders_update (toolset projects)
Name In Type Required Description changeOrderIdpath string Yes
Field Type Required Description titlestring No Up to 200 characters. descriptionstring or null No Up to 5000 characters. scheduleDaysinteger No -365–365. linesarray of object No Up to 100 items. lines[].descriptionstring Yes Up to 500 characters. lines[].quantitynumber Yes -1000000–1000000. lines[].unitPriceCentsinteger Yes Price to the customer per unit; negative for a credit. -100000000–100000000. lines[].costCentsinteger or null No Our unit cost (goes to the budget when approved). -100000000–100000000. lines[].costCategoryenum or null No Budget bucket: LABOR, MATERIALS, SUBCONTRACTORS, EQUIPMENT or OTHER. One of LABOR, MATERIALS, SUBCONTRACTORS, EQUIPMENT, OTHER. lines[].pricebookItemIdstring or null No Picked from the pricebook (GET /pricebook/items).
curl -X PATCH "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /change-orders/{changeOrderId}" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"title":"string","description":"string","scheduleDays":1}'
200: the answer's fields Field Type Description idstring projectIdstring labelstring CO-n within the project. titlestring statusenum One of DRAFT, SENT, APPROVED, DECLINED. priceChangeCentsinteger Before tax; negative for a credit. scheduleDaysinteger linesarray of object lines[].descriptionstring lines[].quantitynumber lines[].unitPriceCentsinteger urlstring The customer's page to approve it (/co/{token}); works once SENT.
DELETE /organizations/{organizationId}/change-orders/{changeOrderId}
Destructive: deletes a DRAFT or DECLINED change order. An approved one is part of the contract (write a new one to undo it).
Permission projects.field (Owner, Admin, Dispatcher, Technician)Risk sensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.MCP tool changeOrders_delete (toolset projects)Approval Over MCP, this tool always waits for your approval in ServFlo. See Approvals .
Name In Type Required Description changeOrderIdpath string Yes
curl -X DELETE "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /change-orders/{changeOrderId}" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description oktrue
POST /organizations/{organizationId}/projects/{projectId}/change-orders
A DRAFT change order (CO-n) on a project: a title, lines (from the pricebook with pricebookItemId, or typed; a negative price is a credit) and the schedule change in working days. Nothing reaches the customer until it is sent (POST …/send). Technicians: their own projects (a draft for the office).
Permission projects.field (Owner, Admin, Dispatcher, Technician)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool changeOrders_create (toolset projects)
Name In Type Required Description projectIdpath string Yes The project (GET /projects).
Field Type Required Description titlestring Yes Up to 200 characters. descriptionstring or null No Up to 5000 characters. scheduleDaysinteger No Working days added (negative: taken off). -365–365. Default 0. linesarray of object No Up to 100 items. Default []. lines[].descriptionstring Yes Up to 500 characters. lines[].quantitynumber Yes -1000000–1000000. lines[].unitPriceCentsinteger Yes Price to the customer per unit; negative for a credit. -100000000–100000000. lines[].costCentsinteger or null No Our unit cost (goes to the budget when approved). -100000000–100000000. lines[].costCategoryenum or null No Budget bucket: LABOR, MATERIALS, SUBCONTRACTORS, EQUIPMENT or OTHER. One of LABOR, MATERIALS, SUBCONTRACTORS, EQUIPMENT, OTHER. lines[].pricebookItemIdstring or null No Picked from the pricebook (GET /pricebook/items).
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /projects/{projectId}/change-orders" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"title":"string"}'
201: the answer's fields Field Type Description idstring projectIdstring labelstring CO-n within the project. titlestring statusenum One of DRAFT, SENT, APPROVED, DECLINED. priceChangeCentsinteger Before tax; negative for a credit. scheduleDaysinteger linesarray of object lines[].descriptionstring lines[].quantitynumber lines[].unitPriceCentsinteger urlstring The customer's page to approve it (/co/{token}); works once SENT.
POST /organizations/{organizationId}/change-orders/{changeOrderId}/send
Sends to the customer: marks it SENT so the customer can approve or decline it on its link and in the portal, and (unless channels is empty) emails and/or texts them the link (consent and quiet hours apply). Technicians only when the business lets the crew send change orders (else 409: it stays a draft for the office).
Permission: changeOrders.send (Owner, Admin, Dispatcher, Technician (own jobs)); risk sensitive (OAuth scope servflo.sensitive).
Permission changeOrders.sendRisk sensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.MCP tool changeOrders_send (toolset projects)Approval Over MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals .
Name In Type Required Description changeOrderIdpath string Yes
Field Type Required Description channelsarray of enum No Up to 2 items. Default ["EMAIL","SMS"]. notestring or null No Up to 1000 characters.
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /change-orders/{changeOrderId}/send" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"channels":["EMAIL","SMS"],"note":"string"}'
200: the answer's fields Field Type Description changeOrderobject changeOrder.idstring changeOrder.projectIdstring changeOrder.labelstring CO-n within the project. changeOrder.titlestring changeOrder.statusenum One of DRAFT, SENT, APPROVED, DECLINED. changeOrder.priceChangeCentsinteger Before tax; negative for a credit. changeOrder.scheduleDaysinteger changeOrder.linesarray of object changeOrder.lines[].descriptionstring changeOrder.lines[].quantitynumber changeOrder.lines[].unitPriceCentsinteger changeOrder.urlstring The customer's page to approve it (/co/{token}); works once SENT. messagesarray of object messages[].channelstring messages[].statusstring
POST /organizations/{organizationId}/change-orders/{changeOrderId}/resend
Sends to the customer: the link of a SENT change order again by email and/or text (consent and quiet hours apply).
Permission: changeOrders.send (Owner, Admin, Dispatcher, Technician (own jobs)); risk sensitive (OAuth scope servflo.sensitive).
Permission changeOrders.sendRisk sensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.MCP tool changeOrders_resend (toolset projects)Approval Over MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals .
Name In Type Required Description changeOrderIdpath string Yes
Field Type Required Description channelsarray of enum No Default both; each is subject to the customer's consent and quiet hours. Up to 2 items. Default ["EMAIL","SMS"]. notestring or null No Up to 1000 characters.
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /change-orders/{changeOrderId}/resend" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"channels":["EMAIL","SMS"],"note":"string"}'
200: the answer's fields An array of objects:
Field Type Description channelstring statusstring
POST /organizations/{organizationId}/change-orders/{changeOrderId}/reopen
Takes a SENT or DECLINED change order back to DRAFT to edit it (the customer can no longer answer until it is sent again).
Permission: changeOrders.send (Owner, Admin, Dispatcher, Technician (own jobs)); risk write (OAuth scope servflo.write).
Permission changeOrders.sendRisk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool changeOrders_reopen (toolset projects)
Name In Type Required Description changeOrderIdpath string Yes
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /change-orders/{changeOrderId}/reopen" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description idstring projectIdstring labelstring CO-n within the project. titlestring statusenum One of DRAFT, SENT, APPROVED, DECLINED. priceChangeCentsinteger Before tax; negative for a credit. scheduleDaysinteger linesarray of object lines[].descriptionstring lines[].quantitynumber lines[].unitPriceCentsinteger urlstring The customer's page to approve it (/co/{token}); works once SENT.
POST /organizations/{organizationId}/change-orders/{changeOrderId}/approve
ACTS FOR THE CUSTOMER (signed on site or said yes by phone): APPROVED is final. The contract grows by the price change, each line's cost joins the budget, the project's target end moves by the schedule days, and a progress billing gains it as a contract line. signatureDataUrl is the PNG signature drawn on the device.
Permission: changeOrders.send (Owner, Admin, Dispatcher, Technician (own jobs)); risk sensitive (OAuth scope servflo.sensitive).
Permission changeOrders.sendRisk sensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.MCP tool changeOrders_approve (toolset projects)Approval Over MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals .
Name In Type Required Description changeOrderIdpath string Yes
Field Type Required Description signatureNamestring or null No Up to 200 characters. signatureDataUrlstring or null No termsstring or null No The terms shown; omitted: the business's change-order terms. Up to 5000 characters.
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /change-orders/{changeOrderId}/approve" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"signatureName":"string","signatureDataUrl":"https://example.com","terms":"string"}'
200: the answer's fields Field Type Description idstring projectIdstring labelstring CO-n within the project. titlestring statusenum One of DRAFT, SENT, APPROVED, DECLINED. priceChangeCentsinteger Before tax; negative for a credit. scheduleDaysinteger linesarray of object lines[].descriptionstring lines[].quantitynumber lines[].unitPriceCentsinteger urlstring The customer's page to approve it (/co/{token}); works once SENT.
POST /organizations/{organizationId}/change-orders/{changeOrderId}/decline
Marks it DECLINED with the reason; nothing changes in the contract.
Permission: changeOrders.send (Owner, Admin, Dispatcher, Technician (own jobs)); risk write (OAuth scope servflo.write).
Permission changeOrders.sendRisk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool changeOrders_decline (toolset projects)
Name In Type Required Description changeOrderIdpath string Yes
Field Type Required Description reasonstring or null No Up to 2000 characters.
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /change-orders/{changeOrderId}/decline" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"reason":"string"}'
200: the answer's fields Field Type Description idstring projectIdstring labelstring CO-n within the project. titlestring statusenum One of DRAFT, SENT, APPROVED, DECLINED. priceChangeCentsinteger Before tax; negative for a credit. scheduleDaysinteger linesarray of object lines[].descriptionstring lines[].quantitynumber lines[].unitPriceCentsinteger urlstring The customer's page to approve it (/co/{token}); works once SENT.