KSeF Connection & Authentication
KSeF Pro for WooCommerce uses the same KSeF API authentication model as the PrestaShop and Magento 2 variants. This page covers the authentication flow with WooCommerce-specific details on credential storage, WordPress transient caching, and HPOS order meta.
Authentication Flow
KSeF authentication is session-based. Your KSeF token initiates sessions — it is not sent with every API call. Here is the complete flow KSeF Pro executes automatically:
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
Signature = HMAC_SHA256(key=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 subsequent calls
Authorization: Bearer SESSION_TOKEN
KSeF Pro handles all four steps automatically. Session tokens are stored as WordPress transients (_ksefpl_session_token, 25-minute TTL) — shorter than the 30-minute MF-side expiry to ensure proactive refresh before timeout.

WordPress-Specific Token Storage
KSeF Pro stores the KSeF API token in the wp_options table, encrypted with AES-256. The encryption key is derived in priority order:
| Priority | Source | How to set |
|---|---|---|
| 1 | KSEFPL_ENCRYPTION_KEY constant in wp-config.php | define('KSEFPL_ENCRYPTION_KEY', '...') |
| 2 | AUTH_KEY from wp-config.php | Already present in all WordPress installations |
Why this matters: The AUTH_KEY can change during site migrations (especially when using WordPress Salts Regenerator or moving to a new server). If AUTH_KEY changes, the stored token becomes unreadable and must be re-entered.
For production installations, define a static KSEFPL_ENCRYPTION_KEY in wp-config.php that survives migrations:
// wp-config.php — add before "That's all, stop editing!"
define('KSEFPL_ENCRYPTION_KEY', 'your-64-character-random-hex-string-here');Generate a secure key:
openssl rand -hex 32Token Storage Diagnostic
If the plugin reports an invalid token after a site migration:
# Check if the stored token is readable
wp eval "echo get_option('ksefpl_api_token') ? 'Token present (encrypted)' : 'Token missing';"If present but unreadable (decryption fails after key change), the plugin shows a red warning in the connection tab. Re-enter the token and save.
Test vs. Production Environments
Test Environment (ksef-test.mf.gov.pl)
| Characteristic | Value |
|---|---|
| URL | https://ksef-test.mf.gov.pl/api |
| FA(2) schema | Same as production (2.0 from April 2026) |
| Token type | Test tokens only — generate at ksef-test.mf.gov.pl |
| UPOs issued | Yes — functionally complete, no legal standing |
| KSeF-IDs | Assigned with test prefix — not in official ledger |
| Availability | 24/7, same performance as production |
Use the test environment to validate:
- Token verification succeeds (NIP/token pair recognized)
- FA(2) XML generates without schema errors (use XML preview)
- Full session cycle completes: open → submit → close → UPO received
- KSeF-ID is written to WooCommerce order meta and visible in the order detail
- WordPress cron processes the queue reliably
Production Environment (ksef.mf.gov.pl)
Switch to production only after successful test validation. The environment dropdown is in WooCommerce → KSeF Pro → KSeF Connection. When switching:
- Change environment to Production
- Replace the test token with your production token (different tokens — not interchangeable)
- Click "Verify connection" — confirm green indicator
- Process one real order and confirm
ACCEPTEDstatus in the audit log
NIP registration 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_NIP\"}}" \
| python3 -m json.toolA response containing a challenge field confirms the NIP is active in production KSeF. An error 10000 means the NIP is not registered — contact your tax authority.
NIP Validation
KSeF Pro validates NIP at three checkpoints:
1. On Seller Data Save
The plugin applies the weighted checksum algorithm:
Weights: 6, 5, 7, 2, 3, 4, 5, 6, 7
Digit 10 must equal (sum of weighted digits 1-9) mod 11
Invalid checksums show an inline red warning. This catches transcription errors (digit transposition) before they cause live submission failures.
2. On "Verify Connection" Click
KSeF Pro sends a session challenge to the selected environment with your NIP. A successful challenge response (HTTP 200 with challenge field) confirms:
- The NIP is registered in KSeF
- The NIP is active (not deactivated)
- The selected environment (test/production) matches the NIP's status in that environment
3. Pre-Submission Check
Immediately before opening a new KSeF session, KSeF Pro performs a lightweight ping. This catches tokens revoked between configuration save and submission time. If the check fails:
- The submission is blocked
- An error entry is written to the audit log with the KSeF error code
- No order status changes occur
- The WordPress cron retries according to the retry policy
Session Token Lifecycle
| State | WordPress Store | Description |
|---|---|---|
| No session | No transient | Module is idle |
| Authorising | _ksefpl_auth_pending | Challenge/response in progress |
| Active | _ksefpl_session_token (25-min TTL) | Session open; invoices can be submitted |
| Sending | Session meta in {prefix}_ksefpl_sessions | Batch submission in progress |
| Closing | Session record status=closing | Waiting for MF UPO processing |
| Closed | Session record status=closed | UPO downloaded; KSeF-IDs written to orders |
| Expired | Transient TTL elapsed or deleted | Must open new session |
| Terminated | Session record status=terminated | Invoices NOT accepted — must re-submit |
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 in a new session from the audit log.
HPOS and Order Meta
Under HPOS (WooCommerce High-Performance Order Storage), order meta is stored in wc_orders_meta instead of wp_postmeta. KSeF Pro handles this transparently. The order meta keys are identical regardless of storage backend:
| Meta key | Content | Example |
|---|---|---|
| _ksefpl_ksef_id | Permanent KSeF-ID | 1234567890-20250301-000001 |
| _ksefpl_session_ref | KSeF session reference number | 20250301ABCD1234 |
| _ksefpl_submission_status | Current status | ACCEPTED |
| _ksefpl_submission_ts | Submission Unix timestamp | 1740826800 |
| _ksefpl_upo_path | Absolute path to UPO file | /var/www/.../ksefpl-upo/2025/03/1001.xml |
| _ksefpl_buyer_nip | Buyer NIP from checkout | 9876543210 |
To query KSeF status for an order programmatically:
$order = wc_get_order($order_id);
$ksef_id = $order->get_meta('_ksefpl_ksef_id');
$status = $order->get_meta('_ksefpl_submission_status');
$upo_path = $order->get_meta('_ksefpl_upo_path');This works identically under both HPOS and legacy storage — get_meta() abstracts the underlying table.
Connectivity and Firewall
Required Outbound Connections
| Host | Port | Protocol |
|---|---|---|
| ksef-test.mf.gov.pl | 443 | HTTPS |
| ksef.mf.gov.pl | 443 | HTTPS |
| api.nbp.pl | 443 | HTTPS (for PLN exchange rates) |
The NBP (National Bank of Poland) API is used for currency conversion when orders are placed in non-PLN currencies. If blocked, KSeF Pro falls back to the manual exchange rate configured in Advanced settings.
Test Connectivity
# Test KSeF access
curl -sI https://ksef-test.mf.gov.pl/api/online/Session/AuthorisationChallenge \
-H "Content-Type: application/json" | head -1
# Expected: HTTP/2 405
# Test NBP access
curl -s "https://api.nbp.pl/api/exchangerates/rates/A/EUR?format=json" | python3 -m json.tool | head -5
# Expected: JSON with "mid" rateShared Hosting Restrictions
Many shared hosting providers block outbound connections to arbitrary hosts. If your host uses an IP whitelist approach, request that ksef-test.mf.gov.pl and ksef.mf.gov.pl be added. Use hostname-based rules — the MF IP addresses change periodically.
Token Rotation
When rotating your KSeF token (recommended annually or after a security incident):
- Generate the new token on the KSeF portal — both old and new tokens are valid simultaneously
- In WooCommerce → KSeF Pro → KSeF Connection, replace the old token
- Click "Verify connection" to confirm the new token works
- Delete the old token on the KSeF portal after confirming
- If you have in-flight KSeF sessions using the old token, let them complete first before deleting
Token rotation does not affect existing KSeF-IDs or audit records.