Paired Mode โ Dual-Channel Invoicing (Magento 2)
KSeF Pro for Magento 2 can operate in Paired Mode alongside Fakturownia Pro for Magento 2. A single Magento invoice event triggers both KSeF submission (government channel) and Fakturownia.pl invoice creation (customer PDF channel) โ with the KSeF-ID embedded in the customer PDF.
Standalone vs. Paired Mode
| Aspect | Standalone KSeF Pro | Paired Mode |
|---|---|---|
| Government submission | Yes โ FA(2) XML to KSeF | Yes โ same |
| Customer-facing PDF | No | Yes โ Fakturownia Pro generates PDF |
| KSeF-ID on customer PDF | N/A | Yes โ populated via event observer |
| Magento event architecture | InvoiceSaveAfterObserver (KSeF only) | InvoiceSaveAfterObserver + KsefIdReceivedObserver |
| Configuration | KSeF Pro admin panel only | Shared rule engine in KSeF Pro |
| Multi-store support | Per-website KSeF token + NIP | Per-website KSeF + Fakturownia credentials |
| Required extensions | KSeF Pro only | KSeF Pro + Fakturownia Pro |
| Best for | Stores using another PDF solution | Stores needing both compliance and customer PDF automated |
When NOT to use Paired Mode: If you manage Fakturownia invoices manually, use a third-party ERP integration, or have a separate PDF generation extension, Paired Mode will conflict. Enabling it hands control of Fakturownia invoice creation to KSeF Pro's shared rule engine, overriding Fakturownia Pro's own observer.
Why Paired Mode?
Magento generates invoices natively, but KSeF requires a separate FA(2) XML submission to the government. Fakturownia Pro generates the customer-facing PDF. Without Paired Mode, you need to monitor and manually coordinate two separate processes.
| Channel | Extension | Output | Recipient | |---|---|---|---| | Government | KSeF Pro | FA(2) XML โ KSeF-ID + UPO | Ministry of Finance | | Customer | Fakturownia Pro M2 | PDF invoice with KSeF-ID | Customer email + account |
Without Paired Mode, the KSeF-ID is not on the customer PDF unless you manually update each Fakturownia invoice after submission โ not practical at any volume.
Requirements
- KSeF Pro for Magento 2 โ installed, KSeF connection verified, test submission completed
- Fakturownia Pro for Magento 2 โ version 3.0 or later, Fakturownia API token connected
- Both extensions individually configured and working
- Compatible Magento: 2.4.5 or later
- PHP: 8.1 or later
Step-by-Step Setup
Phase 1: Verify each extension independently
- Run
bin/magento ksefpl:test-connectionand confirm success - Create a test Magento invoice for an order and verify it appears in the KSeF audit log as
ACCEPTED - Run
bin/magento fakturownia:connection:testand confirm a green result - Trigger a manual Fakturownia invoice from the order detail and verify it appears in Fakturownia.pl
Phase 2: Enable Paired Mode
- Go to Stores โ Configuration โ PlugKit โ KSeF Pro โ Invoice Settings
- Enable the "Paired mode with Fakturownia Pro" toggle
- Select trigger order (see below)
- Save configuration
- Flush config cache:
php bin/magento cache:clean config - Recompile DI to register the new observer:
php bin/magento setup:di:compile

