KSeF 2.0 — National e-Invoice System Integration (Poland)
by Aura Odoo Tech http://auraodoo.tech/| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Invoicing (account)
• Discuss (mail) |
| Lines of code | 1401 |
| Technical Name |
ksef_integration |
| License | OPL-1 |
| Website | http://auraodoo.tech/ |
| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Invoicing (account)
• Discuss (mail) |
| Lines of code | 1401 |
| Technical Name |
ksef_integration |
| License | OPL-1 |
| Website | http://auraodoo.tech/ |
🇵🇱 KSeF 2.0 Integration
Full integration with the Polish Krajowy System e-Faktur (KSeF 2.0) — National e-Invoice System operated by the Ministry of Finance.
Overview
This module seamlessly connects Odoo 19 with the Polish Government's KSeF 2.0 REST API. It lets you send, receive, and track e-invoices (FA-XML) directly from the Odoo accounting interface — both individually in real time and in bulk asynchronous batches.
AccountMove._build_fa_xml() with the Aura Odoo Tech renderer.
Module Architecture & Data Flow
(account.move)
Send / Batch
(services/ksef_client.py)
mf.gov.pl
Response / KSeF ID
Audit Trail
Status & KSeF Ref#
The module is layered into four clear tiers:
| Tier | Files | Responsibility |
|---|---|---|
| Models | models/ |
ORM fields, computed values, business logic on invoices |
| Services | services/ksef_client.py |
Low-level HTTP wrapper for the KSeF REST API (no Odoo ORM) |
| Wizards | wizard/ |
Interactive UI dialogs for send / batch-send |
| Controllers | controllers/main.py |
Inbound webhook endpoint (POST /ksef/webhook) |
Key Features
🔑 Token Authentication
- Challenge → SHA-256 hash → SessionToken flow
- Supports Production, Demo, and Test environments
- Automatic session creation & termination
- Session tracked in
ksef.sessionmodel
📤 Interactive Sending
- Send one invoice at a time from the form view
- Real-time status polling after submission
- KSeF Reference Number written back automatically
- FA-XML attached to invoice as a file
📦 Batch Sending
- Multi-select invoices → pack into ZIP → upload
- Asynchronous processing by KSeF
- Batch ID logged per invoice
- Poll batch status on demand
📋 Invoice Types
- FA – Regular VAT invoices
- FAK – Corrective invoices (credit notes)
- FZA – Advance payment invoices
- FRZ – Settlement (final) invoices
💱 Currency Support
- PLN invoices — native direct submission
- Foreign currencies (EUR, USD, …) supported
- Exchange rate passed via
KodWalutyFA-XML field
📊 Audit Trail
- Every API interaction logged in
ksef.invoice.log - Log visible on stat-button of each invoice
- Stores raw JSON response & sent XML
- Accessible from Accounting → KSeF → Log
⚙️ Auto-Send on Confirm
- Optional automatic send when invoice is posted
- Toggle in Accounting → Configuration → KSeF
- Skips already accepted invoices automatically
🔗 Webhook Support
- Inbound
POST /ksef/webhookendpoint - Handles push notifications from KSeF middleware
- Updates invoice status automatically on receipt
Models (Database Objects)
account.move — Invoice Extension
The core Odoo invoice model is extended with the following KSeF fields:
| Field | Type | Description |
|---|---|---|
ksef_state |
Selection | Current KSeF status of the invoice (see status pills below) |
ksef_reference_number |
Char | Official KSeF ID assigned after acceptance |
ksef_element_reference |
Char | Temporary reference used for status polling |
ksef_sent_at |
Datetime | Timestamp when invoice was sent to KSeF |
ksef_accepted_at |
Datetime | Timestamp when KSeF confirmed acceptance |
ksef_environment |
Selection | Environment used during sending (test/demo/prod) |
ksef_fa_type |
Selection | FA invoice type (FA / FAK / FZA / FRZ) — auto computed |
ksef_log_ids |
One2many | Linked audit log entries |
Invoice Status Values:
not_sent – Not Sent pending – Pending / Processing accepted – Accepted by KSeF rejected – Rejected error – Error received – Received from KSeFksef.invoice.log — Audit Log
Records every interaction between Odoo and KSeF per invoice.
| Field | Description |
|---|---|
invoice_id |
Linked invoice (cascade delete) |
operation |
send / batch_send / status_poll / download / receive |
invoice_type |
FA type at time of operation |
element_reference_number |
Temporary reference for polling |
ksef_reference_number |
Official KSeF ID |
batch_id |
Batch identifier if part of a batch send |
state |
pending / processing / accepted / rejected / error / received |
ksef.session — Session Tracker
Tracks each authenticated KSeF API session for audit and management.
| Field | Description |
|---|---|
nip |
Polish Tax Identification Number (10 digits) |
environment |
test / demo / prod |
session_token |
Active session token from KSeF |
state |
active / terminated / expired / error |
terminated_at |
Session close timestamp |
res.config.settings — Configuration Panel
Settings stored as system parameters (ir.config_parameter):
| Parameter | Key | Default |
|---|---|---|
| KSeF Environment | ksef.environment |
test |
| Taxpayer NIP | ksef.nip |
— |
| API Token | ksef.api_token |
— |
| Auto-send on Confirm | ksef.auto_send |
false |
| Store KSeF XML | ksef.store_xml |
true |
| API Timeout (sec) | ksef.timeout |
30 |
KSeF API Client (Services Layer)
services/ksef_client.py is a pure Python HTTP wrapper — no Odoo ORM dependency —
making it fully testable in isolation.
Covered API Endpoints
Authentication
POST /api/online/Session/AuthorisationChallengePOST /api/online/Session/AuthorisationGET /api/online/Session/Terminate
Interactive Invoice
POST /api/online/Invoice/SendGET /api/online/Invoice/Status/{ElementRef}GET /api/online/Invoice/Get/{KsefRef}
Batch Sending
POST /api/batch/InitPUT /api/batch/Upload/{BatchId}/{PartName}POST /api/batch/Finish/{BatchId}GET /api/batch/Status/{BatchId}
Inbox (Received Invoices)
GET /api/online/Invoice/GetForSellerGET /api/online/Invoice/GetForBuyer
Authentication Flow (Challenge–Response)
# 1. Request challenge (timestamp token) from KSeF challenge = client.authorisation_challenge(nip="1234567890") # 2. Hash: SHA-256( base64(api_token) + challenge_timestamp ) # 3. Send hashed credentials → receive SessionToken client.authorise(nip, api_token, challenge) # 4. All subsequent calls carry the SessionToken header status = client.invoice_status(element_reference) # 5. Terminate session when done client.terminate_session()
Sending Workflows
1 — Interactive (Single Invoice)
Navigate to a posted customer invoice (out_invoice / out_refund).
The KSeF Send Wizard opens, pre-filled with the current invoice.
Check environment, polling option, and whether to re-send already accepted invoices. Click Send.
The wizard calls _ksef_authenticate() using NIP + API Token from settings.
_build_fa_xml() generates the invoice XML. A base64-encoded copy is
attached if Store KSeF XML is enabled.
POST /api/online/Invoice/Send — returns an
ElementReferenceNumber.
If Poll Status After Sending is on, the wizard waits for KSeF to process and retrieve the official KSeF Reference Number.
KSeF Ref#, status, and timestamps are saved on the invoice. A log entry is created in
ksef.invoice.log.
2 — Batch (Multiple Invoices)
In the invoice list view, tick multiple posted invoices.
Action → Send to KSeF (Batch). Optionally rename the batch label.
Each invoice's FA-XML is written into a .zip in memory
(zipfile.ZipFile).
POST /api/batch/Init — receives batchId.
PUT /api/batch/Upload/{batchId}/part1.zip — uploads the entire archive.
POST /api/batch/Finish/{batchId} — KSeF begins async processing.
Batch ID is stored per invoice. Use Accounting → KSeF → Transmission Log to
poll GET /api/batch/Status/{batchId} and update statuses.
3 — Auto-Send on Invoice Confirmation
action_post(). Immediately after a invoice is confirmed (posted), it automatically
calls the interactive send flow without any user intervention. Already accepted invoices are
always skipped.
Installation & Setup
Place the ksef_integration/ folder into your Odoo addons path.
Restart the server so the new module is detected:
sudo systemctl restart odoo
Go to Apps → (search) KSeF Integration → click Install.
Navigate to Accounting → Configuration → Settings → KSeF 2.0 and enter:
•
Environment (Test / Demo / Production)
• Taxpayer NIP (10 digits)
• API Token
(from KSeF portal)
Click Test KSeF Connection — the module runs a full challenge → auth → terminate cycle. A success notification confirms everything is working.
Menu & UI Navigation
| Path | What You Can Do |
|---|---|
| Accounting → KSeF → Dashboard | Overview of KSeF activity |
| Accounting → KSeF → Transmission Log | Full audit log of all KSeF API calls |
| Accounting → KSeF → Sessions | View and terminate active KSeF sessions |
| Accounting → Configuration → Settings → KSeF 2.0 | Environment, NIP, token, auto-send toggle |
| Invoice Form → "Send to KSeF" button | Interactive send wizard for one invoice |
| Invoice List → Action → "Send to KSeF (Batch)" | Batch send wizard for selected invoices |
| Invoice Form → KSeF Log stat-button | Audit log entries for that specific invoice |
Dependencies
| Module | Purpose | Required? |
|---|---|---|
account |
Base Odoo invoicing framework | ✅ Yes |
account_edi |
EDI framework / FA-XML rendering hooks | ✅ Yes |
base_setup |
Settings panel integration | ✅ Yes |
| Aura Odoo Tech Invoice (paid) | Production-grade FA(2)/FA(3) XML generation | ⚠️ Recommended |
_build_fa_xml() generates a functional placeholder XML.
For production use, the FA(2)/FA(3) schema-compliant generation requires the
Aura Odoo Tech Invoice module. Replace the placeholder method with the
Aura Odoo Tech renderer before going live.
KSeF Environments
| Environment | Base URL | Use For |
|---|---|---|
| Production | https://ksef.mf.gov.pl |
Live legal invoices |
| Demo | https://ksef-demo.mf.gov.pl |
Demos without legal effect |
| Test | https://ksef-test.mf.gov.pl |
Development & testing |
Invoice Type (FA Type) Mapping
| FA Type | Odoo move_type | Description |
|---|---|---|
| FA | out_invoice / in_invoice |
Regular VAT invoice |
| FAK | out_refund / in_refund or debit origin |
Corrective invoice (credit note) |
| FZA | out_invoice flagged manually | Advance payment invoice |
| FRZ | out_invoice flagged manually | Settlement (final) invoice against FZA |
ksef_fa_type is computed automatically from move_type and
debit_origin_id. FZA and FRZ types must be manually selected on the invoice
when applicable.
Webhook Endpoint
The module exposes an HTTP controller at POST /ksef/webhook for receiving
push notifications from a KSeF middleware or integration platform. When a POST is received:
- The payload is parsed for a KSeF Reference Number or batch status update.
- The matching
account.moverecord is located and its status updated. - A new
ksef.invoice.logentry with operationreceiveis created.
External References
📄 Official KSeF Resources
- KSeF Portal — podatki.gov.pl
- FA(2)/FA(3) Schema Documentation
- Production API:
ksef.mf.gov.pl - Test API:
ksef-test.mf.gov.pl
🔧 Aura Odoo Tech Integration
- Aura Odoo Tech KSeF 2.0 module info
- Required for certified FA-XML output
- Replace
_build_fa_xml()with Aura Odoo Tech renderer
Module File Structure
ksef_integration/ ├── __manifest__.py # Module metadata, dependencies, version ├── __init__.py ├── models/ │ ├── account_move.py # Invoice extension: fields, send logic, XML builder │ ├── ksef_config.py # Settings (res.config.settings extension) │ ├── ksef_invoice_log.py # Audit log model │ └── ksef_session.py # Session tracker model ├── services/ │ └── ksef_client.py # Pure HTTP wrapper for KSeF REST API ├── wizard/ │ ├── ksef_send_wizard.py # Interactive send dialog │ └── ksef_batch_wizard.py # Batch send dialog ├── controllers/ │ └── main.py # Webhook controller POST /ksef/webhook ├── views/ │ ├── ksef_menu.xml # Menu items under Accounting → KSeF │ ├── ksef_config_views.xml # Settings panel │ ├── account_move_ksef_views.xml # Invoice form button & stat-button │ ├── ksef_invoice_log_views.xml # Log list & form views │ ├── ksef_send_wizard_views.xml # Interactive send wizard view │ └── ksef_batch_wizard_views.xml # Batch wizard view ├── data/ │ └── ksef_data.xml # Default data / server actions ├── security/ │ └── ir.model.access.csv # Access rights for all KSeF models └── static/description/ └── index.html # This page
Odoo Proprietary License v1.0 This software and associated files (the "Software") may only be used (executed, modified, executed after modifications) if you have purchased a valid license from the authors, typically via Odoo Apps, or if you have received a written agreement from the authors of the Software (see the COPYRIGHT file). You may develop Odoo modules that use the Software as a library (typically by depending on it, importing it and using its resources), but without copying any source code or material from the Software. You may distribute those modules under the license of your choice, provided that this license is compatible with the terms of the Odoo Proprietary License (For example: LGPL, MIT, or proprietary licenses similar to this one). It is forbidden to publish, distribute, sublicense, or sell copies of the Software or modified copies of the Software. The above copyright notice and this permission notice must be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Please log in to comment on this module