REST API reference

Service Fusion API

15 endpoints for Service Fusion. Each one is a POST with a JSON body, called with your API key.

Base URL
https://cotlet.dev/api/v1/service-fusion
Connects with
Your own Service Fusion user
Integration page
Service Fusion
Service Fusion Endpoints
Endpoint Access Description
list_customers read Customers matching a name, phone, email, address or tag, with last serviced date.
list_job_statuses read The job statuses your account uses, with their type.
list_jobs read Jobs with number, status, customer, assigned techs and start date.
get_job read Full job: description, location, techs, products, services, notes and charges.
list_estimates read Estimates with number, status, customer, requested date and options.
get_estimate read Estimate with each option, its line items and total.
list_invoices read Invoices with number, customer, total, date, paid flag and pay-online link.
create_customer write New customer with a primary contact and service location.
create_job write New job for a customer, scheduled or unscheduled, optionally with technicians assigned.
update_job_status write Move a job to another status, e.g. On The Way, Completed or Cancelled.
create_estimate write New estimate for a customer with products and services. Nothing is sent until send_estimate.
convert_estimate_to_job write Turn one estimate option into a job, the way Convert to Job does in the app.
create_invoice write Invoice a job from its products, services and charges. Nothing is sent or charged.
send_estimate write Email or text an estimate with a link to view and accept it online.
send_invoice write Email or text an invoice with a link to view and pay it online.

POST https://cotlet.dev/api/v1/service-fusion/list_customers

Returns customers with their contacts, service location and last serviced date. Use it before create_customer to find a repeat caller by phone or email. create_job and create_estimate take the customer name exactly as shown here.

Parameters

Parameters: list_customers
NameTypeDescription
query string Name, phone, email or address to search for.
tags string[] Only customers with these tags.
page integer Page number. Default: 1.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/list_customers \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("service-fusion", "list_customers")
Node.js
const result = await cotlet.call('service-fusion', 'list_customers');
CLI
cotlet call service-fusion list_customers

Example response

{
  "customers": [
    {
      "customer_id": "22814",
      "customer_name": "Jane Doe",
      "contact": {
        "first_name": "Jane",
        "last_name": "Doe",
        "phone": "555-0142",
        "email": "jane.doe@example.com"
      },
      "location": {
        "street_1": "48 Maple Court",
        "city": "Plano",
        "state_prov": "TX",
        "postal_code": "75024"
      },
      "tags": [
        "Residential"
      ],
      "last_serviced": "2026-04-18"
    }
  ],
  "page": 1
}

POST https://cotlet.dev/api/v1/service-fusion/list_job_statuses

Returns the statuses from My Office > Estimate & Job Statuses. Accounts can rename statuses, so use these names in list_jobs and update_job_status. The defaults include Unscheduled, Scheduled, Dispatched, On The Way, On Site, Started, Completed, Cancelled, Job Closed and Invoiced.

Parameters

No parameters.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/list_job_statuses \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("service-fusion", "list_job_statuses")
Node.js
const result = await cotlet.call('service-fusion', 'list_job_statuses');
CLI
cotlet call service-fusion list_job_statuses

Example response

{
  "statuses": [
    {
      "name": "Unscheduled",
      "category": "Open"
    },
    {
      "name": "Scheduled",
      "category": "Open"
    },
    {
      "name": "Dispatched",
      "category": "Open"
    },
    {
      "name": "On The Way",
      "category": "In Progress"
    },
    {
      "name": "Completed",
      "category": "In Progress"
    },
    {
      "name": "Invoiced",
      "category": "Closed"
    }
  ]
}

List jobs

read

POST https://cotlet.dev/api/v1/service-fusion/list_jobs

Lists jobs. Filter by status, customer or a start date range, for example every job in Unscheduled. Each item carries the job_id for get_job, update_job_status and create_invoice. Status names are the ones from list_job_statuses.

Parameters

Parameters: list_jobs
NameTypeDescription
status string Status name from list_job_statuses, e.g. Unscheduled or Completed.
customer_name string Only jobs for this customer.
start_from date Jobs starting on or after this date.
start_to date Jobs starting on or before this date.
page integer Page number. Default: 1.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/list_jobs \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("service-fusion", "list_jobs")
Node.js
const result = await cotlet.call('service-fusion', 'list_jobs');
CLI
cotlet call service-fusion list_jobs

Example response

{
  "jobs": [
    {
      "job_id": "1048301",
      "number": "10483",
      "status": "Unscheduled",
      "customer_name": "Mark Reyes",
      "city": "Frisco",
      "description": "Water heater leaking at base",
      "start": null,
      "techs_assigned": []
    },
    {
      "job_id": "1048288",
      "number": "10482",
      "status": "Unscheduled",
      "customer_name": "Priya Shah",
      "city": "Plano",
      "description": "Furnace not igniting",
      "start": null,
      "techs_assigned": []
    }
  ],
  "page": 1
}

