errorbusinessEN 16931

BR-CO-25:Payment due date or payment terms required when amount due is positive

Fix: Step 1: Read BT-115 (cbc:PayableAmount). If it's ≤ 0, the rule cannot fire — investigate why the validator reports it. Step 2: If BT-115 > 0, decide whether to emit a Payment due date or Payment terms (or both): • If your ERP has a contractual due date, write it as `<cbc:DueDate>YYYY-MM-DD</cbc:DueDate>` directly under the cbc:InvoiceTypeCode-level part of the Invoice/CreditNote root. • If the contract is net-30 / net-15 / on receipt and no fixed date applies, emit `<cac:PaymentTerms><cbc:Note>Net 30 days from invoice date</cbc:Note></cac:PaymentTerms>` with a non-empty, human-readable note. Step 3: Make sure the cbc:Note text is not empty and not pure whitespace. Some validators reject `<cbc:Note></cbc:Note>` even though the element exists. Step 4: For credit notes, prefer cac:PaymentTerms/cbc:Note over cbc:DueDate — historically more reliable across validator implementations. Step 5: Recalculate BT-115 to make sure the sign matches the document type (positive on Invoice, sign convention on CreditNote). Step 6: Re-validate. BR-CO-25 should clear without affecting other rules. Provide the required value in the free validator.

BR-CO-25 fires when the Amount due for payment (BT-115) is greater than zero but neither the Payment due date (BT-9, cbc:DueDate) nor the Payment terms (BT-20, cac:PaymentTerms/cbc:Note) is present. Peppol requires the buyer to know when to pay or under what terms — a positive amount with no payment timing is a fatal validation error.

Severity
Fatal
Rule set
EN 16931
Country
All EU
Fix type
INPUT REQUIRED
Confidence
55%

Engine Classification

Business data required · Explicit input workflow · No assumptions made

Required input: Line IDs (comma-separated)

What is BR-CO-25?

BR-CO-25 is a fatal validation rule defined in the EN 16931 specification. It validates the >`) does not satisfy the rule on some validator implementations even though exists() returns true; the safer pattern is a non-empty literal. element under PaymentTerms > Note))) or (. <= 0)`. Common failure modes: (1) The invoice is exported without a due date because the ERP stores the due date on the payment-schedule subrecord and the UBL mapping reads only the header. (2) The invoice has cac:PaymentTerms but the only child is cac:SettlementPeriod or cac:PaymentMeans — not cbc:Note — so the schematron's exists() check fails. (3) Net-zero invoices (totals correct but cbc:PayableAmount > 0 because a prepayment was not subtracted) trip the rule unexpectedly. (4) Credit notes with a positive PayableAmount due to refund logic — historically there was a known schematron issue on credit notes where DueDate at the root is not a valid element. (5) Empty cbc:Note (`<cbc:Note in the UBL invoice XML.

When this rule fires, the invoice is rejected by Peppol access points and never reaches the buyer.

Target path: The rule's XPath is roughly `((. > 0) and (exists(//cbc:DueDate) or exists(//cac:PaymentTerms/cbc:Note))) or (. <= 0)`. Common failure modes: (1) The invoice is exported without a due date because the ERP stores the due date on the payment-schedule subrecord and the UBL mapping reads only the header. (2) The invoice has cac:PaymentTerms but the only child is cac:SettlementPeriod or cac:PaymentMeans — not cbc:Note — so the schematron's exists() check fails. (3) Net-zero invoices (totals correct but cbc:PayableAmount > 0 because a prepayment was not subtracted) trip the rule unexpectedly. (4) Credit notes with a positive PayableAmount due to refund logic — historically there was a known schematron issue on credit notes where DueDate at the root is not a valid element. (5) Empty cbc:Note (`<cbc:Note/>`) does not satisfy the rule on some validator implementations even though exists() returns true; the safer pattern is a non-empty literal.

Why This Error Matters

Invoice rejected. Buyers need to know when payment is expected.

BR-CO-25 is a hard failure — the invoice must be corrected and re-sent before it can reach the recipient.

Validator Behavior

  • ·Causes invoice rejection
  • ·Error returned: BR-CO-25
  • ·Specification: EN 16931

How to Fix It

1.

Check all line IDs

Review InvoiceLine/ID values

2.

Make unique

Use sequential numbers or unique identifiers

Before / After

Failing XML
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
  <cbc:ID>INV-2026-0042</cbc:ID>
  <cbc:IssueDate>2026-05-26</cbc:IssueDate>
  <!-- no cbc:DueDate, no cac:PaymentTerms -->
  <cac:LegalMonetaryTotal>
    <cbc:PayableAmount currencyID="EUR">1190.00</cbc:PayableAmount>
  </cac:LegalMonetaryTotal>
