Skip to content

JB360 / ServiceTitan Integration — System Overview

Repository: jbandassociates/st-integration · AWS account 660537473428, us-east-1

JB360 connects HVAC/plumbing dealers’ Field Service Management Systems (FSMs) — ServiceTitan and Workiz — to the JB Warranties extended-warranty platform (public-api.jbwarranties.com / the JB Warranties member portal).

For an onboarded dealer, the system continuously:

  1. Pull — invoices, locations, and installed equipment out of ServiceTitan into the MySQL staging database (jbwst).
  2. Match — ServiceTitan locations against the dealer’s existing JB Warranties agreements (stored-procedure matching; UI for manual mapping and approval).
  3. Create — warranty agreements in the JB Warranties platform from approved invoice/equipment data.
  4. Write back — agreement references and claim statuses into ServiceTitan (location tags, custom fields, notes, equipment warranty dates, job updates), so technicians see coverage inside their FSM.
  5. Sync claims — JBW claim status → staging DB → ServiceTitan jobs.
ModuleWhat it isStack
jbwuiThe JB360 web portal (admin + dealer) at jbw360.jbwarranties.comReact 18 / MUI / CRA, Cognito auth
jbw-samServerless backend: 63 templated Lambdas (+44 untemplated) + API Gateway + SPA hosting (S3/CloudFront), sync orchestration, JBW API integrationAWS SAM, Node.js 20, MySQL via RDS Proxy
extractionHeavy-duty per-tenant ServiceTitan sync worker (invoice/equipment pull + agreement/claim push), triggered via SQSJava 17 / Spring Boot 3 Lambda

Two paths matter. The interactive path (left/top): the browser loads the SPA from CloudFront and calls API Gateway with a Cognito JWT; jbw-sam Lambdas serve those requests against the jbwst database and the ServiceTitan / JB Warranties APIs. The batch path: EventBridge schedules fire jbw-sam orchestrators, which drop one SQS message per active tenant; each message triggers the Java extraction Lambda, which pulls that tenant’s data from ServiceTitan and pushes agreements/claims back into it. Claims UI additionally embeds the JB Warranties member portal in iframes.

flowchart TB
Browser["<b>Browser</b><br/>jbw360.jbwarranties.com"]:::ui

subgraph AWS["AWS · us-east-1"]
  direction TB
  CF["<b>CloudFront + S3</b><br/>jbwui SPA"]:::aws
  APIGW["<b>API Gateway</b><br/>Cognito-authorized"]:::aws
  Lambdas["<b>jbw-sam</b><br/>107 Node.js Lambdas"]:::aws
  EB["<b>EventBridge</b><br/>daily / hourly schedules"]:::aws
  SQS["<b>SQS</b> prodtenantList<br/>one message per tenant"]:::aws
  EXT["<b>extraction</b><br/>Java 17 Lambda · per-tenant sync"]:::aws
  SES["<b>SES</b><br/>notification emails"]:::aws
  DB[("<b>MySQL jbwst</b><br/>RDS Proxy · IAM auth<br/>44 tables · 10 stored procs")]:::db
end

subgraph EXTS["External services"]
  direction LR
  STAPI["<b>ServiceTitan API</b><br/>api.servicetitan.io"]:::ext
  JBWAPI["<b>JB Warranties API</b><br/>public-api.jbwarranties.com"]:::ext
  WKAPI["<b>Workiz API</b>"]:::ext
  Portal["<b>JB Warranties portal</b><br/>claims iframes"]:::ext
end

Browser --> CF
Browser -->|REST + JWT| APIGW --> Lambdas
EB --> Lambdas
Lambdas --> SES
Lambdas <--> DB
Lambdas -->|getTenantInfo| SQS --> EXT
EXT <--> DB
EXT <-->|invoices in · tags & claims out| STAPI
Lambdas <-->|locations · verification| STAPI
Lambdas <-->|agreements · claim status| JBWAPI
Lambdas --> WKAPI
Browser -.-> Portal

classDef ui fill:#dbeafe,stroke:#3b82f6,color:#1e3a8a,stroke-width:1.5px
classDef aws fill:#fff7ed,stroke:#f59e0b,color:#7c2d12,stroke-width:1.5px
classDef db fill:#dcfce7,stroke:#22c55e,color:#14532d,stroke-width:1.5px
classDef ext fill:#f3e8ff,stroke:#a855f7,color:#581c87,stroke-width:1.5px

jbwui wizard → POST /newdealeronboard (jbwnewonboarding) → verifies ServiceTitan credentials and required tags/custom fields (JBWClientServiceTitanVerification) or Workiz account → stores tenant config in tblTenant/tblDealerOnboard → kicks off an initial data match (jbwagreementsdatamatch).

GET /agreementsync/{dealer}/spcall (UI “Sync Data” button, per tenant) → jbwagreementsdatamatch pulls JBW agreements → tblJBWAgreementData and ST locations → tblSTLocationData (Workiz: job locations → tblWorkizLocationData) → stored proc jbw_st_dataSync matches them → UI grid (Map Location / Pending Approval / Approved) → PUT /agreementsync/approve.

PUT /agreements/{id}/equipmentsync (jbwservicetitansagreementspull) builds the payload from tblAgreement + tblAgreementEquipments and POSTs to the JBW agreements API; writes back jbwAgreementId, PDF URL, warranty dates, status SAVED.

Per-tenant ServiceTitan sync (the extraction loop)

Section titled “Per-tenant ServiceTitan sync (the extraction loop)”

EventBridge Scheduler → getTenantInfo → one SQS message per active tenant (tenantId, dealerId, ST OAuth creds, batchId, syncStartDate) → extraction Java Lambda: pulls invoices/contacts/equipment into the DB, pushes PAID agreements (isSentToST=0) and ready claims (isReadyForST=1) into ServiceTitan as tags/custom fields/notes/job updates → audit row in tblTransmissionDetails(+History), visible in the UI Transaction Log.

UI creates potential claims → dealer files in the JB Warranties iframe → PATCH /claims/stupdate (jbwclaimsstupdate) pulls the JB360ClaimStatus view from the JBW API, updates tblClaims, and flags rows for the next extraction run to push into ServiceTitan jobs (Filed/Paid/Declined tags + custom fields).

ComponentProductionStaging/Dev
UIjbw360.jbwarranties.com, prod API Gateway stagestage.env build → dev API Gateway stage
Cognito (portal)pool per .env/samconfigseparate stage pool
ServiceTitango.servicetitan.comintegration.servicetitan.com
SAM stackjbw-prod-api (only stack in samconfig.toml)none defined in repo

Git history is release-based (“January Release”, “Spring Release Changes”, “Renewal Functionality changes”), roughly quarterly.