Back to Blog

ServiceTitan API Tutorial: How to Pull Jobs, Customers, and Revenue Data Into Your Own Tools

Pipeline Research Team
Blog

Key Takeaways

  • ServiceTitan's API is REST over HTTPS with OAuth 2.0, tenant-scoped, and access is gated behind an application and review process - not self-serve
  • Most contractor integrations live in five endpoint groups: /jobs, /customers, /invoices, /technicians, and /reporting
  • You need three values to authenticate every request: Tenant ID, App Key, and a Client ID and Secret pair from the developer portal
  • Certified apps appear in the ServiceTitan marketplace and can be installed by any customer - uncertified apps are restricted to specific tenants you control
  • Most attribution and BI integrations use webhook-driven job-completion events, not polling, to avoid burning through rate limits

ServiceTitan stores every job, customer, and invoice your business runs. Their API lets you pull that data into Google Sheets, your BI dashboard, or your attribution stack - but the developer portal is not open access, and the gotchas will burn two days if you do not know them upfront. This is the technical walkthrough most contractor agencies wish they had before they started.

What can the ServiceTitan API actually do?

The ServiceTitan API is REST over HTTPS, JSON request and response bodies, OAuth 2.0 authentication. If you have built against Stripe, HubSpot, or any modern SaaS API, the shape will be familiar - resources are exposed as predictable URLs, you authenticate with a bearer token, and you get standard HTTP status codes back.

What makes it different is the tenant model. Every contractor on ServiceTitan has a tenant ID, and every API request is scoped to one tenant. You cannot pull data across multiple contractors with a single token. If you run an agency managing 30 ServiceTitan customers, you need 30 sets of credentials.

The practical use cases break into four groups. Marketing attribution - pulling booked jobs and revenue back to ad campaigns. BI and reporting - feeding ServiceTitan data into Looker, Power BI, or a custom dashboard. Operational sync - pushing leads from a website or marketing platform into ServiceTitan as new customers. And customer-facing tools - service-history portals, price calculators, or scheduling flows beyond what the standard widget supports.

This is the technical layer underneath the ServiceTitan website integration options. The booking widget and tracking pixel are pre-built. The API is where you go when the pre-built options stop being enough.

How do you get API access?

This is the first wall most developers hit. ServiceTitan’s developer portal is not self-serve. You cannot sign up with an email address and start making calls in five minutes.

To get API access, you need three things in order. First, an active ServiceTitan customer account with API entitlement enabled - some contractor plans do not include this by default, and you may need to call your account rep. Second, a developer portal account, which requires an application describing your integration and the tenants you intend to connect to. Third, an approved App Key, which is the identifier ServiceTitan uses to track every request your integration makes.

Expect the review to take one to four weeks. ServiceTitan asks what data you need, why, how you will store it, and whether you are building for a single contractor or pursuing certification. Agencies and internal tools move faster than vendor apps targeting the marketplace.

ServiceTitan separates apps into two categories that matter a lot for what you can ship. Uncertified apps are restricted to specific tenants you authorize - they work for internal use, agency dashboards, or one-off integrations with a single contractor. Certified apps go through a full review process (security, documentation, working integration) and end up listed in the ServiceTitan marketplace where any of their 10,000-plus contractor customers can install them. Certification takes weeks to months and is overkill for most projects.

If your goal is “pull our own ServiceTitan data into our own BI tool,” you want uncertified. If your goal is “build an integration any HVAC company can buy,” you want certified.

How do you authenticate to the ServiceTitan API?

ServiceTitan uses OAuth 2.0 with the client credentials grant. Every authenticated request needs three values that came out of the developer portal: a Tenant ID (per contractor), an App Key (one per app, sent as the ST-App-Key header), and a Client ID and Client Secret pair (used to fetch the bearer token).

The flow is straightforward. POST your Client ID and Client Secret to the auth.servicetitan.io token endpoint. You get back a short-lived bearer token (typically valid for an hour or so - check current docs). Send that token in the Authorization header on every API request, along with the App Key header.

When the token expires, you get a 401 and refresh it. Most production integrations either refresh on a timer just before expiry or catch the 401, refresh, and retry the original call automatically.

The mistake people make here is confusing the App Key with the Client ID. They are different values doing different jobs. The App Key identifies your app to ServiceTitan globally and goes in a header on every request. The Client ID and Secret are credentials used once per session to get a bearer token. Mix them up and you will get 401s that look like an auth bug when really you have your envs swapped.

What endpoints do contractors actually need?

The full API surface is large, but in practice contractor integrations live in five endpoint groups.

/jobs is the workhorse. Returns the job record - customer, address, business unit, job type, status, completion date, technician, and revenue once invoiced. The list endpoint supports filtering by date, status, and modification time, which is what makes incremental syncs possible. Most attribution integrations start here.

/customers holds the customer record. Name, contact info, address, custom fields. You hit this endpoint to look up existing contacts before creating duplicates, or to enrich a job pull with customer-level data the job endpoint does not return inline.

/invoices is where the actual money lives. A job becomes an invoice when it is completed and billed. If you are calculating real booked revenue (not estimated job value), you want invoice data. The invoice endpoint also exposes line items, which matter if you are reporting by service category instead of by job.

/technicians maps job IDs to specific techs. Useful for performance reporting, payroll integrations, and any dashboard that slices revenue by technician.