Get job

read

POST https://cotlet.dev/api/v1/service-fusion/get_job

Returns one job with its location, assigned technicians, products, services, other charges, notes and the invoice number once it is invoiced. Use it to check the status and charges before create_invoice.

Parameters

Parameters: get_job
NameTypeDescription
job_id required string Job ID from list_jobs.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/get_job \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"job_8c41d2"}'
Python
result = client.call("service-fusion", "get_job", {"job_id":"job_8c41d2"})
Node.js
const result = await cotlet.call('service-fusion', 'get_job', {"job_id":"job_8c41d2"});
CLI
cotlet call service-fusion get_job --data '{"job_id":"job_8c41d2"}'

Example response

{
  "job_id": "1048213",
  "number": "10482",
  "status": "Completed",
  "customer_name": "Jane Doe",
  "description": "AC tune-up, upstairs unit",
  "location": {
    "street_1": "48 Maple Court",
    "city": "Plano",
    "state_prov": "TX",
    "postal_code": "75024"
  },
  "start": "2026-10-15T09:00:00-05:00",
  "techs_assigned": [
    "Alex Rivera"
  ],
  "services": [
    {
      "name": "AC tune-up",
      "quantity": 1,
      "rate": 129
    }
  ],
  "products": [],
  "total": 129,
  "invoice_number": null
}

POST https://cotlet.dev/api/v1/service-fusion/list_estimates

Lists estimates. Filter by status, customer or the date the estimate was requested. Each item carries the estimate_id for get_estimate, convert_estimate_to_job and send_estimate.

Parameters

Parameters: list_estimates
NameTypeDescription
status string Estimate status as set in your account.
customer_name string Only estimates for this customer.
requested_from date Requested on or after this date.
page integer Page number. Default: 1.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/list_estimates \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("service-fusion", "list_estimates")
Node.js
const result = await cotlet.call('service-fusion', 'list_estimates');
CLI
cotlet call service-fusion list_estimates

Example response

{
  "estimates": [
    {
      "estimate_id": "3317",
      "number": "3317",
      "status": "Estimate Sent",
      "customer_name": "Carol Smith",
      "requested_on": "2026-10-08",
      "options": [
        "Good",
        "Better",
        "Best"
      ]
    }
  ],
  "page": 1
}

POST https://cotlet.dev/api/v1/service-fusion/get_estimate

Returns one estimate with up to five options. Each option has a name, line items and a total, and shows Converted once it has become a job. Use the option name in convert_estimate_to_job.

Parameters

Parameters: get_estimate
NameTypeDescription
estimate_id required string Estimate ID from list_estimates.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/get_estimate \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"estimate_id":"estimate_8c41d2"}'
Python
result = client.call("service-fusion", "get_estimate", {"estimate_id":"estimate_8c41d2"})
Node.js
const result = await cotlet.call('service-fusion', 'get_estimate', {"estimate_id":"estimate_8c41d2"});
CLI
cotlet call service-fusion get_estimate --data '{"estimate_id":"estimate_8c41d2"}'

Example response

{
  "estimate_id": "3317",
  "number": "3317",
  "status": "Estimate Sent",
  "customer_name": "Carol Smith",
  "options": [
    {
      "name": "Good",
      "total": 1450,
      "converted": false,
      "items": [
        {
          "name": "40 gal water heater, install",
          "quantity": 1,
          "rate": 1450
        }
      ]
    },
    {
      "name": "Better",
      "total": 1890,
      "converted": false,
      "items": [
        {
          "name": "50 gal water heater, install",
          "quantity": 1,
          "rate": 1890
        }
      ]
    }
  ]
}

POST https://cotlet.dev/api/v1/service-fusion/list_invoices

Lists invoices, read from the invoice itself rather than from the job status. The Paid In Full job status is applied by hand, so use the paid flag here. Each item carries the invoice_id for send_invoice.

Parameters

Parameters: list_invoices
NameTypeDescription
paid boolean false: only unpaid invoices. true: only paid invoices. Default: both.
from date Invoices dated on or after this date.
page integer Page number. Default: 1.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/list_invoices \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("service-fusion", "list_invoices")
Node.js
const result = await cotlet.call('service-fusion', 'list_invoices');
CLI
cotlet call service-fusion list_invoices

Example response

{
  "invoices": [
    {
      "invoice_id": "90412",
      "number": "9041",
      "job_number": "10479",
      "customer_name": "Luis Ortega",
      "total": 340,
      "paid": false,
      "date": "2026-10-06",
      "pay_online_url": "https://example.com/pay/9041"
    }
  ],
  "page": 1
}

POST https://cotlet.dev/api/v1/service-fusion/create_customer

