KSeF Connection & Authentication
KSeF Pro for Magento 2 uses the same KSeF API authentication model as the PrestaShop and WooCommerce variants. This page covers the authentication flow with Magento-specific details on credential storage via EncryptorInterface, session token caching in Magento's cache backend, and observer integration.
Authentication Flow
KSeF authentication is session-based. Your token initiates sessions — it is not sent with every API call. KSeF Pro executes this flow automatically using Magento's HTTP client (\Magento\Framework\HTTP\Client\Curl):
Step 1: Request challenge
POST /api/online/Session/AuthorisationChallenge
→ Body: { "contextIdentifier": { "type": "onip", "identifier": "YOUR_NIP" } }
← Response: { "challenge": "abc123...", "timestamp": "2025-03-01T10:00:00Z" }
Step 2: Compute HMAC-SHA256 signature
- Decrypt stored token using \Magento\Framework\Encryption\EncryptorInterface
- Compute: HMAC_SHA256(key=decrypted_token, data=challenge+timestamp)
Step 3: Exchange for session token
POST /api/online/Session/AuthorisationToken
→ Body: {
"challenge": "abc123...",
"authorisation": "HMAC_SIGNATURE",
"identifier": { "type": "onip", "identifier": "YOUR_NIP" }
}
← Response: { "sessionToken": { "token": "SESSION_TOKEN", "context": {...} } }
Step 4: Use SESSION_TOKEN as Bearer for all session API calls
Authorization: Bearer SESSION_TOKEN
KSeF Pro stores the session token in Magento's cache backend (cache tag ksefpl_session_token, TTL 25 minutes) — 5 minutes shorter than the MF-side 30-minute expiry to ensure proactive refresh.

