Skip to main content

Overview

Before sending an e-invoice via Peppol, you need to know your customer’s Peppol ID (also called Peppol participant identifier). The e-invoice.be API provides lookup services to find registered Peppol participants and verify their identifiers.

What is a Peppol ID?

A Peppol ID is a unique identifier for organizations registered on the Peppol network. It consists of:
  • Scheme: The identifier scheme (e.g., 0208 for Belgian companies)
  • Identifier: The actual ID
Format: scheme:identifier0208:0123456789
Belgian Peppol IDs use the CBE number (Crossroads Bank for Enterprises number), which is equivalent to the Belgian VAT number without the ‘BE’ prefix. For example, if the VAT number is BE0123456789, the Peppol ID is 0208:0123456789 (numbers only).
Organizations must be registered with a Peppol Access Point to receive e-invoices. If a customer is not registered, they cannot receive invoices via Peppol.

Lookup by Peppol ID

Verify if a specific Peppol ID is registered and can receive invoices:

Using /api/validate/peppol-id

curl -X GET "https://api.e-invoice.be/api/validate/peppol-id?peppol_id=0208:0123456789" \
     -H "Authorization: Bearer YOUR_API_KEY"

Response

Registered and active:
{
  "valid": true,
  "peppol_id": "0208:0123456789",
  "registered": true,
  "participant_name": "Example Company NV",
  "capabilities": [
    "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2",
    "urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2"
  ]
}
Not registered:
{
  "valid": false,
  "peppol_id": "0208:0123456789",
  "registered": false,
  "message": "Participant not found in Peppol network"
}
Invalid format:
{
  "valid": false,
  "peppol_id": "0123456789",
  "message": "Invalid Peppol ID format. Expected: scheme:identifier (e.g., 0208:0123456789)"
}

Search for Participants

Search the Peppol network for participants by name or identifier:

Using /api/lookup/participants

curl -X GET "https://api.e-invoice.be/api/lookup/participants?query=Example%20Company" \
     -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "results": [
    {
      "peppol_id": "0208:0123456789",
      "name": "Example Company NV",
      "country_code": "BE",
      "registered": true
    },
    {
      "peppol_id": "0208:0987654321",
      "name": "Example Company International BVBA",
      "country_code": "BE",
      "registered": true
    }
  ],
  "total": 2
}

Query Parameters

ParameterDescriptionExample
querySearch term (name or ID)Example Company
country_codeFilter by country (ISO 3166-1 alpha-2)BE
limitMax results (default: 20, max: 100)50

General Lookup

Get detailed information about any Peppol participant:

Using /api/lookup

curl -X GET "https://api.e-invoice.be/api/lookup?peppol_id=0208:0123456789" \
     -H "Authorization: Bearer YOUR_API_KEY"

Response

{
  "peppol_id": "0208:0123456789",
  "participant_name": "Example Company NV",
  "country_code": "BE",
  "registered": true,
  "access_point": "e-invoice.be Access Point",
  "capabilities": [
    "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2",
    "urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2"
  ],
  "registration_date": "2024-01-15T10:00:00Z"
}

Common Peppol ID Schemes

Different countries use different identifier schemes:
CountryScheme CodeIdentifier TypeFormat Example
Belgium0208CBE number (VAT without ‘BE’)0208:0123456789
Netherlands0106KVK number0106:12345678
Germany0204VAT number0204:DE123456789
France0009SIRET0009:12345678901234
UK0088GLN0088:1234567890123
Norway0192Organization number0192:123456789
Sweden0007Organization number0007:1234567890
Denmark0184CVR number0184:12345678
International0088Global Location Number0088:1234567890123
For a complete list of Peppol identifier schemes, see the official Peppol code list.

Integration Examples

