Three records, two shapes
A complete file is three layers: the EXTF management record, the exact versioned column heading, and the booking rows. Only the last two share a shape. The management record always has 31 fields, whichever format version you target.
The first five fields are fixed identifiers. They are what a reader uses to recognise the file at all:
| Field | Value | Meaning |
|---|---|---|
| 1 | EXTF | Identifies an EXTF export file. |
| 2 | 700 | Header version. |
| 3 | 21 | Format category for Buchungsstapel. |
| 4 | Buchungsstapel | Format name. |
| 5 | 13 / 12 | Data format version: 13 or 12. |
A real management record
These lines are produced by the library itself, from metadata with a fixed timestamp so the output is reproducible.
Format version 13
"EXTF";700;21;"Buchungsstapel";13;20260812093000000;;"RE";"my_application";"";1001;1;20260101;4;20260801;20260831;"August 2026";"";1;0;1;"EUR";;"";;;"";;;"";"my-application"
Format version 12 — identical except field 5
"EXTF";700;21;"Buchungsstapel";12;20260812093000000;;"RE";"my_application";"";1001;1;20260101;4;20260801;20260831;"August 2026";"";1;0;1;"EUR";;"";;;"";;;"";"my-application"
Reserved fields are written as empty cells, and text fields stay quoted even when empty. Dropping a field instead of emptying it shifts every later field by one position.
Formats that trip people up
- Created-at timestamp uses
yyyyMMddHHmmssSSS— 17 digits including milliseconds, unquoted. - Fiscal year start and posting period use
yyyyMMdd, unquoted. - Text fields are quoted, including designated empty ones. A quote inside application information is escaped by doubling it.
- Numeric fields are unquoted, including the adviser and client numbers.
The coded fields
Four fields take values from a closed set rather than free input.
| Constant | DATEV value |
|---|---|
FINANCIAL_ACCOUNTING | 1 |
ANNUAL_FINANCIAL_STATEMENTS | 2 |
| Constant | DATEV value |
|---|---|
INDEPENDENT | 0 |
TAX_LAW | 30 |
CALCULATION | 40 |
COMMERCIAL_LAW | 50 |
IFRS | 64 |
Building it from Java
Metadata is built once per file and validated on construction, so an impossible combination fails before any row is written. The builder chooses the format version, and the exporter refuses a management record whose version does not match its heading.
import io.github.mrtyldr.datev.core.DatevMetadata;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Currency;
DatevMetadata metadata = DatevMetadata.bookingBatchV13()
.createdAt(LocalDateTime.now())
.origin("RE")
.exportedBy("my_application")
.advisorNumber(1001)
.clientNumber(1)
.fiscalYearStart(LocalDate.of(2026, 1, 1))
.accountLength(4)
.period(LocalDate.of(2026, 8, 1), LocalDate.of(2026, 8, 31))
.description("August 2026")
.currency(Currency.getInstance("EUR"))
.applicationInformation("my-application")
.build();
String record = metadata.toCsvLine(); // the 31-field management record
A v12 management record cannot be combined with the 125-column v13 heading. The builder rejects the mismatch rather than writing a file that no importer can interpret.