Credential Storage in Magento
KSeF Pro stores the API token using \Magento\Framework\Encryption\EncryptorInterface. This interface wraps Magento's deployment-specific MAGE_KEY from app/etc/env.php. The encrypted value is saved to core_config_data under the path ksefpl/connection/api_token.
MAGE_KEY Considerations
On-premises: The MAGE_KEY is stable unless you explicitly regenerate it. After any MAGE_KEY rotation, re-enter the KSeF token in Stores → Configuration → PlugKit → KSeF Pro.
Adobe Commerce Cloud: Each cloud environment (Production, Staging, Integration) has a distinct MAGE_KEY. When you clone a database from Production to Staging, the KSeF token in core_config_data is encrypted with the Production key and unreadable in Staging. Re-enter the Staging/test token in the Staging environment.
Best practice for cloud: Store the KSeF token as a cloud environment variable rather than in the database:
magento-cloud variable:set \
--name=KSEFPL_API_TOKEN \
--value="your-test-token-here" \
--sensitive=true \
--environment=stagingKSeF Pro checks KSEFPL_API_TOKEN in the environment before reading from core_config_data. This approach survives database clones and environment resets.
Diagnosing Decryption Failures
php bin/magento ksefpl:test-connectionIf the stored token is unreadable (wrong MAGE_KEY), the output includes: Unable to decrypt stored token — re-enter the API token in configuration. Re-enter the token in the Admin configuration and save.
Test vs. Production Environments
Test Environment (ksef-test.mf.gov.pl)
| Characteristic | Test | Production |
|---|---|---|
| API URL | https://ksef-test.mf.gov.pl/api | https://ksef.mf.gov.pl/api |
| FA(2) schema | Same (2.0 from April 2026) | Authoritative |
| Token type | Test tokens only | Production tokens only |
| UPOs issued | Yes — functionally complete | Yes — legally binding |
| KSeF-IDs | Assigned, no legal standing | Permanent, in VAT ledger |
| Legal standing | None | Mandatory |
Validate the following against the test environment before going live:
ksefpl:test-connectionreturns success- FA(2) XML preview shows correct seller NIP, address, and tax codes
- A test Magento invoice completes:
PENDING→SUBMITTED→ACCEPTEDin the audit log - KSeF-ID is written to the Magento invoice record
- UPO is downloadable from the audit log
Switching to Production
- In Magento Admin: Stores → Configuration → PlugKit → KSeF Pro → KSeF Connection
- Change Environment to
Production - Replace the test token with your production token
- Click "Test KSeF Connection" — green indicator required
- Flush config cache:
php bin/magento cache:clean config
NIP production check before going live:
curl -s -X POST https://ksef.mf.gov.pl/api/online/Session/AuthorisationChallenge \
-H "Content-Type: application/json" \
-d '{"contextIdentifier":{"type":"onip","identifier":"YOUR_10_DIGIT_NIP"}}' \
| python3 -m json.toolA challenge field in the response confirms the NIP is registered and active in production KSeF.
NIP Validation
KSeF Pro validates NIP at three checkpoints:
1. On Configuration Save
- Strips formatting characters
- Validates 10-digit format
- Applies weighted checksum algorithm (weights 6,5,7,2,3,4,5,6,7 against digits 1–9; digit 10 = sum mod 11)
- Red inline error on failure; config cannot be saved with invalid NIP
2. On "Test KSeF Connection" Click
- Sends a challenge request to the selected environment
- MF server validates the NIP against the token's registered NIP
- Error
20100= NIP mismatch (config NIP differs from token's NIP) - Error
10000= NIP not registered in KSeF for this environment
3. Pre-Queue Entry (Observer)
The InvoiceSaveAfterObserver performs a lightweight pre-flight check before adding a job to ksefpl_queue. If the token is revoked since the last successful connection test, the job is added with status AUTH_ERROR — it will not be submitted until the connection is re-verified in the Admin. This prevents a backlog of FAILED jobs accumulating during a token rotation.
Observer Integration
KSeF Pro hooks into Magento's invoice lifecycle via the observer pattern, not event plugins:
<!-- PlugKit/KsefPl/etc/events.xml -->
<event name="sales_order_invoice_save_after">
<observer name="ksefpl_invoice_queue"
instance="PlugKit\KsefPl\Observer\InvoiceSaveAfterObserver"
sortOrder="200" />
</event>
<event name="sales_order_creditmemo_save_after">
<observer name="ksefpl_creditmemo_queue"
instance="PlugKit\KsefPl\Observer\CreditMemoSaveAfterObserver"
sortOrder="200" />
</event>sortOrder="200" ensures KSeF Pro fires after other invoice observers (e.g., Fakturownia Pro, ERP connectors). Change the sort order in your custom module's di.xml if KSeF Pro needs to fire in a different position.
Both observers only queue the submission — they complete in milliseconds and never make HTTP calls to the KSeF API. Actual API calls happen asynchronously via the cron jobs.
Session Token Lifecycle
| State | Cache Tag | DB Status | Description |
|---|---|---|---|
| No session | No cache entry | — | Module idle |
| Authorising | ksefpl_auth_pending | — | Challenge/response in progress |
| Active | ksefpl_session_token | ksefpl_sessions.status=active | Session open; invoices can be submitted |
| Sending | Session token + lock | status=sending | Batch in progress |
| Closing | Session token | status=closing | Waiting for MF UPO |
| Closed | Cache cleared | status=closed | UPO received; KSeF-IDs assigned |
| Expired | Cache TTL elapsed | status=expired | Must open new session |
| Terminated | Cache cleared | status=terminated | Invoices NOT accepted |
The terminated state is the critical one. Any invoices in a terminated session were not accepted by KSeF and have no KSeF-IDs. They must be resubmitted. KSeF Pro marks them as FAILED in the audit log with reason SESSION_TERMINATED.
Firewall and Network Requirements
KSeF Pro uses \Magento\Framework\HTTP\Client\Curl for all outbound API calls. Required outbound HTTPS connections:
| Host | Port | Required for |
|---|---|---|
| ksef-test.mf.gov.pl | 443 | Test environment API |
| ksef.mf.gov.pl | 443 | Production environment API |
| api.nbp.pl | 443 | NBP exchange rates (non-PLN invoices) |
Adobe Commerce Cloud
Outbound HTTPS to arbitrary hosts is allowed by default on all Adobe Commerce Cloud environments. No allowlist changes are needed.
On-Premises Firewall
If your Magento server is behind an outbound firewall, add all three hostnames to the allowlist. Use hostname-based rules — MF and NBP IP addresses change periodically.
Test connectivity from the Magento server:
# Test KSeF API
php bin/magento ksefpl:test-connection
# Test manually
curl -sI https://ksef-test.mf.gov.pl \
| head -1
# Expected: HTTP/2 200 or HTTP/2 405Multi-Store Scope Architecture
Magento's scope hierarchy (Default → Website → Store View) applies to KSeF Pro configuration. Each website scope can have its own KSeF token and NIP for stores operating under separate legal entities.
| Scope | When to use | |---|---| | Default | Single legal entity, one KSeF account for all stores | | Website | Multiple legal entities — different NIPs, different tokens per website | | Store View | Not recommended for KSeF settings — NIP is a legal entity property, not locale-specific |
To configure at website scope:
- In Stores → Configuration, use the Store View dropdown (top-left) to select the target website
- Uncheck "Use Default" next to the API token and NIP fields
- Enter website-specific values
- Save — these settings override Default scope for all orders from this website
Check effective NIP at a given scope:
php bin/magento config:show ksefpl/seller/nip --scope=websites --scope-code=<website_code>Token Rotation
When rotating your KSeF token (recommended annually):
- Generate the new token on the KSeF portal — old and new tokens are valid simultaneously
- In Magento Admin, enter the new token and click "Test KSeF Connection"
- Save configuration — the new token replaces the old one in
core_config_data - Allow any in-flight sessions using the old token to complete (check
ksefpl_sessionsforactivestatus) - Delete the old token on the KSeF portal
On Adobe Commerce Cloud, update the environment variable if used:
magento-cloud variable:set --name=KSEFPL_API_TOKEN --value="new-token" --sensitive=true