Direct debits (pain.008)
A direct debit is a pull payment: a creditor (payee) collects money from one or more debtors, each authorized by a signed mandate. The pain.008.001.08 message type is the modern ISO 20022 Direct Debit Initiation message used across the SEPA zone.
The model
Section titled “The model”import { euros, type DirectDebitDocument } from 'sepa-xml-ts'
const doc: DirectDebitDocument = { messageId: 'DD-2026-0001', createdAt: '2026-06-01T09:00:00Z', initiatingParty: 'ACME GmbH',
// The creditor is specified once at document level. // The writer fans it out into every PmtInf automatically. creditor: { name: 'ACME GmbH', iban: 'DE89370400440532013000', bic: 'COBADEFFXXX', creditorId: 'DE98ZZZ09999999999', // SEPA Creditor Identifier },
batches: [ { id: 'BATCH-001', collectionDate: '2026-06-10', // ReqdColltnDt/Dt: YYYY-MM-DD sequenceType: 'FRST', // FRST | RCUR | OOFF | FNAL localInstrument: 'CORE', // CORE | B2B (defaults to CORE)
collections: [ { endToEndId: 'SUB-1001', amount: euros('49.99'), debtor: { name: 'Kunde Eins', iban: 'NL91ABNA0417164300', }, mandate: { id: 'MND-001', signatureDate: '2026-01-15', // YYYY-MM-DD }, remittanceInfo: 'Subscription June', // optional }, ], }, ],}Model types
Section titled “Model types”| Type | XSD element |
|---|---|
DirectDebitDocument | Document/CstmrDrctDbtInitn |
Creditor | Cdtr + CdtrAcct + CdtrAgt + CdtrSchmeId |
DirectDebitBatch | PmtInf |
Collection | DrctDbtTxInf |
Mandate | DrctDbtTx/MndtRltdInf |
SequenceType | PmtTpInf/SeqTp |
LocalInstrument | PmtTpInf/LclInstrm/Cd |
Sequence types
Section titled “Sequence types”| Value | Meaning |
|---|---|
FRST | First collection under a mandate |
RCUR | Recurring collection |
OOFF | One-off collection (mandate used once) |
FNAL | Final collection, mandate will be cancelled |
SEPA Creditor Identifier
Section titled “SEPA Creditor Identifier”The creditorId field on Creditor is a SEPA Creditor Identifier (e.g. DE98ZZZ09999999999).
The library validates the check digits strictly using ISO 7064 MOD 97-10, the same algorithm as
IBAN validation. An incorrect check digit is caught at validation time before the file is written.
The structure is:
- 2-letter country code
- 2 check digits (ISO 7064 MOD 97-10)
- 3-char creditor business code (e.g.
ZZZ) - national identifier (1 to 28 alphanumeric characters)
Use buildCreditorId(country, businessCode, nationalId) from the library to compute a correct
identifier programmatically.
Writing to XML
Section titled “Writing to XML”import { writeDirectDebit } from 'sepa-xml-ts'
const xml = writeDirectDebit(doc)writeDirectDebit validates the model internally before writing. It throws if the model is
invalid.
Derived fields
Section titled “Derived fields”The writer derives the following fields. You do not supply them:
| Field | How it is derived |
|---|---|
GrpHdr/NbOfTxs | Total count of all collections across all batches |
GrpHdr/CtrlSum | Sum of all collection amounts (exact bigint addition) |
PmtInf/NbOfTxs | Count of collections in this batch |
PmtInf/CtrlSum | Sum of collection amounts in this batch |
PmtInf/PmtMtd | Always DD |
PmtInf/PmtTpInf/SvcLvl/Cd | Always SEPA |
PmtInf/ChrgBr | Always SLEV |
CdtrSchmeId/.../SchmeNm/Prtry | Always SEPA |
Structural gotchas
Section titled “Structural gotchas”CdtrAgt (at PmtInf level) and DbtrAgt (per transaction) are structurally required by the XSD
even when no BIC is present. The writer emits the correct empty-institution placeholder
automatically when bic is absent:
<CdtrAgt><FinInstnId/></CdtrAgt>This is handled transparently. You only need to supply bic when you know it.
Sequence-type and mandate rules
Section titled “Sequence-type and mandate rules”validateDirectDebit and writeDirectDebit enforce three cross-field SEPA rulebook constraints.
These apply to both CORE and B2B direct debits, and to both the ISO variant and the German DK
variant.
R1: signature before collection. mandate.signatureDate must not be after the batch
collectionDate. A collection cannot be initiated on a mandate that has not been signed yet.
Equal dates are allowed (signing and collecting on the same day is valid).
R2: OOFF is single-use. A mandate id used in any batch with sequenceType: 'OOFF' must
appear in exactly one collection across the whole document, and must not also appear under any
other sequence type. A one-off authorization covers one collection.
R3: consistent scheme per mandate. A given mandate id must not appear under both CORE and
B2B local instruments in the same document. A CORE mandate and a B2B mandate are distinct
authorizations. Note that localInstrument defaults to CORE when omitted, matching the writer
default.
validateDirectDebit returns the violations as ruleIssues on the result. writeDirectDebit
throws before emitting any XML when a rule is violated.
Variants
Section titled “Variants”To write a German DK pain.008.003.02 file:
const xml = writeDirectDebit(doc, { variant: 'pain.008.003.02' })See National variants for the structural differences and XSD details.