S

MCP Agent Skill — sepa-datev

SEPA Direct Debit & DATEV Export Skill for MCP Agent

German-market payment-rails and accounting-export knowledge for QA and SE agents — pain.008 structure and character rules, mandate lifecycle and sequence types, R-transaction reason codes, IBAN/Creditor-ID validation, DATEV EXTF format, SKR charts and non-profit tax spheres, with a synthetic fixture matrix. Verified against EPC and DATEV primary sources.

Available free v1.0.0
$ sidebutton install sepa-datev
Download ZIP
README 11.0 KB

SEPA Direct Debit & DATEV Export

Fee billing is the highest-trust surface of any German membership product. A billing run that reports success but emits a malformed file is a failed run — the failure just surfaces later, at the bank, in someone else's accounting system. This pack supplies the format knowledge needed to say which field is wrong and which rule it violates, rather than "the button did not error".

Everything here is specification-layer knowledge, verified against primary EPC and DATEV sources — what any German-market billing product must emit. What a specific product actually does (its export dialects, its status vocabulary, its configuration) belongs in that product's own domain pack, layered on top of this one.

Module Inventory

ModuleCovers_skill.md
sepa-direct-debitpain.008 structure and character rules, mandate lifecycle, timing, CORE vs B2B, R-transaction reason codes, IBAN/Creditor-ID validation, bank-statement reconciliation0.8
datev-extfEXTF/Buchungsstapel header and record format, silent-non-import rules, SKR03/04/42/49 charts, non-profit tax spheres and KOST10.75

The failure taxonomy, fixture matrix and validation heuristics below span both modules — run the whole heuristics list on every export; an XML failure must never suppress the DATEV checks.

Failure Taxonomy

Ordered by how late the failure surfaces. Later is worse: the cost of a defect here is roughly the time until someone notices.

#ClassExampleDetected by
1Rejected by schemaMissing MndtId, wrong namespace, NbOfTxs ≠ actual countXSD validation — free, run it first
2Rejected by the bankChrgBrSLEV, non-EUR InstdAmt, illegal character in a reference, CtrlSum mismatchBank upload — the club sees an error and calls support
3Accepted, books wronglyRight amount to the wrong member; EndToEndId not unique; wrong ReqdColltnDt; BtchBookg flipped so the statement shows one lumpOnly by reading the file — this is the class this module exists for
4Correct file, wrong business rulePre-notification under 14 days; collecting from a member who resigned; double-billing a family-group payerBusiness-rule assertions over the run
5Surfaces weeks laterMD01 from a dormant mandate; AM05 duplicates; refunds inside the 8-week windowReturn file — after the money moved

A QA report is useful in proportion to how high up this list it can push a defect.

Test Fixture Matrix

Synthetic only. Every value below was generated or is a published documentation example; none is a real account. Never copy a value out of a real screen, statement, or export.

Verified-valid IBANs (each passes MOD-97-10, checked locally):

DE50100000000000000001      DE23100000000000000002
DE41500105170123456789      DE62370400440532013001
DE72120300000000202052

Must-be-rejected IBANs (each verified to fail):

ValueDefect
DE00500105170123456789Check digits zeroed
DE41500105170132456789Two account digits transposed
DE41500105170123456780Single digit changed
DE415001051701234567821 characters
DE41500105170123456789023 characters
de41500105170123456789Lower-case. Note: this one passes MOD-97-10 (uppercase it and the remainder is 1) — it must be rejected on the ISO 13616 upper-case rule, which is why assertion 6 states the case rule separately. A validator that silently upper-cases its input will pass this fixture; that is the defect it is testing for

Verified-valid Gläubiger-IDs: DE13ZZZ00000000123, DE52ZZZ00012345678, DE98ZZZ09999999999. Rejected: DE98ZZZ09999999998 (national identifier mutated).

Member and run cases — each maps to a failure class above:

#FixtureTargets
1Names with ä ö ü ß, capital , and a non-German diacritic (ą, ł)Character-set rules — names transliterate, references reject
2A name long enough to overflow Ustrd / BuchungstextTruncation
3First-ever collection sent as RCURMust passFRST is not mandatory
4FRST then RCUR on one mandateCorrect transition
5RCUR after FNAL, and OOFF reusedMust fail
6Mandate with no collection for 36 monthsDormancy → MD01
7Mandate amended: new IBAN same bank; new bank; changed MndtIdAmdmntInd + the matching Orgnl* element
8Minor billed through a guardian (Erziehungsberechtigte)Debtor is the guardian, member is the child — names must not be swapped
9Family/group account with one payer and three managed membersOne debtor, correct total, no double billing
10Mid-year fee change and an early-ended feePro-rating and refund handling
11Two invoice numbers in one Verwendungszweck; a truncated oneCSV reconciliation
12Rücklastschrift (returned debit) in the uploaded statementInvoice reopens/holds with the return fee attached — per the product's documented behaviour
13Year-end run: Belegdatum in December, header fiscal year the nextThe DDMM year trap
14Booking dated outside Datum vonDatum bisHeader/period consistency
15Run with zero collectable membersNbOfTxs = 0 handling, empty-file behaviour
16Amount 0,00, -1,00, and one above 999999999.99InstdAmt inclusive range 0.01..999999999.99 (SEPA rejects 0.00 too, IG 2.98); DATEV rejects 0,00 in Umsatz
17Two members with identical names and amountsEndToEndId uniqueness
18A collection date under 14 days after invoice sendPre-notification rule
19A Rechnungsnummer containing a space, a dot, or an umlautDATEV Belegfeld 1 charset
20Bookings across all four tax spheres in one exportKOST1 populated per row (SKR42)
21A batch at the row boundary — 99,996 / 99,997 / 99,998 postingsDATEV per-file row limit (99,999 rows incl. summary lines)