Node.js 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 lookupCustomer(cbeNumber) {
  try {
    // Construct Peppol ID (Belgian example)
    // Note: For Belgium, use CBE number without 'BE' prefix
    // If you have VAT number BE0123456789, use just 0123456789
    const peppolId = `0208:${cbeNumber}`;

    // Validate the Peppol ID
    const response = await api.get('/api/validate/peppol-id', {
      params: { peppol_id: peppolId }
    });

    if (response.data.valid && response.data.registered) {
      console.log('✓ Customer can receive e-invoices via Peppol');
      console.log('  Name:', response.data.participant_name);
      console.log('  Peppol ID:', response.data.peppol_id);
      return response.data;
    } else {
      console.log('✗ Customer is not registered on Peppol network');
      console.log('  They cannot receive e-invoices electronically');
      return null;
    }

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

// Example usage
lookupCustomer('0123456789');  // CBE number without 'BE' prefix

Search Example

async function searchCustomerByName(companyName) {
  try {
    const response = await api.get('/api/lookup/participants', {
      params: {
        query: companyName,
        country_code: 'BE',
        limit: 10
      }
    });

    if (response.data.results.length === 0) {
      console.log('No Peppol participants found for:', companyName);
      return [];
    }

    console.log(`Found ${response.data.total} participant(s):`);
    response.data.results.forEach(participant => {
      console.log(`  - ${participant.name} (${participant.peppol_id})`);
    });

    return response.data.results;

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

// Example usage
searchCustomerByName('Example Company');

Pre-Flight Check Workflow

Before creating an invoice, validate the recipient:
async function createInvoiceWithValidation(invoiceData) {
  try {
    // 1. Validate recipient is on Peppol network
    const customerPeppolId = invoiceData.customer.party_legal_entity.company_id;

    console.log('Checking if customer can receive e-invoices...');
    const validation = await api.get('/api/validate/peppol-id', {
      params: { peppol_id: customerPeppolId }
    });

    if (!validation.data.valid || !validation.data.registered) {
      console.error('❌ Customer cannot receive e-invoices via Peppol');
      console.error('   Peppol ID:', customerPeppolId);
      console.error('   Please use alternative delivery method (email, PDF)');
      return null;
    }

    console.log('✓ Customer can receive e-invoices');

    // 2. Validate invoice JSON
    console.log('Validating invoice JSON...');
    const jsonValidation = await api.post('/api/validate/json', invoiceData);

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

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

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

    // 4. Send via Peppol
    console.log('Sending via Peppol...');
    const result = await api.post(`/api/documents/${document.data.id}/send`);
    console.log('✓ Invoice sent:', result.data.state);

    return document.data;

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

Handling Unregistered Customers

If a customer is not on the Peppol network:
  1. Inform them: Let them know about Peppol e-invoicing benefits
  2. Alternative delivery: Send PDF invoices via email
  3. Register with e-invoice.be: Customers can sign up at e-invoice.be

Example: Fallback Logic

async function sendInvoiceToCustomer(invoiceData) {
  const peppolId = invoiceData.customer.party_legal_entity.company_id;

  // Check if customer is on Peppol
  const validation = await api.get('/api/validate/peppol-id', {
    params: { peppol_id: peppolId }
  });

  if (validation.data.valid && validation.data.registered) {
    // Send via Peppol
    return await sendViaPeppol(invoiceData);
  } else {
    // Fallback to email with PDF
    console.log('Customer not on Peppol, sending PDF via email');
    return await sendPdfViaEmail(invoiceData);
  }
}

Best Practices

Always check if a recipient can receive e-invoices before creating documents:
// ✓ Good: Check first
const isValid = await validatePeppolId(customerId);
if (isValid) {
  await createAndSendInvoice(data);
}

// ✗ Bad: Create first, fail later
await createAndSendInvoice(data); // May fail
Cache participant lookups to reduce API calls:
const participantCache = new Map();
const CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours

async function lookupWithCache(peppolId) {
  const cached = participantCache.get(peppolId);
  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.data;
  }

  const data = await lookupParticipant(peppolId);
  participantCache.set(peppolId, {
    data,
    timestamp: Date.now()
  });

  return data;
}
Different countries use different schemes. Build a mapping:
const PEPPOL_SCHEMES = {
  'BE': '0208',  // Belgian CBE (numbers only, no 'BE' prefix)
  'NL': '0106',  // Dutch KVK
  'DE': '0204',  // German VAT
  'FR': '0009',  // French SIRET
  'UK': '0088',  // UK GLN
};

function buildPeppolId(countryCode, identifier) {
  const scheme = PEPPOL_SCHEMES[countryCode];
  if (!scheme) {
    throw new Error(`Unknown country: ${countryCode}`);
  }
  return `${scheme}:${identifier}`;
}
When a customer isn’t found, guide them:
if (!validation.data.registered) {
  console.log(`
    Customer is not registered on the Peppol network.

    To receive e-invoices, they need to:
    1. Sign up at https://app.e-invoice.be
    2. Complete registration with their Peppol ID
    3. Configure their account to receive invoices

    Alternative: Send a PDF invoice via email instead.
  `);
}

Next Steps