openapi: 3.0.3 info: title: Service Fusion Open API description: >- The Service Fusion Open API is a REST/JSON interface to Service Fusion field service management (FSM) software for home-service contractors. It exposes the core operational records - customers and their contacts, jobs (work orders), estimates, invoices, payments, the product/service catalog, technicians, and calendar tasks - over HTTPS. Requests are authenticated with OAuth 2.0; obtain an access token from the token endpoint at https://api.servicefusion.com/oauth/access_token using an authorization_code or client_credentials grant, then send it as a Bearer token. API access is available on the Service Fusion Pro plan and is rate limited to roughly 60 requests per minute. Grounding note - customers, jobs, estimates, invoices, and techs are documented resources on the Service Fusion API. Contacts, products, services, payments, and calendar tasks are modeled here from the Service Fusion FSM data model and the platform's read-and-create API conventions; verify exact paths, fields, and available methods against the live reference at https://docs.servicefusion.com/ before production use. In practice the public API is read-and-create heavy - list (GET), retrieve (GET), and create (POST) are the reliably available operations; update (PUT) and delete (DELETE) are not consistently exposed across resources. version: '1.0' contact: name: Service Fusion url: https://www.servicefusion.com servers: - url: https://api.servicefusion.com/v1 description: Service Fusion Open API v1 security: - oauth2: [] - bearerAuth: [] tags: - name: Customers description: Customer accounts served by the contractor. - name: Contacts description: Individual contacts and service locations on a customer account. - name: Jobs description: Jobs (work orders) scheduled and dispatched to technicians. - name: Estimates description: Estimates (quotes) presented to customers before work begins. - name: Invoices description: Invoices billed to customers for completed work. - name: Products and Services description: Catalog of products (parts/inventory) and services (labor/tasks). - name: Payments description: Payments applied against invoices. - name: Techs and Users description: Technicians and users the work is assigned to. - name: Calendar Tasks description: Non-job scheduled calendar items and reminders. paths: /customers: get: operationId: listCustomers tags: [Customers] summary: List customers description: Lists customer accounts. Supports filtering, sorting, field expansion, and pagination. parameters: - $ref: '#/components/parameters/Filters' - $ref: '#/components/parameters/Sort' - $ref: '#/components/parameters/Expand' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PerPage' responses: '200': description: A paginated list of customers. content: application/json: schema: $ref: '#/components/schemas/CustomerList' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' post: operationId: createCustomer tags: [Customers] summary: Create a customer description: Creates a new customer account. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CustomerInput' responses: '201': description: The created customer. content: application/json: schema: $ref: '#/components/schemas/Customer' '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' '429': $ref: '#/components/responses/RateLimited' /customers/{id}: parameters: - $ref: '#/components/parameters/Id' get: operationId: getCustomer tags: [Customers] summary: Retrieve a customer description: Retrieves a single customer account by ID. parameters: - $ref: '#/components/parameters/Expand' responses: '200': description: The requested customer. content: application/json: schema: $ref: '#/components/schemas/Customer' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /customers/{id}/contacts: parameters: - $ref: '#/components/parameters/Id' get: operationId: listCustomerContacts tags: [Contacts] summary: List a customer's contacts description: Lists the contacts and service locations attached to a customer account. responses: '200': description: A list of contacts for the customer. content: application/json: schema: $ref: '#/components/schemas/ContactList' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' post: operationId: createCustomerContact tags: [Contacts] summary: Add a contact to a customer description: Creates a new contact under the given customer account. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ContactInput' responses: '201': description: The created contact. content: application/json: schema: $ref: '#/components/schemas/Contact' '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' /jobs: get: operationId: listJobs tags: [Jobs] summary: List jobs description: >- Lists jobs (work orders). Always pass a sort parameter (for example sort=-start_date); unsorted /jobs list queries are known to hang. parameters: - $ref: '#/components/parameters/Filters' - $ref: '#/components/parameters/Sort' - $ref: '#/components/parameters/Expand' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PerPage' responses: '200': description: A paginated list of jobs. content: application/json: schema: $ref: '#/components/schemas/JobList' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' post: operationId: createJob tags: [Jobs] summary: Create a job description: Creates a new job (work order) for a customer. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/JobInput' responses: '201': description: The created job. content: application/json: schema: $ref: '#/components/schemas/Job' '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' /jobs/{id}: parameters: - $ref: '#/components/parameters/Id' get: operationId: getJob tags: [Jobs] summary: Retrieve a job description: Retrieves a single job by ID, with optional expanded relationships. parameters: - $ref: '#/components/parameters/Expand' responses: '200': description: The requested job. content: application/json: schema: $ref: '#/components/schemas/Job' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /estimates: get: operationId: listEstimates tags: [Estimates] summary: List estimates description: Lists estimates (quotes), with filtering, sorting, and pagination. parameters: - $ref: '#/components/parameters/Filters' - $ref: '#/components/parameters/Sort' - $ref: '#/components/parameters/Expand' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PerPage' responses: '200': description: A paginated list of estimates. content: application/json: schema: $ref: '#/components/schemas/EstimateList' '401': $ref: '#/components/responses/Unauthorized' post: operationId: createEstimate tags: [Estimates] summary: Create an estimate description: Creates a new estimate for a customer with line items. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EstimateInput' responses: '201': description: The created estimate. content: application/json: schema: $ref: '#/components/schemas/Estimate' '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' /estimates/{id}: parameters: - $ref: '#/components/parameters/Id' get: operationId: getEstimate tags: [Estimates] summary: Retrieve an estimate description: Retrieves a single estimate by ID. responses: '200': description: The requested estimate. content: application/json: schema: $ref: '#/components/schemas/Estimate' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /invoices: get: operationId: listInvoices tags: [Invoices] summary: List invoices description: Lists invoices. Filter by status (e.g. open/unpaid) to view outstanding accounts receivable. parameters: - $ref: '#/components/parameters/Filters' - $ref: '#/components/parameters/Sort' - $ref: '#/components/parameters/Expand' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PerPage' responses: '200': description: A paginated list of invoices. content: application/json: schema: $ref: '#/components/schemas/InvoiceList' '401': $ref: '#/components/responses/Unauthorized' post: operationId: createInvoice tags: [Invoices] summary: Create an invoice description: Creates a new invoice for a customer or completed job. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/InvoiceInput' responses: '201': description: The created invoice. content: application/json: schema: $ref: '#/components/schemas/Invoice' '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' /invoices/{id}: parameters: - $ref: '#/components/parameters/Id' get: operationId: getInvoice tags: [Invoices] summary: Retrieve an invoice description: Retrieves a single invoice by ID. responses: '200': description: The requested invoice. content: application/json: schema: $ref: '#/components/schemas/Invoice' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /products: get: operationId: listProducts tags: [Products and Services] summary: List products description: Lists catalog products (parts and inventory items). parameters: - $ref: '#/components/parameters/Filters' - $ref: '#/components/parameters/Sort' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PerPage' responses: '200': description: A paginated list of products. content: application/json: schema: $ref: '#/components/schemas/CatalogItemList' '401': $ref: '#/components/responses/Unauthorized' post: operationId: createProduct tags: [Products and Services] summary: Create a product description: Creates a new catalog product. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CatalogItemInput' responses: '201': description: The created product. content: application/json: schema: $ref: '#/components/schemas/CatalogItem' '401': $ref: '#/components/responses/Unauthorized' /services: get: operationId: listServices tags: [Products and Services] summary: List services description: Lists catalog services (labor and flat-rate tasks). parameters: - $ref: '#/components/parameters/Filters' - $ref: '#/components/parameters/Sort' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PerPage' responses: '200': description: A paginated list of services. content: application/json: schema: $ref: '#/components/schemas/CatalogItemList' '401': $ref: '#/components/responses/Unauthorized' post: operationId: createService tags: [Products and Services] summary: Create a service description: Creates a new catalog service. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CatalogItemInput' responses: '201': description: The created service. content: application/json: schema: $ref: '#/components/schemas/CatalogItem' '401': $ref: '#/components/responses/Unauthorized' /payments: get: operationId: listPayments tags: [Payments] summary: List payments description: Lists payments recorded against invoices. parameters: - $ref: '#/components/parameters/Filters' - $ref: '#/components/parameters/Sort' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PerPage' responses: '200': description: A paginated list of payments. content: application/json: schema: $ref: '#/components/schemas/PaymentList' '401': $ref: '#/components/responses/Unauthorized' post: operationId: createPayment tags: [Payments] summary: Record a payment description: Records a payment applied to an invoice. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PaymentInput' responses: '201': description: The recorded payment. content: application/json: schema: $ref: '#/components/schemas/Payment' '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' /techs: get: operationId: listTechs tags: [Techs and Users] summary: List techs and users description: Lists the technicians and users in the account. parameters: - $ref: '#/components/parameters/Filters' - $ref: '#/components/parameters/Sort' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PerPage' responses: '200': description: A paginated list of techs and users. content: application/json: schema: $ref: '#/components/schemas/TechList' '401': $ref: '#/components/responses/Unauthorized' /techs/{id}: parameters: - $ref: '#/components/parameters/Id' get: operationId: getTech tags: [Techs and Users] summary: Retrieve a tech description: Retrieves a single technician or user by ID. responses: '200': description: The requested tech or user. content: application/json: schema: $ref: '#/components/schemas/Tech' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /calendar-tasks: get: operationId: listCalendarTasks tags: [Calendar Tasks] summary: List calendar tasks description: Lists non-job calendar tasks such as reminders and follow-ups. parameters: - $ref: '#/components/parameters/Filters' - $ref: '#/components/parameters/Sort' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PerPage' responses: '200': description: A paginated list of calendar tasks. content: application/json: schema: $ref: '#/components/schemas/CalendarTaskList' '401': $ref: '#/components/responses/Unauthorized' post: operationId: createCalendarTask tags: [Calendar Tasks] summary: Create a calendar task description: Creates a new calendar task, optionally assigned to a tech or user. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CalendarTaskInput' responses: '201': description: The created calendar task. content: application/json: schema: $ref: '#/components/schemas/CalendarTask' '401': $ref: '#/components/responses/Unauthorized' '422': $ref: '#/components/responses/ValidationError' components: securitySchemes: oauth2: type: oauth2 description: OAuth 2.0. Access tokens are issued at https://api.servicefusion.com/oauth/access_token. flows: authorizationCode: authorizationUrl: https://api.servicefusion.com/oauth/authorize tokenUrl: https://api.servicefusion.com/oauth/access_token scopes: {} clientCredentials: tokenUrl: https://api.servicefusion.com/oauth/access_token scopes: {} bearerAuth: type: http scheme: bearer description: Bearer access token obtained via the OAuth 2.0 token endpoint. parameters: Id: name: id in: path required: true description: The unique identifier of the resource. schema: type: string Filters: name: filters in: query required: false description: >- Field filters, expressed as filters[field]=value (for example filters[status]=open). Repeat for multiple fields. style: deepObject explode: true schema: type: object additionalProperties: type: string Sort: name: sort in: query required: false description: >- Sort field, optionally prefixed with - for descending order (for example sort=-start_date). Required on /jobs list requests. schema: type: string Expand: name: expand in: query required: false description: Comma-separated list of related resources to inline in the response. schema: type: string Page: name: page in: query required: false description: 1-based page number for pagination. schema: type: integer minimum: 1 default: 1 PerPage: name: per-page in: query required: false description: Number of records per page. schema: type: integer minimum: 1 maximum: 100 default: 25 responses: Unauthorized: description: Missing or invalid OAuth 2.0 access token. content: application/json: schema: $ref: '#/components/schemas/Error' NotFound: description: The requested resource was not found. content: application/json: schema: $ref: '#/components/schemas/Error' ValidationError: description: The request body failed validation. content: application/json: schema: $ref: '#/components/schemas/Error' RateLimited: description: Rate limit exceeded (roughly 60 requests per minute). Honor Retry-After and back off. content: application/json: schema: $ref: '#/components/schemas/Error' schemas: Pagination: type: object properties: current_page: type: integer per_page: type: integer total: type: integer Error: type: object properties: error: type: string message: type: string Address: type: object properties: street_1: type: string street_2: type: string city: type: string state_prov: type: string postal_code: type: string country: type: string Customer: type: object properties: id: type: string customer_name: type: string account_number: type: string phones: type: array items: type: object properties: phone: type: string type: type: string emails: type: array items: type: string address: $ref: '#/components/schemas/Address' created_at: type: string format: date-time CustomerInput: type: object required: [customer_name] properties: customer_name: type: string phones: type: array items: type: object properties: phone: type: string type: type: string emails: type: array items: type: string address: $ref: '#/components/schemas/Address' CustomerList: type: object properties: items: type: array items: $ref: '#/components/schemas/Customer' _meta: $ref: '#/components/schemas/Pagination' Contact: type: object properties: id: type: string customer_id: type: string fname: type: string lname: type: string contact_type: type: string phone: type: string email: type: string address: $ref: '#/components/schemas/Address' ContactInput: type: object required: [fname] properties: fname: type: string lname: type: string contact_type: type: string phone: type: string email: type: string address: $ref: '#/components/schemas/Address' ContactList: type: object properties: items: type: array items: $ref: '#/components/schemas/Contact' _meta: $ref: '#/components/schemas/Pagination' Job: type: object properties: id: type: string number: type: string customer_name: type: string description: type: string status: type: string category: type: string start_date: type: string format: date-time end_date: type: string format: date-time techs: type: array items: type: string total: type: number JobInput: type: object required: [customer_name] properties: customer_name: type: string description: type: string category: type: string status: type: string start_date: type: string format: date-time end_date: type: string format: date-time techs: type: array items: type: string JobList: type: object properties: items: type: array items: $ref: '#/components/schemas/Job' _meta: $ref: '#/components/schemas/Pagination' LineItem: type: object properties: name: type: string description: type: string quantity: type: number unit_price: type: number taxable: type: boolean Estimate: type: object properties: id: type: string number: type: string customer_name: type: string status: type: string total: type: number line_items: type: array items: $ref: '#/components/schemas/LineItem' created_at: type: string format: date-time EstimateInput: type: object required: [customer_name] properties: customer_name: type: string line_items: type: array items: $ref: '#/components/schemas/LineItem' EstimateList: type: object properties: items: type: array items: $ref: '#/components/schemas/Estimate' _meta: $ref: '#/components/schemas/Pagination' Invoice: type: object properties: id: type: string number: type: string customer_name: type: string status: type: string total: type: number balance_due: type: number line_items: type: array items: $ref: '#/components/schemas/LineItem' created_at: type: string format: date-time InvoiceInput: type: object required: [customer_name] properties: customer_name: type: string job_id: type: string line_items: type: array items: $ref: '#/components/schemas/LineItem' InvoiceList: type: object properties: items: type: array items: $ref: '#/components/schemas/Invoice' _meta: $ref: '#/components/schemas/Pagination' CatalogItem: type: object properties: id: type: string name: type: string description: type: string price: type: number cost: type: number taxable: type: boolean CatalogItemInput: type: object required: [name] properties: name: type: string description: type: string price: type: number cost: type: number taxable: type: boolean CatalogItemList: type: object properties: items: type: array items: $ref: '#/components/schemas/CatalogItem' _meta: $ref: '#/components/schemas/Pagination' Payment: type: object properties: id: type: string invoice_id: type: string amount: type: number method: type: string date: type: string format: date PaymentInput: type: object required: [invoice_id, amount] properties: invoice_id: type: string amount: type: number method: type: string date: type: string format: date PaymentList: type: object properties: items: type: array items: $ref: '#/components/schemas/Payment' _meta: $ref: '#/components/schemas/Pagination' Tech: type: object properties: id: type: string fname: type: string lname: type: string email: type: string phone: type: string role: type: string TechList: type: object properties: items: type: array items: $ref: '#/components/schemas/Tech' _meta: $ref: '#/components/schemas/Pagination' CalendarTask: type: object properties: id: type: string title: type: string description: type: string start_date: type: string format: date-time end_date: type: string format: date-time assigned_to: type: string CalendarTaskInput: type: object required: [title] properties: title: type: string description: type: string start_date: type: string format: date-time end_date: type: string format: date-time assigned_to: type: string CalendarTaskList: type: object properties: items: type: array items: $ref: '#/components/schemas/CalendarTask' _meta: $ref: '#/components/schemas/Pagination'