Change orders
List, create and edit change orders on a job, send them to the customer for approval, and approve, decline or void them.
View as MarkdownA change order changes a job after it is sold: added or removed scope, a contract change in dollars, and extra days. Change orders are numbered per job (CO #1, #2, ...).
There are three kinds:
| Kind | What it is |
|---|---|
quick |
A title, scope text and a fixed dollar amount. |
tm |
Time and materials, priced in the estimate editor from the job's estimate. |
full |
Full pricing in the estimate editor: new work only, or the whole job revised. |
A change order moves through the workspace's stages (for example Estimating, Review, Ready to send, Sent, Approved, Declined). Each stage has a meaning (working, sent, approved or declined) that sets the change order's status. Approving posts the change to the job's contract value and budget and, when the workspace syncs to QuickBooks Online or another accounting system, exports it, exactly as in TruTec.
Writes act as the person who created the API key and need operations turned on for the workspace (403 Operations not enabled otherwise).
The change order object#
| Field | Type | Description |
|---|---|---|
id, co_number |
integer | Id, and the number within the job. |
kind, kind_label, pricing_mode |
string | See above. pricing_mode is additive or revision for priced change orders. |
title, description |
string | |
status |
string | draft, sent, approved, declined or void. |
stage, stage_label |
string | The workspace stage it sits in. |
job_id, job_number, job_name, customer, customer_name, customer_email |
The job and who approves. | |
amount_delta, tax_delta, cost_delta |
number | Contract, tax and cost change in dollars (+/-). |
days_delta |
integer | Schedule days added or removed. |
revised_contract |
number or null | The job's contract value including this change order. |
lines |
array | Lines by cost code (priced change orders). |
ep_estimate_id, est_proposal_id |
integer or null | The estimate and proposal behind a priced change order. |
approved_at, approval_source, signature_name, signed_at |
How and when the customer or office approved it. | |
sent_at, decision_comment, source |
source is office or field (raised from the crew app). |
|
exported_at, export_ref |
Accounting export. | |
created_at, updated_at |
string |
Change orders#
List change orders#
GET /v1/change-orders
Permission: Read jobs
Takes job_id, status, limit (default 50, maximum 200) and offset. This older endpoint returns {"change_orders": [...], "total", "limit", "offset"} instead of the usual data / pagination; each row is the object above without the workflow fields. See Jobs.
Get a change order#
GET /v1/change-orders/{id}
Permission: Read jobs
curl "https://trutec.ai/api/v1/change-orders/5521" \
-H "X-API-Key: sk_your_api_key_here"
{
"data": {
"id": 5521,
"co_number": 2,
"kind": "quick",
"kind_label": "Quick",
"pricing_mode": null,
"title": "Add 40 LF of curb at the entrance",
"description": "Remove and replace 40 LF of damaged curb.",
"status": "sent",
"stage": "sent",
"approved_at": null,
"approval_source": null,
"signature_name": null,
"job_id": 70412,
"job_number": "24-118",
"job_name": "Northgate Plaza reseal",
"customer": "Northgate Property Group",
"customer_email": "[email protected]",
"amount_delta": 1850.5,
"tax_delta": 0.0,
"cost_delta": 0.0,
"days_delta": 1,
"revised_contract": 50350.5,
"ep_estimate_id": null,
"est_proposal_id": null,
"exported_at": null,
"export_ref": null,
"lines": [],
"stage_label": "Sent",
"source": "office",
"customer_name": "Dana Ortiz",
"sent_at": "2026-11-04T15:12:40Z",
"signed_at": null,
"decision_comment": null,
"created_at": "2026-11-04T14:58:02Z",
"updated_at": "2026-11-04T15:12:40Z"
}
}
Create a change order#
POST /v1/change-orders
Permission: Write jobs
| Name | Type | Required | Description |
|---|---|---|---|
job_id |
integer | Yes | |
title |
string | Yes for quick |
Up to 200 characters. |
kind |
string | No | quick (default), tm or full. |
description |
string | No | The scope change. |
amount_delta |
number | No | Dollars, + or -. quick only; priced kinds take their amount from the estimate. |
days_delta |
integer | No | |
customer_name, customer_email |
string | No | Who approves it. |
pricing_mode |
string | No | additive (default) or revision, for full. |
request_key |
string | No | A UUID. Repeating a tm or full create with the same key returns the same change order. |
A quick change order starts as a draft in the first working stage. A tm or full change order copies the job's estimate into a new change-order estimate (the response's ep_estimate_id) to be priced; the key's creator needs the estimator or admin role, and the job needs an estimate (400 otherwise).
curl -X POST "https://trutec.ai/api/v1/change-orders" \
-H "X-API-Key: sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"job_id": 70412,
"title": "Add 40 LF of curb at the entrance",
"amount_delta": 1850.50,
"days_delta": 1,
"customer_email": "[email protected]"
}'
Returns 201 with the change order. Nothing is sent to the customer.
Update a change order#
PATCH /v1/change-orders/{id}
Permission: Write jobs
Send any of title, description, amount_delta, days_delta, customer_name, customer_email. Only draft and sent change orders can change; approved or declined ones return 400.
Send a change order to the customer#
POST /v1/change-orders/{id}/send
Permission: Write jobs
This emails the customer (customer_email) a link to review and sign the change order online, from the key creator's connected mailbox when there is one. The status becomes sent. The response has emailed: false when there is no customer email; the link is still created and can be sent from TruTec. A decided change order returns 400.
Approve or decline#
POST /v1/change-orders/{id}/approve
POST /v1/change-orders/{id}/decline
Permission: Write jobs
Records the office's decision, the same as moving the change order to the workspace's Approved or Declined stage. Approving updates the job's contract value and budget and runs any accounting export. A change order the customer already signed cannot be declined.
Move to a stage#
POST /v1/change-orders/{id}/stage with {"stage": "review"}
Permission: Write jobs
Moves to any stage key from GET /v1/change-order-stages. A stage that means approved or declined does what Approve or Decline does. An unknown key returns 400.
Void a change order#
POST /v1/change-orders/{id}/void
Permission: Write jobs
Sets the status to void. A priced change order that is signed or approved cannot be voided (409).
List stages#
GET /v1/change-order-stages
Permission: Read jobs
{
"data": [
{ "key": "estimating", "label": "Estimating", "meaning": "working" },
{ "key": "review", "label": "Review", "meaning": "working" },
{ "key": "ready_to_send", "label": "Ready to send", "meaning": "working" },
{ "key": "sent", "label": "Sent", "meaning": "sent" },
{ "key": "approved", "label": "Approved", "meaning": "approved" },
{ "key": "declined", "label": "Declined", "meaning": "declined" }
]
}
Deleting change orders#
Change orders can't be deleted, in TruTec or through the API. Void one instead (POST /v1/change-orders/{id}/void): it stays on the job's list marked void and keeps its number.