DATEV and BambooHR integration
DATEV runs accounting and tax for German businesses, and BambooHR is the system of record for employee and compensation data. Connecting the two means new hires, role and department changes, and pay-rate updates in BambooHR drive the payroll-related bookings and supporting documents that land in DATEV, without anyone re-keying them. ml-connector handles the very different interfaces on each side and moves the data on a schedule you control. Because DATEV takes finalized bookings as asynchronous EXTF CSV files and exposes no readable chart of accounts, ml-connector posts into DATEV and never tries to read the ledger back.
What moves between them
The flow runs from BambooHR into DATEV. ml-connector reads employee records, job-information rows, and compensation rows from BambooHR and posts payroll-related journals into DATEV as EXTF CSV booking batches, with supporting PDFs uploaded through the documents API into DUO. BambooHR departments and divisions map to DATEV Kostenstelle dimensions, and pay rates become booking amounts against the matching Konto and Gegenkonto. Employment-status changes such as hires and terminations are reflected in the bookings and creditor or debtor master rows that DATEV expects. DATEV bookings are one-way and write-only, and its accounts cannot be read back, so ml-connector never writes HR data from DATEV into BambooHR.
How ml-connector handles it
ml-connector stores both credential sets encrypted. On the BambooHR side it runs OAuth 2.0 against the customer's own subdomain for both the authorize and token URLs, since BambooHR has no global token endpoint, and refreshes the one-hour token with the offline_access refresh token. It verifies each webhook with a timing-safe SHA-256 HMAC check, then calls GET /api/v1/employees/{id} with an explicit fields list to pull the current values, because the webhook payload only names the employee and the changed fields. On the DATEV side it runs the PKCE Authorization Code flow, keeps the state parameter at least 20 characters, sends client_id only on refresh, and renews the 15-minute access token before it expires. Departments and cost centers are mapped first, so every booking line references a Konto and Kostenstelle that DATEV will accept. EXTF files are written as NFC-normalized UTF-8 with a whitelisted, deterministic filename, so DATEV's duplicate check on filename plus document type makes a re-submission safe. Because DATEV sends no webhooks, ml-connector polls each EXTF and DXSO job with exponential backoff until it completes or fails, and document uploads use PUT with a stable GUID so a retry does not create a second copy. Every record carries a full audit trail and can be replayed if a downstream call fails.
A real-world example
A German engineering firm with about 250 staff across two sites runs DATEV through its tax advisor for accounting and statutory reporting, and uses BambooHR as the HR system of record for hires, departments, and pay. Before the integration, an accountant exported a headcount and compensation report from BambooHR each month and typed the labor figures into a DATEV booking batch by hand, which meant department allocations drifted and the cost centers in the ledger rarely matched the org chart. With DATEV and BambooHR connected, each BambooHR change is picked up by webhook, the affected employee is re-read in full, and the resulting booking flows into DATEV allocated to the right Kostenstelle. The monthly re-keying is gone and the labor accounts reconcile to the org structure.
What you can do
- Post BambooHR compensation and employee changes into DATEV as EXTF CSV booking batches.
- Map BambooHR departments and divisions to DATEV Kostenstelle so payroll bookings land on valid cost centers.
- Bridge BambooHR per-subdomain OAuth 2.0 to DATEV's PKCE Authorization Code login, refreshing both token types.
- Verify BambooHR SHA-256 HMAC webhooks, then re-read the full employee record before posting.
- Poll each DATEV EXTF and DXSO job to completion, with deterministic filenames, retries, and a full audit trail.
Questions
- Which direction does data move between DATEV and BambooHR?
- The flow runs from BambooHR into DATEV. Employee, job-information, and compensation changes move from BambooHR into DATEV as EXTF booking batches and uploaded documents. DATEV bookings are one-way and write-only and its chart of accounts cannot be read back through the API, so ml-connector never writes HR data from DATEV into BambooHR.
- How does the integration handle BambooHR webhooks?
- BambooHR pushes employee.created, employee.updated, and employee.deleted events signed with SHA-256 HMAC, but the payload only names the employee and the changed fields. ml-connector verifies the signature with a timing-safe comparison, then calls GET /api/v1/employees/{id} with an explicit fields list to fetch the current record. That full record is what gets mapped into the DATEV booking.
- Why does ml-connector poll DATEV instead of waiting for a push?
- DATEV sends no webhooks, and its booking and document imports are asynchronous: you submit an EXTF or DXSO job, receive a job ID, then poll until it completes. ml-connector polls each job with exponential backoff and uses deterministic EXTF filenames so DATEV's duplicate check makes a re-submission safe. Document uploads use PUT with a stable GUID so a retry does not create a second copy.
Related integrations
More DATEV integrations
Other systems that connect to BambooHR
Connect DATEV and BambooHR
Free to use. Add your credentials, ping your real systems, and see if we fit.
Get started