ml-connector
DATEVBasware

DATEV and Basware integration

DATEV is the German accounting and tax backend that holds the books. Basware is the AP Automation platform where supplier invoices are captured, coded, matched, and approved. Connecting the two means an invoice that clears approval in Basware lands in DATEV as a posted booking, with its PDF filed in DATEV Unternehmen Online, instead of being re-keyed by hand. ml-connector handles the very different interfaces on each side: Basware's straightforward P2P REST API and DATEV's mix of REST document upload and asynchronous booking file jobs. Because DATEV's general ledger and posted journals cannot be read back through the API, Basware stays the coding front end and DATEV stays the system of record for the books.

How DATEV works

DATEV is not a single REST API. The accounting:clients product reads the list of companies the logged-in user can access, and accounting:documents uploads invoice and receipt PDFs into DATEV Unternehmen Online. Finalized bookings are written as asynchronous jobs: an EXTF CSV file goes to the on-premise DATEV Rechnungswesen engine through accounting:extf-files, or a DXSO XML booking suggestion goes to DATEV Unternehmen Online through accounting:dxso-jobs. Authentication is OAuth 2.0 authorization code with PKCE against login.datev.de, so a real DATEV user must consent interactively and there is no machine-to-machine flow. Access tokens last 15 minutes and must be refreshed. DATEV has no webhooks, so job status is discovered by polling, and the chart of accounts and posted journals cannot be read back.

How Basware works

Basware exposes its P2P data through a regional REST API over JSON and HTTPS, with all paths under a /v1/ prefix on the base URL for the customer's region (EU, US, AU, or CA). Authentication is OAuth 2.0 client credentials: the client ID and secret are sent as HTTP Basic auth to request a bearer token that is valid for about one hour, with no refresh token. The accountingDocuments endpoint returns coded and approved invoices ready for transfer, paged 100 at a time using a continuation token passed in a request header. Vendors, GL accounts, and accounting dimensions are imported into Basware. Basware can also push an HMAC-SHA256 signed webhook with taskType AccountingDocuments when an invoice is ready, and credentials are provisioned by a Basware consultant rather than self-served.

What moves between them

The main flow runs from Basware into DATEV. When a Basware accounting document reaches the ready-for-transfer state, ml-connector reads its header, lines, and coding, submits the booking to DATEV as an EXTF CSV job to DATEV Rechnungswesen or a DXSO XML job to DATEV Unternehmen Online, and uploads the invoice PDF to DATEV Unternehmen Online as a Rechnungseingang document. Reference data moves the other way where it is available: vendor master records and account codes are imported into Basware so the coding panel offers valid suppliers and accounts. The cadence is event-driven where the Basware webhook fires, with a scheduled poll of accountingDocuments as a backstop, so nothing is missed if a push is dropped.

How ml-connector handles it

ml-connector stores both credential sets encrypted. On the Basware side it requests a fresh bearer token roughly every hour, since the client_credentials flow has no refresh token, and pages accountingDocuments using the continuation token returned in the response header, URL-encoding any percent or slash characters in query values. On the DATEV side it runs the authorization-code OAuth flow with PKCE once interactively, then refreshes the 15-minute access token automatically, sending only the client_id on refresh and including the X-DATEV-Client-Id header on every call. Each Basware invoice is rendered into an EXTF Buchungsstapel CSV or a DXSO XML payload: amount, debit and credit accounts, document date, document number, tax code, and cost center map onto the DATEV fields. The EXTF file is written as NFC-normalized UTF-8 with a deterministic filename, because DATEV rejects duplicate filename plus document-type combinations and silently drops non-precomposed characters. After submission ml-connector polls the DATEV job with exponential backoff until it completes or fails, since there is no push confirmation. Document type names are fetched per client before upload rather than hardcoded. The incoming Basware webhook is verified by recomputing the HMAC-SHA256 over the raw UTF-8 body and checking the timestamp, and the synchronous endpoint returns 200 quickly while the booking runs in the background. Edge cases handled: DATEV GL accounts are not readable, so the account map is configured once and validated against Basware's imported accounts; Basware silently skips records identical to the last version, so a re-trigger changes a field; and after the EXTF job posts to Rechnungswesen the journal cannot be read back, so the Basware document state and the DATEV job result are the audit record.

A real-world example

A German manufacturing group with around 400 staff runs DATEV through its tax advisor for statutory accounting and uses Basware to capture and approve several thousand supplier invoices a month across two legal entities. Before the integration, an accounts payable clerk exported approved invoices from Basware and re-typed each one into DATEV, then uploaded the PDFs separately into DATEV Unternehmen Online, which left bookings days behind and produced typing errors on accounts and cost centers. With DATEV and Basware connected, each invoice that clears approval is submitted to DATEV as a booking job and its PDF filed automatically, allocated to the right account and cost center. The clerk stops re-keying, the tax advisor sees bookings the same day, and month-end no longer starts with a backlog of unposted invoices.

What you can do

  • Submit coded, approved Basware invoices into DATEV as EXTF CSV or DXSO XML booking jobs.
  • Upload each invoice PDF into DATEV Unternehmen Online as an incoming-invoice document.
  • Import vendor master records and account codes into the Basware coding panel so invoices land on valid accounts.
  • Bridge Basware OAuth2 client credentials with DATEV's authorization-code OAuth2 and PKCE, refreshing each token before it expires.
  • Verify the Basware HMAC-SHA256 webhook, poll the DATEV job to completion, and keep a full audit trail with replay.

Questions

Which direction does data move between DATEV and Basware?
The main flow is Basware into DATEV. Coded, approved invoices move from Basware into DATEV as booking jobs, and the invoice PDF is uploaded to DATEV Unternehmen Online. Vendor and account reference data is imported into Basware so the coding panel stays valid. DATEV posted journals and its chart of accounts cannot be read back through the API, so ml-connector does not pull the general ledger out of DATEV.
Why does ml-connector poll DATEV instead of receiving a webhook?
DATEV has no outbound webhooks or push notifications of any kind. Its booking imports are asynchronous: you submit an EXTF or DXSO job, receive a job ID, and then poll for the result. ml-connector polls each DATEV job with exponential backoff until it reports complete or failed, because there is no synchronous confirmation that a booking posted.
How are the two different authentication models handled?
Basware uses OAuth2 client credentials, where ml-connector sends the client ID and secret as Basic auth to get a one-hour bearer token with no refresh, so it simply requests a new token when one expires. DATEV uses authorization-code OAuth2 with PKCE and requires an interactive user login, after which ml-connector refreshes the 15-minute access token automatically and sends the client_id only on refresh. Both credential sets are stored encrypted, and the X-DATEV-Client-Id header is added to every DATEV call.

Related integrations

Connect DATEV and Basware

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

Get started