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
}
| Field | Default | Notes |
|---|---|---|
since | 12 months ago | Only pull customers modified since this timestamp |
with_phone_only | true | Skip customers without a phone |
line_type_filter | "Mobile" | Or "Any" |
active_only | true | Skip inactive customers |
tag | st-sync-YYYY-MM-DD | Tag applied to every imported lead |
list_name | ServiceTitan Sync YYYY-MM-DD | Name of the auto-created list |
dry_run | false | Set true to preview counts without DB writes |
max_customers | 5000 | Hard 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:
| Reason | Meaning |
|---|---|
inactive | Customer not active (when active_only is on) |
garbage_name | Placeholder records (Live Transfer / Test / etc.) |
no_phone | No phone on file |
wrong_phone_type | Landline-only when the Mobile filter is on |
do_not_text | ServiceTitan doNotText = true |
marketing_opt_out | ServiceTitan marketingUpdatesEnabled = false |
contacts_fetch_failed | The 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)
- Call this endpoint to sync. Note the
tag_appliedvalue in the response. - Call
POST /api/v1/campaignswithtarget: { "tag": "<tag_applied>" }.
Done: the campaign targets exactly the leads this sync imported.