</Invoice>
Corrected XML
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
  <cbc:ID>INV-2026-0042</cbc:ID>
  <cbc:IssueDate>2026-05-26</cbc:IssueDate>
  <cbc:DueDate>2026-06-25</cbc:DueDate>
  <cac:PaymentTerms>
    <cbc:Note>Net 30 days from invoice date</cbc:Note>
  </cac:PaymentTerms>
  <cac:LegalMonetaryTotal>
    <cbc:PayableAmount currencyID="EUR">1190.00</cbc:PayableAmount>
  </cac:LegalMonetaryTotal>
</Invoice>

Technical Reference

XPathThe rule's XPath is roughly `((. > 0) and (exists(//cbc:DueDate) or exists(//cac:PaymentTerms/cbc:Note))) or (. <= 0)`. Common failure modes: (1) The invoice is exported without a due date because the ERP stores the due date on the payment-schedule subrecord and the UBL mapping reads only the header. (2) The invoice has cac:PaymentTerms but the only child is cac:SettlementPeriod or cac:PaymentMeans — not cbc:Note — so the schematron's exists() check fails. (3) Net-zero invoices (totals correct but cbc:PayableAmount > 0 because a prepayment was not subtracted) trip the rule unexpectedly. (4) Credit notes with a positive PayableAmount due to refund logic — historically there was a known schematron issue on credit notes where DueDate at the root is not a valid element. (5) Empty cbc:Note (`<cbc:Note/>`) does not satisfy the rule on some validator implementations even though exists() returns true; the safer pattern is a non-empty literal.
SpecEN 16931
StrategyRequires user input: Payment due date or payment terms text. Cannot auto-generate because payment terms depend on customer agreements and business policies.

Code Example

The 'before' invoice has a positive PayableAmount but no DueDate and no PaymentTerms/Note — fatal under BR-CO-25. The 'after' adds both cbc:DueDate (BT-9) and cac:PaymentTerms/cbc:Note (BT-20). Either one alone satisfies the rule; including both is the most defensive option and improves human readability for the buyer's accounts payable team.

Common Causes

  • ·The rule's XPath is roughly `((. > 0) and (exists(//cbc:DueDate) or exists(//cac:PaymentTerms/cbc:Note))) or (. <= 0)`. Common failure modes: (1) The invoice is exported without a due date because the ERP stores the due date on the payment-schedule subrecord and the UBL mapping reads only the header. (2) The invoice has cac:PaymentTerms but the only child is cac:SettlementPeriod or cac:PaymentMeans — not cbc:Note — so the schematron's exists() check fails. (3) Net-zero invoices (totals correct but cbc:PayableAmount > 0 because a prepayment was not subtracted) trip the rule unexpectedly. (4) Credit notes with a positive PayableAmount due to refund logic — historically there was a known schematron issue on credit notes where DueDate at the root is not a valid element. (5) Empty cbc:Note (`<cbc:Note/>`) does not satisfy the rule on some validator implementations even though exists() returns true; the safer pattern is a non-empty literal.

Seeing this in production? The API handles BR-CO-25 automatically. See the fix response →

Frequently Asked Questions

Your invoice has a positive amount due for payment (BT-115) but no payment due date (cbc:DueDate) and no payment terms note (cac:PaymentTerms/cbc:Note). Peppol requires at least one so the buyer knows when or under what conditions to pay.

Partially. We can detect the missing element and inject a default cac:PaymentTerms/cbc:Note ('Payment due on receipt' or your configured default), but a real due date requires input from the source system. Confidence is 0.55 — auto-fix is safe for fallback text, manual review is recommended for the actual date.

Technically the schematron exists() check passes on any present element, including empty ones, but several validator implementations (notably the KoSIT and OpenPeppol reference validators) also enforce non-empty content. Always emit non-empty, human-readable text.

There has been a known issue (eInvoicing-EN16931 GitHub #84) where the schematron looks for cbc:DueDate at the document root on credit notes even though the UBL CreditNote schema places it elsewhere. The reliable workaround is to emit cac:PaymentTerms/cbc:Note on credit notes with a positive PayableAmount instead of relying on cbc:DueDate.

Related Errors

Related Content

Last updated: 5 June 2026

Share this guide:

Validate your invoice

Drop your XML here to check for BR-CO-25

Fix BR-CO-25 with guided input

Upload your invoice and we'll ask for the missing data, then apply a safe, auditable fix.