Přeskočit na hlavní obsah

Zálohové faktury a jejich odečtení

Zálohová faktura je výzva k zaplacení předem, ne daňový doklad. V API se chová jinak než ostatní doklady: nemá datum zdanitelného plnění, nezaúčtovává se a z konečné faktury se odečítá polem, jehož tvar v odpovědi neodpovídá tvaru v požadavku.

Zálohová faktura není daňový doklad

Zálohová faktura sama o sobě nezakládá povinnost přiznat DPH ani nárok na odpočet. Vytištěné PDF to říká přímo — nese větu Zálohová faktura neslouží jako daňový doklad!

Z toho plyne, jak vypadá zdroj v API:

  • Nemá date_vat ani date_vat_prev. Datum zdanitelného plnění na zálohu nepatří, obě pole na tomhle zdroji neexistují.
  • Nemá /account ani accounted. Zálohová faktura se do účetního deníku nezapisuje. Do účetnictví se dostane až přijatá platba, která ji hradí — ta zaúčtování má, viz Platby přijaté.
  • Má dvě částky navíc. to_be_paid říká, kolik na záloze zbývá uhradit; to_be_invoiced, kolik zbývá odečíst na konečné faktuře.

Zdroje jsou dva: Zálohové faktury vydané a Zálohové faktury přijaté. Endpoint pro úhradu má jen ten vydaný.

Celý průběh v jednom příkladu

Scénář má tři kroky: vystavíte zálohu, zaevidujete její úhradu a pak vystavíte konečnou fakturu, na které se záloha odečte.

Ukázková čísla

ID, čísla dokladů a částky jsou vymyšlené. Endpointy, názvy polí a tvar odpovědí odpovídají referenci.

1. Vystavte zálohovou fakturu

curl -s -X POST https://online.iucto.cz/api/1.3/proforma_invoice_issued \
-H "Content-Type: application/json" \
-H "X-Auth-Key: $IUCTO_API_KEY" \
-d '{
"customer_id": 785,
"date": "2026-08-13",
"maturity_date": "2026-08-27",
"currency": "CZK",
"payment_type": "transfer",
"bank_account": 456,
"items": [
{
"text": "Záloha na dodávku podle smlouvy 2026/114",
"amount": 1,
"price": 10000,
"vat": 21
}
]
}'

Povinná pole jsou customer_id, date, maturity_date, currency, payment_type a alespoň jedna položka; položka potřebuje text, amount, price a vat. Odpověď 201 vrací detail dokladu:

{
"_links": { "self": { "href": "/1.3/proforma_invoice_issued/4001" } },
"id": 4001,
"sequence_code": "ZF20260014",
"date": "2026-08-13",
"maturity_date": "2026-08-27",
"currency": "CZK",
"price": 10000.0,
"price_inc_vat": 12100.0,
"to_be_paid": 12100.0,
"to_be_invoiced": 12100.0,
"deleted": false
}

2. Zaevidujte úhradu zálohy

curl -s -X PUT https://online.iucto.cz/api/1.3/proforma_invoice_issued/4001/pay \
-H "Content-Type: application/json" \
-H "X-Auth-Key: $IUCTO_API_KEY" \
-d '{ "date": "2026-08-20", "bank_account": 456 }'

Odpověď 200 není detail zálohy, ale detail nově vzniklé platby přijaté:

{
"_links": { "self": { "href": "/1.3/payment_received/9120" } },
"id": 9120,
"sequence_code": "BP20260233",
"proforma_invoice_id": "4001",
"invoice": null,
"date": "2026-08-20",
"date_vat": "2026-08-20",
"currency": "CZK",
"price": 10000.0,
"price_inc_vat": 12100.0,
"payment_type": "transfer"
}

Po tomhle volání má záloha to_be_paid nula. Odkaz na platbu si uložte — budete ho potřebovat, kdyby se záloha měla rušit.

proforma_invoice_id je řetězec

V odpovědi se vrací jako "4001", ne jako číslo. Parser, který na tomhle poli očekává integer, spadne.

3. Vystavte konečnou fakturu s odečtem

curl -s -X POST https://online.iucto.cz/api/1.3/invoice_issued \
-H "Content-Type: application/json" \
-H "X-Auth-Key: $IUCTO_API_KEY" \
-d '{
"customer_id": 785,
"date": "2026-09-01",
"date_vat": "2026-09-01",
"maturity_date": "2026-09-15",
"currency": "CZK",
"payment_type": "transfer",
"bank_account": 456,
"proforma_invoice": [4001],
"items": [
{
"text": "Dodávka podle smlouvy 2026/114",
"amount": 1,
"price": 10000,
"vat": 21,
"accountentrytype_id": 7,
"vattype_id": 1
},
{
"text": "Uhrazeno zálohou ZF20260014",
"amount": 1,
"price": -10000,
"vat": 21,
"accountentrytype_id": 126,
"vattype_id": 1
}
]
}'

Všimněte si, že odečet jsou dvě různé věci: pole proforma_invoice s ID zálohy a záporná položka s částkou. Proč, vysvětluje následující sekce.

Pravidla akce /pay

PUT /proforma_invoice_issued/{id}/pay je jediná akce /pay v celém API. Ostatní doklady se hradí tak, že k nim založíte platbu; u zálohové faktury existuje tahle zkratka navíc.

