ml-connector
Microsoft Dynamics 365 Business CentralServiceTitan

Microsoft Dynamics 365 Business Central and ServiceTitan integration

Microsoft Dynamics 365 Business Central runs finance, the general ledger, and the chart of accounts. ServiceTitan runs field service operations: dispatch, jobs, customer records, invoicing, and payments for home and commercial trades. Connecting the two carries the revenue ServiceTitan books in the field into Business Central as accounting records without re-keying, and keeps the customer master and price list aligned across both systems. Job invoices and the payments applied against them post into Business Central as sales invoices and customer payments, coded to the right GL dimensions. ml-connector handles the very different authentication on each side and uses ServiceTitan webhooks to react as soon as an invoice is finalized or a payment is taken.

How Microsoft Dynamics 365 Business Central works

Microsoft Dynamics 365 Business Central exposes customers, sales invoices, items, GL accounts, general ledger entries, dimensions, and customer payment journals through the Business Central API v2.0, a REST API built on OData v4 with JSON payloads. Authentication uses Microsoft Entra ID OAuth 2.0 client credentials in the service-to-service flow, scoped to a tenant and a named environment such as production, so the base URL is tenant-specific and every resource nests under a company. The chart of accounts and general ledger entries are read-only, while customers, items, and sales invoices support writes; a sales invoice is created as a draft and posted with the Microsoft.NAV.post bound action. Business Central can push change notifications by subscription, but a notification carries no record data and subscriptions expire every three days, so records are read by polling with a lastModifiedDateTime filter for delta sync.

How ServiceTitan works

ServiceTitan exposes its data through the ServiceTitan V2 API, a REST API over JSON organized into namespaces such as accounting, crm, inventory, and settings. Authentication uses OAuth 2.0 client credentials to obtain a bearer token that is valid for fifteen minutes and must be cached, and every call also carries an ST-App-Key header and the numeric tenant ID embedded in the URL path. Invoices, payments, and customers are readable and writable, while AP inventory bills are read-only and are generated only when a purchase order is received with auto-create-bill enabled. ServiceTitan has no chart-of-accounts API; GL mapping lives inside its accounting settings UI, and business units serve as the primary cost-center dimension. ServiceTitan pushes events such as invoice.created, invoice.updated, and payment.created by webhook, signed HMAC-SHA256 in the x-servicetitan-signature header.

What moves between them

The flow runs in both directions, split by system of record. From ServiceTitan into Microsoft Dynamics 365 Business Central, ml-connector reads finalized job invoices and the payments applied against them and posts them as Business Central sales invoices and customer payment journal lines, with each ServiceTitan business unit mapped to a Business Central dimension so revenue is coded correctly. The customer master is aligned the same direction so Business Central reflects new and changed ServiceTitan customers. From Business Central into ServiceTitan, ml-connector can push items into the ServiceTitan pricebook as services or materials so field pricing matches the ERP. Customers flow before invoices, because a Business Central sales invoice needs an existing customer. The Business Central chart of accounts stays the source of truth, since ServiceTitan has no GL accounts to write back to.

How ml-connector handles it

ml-connector stores both credential sets encrypted. On the Business Central side it requests an Entra ID OAuth 2.0 client-credentials token, scopes every call to the tenant and the configured environment name, and refreshes the token before expiry. On the ServiceTitan side it obtains a bearer token, caches it for its short fifteen-minute life rather than re-requesting per call, and attaches the ST-App-Key header and the tenant ID in the path on every request. Customers are synced before invoices, because a Business Central sales invoice cannot post against a customer that does not exist; each ServiceTitan business unit is mapped to a Business Central dimension, which is how revenue gets a cost center given that ServiceTitan exposes no GL chart. Incoming work is event-driven: ml-connector subscribes to ServiceTitan invoice and payment webhooks, verifies the HMAC-SHA256 signature in the x-servicetitan-signature header against the raw JSON body before processing, then creates and posts the matching Business Central sales invoice or customer payment. Because ServiceTitan replay tooling is still being rolled out, the connector also polls ServiceTitan on a schedule as a backstop, and on the Business Central side polling uses a lastModifiedDateTime filter since notifications carry no payload and expire every three days. Neither system offers an idempotency-key header, so ml-connector dedupes on the ServiceTitan invoice or payment ID and a BullMQ jobId before posting to Business Central. ServiceTitan enforces a hundred-second request timeout and sixty calls per second, and Business Central returns HTTP 429 when throttled, so the connector backs off with jitter and queues rather than fanning out. ServiceTitan AP bills are read-only and derived from received purchase orders, so the connector treats them as a source to read, never a target to write. Every record carries a full audit trail and can be replayed if a downstream call fails.

A real-world example

A regional HVAC and plumbing contractor with roughly 150 field technicians runs ServiceTitan for dispatch, job invoicing, and payments, and uses Microsoft Dynamics 365 Business Central for finance and the general ledger. Before the integration, the accounting team exported invoice and payment registers from ServiceTitan and re-entered the totals into Business Central by hand, splitting revenue across departments manually and chasing differences during month-end close. With Microsoft Dynamics 365 Business Central and ServiceTitan connected, each finalized job invoice and the payment taken against it post into Business Central automatically the moment the ServiceTitan webhook fires, coded to the dimension that matches the originating business unit, and the customer master stays aligned across both systems. The manual re-keying step disappears and close starts from revenue that already reconciles.

What you can do

  • Post ServiceTitan job invoices into Microsoft Dynamics 365 Business Central as sales invoices coded to the right GL dimension.
  • Record ServiceTitan payments in Business Central as customer payment journal lines applied to the matching invoice.
  • Keep the customer master aligned so every Business Central sales invoice posts against a valid customer.
  • Push Business Central items into the ServiceTitan pricebook as services or materials so field pricing matches the ERP.
  • Bridge Microsoft Entra ID OAuth on the ERP side and the ServiceTitan bearer token plus ST-App-Key, with webhooks, dedup, retries, and a full audit trail.

Questions

Which direction does data move between Microsoft Dynamics 365 Business Central and ServiceTitan?
It moves both ways, split by system of record. Finalized job invoices and the payments applied to them are read from ServiceTitan and posted into Business Central as sales invoices and customer payment journal lines, with customers aligned the same direction. Business Central items can push into the ServiceTitan pricebook so field pricing matches the ERP. The Business Central chart of accounts stays authoritative because ServiceTitan exposes no GL accounts to write back to.
How does the integration handle GL coding when ServiceTitan has no chart of accounts?
ServiceTitan has no chart-of-accounts API, so GL coding is resolved on the Business Central side. ml-connector maps each ServiceTitan business unit, which is ServiceTitan's primary cost-center dimension, to a Business Central dimension. When a ServiceTitan invoice posts into Business Central as a sales invoice, that mapping gives the revenue a valid dimension so it lands in the right place in the ledger.
Does ServiceTitan push events, or does ml-connector poll for new invoices and payments?
ServiceTitan supports V2 webhooks, and ml-connector uses them as the primary trigger. It subscribes to invoice and payment events and verifies the HMAC-SHA256 signature in the x-servicetitan-signature header against the raw body before acting. Because ServiceTitan replay tooling is still rolling out, the connector also polls ServiceTitan on a schedule as a backstop, and on the Business Central side it polls with a lastModifiedDateTime filter since notifications carry no payload and expire every three days.

Related integrations

Connect Microsoft Dynamics 365 Business Central and ServiceTitan

Free to use. Add your credentials, ping your real systems, and see if we fit.

Get started