Validation Heuristics — Run These On An Export

Assertions in order of cost. Each is cheap and independent — run them all and report every failure. Do not stop at the first: the two blocks below cover two different artefacts (1–13 the pain.008 XML, 14–19 the DATEV file), so an XML failure must never suppress the DATEV checks.

#CheckRule source
1Validates against the XSD for the version the organisation is configured to emit — pain.008.001.08 unless the product's export-format selector says otherwiseIG EPC130-08
2NbOfTxs equals the count of DrctDbtTxInfat group level and again within every PmtInfIG 1.4 and IG 2.4
3CtrlSum equals the sum of InstdAmtat group level and again within every PmtInfIG 1.5 and IG 2.5, both mandatory in SEPA
4Every InstdAmt has Ccy="EUR" and lies in 0.01 .. 999999999.99 inclusiveIG 2.98
5ChrgBr absent or SLEVIG 2.68
6Every IBAN is upper-case (ISO 13616), passes MOD-97-10, and German ones are 22 charsISO 13616 + ISO 7064
7CdtrSchmeId passes the Creditor-Identifier checkVerified locally
8MndtId and EndToEndId: ≤ 35 chars, allowed charset only, no leading/trailing /, no //Length: IG 2.102 / 2.84. Charset and the / rules: the IG character-set rule, not an element index — see sepa-direct-debit § The character set
9EndToEndId unique within the fileReconciliation
10SeqTp present, and consistent with that mandate's historyIG 2.14 + rulebook
11DtOfSgntr present, not in the future, not after ReqdColltnDtIG 2.103
12Where AmdmntInd is true, AmdmntInfDtls is present and carries the element matching what changedIG 2.105 (AmdmntInfDtls), 2.106 (OrgnlMndtId), 2.107 (OrgnlCdtrSchmeId), 2.120 (OrgnlDbtrAcct/SMNDA); and 2.121 OrgnlDbtrAgt absent whenever 2.120 is SMNDA
13Sachkontenlänge in the header matches the target client's DATEV configuration; no all-zero account number. Personal accounts (Debitor/Kreditor) are legitimately one digit longer than Sachkonten, and short accounts need not be zero-padded — do not flag eitherDATEV field spec (see the account-length row above)
14DATEV: line 1 has 31 fields, line 2 has 125, EXTF not DTVF, field 4 agrees with field 3, filename EXTF_*.csvDATEV sample + doc 1044208
15DATEV: every amount uses a decimal comma, no 0,00 in Umsatz; every Belegdatum is 4 digits and inside the header periodDATEV field spec
16DATEV: Belegfeld 1 contains no space, umlaut, ., ,, ; or :DATEV field spec
17DATEV: on an SKR42 client, income and expense rows carry KOST1 (field 37) so the tax sphere is not lost. Establish the client's chart first — on SKR03/SKR04 KOST1 is legitimately optional, and whether the exporter populates it per sphere is a per-product factSKR42 sphere model
18DATEV: file is CP1252 / ISO-8859-1. Treat any UTF-8 as a finding pending confirmation — DATEV's documented Zeichensatz for a Buchungsstapel is ANSI, and the BOM carve-out is not stated in DATEV's own field descriptionDATEV Zeichensatz rule
19Run the file through DATEV's free Prüfprogramm DATEV-Format before reporting any structural DATEV defectDATEV Prüfprogramm

Not checkable on the export — verify out of band. ReqdColltnDt ≥ 14 calendar days after the pre-notification (Rulebook EPC016-06) is a genuine compliance rule, but the pre-notification date is not in the artefact, so it cannot be an assertion over the file (see sepa-direct-debit § Collection Timing & Pre-Notification). Check it against the invoice-send date in the run, and remember the Rulebook allows another timeline if creditor and debtor agreed one — a club's fee bylaws (Beitragsordnung) routinely do.

Use the official validator first. DATEV publishes a free Prüfprogramm DATEV-Format (v2.2.3.0) and a Musterdaten bundle on developer.datev.de, neither requiring a login. Running an export through it costs nothing and settles the structural questions before any manual review — make it the first step of any DATEV ticket.

Authoring Rules

  1. Synthetic fixtures only, forever. Every member, mandate, IBAN and account in this pack was generated or is a published documentation example. Never add a value copied from a real screen, statement, or export.
  2. Pin the specification edition. Every rule cites its document and version; a rule from the wrong year gives money-path QA false confidence, which is worse than no rule.
  3. No product-specific claims. What one vendor's exporter does belongs in that consumer's own domain pack, never here.