Platí pro ni:

  • Vytváří vždy plnou úhradu. Částka se v požadavku zadat nedá — platba vznikne na to, co ze zálohy zbývá uhradit (to_be_paid).
  • Vrací detail platby přijaté, ne detail zálohy. Tvar odpovídá GET /payment_received/{id}.
  • date je povinné a musí spadat do otevřeného účetního období.
  • bank_account a cash_register se vylučují. Poslat lze nejvýš jeden. Když nepošlete ani jeden, použije se bankovní účet z dokladu — to ale jde jen u dokladů s payment_type transfer nebo creditcard, které účet vyplněný mají. Jinak přijde 400 s hláškou Vyberte pokladnu, nebo bankovní účet pro platbu.
  • Měna platby se bere z vybraného účtu nebo pokladny, ne z dokladu.
  • Už uhrazenou zálohu odmítne hláškou Záloha je již uhrazena.

Částečná úhrada

Částečnou úhradu přes /pay zadat nelze. Založte platbu přímo a navažte ji na zálohu polem proforma_invoice_id:

curl -s -X POST https://online.iucto.cz/api/1.3/payment_received \
-H "Content-Type: application/json" \
-H "X-Auth-Key: $IUCTO_API_KEY" \
-d '{
"customer_id": 785,
"proforma_invoice_id": 4001,
"date": "2026-08-20",
"payment_type": "transfer",
"bank_account": 456,
"items": [
{ "text": "Částečná úhrada zálohy ZF20260014", "amount": 1,
"price": 5000, "vat": 21, "accountentrytype_id": 189, "vattype_id": 1 }
]
}'

Platba se páruje nejvýš na jeden doklad — proforma_invoice_id, invoice_id a creditnote_received_id se nedají kombinovat.

Odečtení zálohy na faktuře vydané

Zálohu odečtete tak, že při vytváření nebo editaci faktury vydané pošlete její ID v poli proforma_invoice (od verze API 1.2). Pole je součástí parametrů faktury vydané a přijímá pole ID, tedy i víc záloh najednou.

Samotné pole ale žádnou částku neodečte. Vytvoří jen vazbu mezi fakturou a zálohou. Součet faktury se počítá z jejích položek, takže odečet musí být na faktuře jako samostatná položka se zápornou cenou — přesně jako v kroku 3 výše.

Jak takovou položku sestavit:

Pole položkyHodnota
pricezáporná, ve výši odečítané zálohy
vat, vattype_idstejné jako na záloze
accountentrytype_idtyp účetní položky pro odečet zálohy
textlibovolný popis, typicky s číslem zálohy

ID typů účetních položek jsou pro každou firmu jiná — načtěte si je dotazem GET /accountentry_type?doctype=FV a vyberte položku pro přijaté zálohy. Jinak se zaúčtování řídí stejnými pravidly jako u každé jiné položky, viz Zaúčtování položek.

to_be_invoiced se odečtem přes API nesníží

Hodnota to_be_invoiced na záloze se počítá z položek faktury, které nesou vnitřní odkaz na konkrétní zálohu. Tenhle odkaz se přes API nastavit nedá — položky mají jen pole vyjmenovaná v referenci. Kolik ze zálohy zbývá odečíst, si proto musí integrace hlídat sama.

Past: proforma_invoice se čte jinak, než se zapisuje

Pole proforma_invoice má v odpovědi jiný tvar než v požadavku. Je to jediné místo, kde se dá bez varování poslat zpátky přesně to, co server vrátil, a skončit chybou.

SměrTvar
GET (odpověď)pole objektů — [{ "id": 4001 }]
POST / PUT (požadavek)pole holých čísel — [4001]

Kdo si detail faktury stáhne, změní jednu položku a pošle celý objekt zpět na PUT, narazí. Validace každý prvek pole přetypuje na celé číslo, takže z objektu {"id": 4001} vznikne 1:

{ "errors": { "proforma_invoice": "Neplatné ID zálohové faktury vydané '1'" } }

Odpověď je 400. Tvary chybových těl a jak je rozlišit popisuje Chyby a jak je číst.

Řešení je jednoduché — před zápisem pole převeďte:

$invoice['proforma_invoice'] = array_column($detail['proforma_invoice'], 'id');

Smazání zálohové faktury

DELETE /proforma_invoice_issued/{id} selže, jakmile je na záloze navázaný jiný záznam. Odpověď je 403 s hláškou Nelze smazat záznam. Vazbu vytvoří dvě věci:

  • úhrada — platba přijatá s proforma_invoice_id mířícím na zálohu, ať už vznikla přes /pay nebo přímo,
  • odečet — faktura vydaná, která má zálohu v poli proforma_invoice.

Pořadí kroků při rušení je tedy opačné než při vystavování: nejdřív odeberte zálohu z faktury (PUT na fakturu bez jejího ID v proforma_invoice), pak smažte platbu a teprve nakonec zálohu.

Druhá příčina 403 je uzavřené období — hláška je pak jiná (Doklad je smazaný, nebo účetní období, či období DPH je uzavřeno.), viz Uzavřené období.

Záloha na faktuře přijaté

Na přijaté straně to funguje stejně jako na vydané. POST /invoice_received i PUT /invoice_received/{id} přijmou proforma_invoice jako pole ID zálohových faktur přijatých (od verze API 1.2) a v odpovědi se pole vrací jako pole objektů — stejná asymetrie tvarů jako u faktury vydané.

Kam dál