Skip to main content

Overview

The /api/validate/json endpoint is essential for development. It validates your invoice JSON and ensures it can be converted to valid UBL BIS Billing 3.0 format before you create any documents.
You cannot create documents with invalid JSON. The API will reject invoices that don’t meet UBL BIS Billing 3.0 standards. Always validate during development to catch errors early.

Why Validate?

  • No document creation: Validation doesn’t create any records - it’s risk-free testing
  • Fast feedback: Get instant validation results without creating documents
  • Detailed errors: Receive specific field-level error messages
  • UBL compliance: Ensures your JSON converts to valid UBL BIS Billing 3.0 XML
  • Save API calls: Fix errors before attempting to create documents

Basic Validation

Use POST /api/validate/json with your invoice data:
curl -X POST "https://api.e-invoice.be/api/validate/json" \
     -H "Authorization: Bearer YOUR_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
  "document_type": "INVOICE",
  "invoice_id": "INV-2024-001",
  "invoice_date": "2024-10-24",
  "due_date": "2024-11-23",
  "currency": "EUR",
  "vendor_name": "Your Company BVBA",
  "vendor_tax_id": "BE0123456789",
  "vendor_address": "Main Street 123, 1000 Brussels, Belgium",
  "customer_name": "Customer Company NV",
  "customer_tax_id": "BE0987654321",
  "customer_address": "Customer Lane 456, 2000 Antwerp, Belgium",
  "items": [
    {
      "description": "Professional Services - Consulting services for October 2024",
      "quantity": "10",
      "unit_price": "100.00",
      "unit_code": "C62",
      "tax_rate": "21.00"
    }
  ]
}'
The example above will fail validation! This is intentional - it demonstrates why validation is critical. See below for the errors and how to fix them.

Response Types

Error Response (Real Example)

When validation fails, you’ll receive detailed UBL compliance errors. Here’s what the example above returns:
{
  "id": "b55354b0-5c69-489b-a8f7-44be7d5bdd6b",
  "file_name": "b55354b0-5c69-489b-a8f7-44be7d5bdd6b.xml",
  "is_valid": false,
  "issues": [
    {
      "message": "Belgian enterprise number MUST be stated in the correct format.",
      "type": "error",
      "rule_id": "PEPPOL-COMMON-R043",
      "flag": "fatal"
    },
    {
      "message": "[BR-S-08]-For each different value of VAT category rate (BT-119) where the VAT category code (BT-118) is \"Standard rated\", the VAT category taxable amount (BT-116) in a VAT breakdown (BG-23) shall equal the sum of Invoice line net amounts (BT-131)...",
      "type": "error",
      "rule_id": "BR-S-08",
      "flag": "fatal"
    },
    {
      "message": "Invoice line net amount MUST equal (Invoiced quantity * (Item net price/item price base quantity) + Sum of invoice line charge amount - sum of invoice line allowance amount",
      "type": "error",
      "rule_id": "PEPPOL-EN16931-R120",
      "flag": "fatal"
    }
  ]
}
This is exactly why the validation endpoint exists! These UBL BIS Billing 3.0 compliance errors would prevent your invoice from being sent. Let’s fix them.

Fixed Example

Here’s a corrected version that passes validation:
curl -X POST "https://api.e-invoice.be/api/validate/json" \
     -H "Authorization: Bearer YOUR_API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
  "document_type": "INVOICE",
  "invoice_id": "INV-2024-001",
  "invoice_date": "2024-10-24",
  "due_date": "2024-11-23",
  "currency": "EUR",
  "vendor_name": "Your Company BVBA",
  "vendor_tax_id": "BE0897290877",
  "vendor_address": "Main Street 123, 1000 Brussels, Belgium",
  "customer_name": "Customer Company NV",
  "customer_tax_id": "BE0817331995",
  "customer_address": "Customer Lane 456, 2000 Antwerp, Belgium",
  "items": [
    {
      "description": "Professional Services - Consulting services for October 2024",
      "quantity": "10",
      "unit_price": "100.00",
      "unit_code": "C62",
      "tax_rate": "21.00",
      "amount": "1000.00"
    }
  ]
}'
What changed:
  1. Valid Belgian VAT numbers with correct mod97 checksums:
    • BE0897290877 (vendor) instead of BE0123456789
    • BE0817331995 (customer) instead of BE0987654321
  2. Added amount field to line items: "1000.00" (quantity × unit_price)

