ml-connector
DATEVZendesk

DATEV and Zendesk integration

DATEV runs accounting, bookings, and tax for German businesses through its on-premise engine and cloud document layer. Zendesk runs customer support: tickets, the customers who raise them, and the organizations they belong to. Connecting the two keeps a Zendesk organization aligned with the matching DATEV client, and turns billable support work into accounting records without re-keying. Because Zendesk has no invoices, purchase orders, or general ledger, ml-connector shapes the integration around what Zendesk does hold, the support and account records, and feeds DATEV the documents and bookings it expects. ml-connector handles the very different APIs on each side and moves the data on a schedule you control.

How DATEV works

DATEV is not a conventional REST API. The accounting:clients API reads the companies (clients) a user can access, and the accounting:documents API uploads invoice and receipt PDFs to DATEV Unternehmen Online, both over OAuth2 REST. Finalized bookings go to the on-premise DATEV Rechnungswesen engine as asynchronous EXTF CSV file imports, and booking suggestions go to DUO as asynchronous DXSO XML jobs; both return a job id you poll until processing completes. DATEV has no webhooks, so every result is read by polling. The chart of accounts and posted journal entries cannot be read back through the API, and creditor and debtor master data is embedded in the EXTF file rather than exposed as an endpoint.

How Zendesk works

Zendesk is a pure SaaS customer support platform with a REST Support API scoped to the customer's subdomain, reached at https://{subdomain}.zendesk.com/api/v2/ over TLS 1.2 or higher. It exposes tickets, users, organizations, and groups for read and write, with bulk and incremental export endpoints for large or delta pulls. Organizations carry an external_id field that holds a foreign key back to an external system, which is the natural anchor to a DATEV client. Zendesk pushes events by webhook signed with HMAC-SHA256, but ticket events require the webhook to be wired to a trigger or automation, while user and organization events can subscribe to the event type directly.

What moves between them

The flow runs in two parts. Account data flows from Zendesk into DATEV: when a Zendesk organization is created or updated, ml-connector aligns it to the matching DATEV client and carries the company name, address, and tax details into the creditor and debtor master rows of the EXTF file. Billable support activity also flows from Zendesk into DATEV: a billable, solved Zendesk ticket becomes an invoice document uploaded to DATEV Unternehmen Online and a booking submitted as an EXTF CSV or DXSO XML job. Nothing financial flows back to Zendesk, because Zendesk has no invoice, purchase order, or general ledger object and DATEV will not return posted journal entries. The Zendesk organization external_id holds the DATEV client id so each record resolves to the correct company.

How ml-connector handles it

ml-connector stores both credential sets encrypted. On the Zendesk side it runs the OAuth2 authorization code flow against the customer's subdomain and sends the bearer token on every call, scoping each request to that subdomain since Zendesk has no global endpoint. On the DATEV side it runs OAuth2 authorization code with PKCE, where code_challenge_method must be S256, the state value must be at least twenty characters, and a real DATEV user session is required because there is no machine-to-machine flow; it refreshes the fifteen-minute access token using client_id only, never the client_secret. Organizations are matched to DATEV clients first, with the DATEV client id stored in the Zendesk organization external_id, so every booking references a client that already exists. To capture tickets promptly, ml-connector takes the Zendesk webhook as a trigger, verifying the X-Zendesk-Webhook-Signature HMAC over timestamp plus body, and a scheduled incremental export backfills anything a webhook missed. Because DATEV is pull-only and asynchronous, each EXTF or DXSO submission returns a job id that ml-connector polls with exponential backoff and jitter until the job reports complete or failed. EXTF files are written as UTF-8 with precomposed (NFC) characters and deterministic filenames, since DATEV rejects duplicates on filename plus document type, which makes a re-submission retry-safe. Document types are fetched per DATEV client before upload rather than hardcoded, and every record carries a full audit trail and can be replayed if a downstream call fails.

A real-world example

A German managed IT services firm with about ninety staff runs Zendesk for its customer support desk and DATEV through its tax advisor for the books. Support engineers log billable hours and out-of-contract work as Zendesk tickets, and at month end an accounts clerk read each solved ticket, typed an invoice, and hand-keyed the booking into DATEV, which was slow and produced totals that did not always match the support records. With DATEV and Zendesk connected, each billable ticket marked solved uploads its invoice PDF to DATEV Unternehmen Online and submits the booking as an EXTF job against the right client, while organization changes keep the customer master aligned. The clerk reviews instead of re-types, the invoices tie back to the tickets that produced them, and month-end billing stops being a manual scramble.

What you can do

  • Align each Zendesk organization with its matching DATEV client and keep the customer master in step.
  • Turn a billable, solved Zendesk ticket into a DATEV Unternehmen Online invoice document and a booking job.
  • Submit bookings as EXTF CSV or DXSO XML jobs and poll each job id to completion, since DATEV has no webhooks.
  • Bridge Zendesk OAuth2 and DATEV OAuth2 with PKCE, refreshing the short DATEV token without the client secret.
  • Trigger on Zendesk webhooks with HMAC verification, backfill by incremental export, and keep a full audit trail with replay.

Questions

Which direction does data move between DATEV and Zendesk?
Data moves from Zendesk into DATEV. Organization records align to DATEV clients, and billable solved tickets become invoice documents and bookings submitted to DATEV. Nothing financial moves back to Zendesk, because Zendesk has no invoice, purchase order, or general ledger object and DATEV does not return posted journal entries through its API.
How can the integration sync invoices when Zendesk has no invoice object?
Zendesk holds support and account records, not financial ones, so ml-connector reads a billable, solved ticket and its organization, then builds the accounting side on DATEV. It uploads the invoice PDF to DATEV Unternehmen Online through the accounting:documents API and submits the matching booking as an EXTF CSV or DXSO XML job. The Zendesk organization external_id carries the DATEV client id so the booking lands against the correct company.
Does DATEV confirm a booking right away, or does ml-connector have to wait?
DATEV processing is asynchronous and pull-only, so there is no instant confirmation and no webhook. Each EXTF or DXSO submission returns a job id, and ml-connector polls the job status endpoint with exponential backoff and jitter until it reports complete or failed. Files use deterministic filenames and precomposed UTF-8 so a retry after a timeout does not create a duplicate.

Related integrations

Connect DATEV and Zendesk

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

Get started