# Service Fusion API and MCP server

> Service Fusion has an Open API, but only on the Pro plan, and it has no official MCP server (checked 11 Oct 2026). It lists and reads customers, jobs, estimates and invoices and creates customers, jobs and estimates. It cannot change a job status, convert an estimate or create or send an invoice.

Field service management software for home service contractors (HVAC, plumbing, electrical): customers, estimates, jobs, dispatch and invoices.

## What is the Service Fusion API?

Cotlet's Service Fusion API exposes 15 endpoints for your own Service Fusion account: list customers, list job statuses, list jobs, get job, list estimates, get estimate, list invoices, create customer, create job, update job status, create estimate, convert estimate to job, create invoice, send estimate and send invoice. The list_customers endpoint returns customers matching a name, phone, email, address or tag, with last serviced date. Each endpoint takes simple JSON inputs like customer_name, page or status and works both as an MCP tool for agents and as a REST call for scripts.

- **Category:** [Local services & SaaS](https://cotlet.dev/integrations/category/local-services-saas)
- **Endpoints:** 15 (7 read, 8 write)
- **Updated:** 2026-10-11

Service Fusion has an Open API, but only on the Pro plan, and it has no official MCP server (checked 11 Oct 2026). Cotlet is a hosted MCP server and REST API for Service Fusion with 15 endpoints (7 read, 8 write): your AI agent signs in as you and does the work.

## Does Service Fusion have an official API?

Service Fusion has an Open API, but only on the Pro plan, and it has no official MCP server (checked 11 Oct 2026). It lists and reads customers, jobs, estimates and invoices and creates customers, jobs and estimates. It cannot change a job status, convert an estimate or create or send an invoice.

| Task | Service Fusion official | Cotlet |
|---|---|---|
| Find customers, jobs, estimates and invoices | Partly: Pro plan only | Yes |
| Create customers | Partly: Pro plan only | Yes |
| Create jobs | Partly: Pro plan only | Yes |
| Create estimates | Partly: Pro plan only; the API has no call to send the estimate | Yes |
| Change a job status | No | Yes |
| Convert an estimate option to a job | No | Yes |
| Create an invoice from a job | No | Yes |
| Send estimates and invoices by email or text | No | Yes |

Sources: [Service Fusion API reference (v1)](https://docs.servicefusion.com/), [Service Fusion Help: Zapier](https://servicefusion.zendesk.com/hc/en-us/articles/4404612613005-Zapier), [Service Fusion pricing](https://www.servicefusion.com/pricing), [Service Fusion Help: How To Create An Invoice](https://servicefusion.zendesk.com/hc/en-us/articles/360023788132-How-To-Create-An-Invoice), [Service Fusion Help: Automatic Estimate Status Behavior Overview](https://servicefusion.zendesk.com/hc/en-us/articles/43255219385741-Automatic-Estimate-Status-Behavior-Overview), [Service Fusion Help: Home Advisor Integration](https://servicefusion.zendesk.com/hc/en-us/articles/4409407987853-Home-Advisor-Integration), [Service Fusion Help: Using the Customer Web Portal](https://servicefusion.zendesk.com/hc/en-us/articles/360023787852-Using-the-Customer-Web-Portal), [Service Fusion Help: Estimate Templates Overview](https://servicefusion.zendesk.com/hc/en-us/articles/49226053738637-Estimate-Templates-Overview), [Service Fusion Help: Sending multiple invoice emails simultaneously](https://servicefusion.zendesk.com/hc/en-us/articles/360043844111-Sending-multiple-invoice-emails-simultaneously)

## For AI agents

```text
Service Fusion has an Open API, but only on the Pro plan, and it has no official MCP server (checked 11 Oct 2026). It lists and reads customers, jobs, estimates and invoices and creates customers, jobs and estimates. It cannot change a job status, convert an estimate or create or send an invoice.
Cotlet provides a hosted MCP server and REST API for Service Fusion: 15 tools (7 read, 8 write).
Access       Request access at https://cotlet.dev/app/signup?app=service-fusion; we email the API key.

MCP server   https://cotlet.dev/mcp/v1
REST base    https://cotlet.dev/api/v1/service-fusion
Auth         Authorization: Bearer <COTLET_API_KEY>. Listing endpoints and schemas needs no key; calling an endpoint needs one.
Tools        list_customers, list_job_statuses, list_jobs, get_job, list_estimates, get_estimate, list_invoices, create_customer, create_job, update_job_status, create_estimate, convert_estimate_to_job, create_invoice, send_estimate, send_invoice
Confirm      create_job, update_job_status, convert_estimate_to_job, create_invoice, send_estimate, send_invoice (by default the user approves each call; the user can switch this off per tool, e.g. for scheduled automations)
Markdown     https://cotlet.dev/integrations/service-fusion-api-mcp-server.md

How access works:
1. The user requests access at https://cotlet.dev/app/signup?app=service-fusion (Service Fusion is pre-selected). Each request is reviewed and the API key is sent by email.
2. The user signs in to Service Fusion once in a browser. An agent cannot do this step.
3. The API key goes into the MCP client or the REST call as a bearer token.

Fits: people who want a hosted Service Fusion server that someone else maintains, including non-developers.

Policy: Cotlet never stores passwords, never solves CAPTCHAs, never bypasses MFA.
Company: legal details in the Terms of service at https://cotlet.dev/terms. Contact contact@cotlet.dev.
Session: the user signs in to Service Fusion in a browser; Cotlet keeps only the session, AES-256 encrypted, revocable in the dashboard at any time.
Terms: the user stays responsible for following Service Fusion's terms; Cotlet is not affiliated with Service Fusion.
```

## What can an AI agent do in Service Fusion?

Cotlet is best for field service teams who want an AI agent to book jobs, change statuses and invoice in Service Fusion without running or fixing a server.

- **[Create customers and jobs from new leads](https://cotlet.dev/integrations/service-fusion-api-mcp-server/create-customers-and-jobs-from-leads)** (runs: daily): "New lead from the website form: Jane Doe, 555-0142, 48 Maple Court, Plano. Find her or add her as a customer with referral source Website, and book an AC tune-up for Thursday at 9." → `list_customers`, `create_customer`, `create_job`
- **List unscheduled jobs** (runs: daily): "Which jobs are still Unscheduled? List them with customer and city." → `list_job_statuses`, `list_jobs`
- **[Invoice completed jobs](https://cotlet.dev/integrations/service-fusion-api-mcp-server/invoice-completed-jobs)** (runs: daily): "Invoice every job marked Completed yesterday, skip jobs with no charges, and text the invoices to the customers." → `list_jobs`, `get_job`, `update_job_status`, `create_invoice`, `send_invoice`, `list_invoices`
- **[Convert accepted estimates to jobs](https://cotlet.dev/integrations/service-fusion-api-mcp-server/convert-estimate-to-job)** (runs: daily): "Convert every estimate customers accepted online since yesterday into a job. Schedule the Smiths' Better option on estimate 3317 for Thursday at 9 and leave the rest for dispatch." → `list_estimates`, `get_estimate`, `convert_estimate_to_job`
- **[Draft and text an estimate](https://cotlet.dev/integrations/service-fusion-api-mcp-server/send-estimates-by-text)**: "Draft a water heater replacement estimate for Jane Doe from these notes and text it to her: 50 gal gas unit, install, haul away the old tank, $1,890." → `list_customers`, `create_estimate`, `send_estimate`
- **Weekly unpaid invoices report** (runs: weekly): "Every Monday, list invoices from last week that are still unpaid." → `list_invoices`

## Can Service Fusion automations run on a schedule in n8n, Make or Zapier?

Yes. Cotlet does not replace your automation platform: it gives it a Service Fusion connection it does not have, with the same API key as your agent. Write actions ask for your OK by default; switch that off in your dashboard for the tools you choose, for example to create customers and jobs from new leads, and the schedule runs on its own. Cotlet runs in the cloud, so it keeps going while your computer is off.

| Where | How to connect | How to schedule |
|---|---|---|
| Your AI agent | Add https://cotlet.dev/mcp/v1 with your API key. | A scheduled agent run, for example a Claude Code routine. |
| n8n | MCP Client node with https://cotlet.dev/mcp/v1, or an HTTP Request node to https://cotlet.dev/api/v1/service-fusion/{tool}. | Schedule Trigger node. |
| Make | HTTP module: POST https://cotlet.dev/api/v1/service-fusion/{tool} with an Authorization: Bearer header and a JSON body. | Scenario schedule. |
| Zapier | Webhooks by Zapier: POST https://cotlet.dev/api/v1/service-fusion/{tool} with the same header and body. | Schedule by Zapier trigger. |
| Your own script | POST https://cotlet.dev/api/v1/service-fusion/{tool} with your API key. | cron or GitHub Actions. |

## Tools

**For AI agents:** Every endpoint and its schema is public. The 15 endpoints on this page, with parameters and example responses, can be listed without an account. Calling one returns 403 until the account has an API key with access to Service Fusion.

### list_customers

Customers matching a name, phone, email, address or tag, with last serviced date. Access: read. REST: `POST /api/v1/service-fusion/list_customers`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `query` | string | no | Name, phone, email or address to search for. |
| `tags` | string[] | no | Only customers with these tags. |
| `page` | integer | no | Page number. Default: 1. |

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.

Example response:

```json
{
  "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
}
```

### list_job_statuses

The job statuses your account uses, with their type. Access: read. REST: `POST /api/v1/service-fusion/list_job_statuses`.

No parameters.

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.

Example response:

```json
{
  "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

Jobs with number, status, customer, assigned techs and start date. Access: read. REST: `POST /api/v1/service-fusion/list_jobs`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `status` | string | no | Status name from list_job_statuses, e.g. Unscheduled or Completed. |
| `customer_name` | string | no | Only jobs for this customer. |
| `start_from` | date | no | Jobs starting on or after this date. |
| `start_to` | date | no | Jobs starting on or before this date. |
| `page` | integer | no | Page number. Default: 1. |

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.

Example response:

```json
{
  "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

Full job: description, location, techs, products, services, notes and charges. Access: read. REST: `POST /api/v1/service-fusion/get_job`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | yes | Job ID from list_jobs. |

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.

Example response:

```json
{
  "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
}
```

### list_estimates

Estimates with number, status, customer, requested date and options. Access: read. REST: `POST /api/v1/service-fusion/list_estimates`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `status` | string | no | Estimate status as set in your account. |
| `customer_name` | string | no | Only estimates for this customer. |
| `requested_from` | date | no | Requested on or after this date. |
| `page` | integer | no | Page number. Default: 1. |

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.

Example response:

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

### get_estimate

Estimate with each option, its line items and total. Access: read. REST: `POST /api/v1/service-fusion/get_estimate`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `estimate_id` | string | yes | Estimate ID from list_estimates. |

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.

Example response:

```json
{
  "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
        }
      ]
    }
  ]
}
```

### list_invoices

Invoices with number, customer, total, date, paid flag and pay-online link. Access: read. REST: `POST /api/v1/service-fusion/list_invoices`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `paid` | boolean | no | false: only unpaid invoices. true: only paid invoices. Default: both. |
| `from` | date | no | Invoices dated on or after this date. |
| `page` | integer | no | Page number. Default: 1. |

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.

Example response:

```json
{
  "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
}
```

### create_customer

New customer with a primary contact and service location. Access: write. REST: `POST /api/v1/service-fusion/create_customer`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `customer_name` | string | yes | Customer or company name. |
| `contact` | object | no | first_name, last_name, phone, email. |
| `location` | object | no | street_1, city, state_prov, postal_code. |
| `referral_source` | string | no | One of your referral sources. |
| `tags` | string[] | no | Customer tags. |

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.

Example response:

```json
{
  "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

New job for a customer, scheduled or unscheduled, optionally with technicians assigned. Access: write, asks the user first. REST: `POST /api/v1/service-fusion/create_job`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `customer_name` | string | yes | Existing customer name from list_customers. |
| `description` | string | yes | What the job is. |
| `category` | string | no | One of your job categories. |
| `start` | datetime | no | Scheduled start, ISO 8601. Empty: Unscheduled. |
| `duration_minutes` | integer | no | Expected duration. |
| `techs_assigned` | string[] | no | Technician names as shown in your account. |
| `note_to_customer` | string | no | Shown to the customer. |

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.

Example response:

```json
{
  "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

Move a job to another status, e.g. On The Way, Completed or Cancelled. Access: write, asks the user first. REST: `POST /api/v1/service-fusion/update_job_status`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | yes | Job ID from list_jobs. |
| `status` | string | yes | Status name from list_job_statuses. |

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.

Example response:

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

### create_estimate

New estimate for a customer with products and services. Nothing is sent until send_estimate. Access: write. REST: `POST /api/v1/service-fusion/create_estimate`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `customer_name` | string | yes | Existing customer name from list_customers. |
| `description` | string | yes | What the estimate is for. |
| `items` | object[] | no | Products and services, each with name, quantity and rate. |
| `note_to_customer` | string | no | Shown on the 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.

Example response:

```json
{
  "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

Turn one estimate option into a job, the way Convert to Job does in the app. Access: write, asks the user first. REST: `POST /api/v1/service-fusion/convert_estimate_to_job`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `estimate_id` | string | yes | Estimate ID from list_estimates. |
| `option` | string | no | Option name from get_estimate. Default: the first option. |
| `start` | datetime | no | Scheduled start for the new job, ISO 8601. |

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.

Example response:

```json
{
  "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

Invoice a job from its products, services and charges. Nothing is sent or charged. Access: write, asks the user first. REST: `POST /api/v1/service-fusion/create_invoice`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | yes | Job ID from list_jobs. |

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.

Example response:

```json
{
  "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

Email or text an estimate with a link to view and accept it online. Access: write, asks the user first. REST: `POST /api/v1/service-fusion/send_estimate`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `estimate_id` | string | yes | Estimate ID from list_estimates. |
| `via` | enum | no | email or text. Default: email. |
| `to` | string | no | Phone number or email address. Default: the primary contact on the record. |
| `template` | string | no | Name of one of your Communication Templates. Default: the system template for the channel. |

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.

Example response:

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

### send_invoice

Email or text an invoice with a link to view and pay it online. Access: write, asks the user first. REST: `POST /api/v1/service-fusion/send_invoice`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `invoice_id` | string | yes | Invoice ID from list_invoices. |
| `via` | enum | no | email or text. Default: email. |
| `to` | string | no | Phone number or email address. Default: the primary contact on the record. |
| `template` | string | no | Name of one of your Communication Templates. Default: the system template for the channel. |

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.

Example response:

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

## How do I connect Service Fusion to Claude Code, Codex or Cursor?

Connecting Service Fusion takes three steps: request access, sign in to Service Fusion once, then add one MCP server or call the REST API with the same key.

### Connect Service Fusion to your agent.

1. **Create an account** Sign up and add Service Fusion in the console. Your API key is there too.

2. **Sign in to Service Fusion once** Open the connect page from the console and sign in to Service Fusion the way you always do. We keep the session, never your password, and you can revoke it anytime.

3. **Add Cotlet to your agent** Paste the snippet for your client. The same server and key serve every app you connect, so you do this once.

   Claude Code:

```
claude mcp add --transport http cotlet \
  https://cotlet.dev/mcp/v1 \
  --header "Authorization: Bearer $COTLET_API_KEY"
```

   Cursor:

```
{
  "mcpServers": {
    "cotlet": {
      "url": "https://cotlet.dev/mcp/v1",
      "headers": {
        "Authorization": "Bearer ${COTLET_API_KEY}"
      }
    }
  }
}
```

   Codex:

```
# ~/.codex/config.toml
[mcp_servers.cotlet]
url = "https://cotlet.dev/mcp/v1"
bearer_token_env_var = "COTLET_API_KEY"
```

4. **Ask your agent** Ask in plain words. Your agent finds the Service Fusion tools on the server and calls them for you; anything that reaches other people waits for your OK unless you switch that off for a tool.

```
New lead from the website form: Jane Doe, 555-0142, 48 Maple Court, Plano. Find her or add her as a customer with referral source Website, and book an AC tune-up for Thursday at 9.
```

### Call Service Fusion from your scripts.

1. **Export your API key** Your scripts use the same API key as your agent. Keep it in an environment variable, never in your code.

```
export COTLET_API_KEY="cotlet_..."
```

2. **Call a tool** Every tool is a POST endpoint at /api/v1/service-fusion/{tool}. Send its parameters as JSON, exactly as listed in the endpoints above.

```
curl 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}'
```

3. **Read the result** You get plain JSON back, ready for your script. A failed call costs nothing.

```
{
  "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": []
}
```

## Why use Cotlet for Service Fusion?

**Built for agents**

- One MCP server for every app you connect.
- The same tools as a REST API for scripts and cron jobs.
- Works with Claude Code, Codex and Cursor.

**Your login stays yours**

- You sign in to Service Fusion yourself. We keep only the session, encrypted with AES-256.
- The model never sees a login.
- No stored passwords, no CAPTCHA solving, no MFA bypass.

**You stay in control**

- Pick read only, or read and write.
- Anything that reaches other people waits for your OK, unless you switch it off per tool.
- Revoke access in one click.

**Kept working for you**

- We test every integration daily.
- When Service Fusion changes, the tool pauses until we fix it.
- Failed calls cost nothing.

## Is there a Service Fusion MCP server on GitHub?

No community MCP server exists. The official route is the Zapier connection, which also needs the Pro plan and has three actions: Create Job, Create Customer and Create Company Calendar Task.

|  | Zapier | Cotlet |
|---|---|---|
| Plan needed | Service Fusion Pro, plus a Zapier plan | Any Service Fusion plan you can sign in to |
| Setup | Build a Zap per workflow and map fields by hand | Request access, sign in to Service Fusion once in your browser, add one MCP server or API key |
| What it can do | Create a job, a customer or a calendar task; triggers for new records and job status changes | Also change job status, create estimates and invoices, convert an estimate to a job and send documents, each send confirmed by you |
| Your Service Fusion access | A Pro-plan connection to your account | Your own session, encrypted in an EU vault, limited to the actions you allow, revoked in one click |
| When the session expires | Reconnect the account in Zapier | We keep it alive; if Service Fusion logs you out, your agent gets a link to sign in again |
| Where it runs | Zapier cloud, fixed triggers | Hosted: Claude Code, Codex, Cursor, n8n and scripts, also on a schedule |
| Price | Tasks on your Zapier plan | Free 7-day trial with 5,000 credits, then credits per call |

### Which one fits you

**Pick Cotlet if**

- you are not a developer, or you do not want to maintain a server
- you need it to keep working when Service Fusion changes, without checking it yourself
- your agent or a script should run it on a schedule, also while your computer is off

**Pick an open-source server if**

- you are comfortable installing, updating and fixing it yourself
- you want the session to stay on your own computer
- you only need it now and then, from one MCP client

## How much does the Service Fusion API cost?

Free 7-day trial with 5,000 credits, no card needed. After that, the Service Fusion API comes with the Cotlet plan, from $29 a month for 3,000 credits, with no limit on apps. Each month's credits stay valid for 3 months, so unused credits add up.

| Size | Price | Credits / month | Per credit |
|---|---|---|---|
| Solo | $29/mo | 3,000 | about $0.0097 |
| Pro | $99/mo | 12,000 | about $0.0083 |
| Agency | $299/mo | 40,000 | $0.0075 |

Each successful call uses credits for the work it takes; failed calls and timeouts cost nothing. A hard spend cap is on by default. Authenticate with the `Authorization: Bearer` header. [See full pricing](https://cotlet.dev/pricing)

## How Cotlet holds your access

Cotlet hosts MCP servers and REST APIs for apps with no usable API. Your agent works in your own Service Fusion account.

- **Company details:** The legal name, address and registration numbers of the company behind Cotlet are in the Terms of service. [Terms](https://cotlet.dev/terms)
- **Your session:** You sign in to Service Fusion yourself, in your browser. We keep only the session, never your password: encrypted with AES-256 in an EU vault, isolated to your account and used only when your agent calls a Service Fusion tool you allowed. When it expires, your agent gives you a link to sign in again. [Security](https://cotlet.dev/security)
- **Revoking access:** Disconnect Service Fusion in your dashboard: the session is deleted and access ends at once. Actions that reach other people wait for your OK unless you switch that off per tool.
- **What we never do:** Store passwords, solve CAPTCHAs or bypass MFA.
- **Service Fusion's terms:** You use your own Service Fusion account and stay responsible for following Service Fusion's terms. Cotlet is independent and not affiliated with Service Fusion. [Terms](https://cotlet.dev/terms)
- **Contact:** Questions about the company, security or an app: [contact@cotlet.dev](mailto:contact@cotlet.dev)

## Frequently asked questions

**How do I get access?**

Request access and pick Service Fusion. Cotlet reviews each request and emails you your API key.

**Do I need to be technical?**

No. You sign in to Service Fusion once in your browser and paste one command into your agent, or one URL into n8n. Your agent can walk you through it. There is no server to install, update or fix.

**Is a hosted server safe? My Service Fusion session would leave my computer.**

Cotlet keeps your Service Fusion session encrypted with AES-256 in an EU vault, isolated to your account and used only for the tools you allow: read only, or read and write. The AI model never sees it, and you revoke it in one click. A local server keeps the same session in a file on your computer, readable by any program you run, and needs a fresh sign-in whenever it expires.

**Do I need the Pro plan to use Service Fusion with Cotlet?**

No. The Open API is included only in Pro (checked 11 Oct 2026), but Cotlet signs in to your account in a browser the way you do, so Starter and Plus accounts work too. What it can do is what your user can do in the app.

**Why can an invoice not be created for my job?**

By default Service Fusion only invoices a job that is Completed or closed. The Allow Invoicing Prior To Job Completion setting in My Office > Company Preferences changes that.

**Can my agent post or send messages in Service Fusion without asking me?**

No. Every call to create_job, update_job_status, convert_estimate_to_job, create_invoice, send_estimate or send_invoice waits for your OK by default. For scheduled automations you can switch confirmation off per tool in your dashboard, for example only for approvals. create_customer, create_estimate runs without asking, because it sends nothing to anyone and one call undoes it.

**Can I use the Service Fusion API in n8n?**

Yes. Add https://cotlet.dev/mcp/v1 with your API key in n8n's MCP Client node, or call https://cotlet.dev/api/v1/service-fusion/{tool} from the HTTP Request node.
