Skip to main content

ServiceTitan

Sync customers from a connected ServiceTitan account into AutoRev leads in one call. The integration must be connected first in Settings > Integrations on the AutoRev dashboard.

Sync customers

POST /api/v1/integrations/servicetitan/sync-customers pulls ServiceTitan customers and upserts them as leads in a new auto-tagged list. Scope: write_crm.

What it does

The endpoint reads your tenant's stored ServiceTitan credentials and paginates ServiceTitan's /crm/v2/customers, then fans out /customers/:id/contacts per customer (10 concurrent) to pull phones, emails, and per-contact preferences. TCPA-sensitive fields are filtered automatically (doNotText, marketingUpdatesEnabled: false). Each lead is enriched with balance, ServiceTitan tags, last job date, and the contact memo.

Request options

All fields are optional:

{
"since": "2025-10-21T00:00:00Z",
"with_phone_only": true,
"line_type_filter": "Mobile",
"active_only": true,
"tag": "spring-promo-2026",
"list_name": "ST Spring Sync",
"dry_run": false,
"max_customers": 5000
}
FieldDefaultNotes
since12 months agoOnly pull customers modified since this timestamp
with_phone_onlytrueSkip customers without a phone
line_type_filter"Mobile"Or "Any"
active_onlytrueSkip inactive customers
tagst-sync-YYYY-MM-DDTag applied to every imported lead
list_nameServiceTitan Sync YYYY-MM-DDName of the auto-created list
dry_runfalseSet true to preview counts without DB writes
max_customers5000Hard cap; max 20000

Response

{
"pulled": 959,
"eligible": 896,
"inserted": 885,
"skipped_in_import": [
{ "phone": "+15551234567", "reason": "duplicate_in_list" }
],
"skipped_by_reason": {
"inactive": 0,
"garbage_name": 3,
"no_phone": 21,
"wrong_phone_type": 18,
"do_not_text": 4,
"marketing_opt_out": 10,
"contacts_fetch_failed": 7
},
"list_id": "a1b2c3d4-...",
"list_name": "ServiceTitan Sync 2026-04-20",
"tag_applied": "spring-promo-2026",
"pull_duration_ms": 805,
"contact_fetch_duration_ms": 43829,
"enrichment_duration_ms": 7545
}

Skip reasons:

ReasonMeaning
inactiveCustomer not active (when active_only is on)
garbage_namePlaceholder records (Live Transfer / Test / etc.)
no_phoneNo phone on file
wrong_phone_typeLandline-only when the Mobile filter is on
do_not_textServiceTitan doNotText = true
marketing_opt_outServiceTitan marketingUpdatesEnabled = false
contacts_fetch_failedThe per-customer contacts fetch failed

custom_fields enrichment

Each imported lead's custom_fields carries: external_id (formatted st:<id>), st_tag_type_ids, balance_dollars, marketing_updates_enabled, job_reminders_enabled, last_job_at, days_since_last_job, do_not_mail, do_not_service. ServiceTitan customer tags are resolved to readable names (for example VIP, Warranty) and applied to the lead's tags array.

End-to-end promo flow (2 calls)

  1. Call this endpoint to sync. Note the tag_applied value in the response.
  2. Call POST /api/v1/campaigns with target: { "tag": "<tag_applied>" }.

Done: the campaign targets exactly the leads this sync imported.