Creates the customer record and returns its customer_name for create_job and create_estimate. It sends nothing to anyone and adds no charge, so it runs without asking for your OK. Search with list_customers first so a repeat customer is not created twice.

Parameters

Parameters: create_customer
NameTypeDescription
customer_name required string Customer or company name.
contact object first_name, last_name, phone, email.
location object street_1, city, state_prov, postal_code.
referral_source string One of your referral sources.
tags string[] Customer tags.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/create_customer \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customer_name":"customer name"}'
Python
result = client.call("service-fusion", "create_customer", {"customer_name":"customer name"})
Node.js
const result = await cotlet.call('service-fusion', 'create_customer', {"customer_name":"customer name"});
CLI
cotlet call service-fusion create_customer --data '{"customer_name":"customer name"}'

Example response

{
  "customer_id": "22901",
  "customer_name": "Jane Doe",
  "contact": {
    "first_name": "Jane",
    "last_name": "Doe",
    "phone": "555-0142",
    "email": "jane.doe@example.com"
  },
  "location": {
    "street_1": "48 Maple Court",
    "city": "Plano",
    "state_prov": "TX",
    "postal_code": "75024"
  }
}

Create job

write Confirm

POST https://cotlet.dev/api/v1/service-fusion/create_job

Creates a job under an existing customer. Without a start the job is Unscheduled; with a start and no technician it is Scheduled. If your Outbound Email Settings email customers when a job is created, the customer gets that email. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: create_job
NameTypeDescription
customer_name required string Existing customer name from list_customers.
description required string What the job is.
category string One of your job categories.
start datetime Scheduled start, ISO 8601. Empty: Unscheduled.
duration_minutes integer Expected duration.
techs_assigned string[] Technician names as shown in your account.
note_to_customer string Shown to the customer.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/create_job \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customer_name":"Jane Doe","description":"AC tune-up, upstairs unit","category":"Maintenance","start":"2026-10-15T09:00:00-05:00","duration_minutes":90}'
Python
result = client.call("service-fusion", "create_job", {"customer_name":"Jane Doe","description":"AC tune-up, upstairs unit","category":"Maintenance","start":"2026-10-15T09:00:00-05:00","duration_minutes":90})
Node.js
const result = await cotlet.call('service-fusion', 'create_job', {"customer_name":"Jane Doe","description":"AC tune-up, upstairs unit","category":"Maintenance","start":"2026-10-15T09:00:00-05:00","duration_minutes":90});
CLI
cotlet call service-fusion create_job --data '{"customer_name":"Jane Doe","description":"AC tune-up, upstairs unit","category":"Maintenance","start":"2026-10-15T09:00:00-05:00","duration_minutes":90}'

Example response

{
  "job_id": "1048213",
  "number": "10482",
  "status": "Scheduled",
  "customer_name": "Jane Doe",
  "description": "AC tune-up, upstairs unit",
  "category": "Maintenance",
  "start": "2026-10-15T09:00:00-05:00",
  "duration_minutes": 90,
  "techs_assigned": []
}

Update job status

write Confirm

POST https://cotlet.dev/api/v1/service-fusion/update_job_status

Sets the job to the status you name, as a technician or dispatcher would in the app. Moving a job to On The Way can send the customer a text notification, and Completed stops labor time. Use names from list_job_statuses. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: update_job_status
NameTypeDescription
job_id required string Job ID from list_jobs.
status required string Status name from list_job_statuses.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/update_job_status \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"job_8c41d2","status":"status"}'
Python
result = client.call("service-fusion", "update_job_status", {"job_id":"job_8c41d2","status":"status"})
Node.js
const result = await cotlet.call('service-fusion', 'update_job_status', {"job_id":"job_8c41d2","status":"status"});
CLI
cotlet call service-fusion update_job_status --data '{"job_id":"job_8c41d2","status":"status"}'

Example response

{
  "job_id": "1048213",
  "number": "10482",
  "previous_status": "Started",
  "status": "Completed"
}

POST https://cotlet.dev/api/v1/service-fusion/create_estimate

Creates the estimate under an existing customer and returns its estimate_id. The customer receives nothing; send_estimate does that. An estimate can hold up to five options, each with its own line items.

Parameters

Parameters: create_estimate
NameTypeDescription
customer_name required string Existing customer name from list_customers.
description required string What the estimate is for.
items object[] Products and services, each with name, quantity and rate.
note_to_customer string Shown on the estimate.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/create_estimate \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customer_name":"customer name","description":"description"}'
Python
result = client.call("service-fusion", "create_estimate", {"customer_name":"customer name","description":"description"})
Node.js
const result = await cotlet.call('service-fusion', 'create_estimate', {"customer_name":"customer name","description":"description"});
CLI
cotlet call service-fusion create_estimate --data '{"customer_name":"customer name","description":"description"}'

Example response

