Guides
Authentication, test and live keys
Every request carries a secret key in the Authorization header. The key's prefix decides whether the invoice goes to KSeF TEST or to production KSeF.
Test and live keys
| Key prefix | Mode | Where invoices go | Limit | Legal effect |
|---|---|---|---|---|
sk_test_ |
test | Ministry of Finance KSeF TEST | none | none |
sk_live_ |
live | production KSeF | plan limit | real invoices |
The two modes are fully separate: invoices, numbering, webhooks, events, seller data and the KSeF connection are set up per mode. Every object has a livemode field, and an object of the other mode returns resource_missing or livemode_mismatch.
Sending the key
The key goes in the Authorization header as a Bearer token, always over HTTPS. The simplest test is retrieving the account:
curl https://app.ksefshop.pl/v1/account \
-H "Authorization: Bearer $KSEF_API_KEY"<?php
$ch = curl_init('https://app.ksefshop.pl/v1/account');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('KSEF_API_KEY'),
],
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$data = json_decode($body, true);
if ($status >= 400) {
throw new RuntimeException($data['error']['code'] . ': ' . $data['error']['message']);
}
echo var_export($data['seller_configured'], true), ' ', var_export($data['ksef_connected'], true), PHP_EOL;const res = await fetch("https://app.ksefshop.pl/v1/account", {
headers: {
Authorization: `Bearer ${process.env.KSEF_API_KEY}`,
},
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
console.log(data.seller_configured, data.ksef_connected);import os
import requests
resp = requests.get(
"https://app.ksefshop.pl/v1/account",
headers={
"Authorization": f"Bearer {os.environ['KSEF_API_KEY']}",
},
timeout=30,
)
data = resp.json()
if not resp.ok:
raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
print(data["seller_configured"], data["ksef_connected"])The answer shows whether the seller data is complete (seller_configured) and the KSeF connection works (ksef_connected). The WooCommerce plugin's "Test connection" button calls the same endpoint.
Live mode during early access
During early access, test mode is available. An sk_live_ key returns 403 live_mode_disabled until we enable live mode for your account. We will do it after launch, together with pricing and the documents for API customers.
Connecting KSeF
We send invoices to KSeF on the seller's behalf, with the seller's own KSeF certificate (.crt and .key files with a password) or KSeF token. You upload them in the customer panel, separately for test and live mode; we store them encrypted. In test mode a KSeF TEST certificate is created with one click.
Storing and rolling keys
- A key is shown once, when it is created. We keep only its SHA-256 hash, so we cannot recover it for you.
- Keep the key server-side: in an environment variable or a secrets manager. Never in a browser, a mobile app or a public repository.
- If a key may have leaked, roll it in the panel. The old key stops working at once.
- Requests are not signed: like Stripe, TLS plus a secret key is enough, and idempotency makes retries safe. Webhooks are signed.
Authentication errors
| Code | HTTP | Meaning |
|---|---|---|
api_key_missing |
401 | No Authorization header. |
api_key_invalid |
401 | Wrong or rolled key, or the account is disabled. |
live_mode_disabled |
403 | Live mode is not enabled yet. |