Przewodniki
Korekty przy zwrotach
Zwrot pieniędzy w sklepie zamieniamy w fakturę korygującą (KOR) z pozycjami różnicowymi, powiązaną z numerem KSeF faktury pierwotnej.
Jak zwrot staje się korektą
Gdy zwracasz pieniądze za towar albo dostawę, wysyłasz zwrot do POST /v1/invoices/{id}/corrections. API tworzy fakturę korygującą (KOR, TypKorekty 2) z pozycjami różnicowymi: zwrócone sztuki mają ujemne ilości, a korekta wskazuje numer KSeF faktury pierwotnej. Kolejka czeka, aż faktura pierwotna zostanie przyjęta w KSeF, więc zwrot możesz wysłać od razu. Więcej o samym obowiązku: korekta faktury w KSeF przy zwrocie.
curl -X POST https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF/corrections \
-H "Authorization: Bearer $KSEF_API_KEY" \
-H "Idempotency-Key: refund-RF-1" \
-H "Content-Type: application/json" \
-d '{
"refund": {
"external_id": "RF-1",
"reason": "Zwrot towaru",
"lines": [
{
"name": "Kubek ceramiczny 350 ml",
"sku": "KUB-350",
"quantity": 1,
"unit_price": "49.00",
"vat_rate": "23"
}
],
"shipping": {
"price": "15.99"
}
}
}'<?php
$payload = [
'refund' => [
'external_id' => 'RF-1',
'reason' => 'Zwrot towaru',
'lines' => [
[
'name' => 'Kubek ceramiczny 350 ml',
'sku' => 'KUB-350',
'quantity' => 1,
'unit_price' => '49.00',
'vat_rate' => '23',
],
],
'shipping' => ['price' => '15.99'],
],
];
$ch = curl_init('https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF/corrections');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('KSEF_API_KEY'),
'Idempotency-Key: refund-RF-1',
'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['status'], true), PHP_EOL;const res = await fetch("https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF/corrections", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.KSEF_API_KEY}`,
"Idempotency-Key": "refund-RF-1",
"Content-Type": "application/json",
},
body: JSON.stringify({
refund: {
external_id: "RF-1",
reason: "Zwrot towaru",
lines: [
{
name: "Kubek ceramiczny 350 ml",
sku: "KUB-350",
quantity: 1,
unit_price: "49.00",
vat_rate: "23",
},
],
shipping: { price: "15.99" },
},
}),
});
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.post(
"https://app.ksefshop.pl/v1/invoices/inv_4fJ2kP9xQwErTy7uI0oPaSdF/corrections",
headers={
"Authorization": f"Bearer {os.environ['KSEF_API_KEY']}",
"Idempotency-Key": "refund-RF-1",
},
json={
"refund": {
"external_id": "RF-1",
"reason": "Zwrot towaru",
"lines": [
{
"name": "Kubek ceramiczny 350 ml",
"sku": "KUB-350",
"quantity": 1,
"unit_price": "49.00",
"vat_rate": "23",
},
],
"shipping": {"price": "15.99"},
},
},
timeout=30,
)
data = resp.json()
if not resp.ok:
raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
print(data["id"], data["status"])Co podać
refund.external_id: Twoje id zwrotu. Jeden zwrot to jedna korekta: powtórka zwraca istniejącą korektę z200.lines: zwrócone pozycje z dodatnią liczbą sztuk, ceną jednostkową brutto i stawką VAT, jak na fakturze.shipping.price: zwrócony koszt dostawy brutto; stawka VAT jak w dostawie z faktury.reason: przyczyna drukowana na korekcie, np. „Zwrot towaru”.
Potrzebne jest co najmniej jedno z lines i shipping.
Czego API nie robi
| Sytuacja | Odpowiedź |
|---|---|
| Zwrot samej kwoty, bez pozycji i dostawy | 422 order_unprocessable |
Korekta korekty (cor_... w ścieżce) |
400 correction_requires_invoice |
| Faktura pierwotna odrzucona przez KSeF | korekta skipped, original_rejected |
| Zamówienie bez faktury | korekta skipped, original_not_invoiced |
Status korekty
Korekta ma te same statusy co faktura. Śledzisz ją przez zdarzenia correction.accepted, correction.rejected i correction.skipped, przez GET /v1/invoices/cor_... albo w polu corrections faktury pierwotnej.
WooCommerce
Wtyczka WooCommerce wysyła zamiast refund parę woocommerce_order i woocommerce_refund (zwrot z REST API WooCommerce v3). Pozycje różnicowe wyliczamy z _refunded_item_id.