Document validation rules and specifications
This guide details the validation rules, mathematical integrity constraints, and error response schema applied to documents processed by Banqup. Integration partners can use these specifications to pre-validate payloads, handle asynchronous or sync error states, and ensure compliance with e-invoicing (PEPPOL BIS3) requirements.
1. Overview and validation execution
Documents uploaded to the platform undergo multi-category validation to ensure business-rule accuracy, legal compliance, and network addressability.
Validation runs through a two-pass architecture. When submitting documents via API, integration partners must account for the following execution constraints: the API updates validationData synchronously. HTTP 200 is only returned after validation results are committed. Intercept errors directly in the synchronous response payload.
In addition to synchronous API responses, validation events (such as DocumentValidationFailed) and state changes are published as event messages. Refer to the Message categories and types documentation for details on DocumentCreated, DocumentUpdated, DocumentValidationFailed, and related event schemas.
Validation logic flow
2. Core validation rules
Documents are evaluated across eight core domain categories.
Category 1: Structural and Schematron validation
| Validation Check | Target Scope | Failure Criteria |
|---|
| XML / Syntax Validation | Standard XML Payloads (UBL 2.1, CII) | Document is not well-formed XML or violates standard XSD schemas. |
| Schematron Assertion | PEPPOL BIS Billing 3.0 / EN16931 | Payloads fail active Schematron rules (XSLT-rendered assertions for PEPPOL / country profiles). |
Category 2: Field completeness and schema
| Validator | What It Checks | Failure Criteria |
|---|
| Required Fields | Core metadata (issueDate, invoiceType, currencyCode, netAmount, grossAmount), category-specific fields (documentNumber, supplier.legalName, supplier.address.country), per-line fields (quantity, netAmount, pricing.itemNetPrice), and per-line VAT validity rules. | Fails when any required field is missing or any per-line VAT validity rule is violated. |
| Custom Category Fields | supplierCategory.code on PURCHASE\_RECEIPTdocuments. | Fails when supplierCategory.code is missing from a PURCHASE\_RECEIPT. |
| Document Schema | Full JSON schema for QUOTE, PURCHASE\_RECEIPT, and THIRD\_PARTY\_STATEMENT documents. | Fails when the document does not conform to the applicable JSON schema. |
| Validator | What It Checks | Failure Criteria |
|---|
| PEPPOL Required Fields | Dutch suppliers (country == NLor globalIdentifiers contains nl:vat) on invoices with a positive payable amount must include paymentMeans. | Fails when paymentMeans is missing (PEPPOL rule NL-R-007). |
| PEPPOL VAT Categories | Every VAT category appearing in lines, charges, or allowances must have a matching entry in metadata.vatDetails[] with the required cardinality. | Fails when a VAT category has no matching vatDetails[] entry, or when cardinality is violated: O/E/Z/G/AE/K must appear exactly once; S/L/M must appear at least once. |
Category 4: Counterparty connection and delivery
| Validator | What It Checks | Failure Criteria |
|---|
| Connection Match | The supplier (PURCHASES) or customer (SALES) in the document matches the stored counterparty connection, using the identification hierarchy: global identifiers → trade name → legal name. | Fails when the counterparty cannot be resolved using the standard identification hierarchy. |
Category 5: Uniqueness and numbering
| Validator | What It Checks | Failure Criteria |
|---|
| Document Uniqueness | No other document with the same number and year of the issueDate from the same supplier exists in the space. Supplier identity is resolved using the 5-step hierarchy: country scheme → participant ID → tax number → IBAN → legal name. | Fails when another document from the same supplier already has the same document number. |
| Sequence Alignment | For self-billed SALES documents, the document number does not conflict with the auto-generated sequential numbering series. | Fails when the document number conflicts with the expected auto-generated sequence. |
Category 6: Date bounds
| Validator | What It Checks | Why It Matters |
|---|
| Issue Date Sequence | For documents using auto-generated numbering series: issueDate must not be before the lastUsedAt date stored in the DataStore locked setting for that series. | Invoice numbering series are date-sequential; backdating would violate VAT chronology rules. |
| Quote Expiry | For quotes: dueDate must be strictly in the future (after today). | A quote with a past due date is no longer valid and should not be submitted. |
Category 7: Self-billing requirements
| Validator | What It Checks | Failure Criteria | Default Severity |
|---|
| Document Prefix | The connection metadata contains the required document number prefix for the self-billed category: invoiceDocumentNumberPrefix or creditNoteDocumentNumberPrefix. | Fails when the required prefix is missing. | ERROR |
| Mandate Agreement | The counterparty connection has mandate == true. | Fails when the self-billing mandate is missing (mandate == false). | WARNING |
Category 8: Financial statements
| Validator | What It Checks | Failure Criteria |
|---|
| Closing Balance | For bank statements, verifies that round(openingBalance + Σ(CREDIT lines) − Σ(DEBIT lines)) == closingBalance. | Fails when the calculated closing balance does not equal the reported closingBalance after rounding. |
| Statement Deduplication (Feature-Flagged) | Checks that no other VALIDATED bank statement with the same fromDate, toDate, openingBalance, accountIdentifier, statementNumber already exists. This validation is feature-flagged. | Fails when a matching VALIDATED bank statement already exists. |
4. Error code reference
The API returns normalized error strings within the validation output structure. Intercept these codes to surface action items within your application.
Note: For documents received through the PEPPOL network, validation failures that trigger an ERROR severity level will automatically generate and return a rejection MLR / CDAR response to the original sender.
| Error Code | Severity | Meaning / Remedy |
|---|
document.field.missing | ERROR | Required structural payload field is missing. |
document.field.invalid | ERROR | Field is present but its value fails an arithmetic, formatting, or date-range validation. |
document.semanticError | ERROR | PEPPOL business rule violation, such as mismatched VAT category summaries or missing payment details. |
document.connection | ERROR | Counterparty identity cannot be matched against an existing space connection. |
document.connection.delivery.channel.missing | ERROR | Target counterparty has no active delivery channel configured. |
document.connection.field.missing | ERROR | Target counterparty is missing an electronic addressable identifier. |
document.connection.selfBilling.supplier.registrationIdentifier.missing | ERROR | Supplier has no resolvable global registration identifier required for self-billing. |
document.connection.selfBilling.supplier.prefix.missing | ERROR | Supplier document number prefix is not configured for self-billed auto-numbering. |
document.connection.selfBilling.mandate.missing | WARNING | Self-billing mandate is not confirmed (mandate == false). Does not block processing. |
document.number.duplicate | ERROR | Duplicate document number or bank statement is already registered. |
document.sequence.duplicate | ERROR | Document number conflicts with the applicable document numbering sequence. |