{
  "estimate_id": "3318",
  "number": "3318",
  "status": "Estimate Draft",
  "customer_name": "Jane Doe",
  "description": "Water heater replacement",
  "options": [
    {
      "name": "Option 1",
      "total": 1450
    }
  ]
}

Convert estimate to job

write Confirm

POST https://cotlet.dev/api/v1/service-fusion/convert_estimate_to_job

Converts the option you name into a new job and marks that option Converted. One call creates one job; call again with another option to create another. The job starts Unscheduled unless you pass a start. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: convert_estimate_to_job
NameTypeDescription
estimate_id required string Estimate ID from list_estimates.
option string Option name from get_estimate. Default: the first option.
start datetime Scheduled start for the new job, ISO 8601.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/convert_estimate_to_job \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"estimate_id":"3317","option":"Better","start":"2026-10-15T09:00:00-05:00"}'
Python
result = client.call("service-fusion", "convert_estimate_to_job", {"estimate_id":"3317","option":"Better","start":"2026-10-15T09:00:00-05:00"})
Node.js
const result = await cotlet.call('service-fusion', 'convert_estimate_to_job', {"estimate_id":"3317","option":"Better","start":"2026-10-15T09:00:00-05:00"});
CLI
cotlet call service-fusion convert_estimate_to_job --data '{"estimate_id":"3317","option":"Better","start":"2026-10-15T09:00:00-05:00"}'

Example response

{
  "estimate_id": "3317",
  "option": "Better",
  "converted": true,
  "job_id": "1048390",
  "job_number": "10484",
  "status": "Scheduled",
  "start": "2026-10-15T09:00:00-05:00"
}

Create invoice

write Confirm

POST https://cotlet.dev/api/v1/service-fusion/create_invoice

Does what Invoice, then Invoice Now does on a job. By default the job must be Completed or closed; with Allow Invoicing Prior To Job Completion on in Company Preferences it can be invoiced earlier. The invoice is not sent: use send_invoice. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: create_invoice
NameTypeDescription
job_id required string Job ID from list_jobs.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/create_invoice \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"1048213"}'
Python
result = client.call("service-fusion", "create_invoice", {"job_id":"1048213"})
Node.js
const result = await cotlet.call('service-fusion', 'create_invoice', {"job_id":"1048213"});
CLI
cotlet call service-fusion create_invoice --data '{"job_id":"1048213"}'

Example response

{
  "invoice_id": "90413",
  "number": "9042",
  "job_id": "1048213",
  "job_number": "10482",
  "customer_name": "Jane Doe",
  "total": 129,
  "paid": false,
  "date": "2026-10-15"
}

Send estimate

write Confirm

POST https://cotlet.dev/api/v1/service-fusion/send_estimate

Sends the estimate from the Send button of the app. By text it uses your Text an estimate template and goes to the primary contact, another saved contact or a number you give. The customer can accept the estimate or request a change. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: send_estimate
NameTypeDescription
estimate_id required string Estimate ID from list_estimates.
via enum email or text. Default: email.
to string Phone number or email address. Default: the primary contact on the record.
template string Name of one of your Communication Templates. Default: the system template for the channel.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/send_estimate \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"estimate_id":"3318","via":"text","to":"555-0142"}'
Python
result = client.call("service-fusion", "send_estimate", {"estimate_id":"3318","via":"text","to":"555-0142"})
Node.js
const result = await cotlet.call('service-fusion', 'send_estimate', {"estimate_id":"3318","via":"text","to":"555-0142"});
CLI
cotlet call service-fusion send_estimate --data '{"estimate_id":"3318","via":"text","to":"555-0142"}'

Example response

{
  "estimate_id": "3317",
  "sent": true,
  "via": "text",
  "to": "555-0173",
  "template": "Text an estimate"
}

Send invoice

write Confirm

POST https://cotlet.dev/api/v1/service-fusion/send_invoice

Sends the invoice from the Send button of the app. By text it uses your Text an invoice template; by email you can use any Job/WO Email template. The customer can pay in full or in part from the link. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: send_invoice
NameTypeDescription
invoice_id required string Invoice ID from list_invoices.
via enum email or text. Default: email.
to string Phone number or email address. Default: the primary contact on the record.
template string Name of one of your Communication Templates. Default: the system template for the channel.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/service-fusion/send_invoice \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"invoice_id":"invoice_8c41d2"}'
Python
result = client.call("service-fusion", "send_invoice", {"invoice_id":"invoice_8c41d2"})
Node.js
const result = await cotlet.call('service-fusion', 'send_invoice', {"invoice_id":"invoice_8c41d2"});
CLI
cotlet call service-fusion send_invoice --data '{"invoice_id":"invoice_8c41d2"}'

Example response

{
  "invoice_id": "90413",
  "sent": true,
  "via": "text",
  "to": "555-0142",
  "template": "Text an invoice"
}