Success Response

When your JSON is valid, you’ll receive confirmation along with the generated UBL XML:
{
  "id": "9eec0b03-4649-4ae4-9c4c-323ebb6d53e8",
  "file_name": "9eec0b03-4649-4ae4-9c4c-323ebb6d53e8.xml",
  "is_valid": true,
  "issues": [],
  "ubl_document": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\"..."
}
Response fields:
  • id: Validation session identifier
  • file_name: Generated XML filename
  • is_valid: true when validation passes
  • issues: Empty array when no errors
  • ubl_document: The generated UBL BIS Billing 3.0 XML (truncated above for readability)
Success means:
  • Your JSON is valid and UBL-compliant
  • You can see the exact UBL XML that will be generated
  • You’re ready to create the document using POST /api/documents/ with the same JSON payload
The ubl_document field shows you exactly what XML will be sent via Peppol. This is useful for debugging or understanding how your JSON maps to UBL BIS Billing 3.0.

Validating the UBL XML (Optional)

While the API always returns valid UBL when your JSON passes validation, you can optionally verify the generated UBL XML using the /api/validate/ubl endpoint.
This is completely optional - the JSON validation already ensures UBL compliance. Use this if you want to double-check the XML or validate externally-generated UBL files.

How to Validate UBL XML

Save the ubl_document from the validation response to a file, then validate it:
# First, save the UBL XML to a file (from the validation response above)
cat > invoice.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" ...>
  <!-- Your UBL XML content -->
</Invoice>
EOF

# Then validate the UBL file
curl -X POST "https://api.e-invoice.be/api/validate/ubl" \
     -H "Authorization: Bearer YOUR_API_KEY" \
     -F "[email protected]"

UBL Validation Response

Success (valid UBL):
{
  "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "file_name": "invoice.xml",
  "is_valid": true,
  "issues": []
}
Validation errors (if any):
{
  "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
  "file_name": "invoice.xml",
  "is_valid": false,
  "issues": [
    {
      "message": "Invoice total amount mismatch",
      "type": "error",
      "rule_id": "BR-CO-15",
      "flag": "fatal"
    }
  ]
}

When to Use UBL Validation

Use POST /api/validate/ubl when you:
  • Have existing UBL XML files to verify before sending
  • Want to double-check the generated XML from JSON validation
  • Are migrating from another system with pre-generated UBL documents
  • Need to validate UBL files from external sources
If you’re creating invoices from JSON, stick with /api/validate/json - it’s simpler and handles the UBL generation for you automatically.

Common Validation Errors

Invalid Peppol ID Format

{
  "field": "vendor_tax_id",
  "message": "Invalid Peppol ID format. Expected: scheme:identifier"
}
Fix: Use the correct format scheme:identifier
  • Belgian companies: 0208:0123456789 (CBE number - VAT without ‘BE’ prefix)
  • See Peppol schemes

Invalid Tax Rate

{
  "field": "items[0].tax_rate",
  "message": "Invalid tax rate format. Must be a percentage string"
}
Fix: Use string format for tax rates:
  • Standard rate: "21.00"
  • Reduced rate: "6.00"
  • Zero rated: "0.00"

Missing Required Fields

{
  "field": "vendor_address",
  "message": "Field is required for UBL compliance"
}
Fix: Ensure all required fields are present:
  • Vendor/customer name, tax ID, and address
  • Invoice ID, invoice date, currency
  • At least one item with description, quantity, unit price, and tax rate

Invalid Date Format

{
  "field": "invoice_date",
  "message": "Invalid date format. Use ISO 8601: YYYY-MM-DD"
}
Fix: Use the format YYYY-MM-DD, e.g., 2024-10-24

Invalid Currency Code

{
  "field": "currency",
  "message": "Unsupported currency code"
}
Fix: Use supported ISO 4217 codes: EUR, USD, GBP, JPY, CHF, CAD, AUD, NZD, CNY, INR, SEK, NOK, DKK, SGD, HKD

Development Workflow

1. Build Your Invoice JSON

Start with a template or build your invoice object:
const invoice = {
  document_type: 'INVOICE',
  invoice_id: 'INV-2024-001',
  invoice_date: '2024-10-24',
  currency: 'EUR',
  // ... rest of invoice data
};