Phase 3: Test the full dual-channel flow
- Create a new Magento invoice for a test order
- Wait for the KSeF cron to process (or run
bin/magento ksefpl:process-queuemanually) - Check the KSeF audit log: Sales โ KSeF Pro โ Audit Log โ confirm
KSEF_IDandFAKTUROWNIA_IDare both populated - Check Fakturownia.pl โ confirm the invoice has the
numer_kseffield populated - Download the customer PDF โ confirm the KSeF-ID appears under "KSeF numer"
Trigger Order
KSeF First (Recommended)
KSeF Pro submits via cron and waits for the permanent KSeF-ID (UPO received). Once the KSeF-ID arrives, KSeF Pro dispatches a ksefpl_ksef_id_received Magento event. Fakturownia Pro's KsefIdReceivedObserver listens to this event and creates the Fakturownia invoice with numer_ksef pre-populated.
| Aspect | Detail | |---|---| | Customer PDF timing | Delayed by KSeF processing time (typically 30โ90 seconds after invoice creation) | | KSeF-ID on PDF | Always present โ Fakturownia invoice is not created until ID is confirmed | | Sync guarantee | Both channels either succeed together or fail visibly | | Recommended for | B2B stores, high-value invoices, stores needing strong compliance |
Simultaneous
Both extensions fire independently from the sales_order_invoice_save_after observer. Fakturownia Pro creates the invoice immediately (without KSeF-ID); KSeF Pro submits via cron. When the UPO arrives, KSeF Pro dispatches ksefpl_ksef_id_received and Fakturownia Pro updates the existing invoice with the KSeF-ID via a Fakturownia API PATCH call.
| Aspect | Detail | |---|---| | Customer PDF timing | Immediate โ customer receives PDF before KSeF confirmation | | KSeF-ID on first PDF | Absent โ backfilled on second email (if configured) or available in portal | | Requires | Fakturownia Pro M2 version 3.2+ (PATCH update support) | | Recommended for | B2C stores, high volume, where immediate PDF is prioritised |
Event Architecture
Understanding the Magento event flow helps with debugging and custom integrations.
KSeF First Mode
sales_order_invoice_save_after
โ
PlugKit\KsefPl\Observer\InvoiceSaveAfterObserver
โ Queues KSeF job (Fakturownia Pro held)
โ
ksefpl_process_queue cron
โ FA(2) XML signed and submitted to KSeF
โ Session closed
โ
ksefpl_poll_status + ksefpl_download_upo cron
โ UPO downloaded
โ KSeF-ID stored in ksefpl_invoice_registry
โ
PlugKit\KsefPl\Event\KsefIdReceived dispatched
โ
PlugKit\FakturowniaM2\Observer\KsefIdReceivedObserver
โ Creates Fakturownia invoice via API
โ Sets numer_ksef = KSeF-ID
โ PDF generated and emailed to customer
Simultaneous Mode
sales_order_invoice_save_after
โ (both fire independently)
โโโ PlugKit\KsefPl\Observer\InvoiceSaveAfterObserver
โ โ Queue KSeF job
โ
โโโ PlugKit\FakturowniaM2\Observer\InvoiceSaveAfterObserver
โ Create Fakturownia invoice (no KSeF-ID yet)
โ Email PDF to customer immediately
--- Later (after UPO) ---
PlugKit\KsefPl\Event\KsefIdReceived dispatched
โ
PlugKit\FakturowniaM2\Observer\KsefIdReceivedObserver
โ PATCH Fakturownia invoice: set numer_ksef
For custom integrations: The ksefpl_ksef_id_received event is public and stable across minor versions. Any custom Magento module can observe it to receive the KSeF-ID as soon as it is confirmed โ useful for ERP integrations, notification systems, or BI tools that need real-time KSeF confirmation data.
Event payload:
// Event data keys:
$event->getKsefId() // string: KSeF-ID from Ministry of Finance
$event->getInvoiceId() // int: Magento invoice entity ID
$event->getOrderId() // int: Magento order entity ID
$event->getUpoPath() // string: path to stored UPO XML fileShared Rule Engine
In Paired Mode, KSeF Pro's rule engine governs both channels. Configure under Stores โ Configuration โ PlugKit โ KSeF Pro โ Invoice Settings โ Rule Engine:
| Setting | Effect on Both Channels |
|---|---|
| Invoice trigger (on creation / on capture / manual) | Same trigger fires both |
| B2B vs B2C detection (NIP present on order) | Determines <Podmiot2> in FA(2) and buyer block in Fakturownia |
| Tax rate mapping | FA(2) <StawkaPodatku> codes + Fakturownia rate categories |
| Currency rules | PLN direct / non-PLN with NBP rate |
| Payment method exclusions | Excludes same orders from both channels |
| Customer group conditions | Same group filters for both |
Fakturownia Pro's own trigger configuration is overridden by the shared rule engine when Paired Mode is active. Configure invoicing logic in one place.
KSeF-ID on Customer Documents
When Fakturownia Pro creates the invoice, it receives the KSeF-ID in the numer_ksef field. The Fakturownia.pl default template displays this as "KSeF numer" in the invoice header.
For custom Fakturownia invoice templates, add the {numer_ksef} merge tag. Buyers use this number to:
- Verify the invoice at
https://ksef.mf.gov.pl(public endpoint, no login needed) - Import the document into their accounting software via the KSeF API
- Reference it in their own VAT return filings
Multi-Store Scope in Paired Mode
Magento's scope hierarchy applies to Paired Mode:
- Each website can have a different KSeF token, NIP, and Fakturownia API account
- Rule engine conditions can be scoped per website (e.g., different tax mappings for Polish vs. EU orders)
- Both extensions use the effective scope of the order's originating website
For a store with Website A (Polish B2B, NIP A) and Website B (EU exports, NIP B):
Website A orders โ KSeF token A + NIP A โ Fakturownia account A
Website B orders โ KSeF token B + NIP B โ Fakturownia account B
Configure each website scope in Stores โ Configuration with the scope switcher set to the respective website.
Discrepancy States and Recovery
| State | Meaning | Recovery |
|---|---|---|
| KSEF_OK_FAKTUROWNIA_FAILED | KSeF accepted; Fakturownia API error | Retry Fakturownia leg from audit log |
| KSEF_FAILED_FAKTUROWNIA_SKIPPED | KSeF failed; Fakturownia blocked | Fix KSeF error; retry both |
| KSEF_ID_BACKFILL_FAILED | KSeF-ID received; Fakturownia PATCH failed | Re-run backfill via CLI |
Retry Fakturownia Leg Only
From Sales โ KSeF Pro โ Audit Log, filter by KSEF_OK_FAKTUROWNIA_FAILED:
- Select the affected records
- Click "Retry Fakturownia leg"
Or via CLI:
php bin/magento ksefpl:retry-fakturownia --invoice-id=INV-00001234This creates a new Fakturownia invoice (or updates an existing one) using the stored KSeF-ID โ no new KSeF session is opened.
FAQ
Do I need both extensions?
No. Each extension works independently. KSeF Pro handles government compliance; Fakturownia Pro handles customer PDF invoicing. Paired Mode automates the integration when you need both.
What if KSeF is down but Fakturownia is working?
In "KSeF first" mode: Fakturownia invoice creation is blocked until KSeF recovers. Orders accumulate in the KSeF queue and process once the government API is available.
In "Simultaneous" mode: Fakturownia creates the invoice immediately. Customer receives a PDF without a KSeF-ID. The ID is backfilled once KSeF processes the submission and the UPO is downloaded.
What if Fakturownia is down but KSeF is working?
KSeF submits normally. The Fakturownia leg fails and logs as KSEF_OK_FAKTUROWNIA_FAILED. Retry the Fakturownia leg from the audit log once Fakturownia is available โ the stored KSeF-ID is used, no re-submission to the government.
Does Paired Mode affect existing invoices?
No. Enabling Paired Mode affects only new invoice events going forward. Existing Fakturownia invoices are not modified. Existing KSeF audit records without Fakturownia IDs are not retroactively processed.
What cache types need flushing after configuration changes?
Flush config and full_page at minimum:
php bin/magento cache:clean config full_pageAfter any DI change (adding/removing observers), recompile:
php bin/magento setup:di:compileCredit Memos in Paired Mode
When a Magento credit memo is created:
- KSeF Pro generates an FA(2)
KOR(correction) document referencing the original KSeF-ID - After the correction KSeF-ID arrives via UPO, Fakturownia Pro creates a credit note (
korekta) linked to the original Fakturownia invoice - Customer receives a credit note PDF with the correction KSeF-ID under "KSeF numer"
Both the correction KSeF submission and the Fakturownia credit note are logged as a linked pair in the audit trail under the same order ID.
Cross-Platform KSeF Accounts
If you operate WooCommerce or PrestaShop stores alongside Magento 2, all platforms can share the same KSeF token and NIP. The government's ledger aggregates all submissions regardless of platform origin:
Each platform has its own Fakturownia Pro instance. Department assignment in Fakturownia.pl differentiates invoices by platform if needed.