Referencja API
Endpointy webhooków
Endpointy, na które wysyłamy podpisane zdarzenia o fakturach i korektach. Obsługę po stronie odbiorcy opisuje przewodnik Webhooki.
Obiekt WebhookEndpoint
Adres, na który wysyłamy podpisane zdarzenia. Sekret whsec_... widać tylko w odpowiedzi na utworzenie.
Pola
idstringwymaganeId endpointu.
Prefiks
we_objectstringwymaganeRodzaj obiektu.
Zawsze
webhook_endpointlivemodebooleanwymaganeTryb endpointu.
urlstringwymaganeAdres odbiorcy.
enabled_eventsarray of stringwymaganeSubskrybowane typy zdarzeń.
descriptionstring | nullOpis.
statusstringwymaganeStan endpointu.
Jedna z:
enabled,disabledcreatedintegerwymaganeUtworzono (sekundy Unix).
{
"id": "we_Ab3Cd5Ef7Gh9Ij1Kl3Mn5Op7",
"object": "webhook_endpoint",
"livemode": false,
"url": "https://example.com/ksef/webhook",
"enabled_events": [
"*"
],
"description": "Shop backend",
"status": "enabled",
"created": 1760865185
}Lista endpointów webhooków
GET /v1/webhook_endpoints
Aktywne endpointy w trybie klucza. Sekretów tu nie ma.
Odpowiedzi
- 200Lista endpointów.
- 401Brak klucza albo zły klucz:
api_key_missingapi_key_invalid
curl https://app.ksefshop.pl/v1/webhook_endpoints \
-H "Authorization: Bearer $KSEF_API_KEY"<?php
$ch = curl_init('https://app.ksefshop.pl/v1/webhook_endpoints');
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 count($data['data']), ' obiektów', PHP_EOL;const res = await fetch("https://app.ksefshop.pl/v1/webhook_endpoints", {
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.data.length, data.has_more);import os
import requests
resp = requests.get(
"https://app.ksefshop.pl/v1/webhook_endpoints",
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(len(data["data"]), data["has_more"]){
"object": "list",
"url": "/v1/webhook_endpoints",
"has_more": false,
"data": []
}{
"error": {
"type": "authentication_error",
"code": "api_key_invalid",
"message": "The API key is wrong, revoked, or the account is disabled.",
"doc_url": "https://ksefshop.pl/api/errors#api_key_invalid"
}
}Utwórz endpoint webhooka
POST /v1/webhook_endpoints
Rejestruje adres dla zdarzeń. Sekret whsec_... do weryfikacji podpisu jest w odpowiedzi tylko ten jeden raz. W trybie produkcyjnym adres musi zaczynać się od https://; w testowym wolno http://. Maksymalnie 16 endpointów na tryb.
Parametry
Idempotency-Keyheader · stringDowolny unikalny tekst (1-255 znaków), np.
order-SO-1001. Ponowienie z tym samym kluczem przez 24 godziny zwraca pierwszą odpowiedź. Idempotencja
Treść żądania (JSON)
urlstringwymaganeAdres odbiorcy; w trybie produkcyjnym tylko
https://.enabled_eventsarray of stringwymaganeTypy zdarzeń albo
*dla wszystkich.Jedna z:
invoice.accepted,invoice.rejected,invoice.skipped,correction.accepted,correction.rejected,correction.skipped,*· 1-∞ elementówdescriptionstringOpis dla Ciebie.
maks. 500 znaków
Odpowiedzi
- 201Endpoint razem z sekretem.
- 400Błędne żądanie, np.
parameter_invalidbuyer_nip_invalidvat_rate_unsupported - 401Brak klucza albo zły klucz:
api_key_missingapi_key_invalid - 409Klucz idempotencji użyty z innym żądaniem albo PDF jeszcze niegotowy:
idempotency_key_reusedpdf_not_ready - 429Przekroczony limit zapytań, czekaj
Retry-Aftersekund:rate_limited
curl -X POST https://app.ksefshop.pl/v1/webhook_endpoints \
-H "Authorization: Bearer $KSEF_API_KEY" \
-H "Idempotency-Key: webhook-shop-backend" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/ksef/webhook",
"enabled_events": [
"*"
],
"description": "Shop backend"
}'<?php
$payload = [
'url' => 'https://example.com/ksef/webhook',
'enabled_events' => ['*'],
'description' => 'Shop backend',
];
$ch = curl_init('https://app.ksefshop.pl/v1/webhook_endpoints');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('KSEF_API_KEY'),
'Idempotency-Key: webhook-shop-backend',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);
$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['id'], true), ' ', var_export($data['secret'], true), PHP_EOL;const res = await fetch("https://app.ksefshop.pl/v1/webhook_endpoints", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KSEF_API_KEY}`,
"Idempotency-Key": "webhook-shop-backend",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com/ksef/webhook",
enabled_events: ["*"],
description: "Shop backend",
}),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
console.log(data.id, data.secret);import os
import requests
resp = requests.post(
"https://app.ksefshop.pl/v1/webhook_endpoints",
headers={
"Authorization": f"Bearer {os.environ['KSEF_API_KEY']}",
"Idempotency-Key": "webhook-shop-backend",
},
json={
"url": "https://example.com/ksef/webhook",
"enabled_events": ["*"],
"description": "Shop backend",
},
timeout=30,
)
data = resp.json()
if not resp.ok:
raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
print(data["id"], data["secret"]){
"id": "we_Ab3Cd5Ef7Gh9Ij1Kl3Mn5Op7",
"object": "webhook_endpoint",
"livemode": false,
"url": "https://example.com/ksef/webhook",
"enabled_events": [
"*"
],
"description": "Shop backend",
"status": "enabled",
"created": 1760865185,
"secret": "whsec_shownOnlyOnceExampleValue0000"
}{
"error": {
"type": "invalid_request_error",
"code": "buyer_nip_invalid",
"message": "buyer.nip is not a valid Polish NIP (checksum).",
"param": "order.buyer.nip",
"doc_url": "https://ksefshop.pl/api/errors#buyer_nip_invalid"
}
}{
"error": {
"type": "authentication_error",
"code": "api_key_invalid",
"message": "The API key is wrong, revoked, or the account is disabled.",
"doc_url": "https://ksefshop.pl/api/errors#api_key_invalid"
}
}{
"error": {
"type": "idempotency_error",
"code": "idempotency_key_reused",
"message": "Idempotency-Key \"k-1002\" was already used with a different request.",
"doc_url": "https://ksefshop.pl/api/errors#idempotency_key_reused"
}
}Pobierz endpoint webhooka
GET /v1/webhook_endpoints/{id}
Jeden endpoint po id we_....
Parametry
idpath · stringwymaganeIdentyfikator obiektu.
Prefiks
we_
Odpowiedzi
- 200Endpoint.
- 401Brak klucza albo zły klucz:
api_key_missingapi_key_invalid - 404Nie ma takiego obiektu (albo należy do innego konta lub trybu):
resource_missing
curl https://app.ksefshop.pl/v1/webhook_endpoints/we_Ab3Cd5Ef7Gh9Ij1Kl3Mn5Op7 \
-H "Authorization: Bearer $KSEF_API_KEY"<?php
$ch = curl_init('https://app.ksefshop.pl/v1/webhook_endpoints/we_Ab3Cd5Ef7Gh9Ij1Kl3Mn5Op7');
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['id'], true), ' ', var_export($data['status'], true), PHP_EOL;const res = await fetch("https://app.ksefshop.pl/v1/webhook_endpoints/we_Ab3Cd5Ef7Gh9Ij1Kl3Mn5Op7", {
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.id, data.status);import os
import requests
resp = requests.get(
"https://app.ksefshop.pl/v1/webhook_endpoints/we_Ab3Cd5Ef7Gh9Ij1Kl3Mn5Op7",
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["id"], data["status"]){
"id": "we_Ab3Cd5Ef7Gh9Ij1Kl3Mn5Op7",
"object": "webhook_endpoint",
"livemode": false,
"url": "https://example.com/ksef/webhook",
"enabled_events": [
"*"
],
"description": "Shop backend",
"status": "enabled",
"created": 1760865185
}{
"error": {
"type": "authentication_error",
"code": "api_key_invalid",
"message": "The API key is wrong, revoked, or the account is disabled.",
"doc_url": "https://ksefshop.pl/api/errors#api_key_invalid"
}
}{
"error": {
"type": "not_found_error",
"code": "resource_missing",
"message": "No such invoice: 'inv_4fJ2kP9xQwErTy7uI0oPaSdF'",
"doc_url": "https://ksefshop.pl/api/errors#resource_missing"
}
}Usuń endpoint webhooka
DELETE /v1/webhook_endpoints/{id}
Wyłącza endpoint: nie dostanie już nowych zdarzeń. Zdarzenia nadal są dostępne w /v1/events.
Parametry
idpath · stringwymaganeIdentyfikator obiektu.
Prefiks
we_
Odpowiedzi
- 200Usunięto.
- 401Brak klucza albo zły klucz:
api_key_missingapi_key_invalid - 404Nie ma takiego obiektu (albo należy do innego konta lub trybu):
resource_missing
curl -X DELETE https://app.ksefshop.pl/v1/webhook_endpoints/we_Ab3Cd5Ef7Gh9Ij1Kl3Mn5Op7 \
-H "Authorization: Bearer $KSEF_API_KEY"<?php
$ch = curl_init('https://app.ksefshop.pl/v1/webhook_endpoints/we_Ab3Cd5Ef7Gh9Ij1Kl3Mn5Op7');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
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['id'], true), ' ', var_export($data['deleted'], true), PHP_EOL;const res = await fetch("https://app.ksefshop.pl/v1/webhook_endpoints/we_Ab3Cd5Ef7Gh9Ij1Kl3Mn5Op7", {
method: "DELETE",
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.id, data.deleted);import os
import requests
resp = requests.delete(
"https://app.ksefshop.pl/v1/webhook_endpoints/we_Ab3Cd5Ef7Gh9Ij1Kl3Mn5Op7",
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["id"], data["deleted"]){
"id": "we_Ab3Cd5Ef7Gh9Ij1Kl3Mn5Op7",
"object": "webhook_endpoint",
"deleted": true
}{
"error": {
"type": "authentication_error",
"code": "api_key_invalid",
"message": "The API key is wrong, revoked, or the account is disabled.",
"doc_url": "https://ksefshop.pl/api/errors#api_key_invalid"
}
}{
"error": {
"type": "not_found_error",
"code": "resource_missing",
"message": "No such invoice: 'inv_4fJ2kP9xQwErTy7uI0oPaSdF'",
"doc_url": "https://ksefshop.pl/api/errors#resource_missing"
}
}Dostawa zdarzenia
Gdy faktura albo korekta osiągnie stan końcowy, wysyłamy POST z obiektem Event na każdy włączony endpoint, który subskrybuje ten typ zdarzenia.
| Nagłówek | Wartość |
|---|---|
KSeF-Signature |
t=<unix>,v1=<hex>, gdzie v1 = HMAC-SHA256(secret, t + "." + surowe body) |
KSeF-Event-Id |
Id zdarzenia (evt_...), do odrzucania duplikatów |
Content-Type |
application/json |
Każda odpowiedź 2xx oznacza dostarczenie. Weryfikację podpisu w czterech językach i harmonogram ponowień opisuje przewodnik Webhooki.