2. Validate First

Always validate before attempting to create:
const validation = await api.post('/api/validate/json', invoice);

if (!validation.data.valid) {
  console.error('Validation errors:', validation.data.errors);
  // Fix errors and try again
  return;
}

3. Create Document

Only after validation passes, create the document:
const document = await api.post('/api/documents/', invoice);

Complete Development Example

const axios = require('axios');

const api = axios.create({
  baseURL: 'https://api.e-invoice.be',
  headers: {
    'Authorization': `Bearer ${process.env.E_INVOICE_API_KEY}`,
    'Content-Type': 'application/json'
  }
});

async function validateAndCreateInvoice(invoiceData) {
  try {
    // Step 1: Validate the JSON
    console.log('Validating invoice JSON...');
    const validation = await api.post('/api/validate/json', invoiceData);

    if (!validation.data.valid) {
      console.error('❌ Validation failed:');
      validation.data.errors.forEach(error => {
        console.error(`  - ${error.field}: ${error.message}`);
      });
      return null;
    }

    console.log('✓ Invoice JSON is valid');

    // Step 2: Create the document
    console.log('Creating invoice...');
    const document = await api.post('/api/documents/', invoiceData);
    console.log('✓ Invoice created:', document.data.id);

    return document.data;

  } catch (error) {
    console.error('Error:', error.response?.data || error.message);
    return null;
  }
}

// Example usage - using valid data
const invoiceData = {
  document_type: 'INVOICE',
  invoice_id: 'INV-2024-001',
  invoice_date: '2024-10-24',
  due_date: '2024-11-23',
  currency: 'EUR',
  vendor_name: 'Your Company BVBA',
  vendor_tax_id: 'BE0897290877',  // Valid Belgian VAT with mod97 checksum
  vendor_address: 'Main Street 123, 1000 Brussels, Belgium',
  customer_name: 'Customer Company NV',
  customer_tax_id: 'BE0817331995',  // Valid Belgian VAT with mod97 checksum
  customer_address: 'Customer Lane 456, 2000 Antwerp, Belgium',
  items: [
    {
      description: 'Professional Services - Consulting services for October 2024',
      quantity: '10',
      unit_price: '100.00',
      unit_code: 'C62',
      tax_rate: '21.00',
      amount: '1000.00'  // Required: quantity × unit_price
    }
  ]
};

validateAndCreateInvoice(invoiceData);

Testing Strategy

During Development

Use /api/validate/json liberally:
  1. Test edge cases: Validate unusual scenarios (zero amounts, multiple currencies, etc.)
  2. Test all document types: Validate invoices, credit notes, and debit notes
  3. Iterate quickly: Fix errors and re-validate without creating documents
  4. Build test suites: Create automated validation tests

Before Production

  1. Validate representative samples of all invoice types
  2. Test with real customer Peppol IDs
  3. Verify all tax categories and currency codes you’ll use
  4. Test complex scenarios (allowances, charges, multiple line items)

Validating UBL XML

If you have existing UBL XML files, validate them with POST /api/validate/ubl:
curl -X POST "https://api.e-invoice.be/api/validate/ubl" \
     -H "Authorization: Bearer YOUR_API_KEY" \
     -H "Content-Type: application/xml" \
     --data-binary @invoice.xml
This validates that your UBL file meets Peppol BIS Billing 3.0 requirements.

Best Practices

Don’t wait until production. Validate during development to catch issues early:
  • Test each new invoice template
  • Validate after schema changes
  • Include validation in CI/CD pipelines
if (!validation.data.valid) {
  // Log detailed errors
  logger.error('Invoice validation failed', {
    invoice_id: invoiceData.invoice_id,
    errors: validation.data.errors
  });

  // Notify developers/users
  notifyError(validation.data.errors);

  // Don't attempt to create the document
  return;
}
If you’re generating invoices from templates, validate the template once and cache the result:
const templateCache = new Map();

function validateTemplate(templateName, templateData) {
  if (templateCache.has(templateName)) {
    return templateCache.get(templateName);
  }

  const isValid = validateInvoiceJSON(templateData);
  templateCache.set(templateName, isValid);
  return isValid;
}
Test validation extensively in the staging environment before moving to production:
  • Staging: https://api-dev.e-invoice.be
  • Production: https://api.e-invoice.be

Next Steps