openapi: 3.1.0
info:
title: ServiceTitan CRM API
description: |
The CRM API provides access to ServiceTitan customer-of-record data — residential and
commercial customers, locations, contacts, leads, bookings, tags, and booking provider
sessions. All paths are tenant-scoped and require an OAuth 2.0 access token plus the
ST-App-Key header.
version: "2.0.0"
contact:
name: ServiceTitan Developer Support
url: https://developer.servicetitan.io/
email: [email protected]
license:
name: ServiceTitan Terms of Service
url: https://www.servicetitan.com/legal/terms-of-service
servers:
- url: https://api.servicetitan.io/crm/v2/{tenant}
description: Production
variables:
tenant:
default: "0000000"
description: Tenant ID assigned by ServiceTitan
- url: https://api-integration.servicetitan.io/crm/v2/{tenant}
description: Integration (Sandbox)
variables:
tenant:
default: "0000000"
description: Tenant ID assigned by ServiceTitan
security:
- OAuth2: []
AppKey: []
tags:
- name: Customers
description: Customer-of-record records
- name: Locations
description: Customer service locations and addresses
- name: Contacts
description: Customer contact methods (phone, email)
- name: Leads
description: Pre-customer lead records
- name: Bookings
description: Customer-initiated booking requests
- name: Tags
description: Tag types and customer tagging
paths:
/customers:
get:
summary: List Customers
description: Returns a paginated list of customers matching the provided filters.
operationId: listCustomers
tags: [Customers]
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/IncludeTotal'
- $ref: '#/components/parameters/Ids'
- $ref: '#/components/parameters/ModifiedBefore'
- $ref: '#/components/parameters/ModifiedOnOrAfter'
- $ref: '#/components/parameters/CreatedBefore'
- $ref: '#/components/parameters/CreatedOnOrAfter'
responses:
'200':
description: Paginated list of customers
content:
application/json:
schema:
$ref: '#/components/schemas/CustomerPagedResponse'
post:
summary: Create Customer
description: Creates a new customer record in the tenant.
operationId: createCustomer
tags: [Customers]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CustomerCreateRequest'
responses:
'200':
description: Created customer
content:
application/json:
schema:
$ref: '#/components/schemas/Customer'
/customers/{id}:
get:
summary: Get Customer
operationId: getCustomer
tags: [Customers]
parameters:
- $ref: '#/components/parameters/Id'
responses:
'200':
description: Customer record
content:
application/json:
schema:
$ref: '#/components/schemas/Customer'
patch:
summary: Update Customer
operationId: updateCustomer
tags: [Customers]
parameters:
- $ref: '#/components/parameters/Id'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CustomerUpdateRequest'
responses:
'200':
description: Updated customer
content:
application/json:
schema:
$ref: '#/components/schemas/Customer'
/customers/{id}/contacts:
get:
summary: List Customer Contacts
operationId: listCustomerContacts
tags: [Contacts]
parameters:
- $ref: '#/components/parameters/Id'
responses:
'200':
description: List of customer contacts
content:
application/json:
schema:
$ref: '#/components/schemas/ContactPagedResponse'
post:
summary: Create Customer Contact
operationId: createCustomerContact
tags: [Contacts]
parameters:
- $ref: '#/components/parameters/Id'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ContactCreateRequest'
responses:
'200':
description: Created contact
content:
application/json:
schema:
$ref: '#/components/schemas/Contact'
/locations:
get:
summary: List Locations
operationId: listLocations
tags: [Locations]
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/CustomerId'
- $ref: '#/components/parameters/ModifiedOnOrAfter'
responses:
'200':
description: Paginated list of locations
content:
application/json:
schema:
$ref: '#/components/schemas/LocationPagedResponse'
post:
summary: Create Location
operationId: createLocation
tags: [Locations]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LocationCreateRequest'
responses:
'200':
description: Created location
content:
application/json:
schema:
$ref: '#/components/schemas/Location'
/locations/{id}:
get:
summary: Get Location
operationId: getLocation
tags: [Locations]
parameters:
- $ref: '#/components/parameters/Id'
responses:
'200':
description: Location record
content:
application/json:
schema:
$ref: '#/components/schemas/Location'
patch:
summary: Update Location
operationId: updateLocation
tags: [Locations]
parameters:
- $ref: '#/components/parameters/Id'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LocationUpdateRequest'
responses:
'200':
description: Updated location
content:
application/json:
schema:
$ref: '#/components/schemas/Location'
/leads:
get:
summary: List Leads
operationId: listLeads
tags: [Leads]
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/Status'
- $ref: '#/components/parameters/ModifiedOnOrAfter'
responses:
'200':
description: Paginated list of leads
content:
application/json:
schema:
$ref: '#/components/schemas/LeadPagedResponse'
post:
summary: Create Lead
operationId: createLead
tags: [Leads]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LeadCreateRequest'
responses:
'200':
description: Created lead
content:
application/json:
schema:
$ref: '#/components/schemas/Lead'
/leads/{id}/dismiss:
put:
summary: Dismiss Lead
operationId: dismissLead
tags: [Leads]
parameters:
- $ref: '#/components/parameters/Id'
responses:
'200':
description: Lead dismissed
/bookings:
get:
summary: List Bookings
operationId: listBookings
tags: [Bookings]
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/ModifiedOnOrAfter'
responses:
'200':
description: Paginated list of bookings
content:
application/json:
schema:
$ref: '#/components/schemas/BookingPagedResponse'
post:
summary: Create Booking
operationId: createBooking
tags: [Bookings]
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BookingCreateRequest'
responses:
'200':
description: Created booking
content:
application/json:
schema:
$ref: '#/components/schemas/Booking'
/tagtypes:
get:
summary: List Tag Types
operationId: listTagTypes
tags: [Tags]
responses:
'200':
description: Tag types
content:
application/json:
schema:
$ref: '#/components/schemas/TagTypePagedResponse'
components:
securitySchemes:
OAuth2:
type: oauth2
flows:
clientCredentials:
tokenUrl: https://auth.servicetitan.io/connect/token
scopes: {}
AppKey:
type: apiKey
in: header
name: ST-App-Key
parameters:
Id:
name: id
in: path
required: true
schema: { type: integer, format: int64 }
CustomerId:
name: customerId
in: query
schema: { type: integer, format: int64 }
Ids:
name: ids
in: query
schema: { type: string }
description: Comma-separated list of IDs
Page:
name: page
in: query
schema: { type: integer, default: 1, minimum: 1 }
PageSize:
name: pageSize
in: query
schema: { type: integer, default: 50, maximum: 500 }
IncludeTotal:
name: includeTotal
in: query
schema: { type: boolean }
Status:
name: status
in: query
schema: { type: string }
ModifiedBefore:
name: modifiedBefore
in: query
schema: { type: string, format: date-time }
ModifiedOnOrAfter:
name: modifiedOnOrAfter
in: query
schema: { type: string, format: date-time }
CreatedBefore:
name: createdBefore
in: query
schema: { type: string, format: date-time }
CreatedOnOrAfter:
name: createdOnOrAfter
in: query
schema: { type: string, format: date-time }
schemas:
Customer:
type: object
properties:
id: { type: integer, format: int64 }
active: { type: boolean }
name: { type: string }
type: { type: string, enum: [Residential, Commercial] }
address: { $ref: '#/components/schemas/Address' }
customFields:
type: array
items: { $ref: '#/components/schemas/CustomField' }
balance: { type: number, format: double }
doNotMail: { type: boolean }
doNotService: { type: boolean }
createdOn: { type: string, format: date-time }
modifiedOn: { type: string, format: date-time }
memberships:
type: array
items: { type: object }
contacts:
type: array
items: { $ref: '#/components/schemas/Contact' }
hasActiveMembership: { type: boolean }
CustomerCreateRequest:
type: object
required: [name, type, locations]
properties:
name: { type: string }
type: { type: string, enum: [Residential, Commercial] }
doNotMail: { type: boolean }
doNotService: { type: boolean }
locations:
type: array
items: { $ref: '#/components/schemas/LocationCreateRequest' }
contacts:
type: array
items: { $ref: '#/components/schemas/ContactCreateRequest' }
customFields:
type: array
items: { $ref: '#/components/schemas/CustomField' }
CustomerUpdateRequest:
type: object
properties:
name: { type: string }
type: { type: string }
doNotMail: { type: boolean }
doNotService: { type: boolean }
customFields:
type: array
items: { $ref: '#/components/schemas/CustomField' }
CustomerPagedResponse:
type: object
properties:
page: { type: integer }
pageSize: { type: integer }
hasMore: { type: boolean }
totalCount: { type: integer, nullable: true }
data:
type: array
items: { $ref: '#/components/schemas/Customer' }
Location:
type: object
properties:
id: { type: integer, format: int64 }
customerId: { type: integer, format: int64 }
active: { type: boolean }
name: { type: string }
address: { $ref: '#/components/schemas/Address' }
zoneId: { type: integer, format: int64 }
taxZoneId: { type: integer, format: int64, nullable: true }
createdOn: { type: string, format: date-time }
modifiedOn: { type: string, format: date-time }
LocationCreateRequest:
type: object
required: [address]
properties:
name: { type: string }
address: { $ref: '#/components/schemas/Address' }
zoneId: { type: integer }
LocationUpdateRequest:
type: object
properties:
name: { type: string }
address: { $ref: '#/components/schemas/Address' }
zoneId: { type: integer }
LocationPagedResponse:
type: object
properties:
page: { type: integer }
pageSize: { type: integer }
hasMore: { type: boolean }
data:
type: array
items: { $ref: '#/components/schemas/Location' }
Contact:
type: object
properties:
id: { type: integer, format: int64 }
type: { type: string, enum: [Phone, MobilePhone, Email, Fax] }
value: { type: string }
memo: { type: string, nullable: true }
modifiedOn: { type: string, format: date-time }
ContactCreateRequest:
type: object
required: [type, value]
properties:
type: { type: string }
value: { type: string }
memo: { type: string }
ContactPagedResponse:
type: object
properties:
data:
type: array
items: { $ref: '#/components/schemas/Contact' }
Lead:
type: object
properties:
id: { type: integer, format: int64 }
status: { type: string, enum: [Open, Converted, Dismissed] }
customerId: { type: integer, format: int64, nullable: true }
locationId: { type: integer, format: int64, nullable: true }
businessUnitId: { type: integer, format: int64, nullable: true }
jobTypeId: { type: integer, format: int64, nullable: true }
priority: { type: string }
summary: { type: string }
callReasonId: { type: integer, nullable: true }
campaignId: { type: integer, nullable: true }
followUpDate: { type: string, format: date-time, nullable: true }
createdOn: { type: string, format: date-time }
modifiedOn: { type: string, format: date-time }
LeadCreateRequest:
type: object
required: [summary]
properties:
customerId: { type: integer, nullable: true }
locationId: { type: integer, nullable: true }
businessUnitId: { type: integer }
jobTypeId: { type: integer }
summary: { type: string }
priority: { type: string }
campaignId: { type: integer }
LeadPagedResponse:
type: object
properties:
data:
type: array
items: { $ref: '#/components/schemas/Lead' }
Booking:
type: object
properties:
id: { type: integer, format: int64 }
source: { type: string }
name: { type: string }
address: { $ref: '#/components/schemas/Address' }
customerType: { type: string }
start: { type: string, format: date-time }
summary: { type: string }
campaignId: { type: integer, nullable: true }
businessUnitId: { type: integer, nullable: true }
isFirstTimeClient: { type: boolean }
uploadedImages:
type: array
items: { type: string }
status: { type: string, enum: [Pending, Converted, Dismissed] }
modifiedOn: { type: string, format: date-time }
BookingCreateRequest:
type: object
required: [name, summary, start]
properties:
source: { type: string }
name: { type: string }
address: { $ref: '#/components/schemas/Address' }
customerType: { type: string }
start: { type: string, format: date-time }
summary: { type: string }
campaignId: { type: integer }
businessUnitId: { type: integer }
BookingPagedResponse:
type: object
properties:
data:
type: array
items: { $ref: '#/components/schemas/Booking' }
TagType:
type: object
properties:
id: { type: integer }
name: { type: string }
color: { type: string }
active: { type: boolean }
TagTypePagedResponse:
type: object
properties:
data:
type: array
items: { $ref: '#/components/schemas/TagType' }
Address:
type: object
properties:
street: { type: string }
unit: { type: string, nullable: true }
city: { type: string }
state: { type: string }
zip: { type: string }
country: { type: string }
latitude: { type: number, nullable: true }
longitude: { type: number, nullable: true }
CustomField:
type: object
properties:
typeId: { type: integer }
name: { type: string }
value: { type: string }