JB360 / ServiceTitan Integration — System Overview
Repository:
jbandassociates/st-integration· AWS account 660537473428, us-east-1
What This System Does
Section titled “What This System Does”JB360 connects HVAC/plumbing dealers’ field-service CRMs — ServiceTitan (primary) and Workiz (secondary) — to the JB Warranties extended-warranty platform (public-api.jbwarranties.com / the JB&Associates member portal).
For an onboarded dealer, the system continuously:
- Pulls the dealer’s invoices, locations, and installed equipment out of ServiceTitan into a MySQL staging database (
jbwst). - Matches ServiceTitan locations against the dealer’s existing JB Warranties agreements (stored-procedure matching, with a UI for manual mapping and approval).
- Creates warranty agreements in the JB Warranties platform from approved invoice/equipment data.
- Pushes agreement references and claim statuses back into ServiceTitan (location tags, custom fields, notes, equipment warranty dates, job updates), so technicians see warranty coverage inside their CRM.
- Syncs claims bidirectionally (JBW claim status → staging DB → ServiceTitan jobs).
The Three Modules
Section titled “The Three Modules”| Module | What it is | Stack |
|---|---|---|
jbwui | The JB360 web portal (admin + dealer) at jbw360.jbwarranties.com | React 18 / MUI / CRA, Cognito auth |
jbw-sam | Serverless backend: ~65 Lambdas + API Gateway + SPA hosting (S3/CloudFront), sync orchestration, JBW API integration | AWS SAM, Node.js 20, MySQL via RDS Proxy |
extraction | Heavy-duty per-tenant ServiceTitan sync worker (invoice/equipment pull + agreement/claim push), triggered via SQS | Java 17 / Spring Boot 3 Lambda |
Architecture
Section titled “Architecture”
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/>~65 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&Associates 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
Key End-to-End Flows
Section titled “Key End-to-End Flows”Dealer onboarding
Section titled “Dealer onboarding”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).
Agreement sync & matching
Section titled “Agreement sync & matching”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.
Agreement creation in JBW
Section titled “Agreement creation in JBW”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.
Claims
Section titled “Claims”UI creates potential claims → dealer files in the JB&Associates 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).
Environments
Section titled “Environments”| Production | Staging/Dev | |
|---|---|---|
| UI | jbw360.jbwarranties.com, prod API Gateway stage | stage.env build → dev API Gateway stage |
| Cognito (portal) | pool per .env/samconfig | separate stage pool |
| ServiceTitan | go.servicetitan.com | integration.servicetitan.com |
| SAM stack | jbw-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.
Cross-Cutting Concerns Worth Knowing
Section titled “Cross-Cutting Concerns Worth Knowing”- Auth is attached out-of-band: the SAM template deploys API Gateway with no authorizer; a manually-managed Lambda (
jbwapiauthorizerupdate) attaches the Cognito authorizer after each deploy. See jbw-sam. (Live check 2026-07-07: the authorizer IS currently attached on prod and dev — see 05-deployed-infrastructure.md.) - DB credentials: production paths use RDS IAM auth (no passwords); but plaintext dev creds exist in
extraction/src/main/resources/application.yml. - Hardcoded secrets: ServiceTitan app key + JBW API token in
jbw-sam/template.yaml/samconfig.toml; Workiz token in handler source; AES key injbwui/src/utils/encryption.js. No SSM/Secrets Manager in the SAM stack. - SQL injection surface: both
jbw-samhandlers and parts ofextractionbuild SQL by string interpolation. - Template drift: ~30 Lambda source dirs are not in
template.yaml(console-managed); the template also has an indentation bug that breaks validation (see jbw-sam caveats).
Documentation Map
Section titled “Documentation Map”- 02-extraction.md — Java sync worker
- 03-jbw-sam.md — serverless backend
- 04-jbwui.md — React portal
- Code references: extraction · jbw-sam · jbwui
- Live AWS environment: aws/ — inventory, schedules, queues, network, database