Skip to content

French e-invoicing (2026 reform)

France mandates electronic invoicing for domestic B2B transactions:

  • September 2026: every company must be able to receive e-invoices; large companies and mid-caps must also emit them.
  • September 2027: emission becomes mandatory for SMEs and micro-companies.

B2B invoices must transit through a Plateforme Agréée (PA), a government-accredited platform, in a structured format: Factur-X (PDF with embedded XML), UBL or CII. Pennylane is itself an accredited PA, so Pennylane users need no third-party platform. The API exposes the whole flow, and this SDK covers all of it.

Check your PA registrations

<?php

use Pennylane\Sdk\Pennylane;

$client = new Pennylane(); // reads PENNYLANE_API_TOKEN

foreach ($client->paRegistrations->list() as $registration) {
    echo $registration->siret . ' ' . $registration->status . PHP_EOL;
}

Send an invoice through the PA network

Finalize the invoice, then hand it to the platform:

$invoice = $client->customerInvoices->finalize($draft->id);
$client->customerInvoices->sendToPa($invoice->id);

Track the delivery status either on the invoice's e-invoicing field ($invoice->eInvoicing->status), via the change feed, or with the webhook event customer_invoice.e_invoicing_status_updated (see the webhooks guide).

Receive supplier e-invoices

Invoices arriving through the network land in Pennylane automatically. If you receive structured invoices through another channel, import them:

use Pennylane\Sdk\FileUpload;

$client->supplierInvoices->importEInvoice(FileUpload::fromPath('invoice.xml'));

The Factur-X or XML data is parsed structurally (no OCR), so supplier, amounts and lines are reliable.

Import sales e-invoices from another tool

If you invoice from an external ERP but keep Pennylane as your accounting system and PA, push your sales invoices as e-invoices:

$client->customerInvoices->importEInvoice(
    FileUpload::fromPath('factur-x.pdf'),
    invoiceOptions: [
        // pre-fills the customer and matches invoice lines by e_invoice_line_id
        // (the Factur-X BT-126 LineID), see the method docblock
        'customer_id' => 123,
    ],
);

Update e-invoice status (advanced)

Purchase-side workflows can update the lifecycle status of a received supplier e-invoice:

$client->supplierInvoices->updateEInvoiceStatus(
    $invoiceId,
    status: 'approved',
);

// Disputing a line requires a reason code
$client->supplierInvoices->updateEInvoiceStatus(
    $invoiceId,
    status: 'disputed',
    reason: 'incorrect_vat_rate',
);

status is one of disputed, refused or approved. reason is required with disputed (for example incorrect_vat_rate, incorrect_unit_prices, incorrect_billed_quantity, defective_delivered_item, bank_details_error) or with refused (for example incorrect_vat_rate, contract_completed, duplicate_invoice, non_compliant_invoice); it is omitted when status is approved.

Deadlines are business-critical

If you integrate invoicing for September 2026, test the PA flow early in a sandbox. The SDK raises ValidationException with the API's details when a document does not meet the format requirements.