KSeF - National e-Invoice System
KSeF is a Polish Ministry of Finance platform for structured invoices. The plugin prepares your store for KSeF integration - it detects orders requiring a VAT invoice, adds a status column and hooks for integration with invoicing systems.
KSeF legal status
Section titled “KSeF legal status”KSeF is in the implementation phase. The plugin does not issue invoices in KSeF, but makes integration easier with systems that do (e.g. Fakturownia, iFirma, wFirma, InFakt).
Main KSeF module features:
- Automatic detection of orders with a NIP number
- KSeF status column on the orders list
- Hooks for integration with external invoicing systems
- Order meta data ready for passing to the KSeF system
Detecting orders with NIP
Section titled “Detecting orders with NIP”When a customer provides a NIP during order placement (the NIP field is part of the Checkout module), the plugin automatically:
- Validates the NIP format (10 digits, checksum verification)
- Marks the order as requiring a VAT invoice
- Saves the NIP in order meta data
- Optionally retrieves company data from the GUS/CEIDG API
NIP validation
Section titled “NIP validation”The plugin checks NIP correctness at two levels:
- Format - 10 digits, correct checksum (weights: 6, 5, 7, 2, 3, 4, 5, 6, 7)
- Online verification - optional check in the VIES database (for EU NIPs) or GUS API
KSeF status column
Section titled “KSeF status column”On the orders list (WooCommerce > Orders) a KSeF column appears with status icons:
| Icon | Status | Description |
|---|---|---|
| Gray | Not applicable | Order without NIP, invoice not required |
| Blue | Pending | Order with NIP, invoice to be issued |
| Green | Issued | Invoice has been issued (status set by hook) |
| Red | Error | A problem occurred with issuing the invoice |
You can filter orders by KSeF status, e.g. display only those pending an invoice.
Bulk actions
Section titled “Bulk actions”On the orders list you can bulk-mark multiple orders as “issued in KSeF”.
polski/ksef/invoice_ready
Section titled “polski/ksef/invoice_ready”Triggered when an order with NIP is paid and ready for invoice issuance. The main hook for integration with invoicing systems.
/** * @param int $order_id WooCommerce order ID. * @param WC_Order $order Order object. * @param string $nip Customer NIP number. * @param array $invoice_data Invoice data (company name, address, NIP). */add_action('polski/ksef/invoice_ready', function (int $order_id, WC_Order $order, string $nip, array $invoice_data): void { // Example: send data to the Fakturownia API $api_token = get_option('fakturownia_api_token'); $account = get_option('fakturownia_account');
$invoice_payload = [ 'invoice' => [ 'kind' => 'vat', 'number' => null, // auto-numbering 'sell_date' => $order->get_date_paid()->format('Y-m-d'), 'issue_date' => current_time('Y-m-d'), 'payment_type' => 'transfer', 'seller_name' => get_option('woocommerce_store_name'), 'buyer_name' => $invoice_data['company_name'], 'buyer_tax_no' => $nip, 'buyer_street' => $invoice_data['address'], 'buyer_city' => $invoice_data['city'], 'buyer_post_code' => $invoice_data['postcode'], 'positions' => [], ], ];
foreach ($order->get_items() as $item) { $invoice_payload['invoice']['positions'][] = [ 'name' => $item->get_name(), 'quantity' => $item->get_quantity(), 'total_price_gross' => $item->get_total() + $item->get_total_tax(), 'tax' => round(($item->get_total_tax() / $item->get_total()) * 100), ]; }
$response = wp_remote_post("https://{$account}.fakturownia.pl/invoices.json", [ 'body' => wp_json_encode($invoice_payload), 'headers' => [ 'Content-Type' => 'application/json', 'Authorization' => 'Token token=' . $api_token, ], ]);
if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 201) { $body = json_decode(wp_remote_retrieve_body($response), true); update_post_meta($order_id, '_ksef_status', 'issued'); update_post_meta($order_id, '_ksef_invoice_id', $body['id'] ?? ''); } else { update_post_meta($order_id, '_ksef_status', 'error'); }}, 10, 4);polski/ksef/is_required
Section titled “polski/ksef/is_required”Filter allowing you to programmatically determine whether an order requires a KSeF invoice.
/** * @param bool $is_required Whether a KSeF invoice is required. * @param WC_Order $order Order object. * @return bool */add_filter('polski/ksef/is_required', function (bool $is_required, WC_Order $order): bool { // Example: require KSeF invoice for orders above 450 PLN if ($order->get_total() > 450) { return true; }
return $is_required;}, 10, 2);Example - automatic status marking after integration
Section titled “Example - automatic status marking after integration”/** * Update KSeF status after receiving a response from the invoicing system. */add_action('my_invoicing/invoice_created', function (int $order_id, string $ksef_number): void { $order = wc_get_order($order_id); if (!$order) { return; }
$order->update_meta_data('_ksef_status', 'issued'); $order->update_meta_data('_ksef_number', $ksef_number); $order->add_order_note( sprintf('Invoice issued in KSeF. KSeF number: %s', $ksef_number) ); $order->save();}, 10, 2);Order meta data
Section titled “Order meta data”The KSeF module saves the following meta data in orders:
| Meta key | Description |
|---|---|
_billing_nip | Customer NIP number |
_billing_company | Company name |
_ksef_required | Whether the order requires an invoice (yes/no) |
_ksef_status | Invoice status (pending, issued, error) |
_ksef_number | KSeF invoice number (after issuance) |
_ksef_invoice_id | Invoice ID in the external system |
Configuration
Section titled “Configuration”KSeF module settings: WooCommerce > Settings > Polski > KSeF.
| Option | Description | Default value |
|---|---|---|
| Enable KSeF module | Activates detection and tracking | Yes |
| Online NIP validation | Check NIP in GUS/VIES API | No |
| Auto-fetch company data | Fetch data from GUS after entering NIP | No |
| Hook trigger status | Order status at which to trigger invoice_ready | processing |
Troubleshooting
Section titled “Troubleshooting”KSeF column does not display on the orders list Click “Screen Options” and check the KSeF column. Make sure the module is enabled in settings.
NIP is not saved in the order Check that the NIP field is enabled in WooCommerce > Settings > Polski > Checkout. The field must be active for customers to fill it in.
The invoice_ready hook is not triggered Check the “Hook trigger status” setting. By default the hook fires at “Processing” status. For custom statuses, change this option.
Next steps
Section titled “Next steps”- Report issues: GitHub Issues
- Discussions and questions: GitHub Discussions