servicetitan@v2 to select API v2; servicetitan resolves to this default version.
Configuration
Create an application with read permissions for the resources you select and
connect it to the tenant. Credentials and app access must match the environment.
Filament obtains and renews a client-credentials access token and sends the
application key in
ST-App-Key. Connection testing reads the first jobs export
page; it does not establish access to every API family. See the official
API documentation.
Resources
Select the resources your application can access. Other ServiceTitan resources,
including reporting, forms, equipment systems, and newer export feeds, are outside
the current resource set.
Modes
All resources support full reads. Incremental reads are available for 42: 40 export resources use ServiceTitan’s opaquecontinueFrom token;
non_job_timesheets and payrolls use modifiedOnOrAfter with a fixed lower
bound throughout pagination and sort=+ModifiedOn.
These six resources support full reads only: job_types, campaigns,
campaign_costs, campaign_categories, technician_shifts,
and membership_status_changes.
Use incremental upsert for mutable export records. No cursor-column selection
or lookback is supported for export tokens. The first incremental run walks the
complete export. A preceding full run does not seed its incremental token.
Subsequent successful runs resume at the saved token. Append writes can retain
replayed records after failures; they do not produce a deduplicated current view.
gross_pay_items uses the gross pay item id as its primary key and saves the
export’s continueFrom token for incremental reads. payrollId identifies the
parent payroll and must not be used to deduplicate its earnings items.
ServiceTitan permits null item IDs; keyed writes reject such records without
advancing the run’s checkpoint. Use full read with replace for accounts containing
items without IDs. See the official payroll schema.
For existing pipelines, select incremental read and upsert write explicitly.
The first incremental run establishes the export checkpoint with a complete read.
Changing the key does not repair rows already overwritten by payroll-level
upserts or remove duplicate rows left by previous append runs; rebuild affected
destination data from a complete export before relying on incremental updates.
Use full replace for technician_shifts.
Technician shifts can be hard-deleted upstream, requiring
replacement to remove missing rows. Ordinary export upserts do not infer deletes
from records absent in a delta.
Behavior
Export requests setincludeRecentChanges=false, accepting ServiceTitan’s
approximately 15-minute export visibility delay. Each page uses hasMore and
continueFrom, including empty pages. The terminal token is delivered separately
from rows and becomes durable only after successful run commit. Failed runs
replay from the prior committed token. Missing or malformed envelopes and cursor
cycles fail the run. Invalid saved tokens are not silently discarded.
job_types, campaigns, and technician_shifts request active=Any on every
page. Transactional full reads use 5,000-row pages; the two timestamp streams use
1,000-row pages. includeTotal=true is sent on each transactional page.
Exports do not send pageSize. Requests share a 45-per-second limiter across
all resource readers in a run, with a burst of one. There is one reader per selected resource (up to
48); adding readers does not multiply the request budget. Separate runs and
pipelines have independent limiters. Requests use the HTTP engine’s retry
handling for throttling and server errors.
Nested arrays and objects stay JSON. Date/time values remain strings, preserving
seven-digit fractional seconds. Integer IDs use 64-bit integers, and decimal values travel as text to
preserve digits. The trailing raw column retains unprojected properties.
job_history keeps one row per jobId, its complete history array, and nullable
lastEventDate, the lexical maximum nonempty event date.
Export upserts use Filament’s insertion-order version policy. If an export
returns an older version after a newer version, the older record can replace
the newer destination row. Rows are not ordered by modifiedOn or
lastEventDate. Begin with a fresh backfill and keep separate tenants in
separate destination tables or namespaces.