ml-connector
Microsoft Dynamics 365 F&OServiceTitan

Microsoft Dynamics 365 F&O and ServiceTitan integration

Microsoft Dynamics 365 F&O runs corporate financials, accounts payable, and the general ledger. ServiceTitan runs field-service dispatch, job invoicing, payments, and purchasing for home and commercial service businesses. Connecting the two means the invoices, payments, and supplier bills generated in the field flow into the ERP without re-keying, and the customer and vendor masters stay in agreement. ml-connector handles the different APIs on each side and moves the data on a schedule you control. Because ServiceTitan exposes no general ledger chart-of-accounts API, the GL stays in Microsoft Dynamics 365 F&O where it belongs.

How Microsoft Dynamics 365 F&O works

Microsoft Dynamics 365 F&O exposes vendors, customers, purchase orders, vendor invoices, customer invoices, main accounts, general journal entries, and financial dimensions through OData v4 at a tenant-specific environment URL under the /data/ path, so there is no shared hostname. It authenticates with Microsoft Entra ID OAuth 2.0 using the client-credentials flow, and Bearer tokens expire after about an hour and are refreshed by re-requesting. There is no traditional webhook API; the Business Events framework can push lightweight JSON payloads to an HTTPS endpoint on actions like invoice posted, but those payloads carry identifiers rather than full records, so the handler reads back over OData. Posted general journal entries are read-only.

How ServiceTitan works

ServiceTitan exposes its data through the V2 REST API, scoped by namespace and tenant ID in the URL path. Job invoices and payments sit in the accounting namespace, customers in crm, purchase orders and vendors in inventory, and business units in settings. It authenticates with OAuth 2.0 client credentials plus a required ST-App-Key header, and access tokens last 15 minutes and must be cached. AP bills are not directly writable; ServiceTitan generates an inventory bill when a purchase order with auto-create-bill enabled is received. ServiceTitan can push V2 webhooks signed with HMAC-SHA256, and it exposes no general ledger chart-of-accounts endpoint.

What moves between them

The main flow runs from ServiceTitan into Microsoft Dynamics 365 F&O. ml-connector reads ServiceTitan job invoices and the payments applied against them and posts them into D365 F&O as customer invoices and customer payments, mapped to the matching D365 customers and main accounts. The inventory bills ServiceTitan derives from received purchase orders flow the same direction and post as D365 vendor invoices. Customer and vendor records move into D365 so the masters reflect ServiceTitan accounts, and business units are aligned to D365 financial dimensions so each line lands on a valid cost center. ServiceTitan has no GL endpoint, so the general ledger stays in D365 and ml-connector never writes ledger entries back to ServiceTitan.

How ml-connector handles it

ml-connector stores both credential sets encrypted. On the ServiceTitan side it requests a client-credentials token, caches it for its 15-minute life, and sends it with the ST-App-Key header on every call, embedding the tenant ID in each namespace path. On the D365 side it accepts the tenant environment host per customer, since D365 publishes no shared base URL, requests an Entra ID Bearer token, and refreshes it when a call returns 401. ServiceTitan inventory bills cannot be created over the API, so ml-connector reads the bills ServiceTitan generates from received purchase orders and posts them as D365 vendor invoices. Because the D365 VendorInvoiceHeader is writable only before posting, headers are created before lines and left unposted for approval. Customers and vendors are mapped first so every invoice references a master that already exists, and ServiceTitan business units map to D365 financial dimensions, which must be passed as the configured display string. Neither side offers an idempotency key, so ml-connector dedupes on the ServiceTitan record id and a BullMQ jobId before posting, and uses the natural D365 key, such as InvoiceNumber plus VendorAccount, to avoid a duplicate-key error on a re-read record. Where ServiceTitan webhooks are enabled it can take an HMAC-SHA256 verified invoice or payment push as a trigger, while a scheduled poll backfills anything a webhook missed. ServiceTitan rate limits at 60 calls per second per tenant and D365 returns HTTP 429 with a Retry-After header, so ml-connector backs off and retries within both limits. 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 250 employees across several branches runs ServiceTitan for dispatch, job invoicing, and parts purchasing, and runs Microsoft Dynamics 365 F&O as the corporate ERP for accounts payable and the general ledger. Before the integration, an accounting clerk exported invoice and payment reports from ServiceTitan each week and keyed the totals into D365 by hand, and supplier bills from received purchase orders were re-entered a second time, so revenue posted late, branch costs were sometimes booked to the wrong dimension, and month-end close started with the field numbers out of sync with the ledger. With Microsoft Dynamics 365 F&O and ServiceTitan connected, each job invoice, payment, and inventory bill flows into D365 within the polling window, allocated to the correct customer, vendor, and financial dimension. The re-keying is gone, branch costs land on the right cost center, and close starts from reconciled numbers.

What you can do

  • Post ServiceTitan job invoices and applied payments into Microsoft Dynamics 365 F&O as customer invoices and payments.
  • Post ServiceTitan inventory bills derived from received purchase orders into D365 F&O as vendor invoices.
  • Keep D365 customer and vendor masters aligned with ServiceTitan accounts and suppliers.
  • Map ServiceTitan business units to D365 financial dimensions so field-service revenue and AP land on valid accounts.
  • Bridge ServiceTitan OAuth with the ST-App-Key header to Entra ID OAuth, with dedup, retries, and a full audit trail on every record.

Questions

Which direction does data move between Microsoft Dynamics 365 F&O and ServiceTitan?
The main flow is ServiceTitan into Microsoft Dynamics 365 F&O. Job invoices, payments, inventory bills, customers, and vendors move from ServiceTitan into D365 as customer invoices, payments, vendor invoices, and master records. ServiceTitan exposes no general ledger chart-of-accounts API, so the GL stays in D365 and ml-connector never writes ledger entries back to ServiceTitan.
How are ServiceTitan AP bills handled, since they cannot be created over the API?
ServiceTitan does not let you POST a bill directly. It generates an inventory bill when a purchase order with auto-create-bill enabled is received, so ml-connector reads that derived bill and posts it into D365 F&O as a vendor invoice. The D365 vendor invoice header is created before its lines and left unposted, since the header is only writable before posting.
Does ServiceTitan push records, or does ml-connector poll for them?
Both are supported. ServiceTitan can push V2 webhooks signed with HMAC-SHA256, so invoice and payment events are verified and used as triggers. A scheduled poll over the V2 REST API still runs to backfill anything a webhook missed, and D365 itself is read and written over OData on a schedule because its Business Events carry only identifiers.

Related integrations

Connect Microsoft Dynamics 365 F&O and ServiceTitan

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

Get started