ml-connector
DATEVShipBob

DATEV and ShipBob integration

DATEV runs accounting and tax for German and Austrian businesses. ShipBob runs e-commerce fulfillment, storage, and shipping. Connecting the two means the fulfillment and shipping fees ShipBob charges, captured on its billing invoices, post into DATEV as supplier bookings without re-keying, and the original invoice PDF lands in DATEV Unternehmen Online for the tax advisor. ml-connector reads ShipBob over REST and submits the resulting bookings to DATEV as asynchronous file jobs on a schedule you control. Because ShipBob is a fulfillment platform with no general ledger, the chart of accounts stays in DATEV where it belongs.

How DATEV works

DATEV is not a single REST service. The accounting:clients and accounting:documents products are REST and let you list clients and upload invoice PDFs to DATEV Unternehmen Online, but actual bookings go through the accounting:extf-files product as EXTF-format CSV jobs to DATEV Rechnungswesen or the accounting:dxso-jobs product as DXSO XML jobs to DUO. Both booking channels are asynchronous: you submit a file, receive a job id, and poll the job status endpoint because DATEV has no webhooks. Authentication is OAuth 2.0 Authorization Code with PKCE through login mit DATEV, requiring an interactive user session, with access tokens that expire after 900 seconds. The standard DATEV chart of accounts is not readable through the API, and finalized EXTF bookings are write-only.

How ShipBob works

ShipBob exposes its full merchant surface through the ShipBob Developer API, a REST service returning JSON under a dated version path such as 2026-01. It covers orders, shipments, products, inventory, warehouse receiving orders, returns, and billing. The billing endpoints list invoices and the underlying fee transactions ShipBob charges the merchant for pick, pack, ship, and storage. Authentication is OAuth 2.0 Authorization Code or a Personal Access Token, with a one-hour access token and a 30-day refresh token, and every call carries the shipbob_channel_id header. ShipBob also pushes signed HMAC-SHA256 webhooks for events such as order.shipped and billing.charge.created, and pagination is driven by a next-page response header.

What moves between them

The flow runs from ShipBob into DATEV. ml-connector reads ShipBob billing invoices and the fee transactions behind them, then writes them into DATEV as supplier bookings by submitting an EXTF CSV job to DATEV Rechnungswesen, mapped to the matching DATEV GL accounts, tax codes, and cost centers. The invoice PDF is uploaded to DATEV Unternehmen Online through the documents API as a Rechnungseingang so the tax advisor sees the source receipt next to the booking. Shipped-order and tracking data can be read for reconciliation, while inventory, products, and returns stay in ShipBob. DATEV bookings are write-only and ShipBob billing is read-only, so ml-connector never writes financial entries back into ShipBob.

How ml-connector handles it

ml-connector stores both credential sets encrypted. On the ShipBob side it runs the OAuth2 Authorization Code flow or uses a Personal Access Token, refreshes the one-hour access token, stores each rotated 30-day refresh token immediately, and sends the shipbob_channel_id header on every call. On the DATEV side it drives the PKCE Authorization Code flow through login mit DATEV, where the state parameter must be at least 20 characters, and it refreshes the 900-second access token using client_id only, never the client_secret. ShipBob billing webhooks such as billing.charge.created can trigger a run after HMAC-SHA256 verification, and a scheduled poll backfills anything missed, since DATEV cannot push. Each ShipBob invoice becomes an EXTF booking batch: ShipBob fee types map to DATEV GL accounts because the DATEV chart of accounts is not API-readable and must be configured in advance, amounts and tax codes are set on the Konto and Gegenkonto, and the PDF uploads to DUO as a Rechnungseingang. The EXTF submission is asynchronous, so ml-connector polls the job status with exponential backoff and treats the documented duplicate-file error as a stop signal by generating stable, deterministic filenames from the ShipBob invoice id. ShipBob has no idempotency header, so it dedupes on the invoice reference and a BullMQ jobId. EXTF files are written UTF-8 with precomposed NFC characters and a restricted filename character set, and every record carries a full audit trail and can be replayed if a downstream call fails.

A real-world example

A German direct-to-consumer brand with roughly 80 employees sells through its own online store and outsources warehousing and shipping to ShipBob, while its tax advisor keeps the books in DATEV. Before the integration, a bookkeeper downloaded each ShipBob billing invoice, split the pick, pack, ship, and storage fees by hand, keyed them into DATEV as a supplier booking, and emailed the PDF to the tax advisor for filing. Fees were posted late, tax codes were sometimes wrong, and the fulfillment costs never tied out at month-end close. With DATEV and ShipBob connected, each ShipBob invoice posts into DATEV as an EXTF booking against the right expense accounts, the PDF lands in DATEV Unternehmen Online automatically, and the manual split disappears. The fulfillment costs reconcile and close starts from accurate numbers.

What you can do

  • Post ShipBob billing invoices into DATEV as supplier bookings through EXTF CSV file import after each fulfillment cycle.
  • Map ShipBob pick, pack, ship, and storage fee types to the correct DATEV GL accounts, tax codes, and cost centers.
  • Upload each ShipBob invoice PDF to DATEV Unternehmen Online as a Rechnungseingang document for the tax advisor.
  • Bridge ShipBob OAuth2 with the DATEV login mit DATEV PKCE flow and refresh the 900-second DATEV token automatically.
  • Poll DATEV asynchronous import jobs with backoff, deduplicate on stable invoice filenames, and keep a full audit trail on every record.

Questions

Which direction does data move between DATEV and ShipBob?
The flow is ShipBob into DATEV. ShipBob billing invoices and their fee transactions move into DATEV as supplier bookings, and the invoice PDF uploads to DATEV Unternehmen Online. ShipBob is a fulfillment platform with no general ledger, so the chart of accounts stays in DATEV and ml-connector never writes financial entries back into ShipBob.
How does the integration handle DATEV bookings when DATEV has no webhooks and no synchronous posting?
DATEV bookings are submitted as asynchronous EXTF CSV jobs, so ml-connector sends the file, receives a job id, and polls the status endpoint with exponential backoff until it completes or fails. Because DATEV cannot push events, ShipBob billing webhooks and a scheduled poll drive the work instead. Stable, deterministic filenames derived from the ShipBob invoice id make a retry safe against DATEV duplicate-file detection.
Why are ShipBob fees mapped to accounts manually instead of pulled from DATEV?
The standard DATEV chart of accounts cannot be read through the API, so the GL accounts, tax codes, and cost centers for ShipBob pick, pack, ship, and storage fees are configured in ml-connector ahead of time. Each ShipBob fee type is mapped to a DATEV account and tax key so the EXTF booking lands on a valid Konto and Gegenkonto. This mapping is set once and reused on every invoice.

Related integrations

Connect DATEV and ShipBob

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

Get started