/reporting is the pre-built reports surface. ServiceTitan has internal reports (booked revenue by campaign, lead source breakdown, sold revenue by business unit) exposed through this endpoint. If a report already exists inside ServiceTitan’s UI, you can usually pull it through the reporting API instead of reconstructing it from raw jobs and invoices.

This is also where the line between API work and Marketing Pro work gets blurry. Many of the marketing reports - especially anything tied to ad attribution - depend on having the ServiceTitan and Google Ads integration configured correctly upstream. The API can pull the data, but only if Marketing Pro is populating it in the first place.

Sample: pulling completed jobs in Node.js

Here is the rough shape of a “list jobs completed in the last 24 hours” call. This is illustrative, not copy-paste production code - you will need to handle token refresh, pagination, and error retries.

// 1. Get a bearer token from the OAuth endpoint
const tokenResp = await fetch('https://auth.servicetitan.io/connect/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'client_credentials',
    client_id: process.env.ST_CLIENT_ID,
    client_secret: process.env.ST_CLIENT_SECRET,
  }),
});
const { access_token } = await tokenResp.json();

// 2. Pull jobs modified in the last 24 hours for one tenant
const since = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
const tenantId = process.env.ST_TENANT_ID;

const jobsResp = await fetch(
  `https://api.servicetitan.io/jpm/v2/tenant/${tenantId}/jobs?modifiedOnOrAfter=${since}&page=1&pageSize=50`,
  {
    headers: {
      'Authorization': `Bearer ${access_token}`,
      'ST-App-Key': process.env.ST_APP_KEY,
    },
  }
);
const jobs = await jobsResp.json();

A few things to notice. The tenant ID lives in the URL path - this is how requests are scoped. The App Key goes in the ST-App-Key header alongside the bearer token. The modifiedOnOrAfter filter is what makes incremental syncs possible without re-pulling every job every run.

Pagination is required for any real dataset. ServiceTitan returns paginated responses with hasMore flags. A contractor running 30 jobs a day across the last year has roughly 10,000 jobs - you will not get them in a single page no matter what page size you ask for. Build the pagination loop on day one or your sync will silently truncate.

What rate limits and gotchas should you know about?

ServiceTitan publishes rate limits per tenant and per endpoint, and the numbers shift - always check the current developer portal docs for your account rather than trusting a number from a blog post. The general shape: limits are generous enough for normal sync workloads but punitive enough to break naive polling.

The pattern that scales: use webhooks for event-driven data, use polling only for backfills and reconciliation. ServiceTitan supports webhooks for job lifecycle events (booked, completed, invoiced) and customer events. A job-completion webhook fires the moment the tech closes the call, and your attribution system tags the campaign right then - no polling needed.

Most attribution integrations on the platform use exactly this pattern. The CallRail to ServiceTitan integration pushes call data into ServiceTitan via the ExternalCallAttributions API and reads back job outcomes via webhook. Polling is reserved for backfill jobs and end-of-day reconciliation.

A few specific gotchas that catch people:

Tenant ID is not the same as account ID. ServiceTitan has multiple internal IDs and developers regularly use the wrong one in the URL path, then get cryptic 404s. The tenant ID is the one issued to you in the developer portal alongside the App Key.

Some endpoints require Marketing Pro or other add-on packages. Pulling /reporting data for campaign-level revenue, for example, only works if the customer has the Marketing Pro Ads Package on their license. The API will return a permission error rather than empty results, but the error message does not always make the missing-package situation obvious.

Custom fields are not returned by default. If a contractor has set up custom fields on jobs or customers (lead source, referral name, special tags), you usually have to request them explicitly via the includeCustomFields query parameter. Forget this and your “lead source” column will look empty even though the data is there.

Timezones are sneaky. ServiceTitan returns timestamps in a mix of UTC and local time depending on the endpoint. Anchor everything to UTC in your storage layer and convert at display time, or your “jobs completed yesterday” report will be wrong by 8 hours half the year.

Should you build it yourself or use an integration partner?

This depends on how much of the work is “pull data” versus “interpret the data.”

Pure data pulls are well within reach of any backend engineer. A node script that calls /jobs nightly and writes to BigQuery or Postgres is a one-week project. The credentials take longer to get than the integration takes to build.

The harder problem is what to do with the data once you have it. Marketing attribution, for example, is not just “pull the booked revenue field” - it is matching that revenue back to the original click, ad, keyword, and visitor session. That is where most home-grown integrations get stuck and where the build-vs-buy math starts to favor an integration partner.

If you are building a contractor BI dashboard, raw API access is plenty. If you are building marketing attribution from scratch, you will rebuild a meaningful chunk of what marketing attribution tools for HVAC and plumbing already do - call tracking, multi-touch attribution, Google Ads offline conversion import for contractors, and the conversion tracking guide layer. Read those before you start writing code; you may find the build is bigger than the ROI.

For visitor-to-ServiceTitan attribution specifically, Pipeline already handles the visitor identification, contact creation, and job-source matching against the ServiceTitan API - see the Pipeline ServiceTitan integration for what that flow looks like end-to-end, and the home service marketing attribution overview for how the broader stack fits together.

Whichever route you take, get the credentials process started this week. The application takes minutes, the review takes weeks, and nothing else moves until the App Key is in your hand.

Frequently Asked Questions