ml-connector
DATEVMicrosoft Dynamics 365 Sales

DATEV and Microsoft Dynamics 365 Sales integration

Microsoft Dynamics 365 Sales runs the order-to-cash front end: leads, opportunities, quotes, orders, and the invoices billed against them. DATEV runs the German accounting and tax backend. Connecting the two means each outgoing sales invoice raised in Dynamics 365 Sales reaches DATEV without re-keying, both as a stored document and as a posted booking against the right revenue and tax accounts. The customer accounts behind those invoices flow the same way so the debtor records in DATEV match the CRM. Because DATEV bookings are write-only and it has no GL read API, posted ledger entries are never pulled back into the CRM.

How DATEV works

DATEV is on-premise accounting (Rechnungswesen) with a cloud document layer (DATEV Unternehmen Online). It is not a single REST API. The accounting:clients product lists the client companies you can access by REST, and accounting:documents uploads invoice PDFs and e-invoices to DUO. Finalized bookings are submitted as EXTF-format CSV files through accounting:extf-files, or as DXSO XML jobs through accounting:dxso-jobs, both asynchronous: you submit, get a job id, and poll until complete. Auth is OAuth 2.0 Authorization Code with PKCE through Login mit DATEV, and a real user must consent, since there is no machine-to-machine flow. There are no webhooks, the full chart of accounts is not readable, and posted journal entries cannot be read back.

How Microsoft Dynamics 365 Sales works

Microsoft Dynamics 365 Sales is built on Microsoft Dataverse and is reached entirely through the Dataverse Web API, an OData v4 REST surface with JSON payloads at a per-environment URL such as https://{org}.api.crm.dynamics.com/api/data/v9.2/. It exposes accounts, contacts, leads, opportunities, quotes, salesorders, and invoices, all readable and writable with GET, POST, and PATCH. Authentication is OAuth 2.0 through Microsoft Entra ID using client credentials, which needs an app registration plus an Application User assigned a security role in the environment. It supports outbound webhooks via the Dataverse event framework and per-entity change tracking with delta tokens for incremental reads. Dynamics 365 Sales has no GL accounts, no AP, and no vendor records.

What moves between them

The flow runs from Microsoft Dynamics 365 Sales into DATEV. ml-connector reads outgoing sales invoices, and the orders and accounts behind them, from Dynamics 365 Sales. Each invoice is uploaded to DATEV Unternehmen Online as a Rechnungsausgang document and is posted into DATEV Rechnungswesen as an EXTF booking batch, mapped to the matching revenue accounts, tax codes, and cost centers. The customer accounts move the same direction so the debtor master in DATEV reflects the CRM. Cadence follows invoice activity in the CRM, batched into periodic file submissions to respect DATEV's preference against high-frequency calls. DATEV bookings are write-only and there is no GL read API, so nothing posts back from DATEV into Dynamics 365 Sales.

How ml-connector handles it

ml-connector stores both credential sets encrypted and bridges two different OAuth models. The Dynamics 365 Sales side uses Microsoft Entra ID client credentials, fully non-interactive, scoped to the environment URL with /.default, and the bearer token is refreshed before its roughly 60-minute expiry. The DATEV side uses Authorization Code with PKCE through Login mit DATEV, which a tax advisor or client must consent to once interactively, after which ml-connector refreshes the 15-minute access token using the refresh token and the client id only, never the client secret. New invoices are detected by Dataverse change tracking delta tokens, or by a registered webhook on GenerateInvoiceFromOrder or a statecode change, while keeping the synchronous endpoint fast. For each invoice ml-connector looks up the DATEV client id, fetches the client-specific document types before upload since they are not fixed, uploads the PDF or e-invoice via the idempotent PUT with a stable GUID, then builds an EXTF CSV booking with UTF-8 NFC-precomposed characters and an allowed-character filename. The EXTF and DXSO jobs are async, so ml-connector submits and polls the job with backoff. Because DATEV detects duplicate files by filename and document type and rejects them, filenames are deterministic so a retry is safe, and a BullMQ jobId dedupes a re-read invoice. Revenue accounts, tax codes, and cost centers are mapped up front, since the DATEV chart of accounts cannot be read back; a sandbox submission only checks structure, so success there is not proof of a correct production posting.

A real-world example

A German engineering services firm with about 120 staff runs Microsoft Dynamics 365 Sales for its pipeline and order-to-cash, raising customer invoices when projects ship, while its tax advisor keeps the books in DATEV. Before the integration, an accountant exported invoices from the CRM each week, emailed the PDFs to the advisor, and re-keyed the figures into DATEV, which delayed VAT-relevant postings and left the debtor list in DATEV out of step with the CRM. With DATEV and Microsoft Dynamics 365 Sales connected, each finalized invoice is uploaded as a Rechnungsausgang document and posted as an EXTF booking on the correct revenue and tax accounts, with the customer carried across as a debtor. The weekly export-and-retype step is gone and the monthly handover to the advisor starts from data already in DATEV.

What you can do

  • Post Microsoft Dynamics 365 Sales outgoing invoices into DATEV as EXTF booking batches on the right revenue and tax accounts.
  • Upload each invoice PDF or e-invoice to DATEV Unternehmen Online as a Rechnungsausgang document using the idempotent GUID-based PUT.
  • Carry Dynamics 365 Sales customer accounts into DATEV as debtor master records so the two stay aligned.
  • Bridge Microsoft Entra ID client credentials with DATEV's interactive Login mit DATEV consent and 15-minute token refresh.
  • Detect new invoices by Dataverse change tracking, submit async DATEV jobs, and poll with retries and a full audit trail.

Questions

Which direction does data move between DATEV and Microsoft Dynamics 365 Sales?
The flow is one way, from Microsoft Dynamics 365 Sales into DATEV. Outgoing sales invoices and their customer accounts move from the CRM into DATEV as DUO documents and EXTF bookings. DATEV bookings are write-only and it has no GL read API, so posted ledger entries are never read back into Dynamics 365 Sales.
How does the integration handle DATEV's asynchronous file imports and lack of webhooks?
DATEV bookings are not a synchronous REST write. ml-connector submits each booking as an EXTF CSV or DXSO XML job, receives a job id, and polls the job endpoint with backoff until it completes or fails, since DATEV sends no webhooks. On the Dynamics side it uses Dataverse change tracking or a registered webhook to learn about new invoices, then batches them into periodic DATEV submissions.
DATEV and Dynamics 365 Sales use different OAuth flows, so how does the connector authenticate both?
They do differ, and ml-connector bridges them. Microsoft Dynamics 365 Sales uses non-interactive Entra ID client credentials scoped to the environment URL. DATEV uses Authorization Code with PKCE through Login mit DATEV, which a tax advisor or client consents to once interactively; after that ml-connector refreshes the short 15-minute token automatically using the client id only, not the client secret.

Related integrations

Connect DATEV and Microsoft Dynamics 365 Sales

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

Get started