Vystavení dokladu

POST
/api/v2/sync/invoices

Operace je určená pro systémy mimo pokladnu, například e-shop nebo rezervační systém: doklad vystaví server a vrátí ho celý zpátky. Jeden požadavek nese 1 až 100 dokladů. Každý se zpracuje samostatně a buď se zapíše celý, nebo vůbec.

Pole options.response musí mít hodnotu documents. Bez ní běží interní režim, který používá pokladna, a ten vrací jen pole successInvoices bez dat dokladu. Odpověď v režimu documents poznáte podle pole documents.

Číslo dokladu a variabilní symbol

Číslo neposílejte. Server přidělí další číslo v řadě skladu vystavení, dopočítá numberFormated podle prefixu a počtu číslic v tiskové sestavě a nastaví variable. Přidělování probíhá pod zámkem, takže souběžné požadavky nedostanou stejné číslo.

Variabilní symbol má vždy 1 až 10 číslic. Když ho nepošlete, použije se numberFormated. Tisková sestava skladu proto potřebuje číselný prefix, například [ROK] a 6 číslic, což dá 2026000042. Prefix s písmeny nebo číslo delší než 10 znaků doklad odmítne s kódem variable-invalid.

Opakované odeslání

Pole hash je povinné a v rámci firmy jedinečné. Když doklad se stejným hash už existuje, nový nevznikne, sklad se znovu neodepíše a odpověď vrátí existující doklad s duplicate: true.

Po výpadku spojení nebo vypršení časového limitu proto pošlete stejný požadavek znovu se stejným hash. Dokud nemáte odpověď, nový hash negenerujte.

Sklady a nastavení

Pro každý prodejní kanál (pokladna na místě, e-shop) doporučujeme samostatný sklad s vlastní tiskovou sestavou. Sklad určuje číselnou řadu, prefix, bankovní účet, nastavení EET i uzávěrku a doklady se započítají do uzávěrky svého skladu.

  • Do skladu, do kterého vystavuje API, nevystavujte zároveň z pokladny v prohlížeči, jinak se čísla z obou zdrojů mohou překrývat.
  • Dva sklady nesmí mít tiskovou sestavu se stejným prefixem, jinak by vznikla dvě stejná čísla dokladu.
  • Uživatel, kterému patří API token, musí mít přístup do všech skladů, do kterých vystavuje.

Položky a ceny

Ceny dokladu počítá váš systém, server je nepřepočítává. Kódy měny (prices.currency) a sazeb DPH (vat.code) musí existovat v číselnících firmy, jinak se doklad odmítne s kódem validation.

Položka bez id produktu je volná položka, například vstupenka nebo voucher. Neodepisuje sklad a do pole code můžete uložit vlastní kód. V odpovědi se vrací id položky a code, takže si můžete uložit vazbu kód → doklad → položka. Pro jednoznačné dohledání posílejte každý kód jako samostatnou položku s count: 1.

Odběratel

Pole contact Co server udělá
{"id": 123} Použije existující kontakt firmy.
externalId a údaje Hledá kontakt podle externalId (vaše ID zákazníka), pak podle IČ.
ic a údaje bez externalId Hledá kontakt podle IČ, při více shodách nejnovější.
nic nenalezeno Založí nový kontakt v adresáři.

Údaje odběratele: companyName, name, surname, ic, dic, street, town, zip, country, email, phone. Musí obsahovat aspoň companyName nebo jméno. IČ u country CZ (výchozí) má 8 číslic.

Nalezený kontakt se přepíše na poslané údaje. Výsledek najdete v contactId a contactAction: created (založen), updated (údaje se změnily), matched (beze změny). Fyzická osoba bez IČ a bez externalId se zakládá vždy nově.

Doklad nad 10 000 Kč včetně DPH musí mít odběratele, jinak se odmítne s kódem customer-required. Pokud potřebujete podobu odběratele v okamžiku prodeje, zapněte modul Archiv dokladů (PDF/A), viz Archiv dokladu.

EET a uhrazenost

O EET se stará pokladna podle tiskové sestavy skladu vystavení, kód POK ani údaje EET neposílejte. Výsledek je v eet.status:

  • none: doklad se do EET neeviduje,
  • registered: evidován, kód v eet.pok,
  • pending: EET je nedostupné. Doklad je platný a pokladna ho doeviduje později.

Uhrazenost nastavíte polem paid. Bez něj je doklad placený hotově nebo kartou uhrazený a ostatní neuhrazené. Hotovostní platba nad 270 000 Kč se odmítne s kódem cash-limit.

HTML dokladu

S options.html: true obsahuje html samostatný dokument se styly, logem a QR kódem uvnitř, bez odkazů na jiné adresy. Můžete ho vytisknout nebo převést do PDF. Účtenka (cash) má šířku 58 nebo 80 mm podle tiskárny v tiskové sestavě skladu uživatele, kterému patří API token (bez tiskárny 80 mm). Šířka je v paperWidth, v požadavku se nenastavuje. Faktura (invoice) formát A4 nebo vlastní tiskovou šablonu firmy. U jiných typů je html null a důvod je v htmlError.

htmlSha256 je otisk SHA-256 vráceného HTML. S logem firmy může mít HTML stovky kB. Server HTML neukládá, každé volání ho vytvoří znovu podle aktuálních údajů dokladu a firmy. Opakované odeslání se stejným hash proto může vrátit jiné HTML, například po změně loga. Stejné HTML vrátí kdykoli později i operace HTML dokladu.

Archiv dokladu

Archiv zapíná modul 10224 Archiv dokladů (PDF/A) uživatele, kterému patří API token. V požadavku se nic nenastavuje, starší volba options.archive se ignoruje. S modulem vznikne u každého dokladu na pozadí archivní PDF/A, obvykle do dvou minut. Bez modulu se doklad vystaví normálně, jen bez archivu.

Stav je v archive:

  • status: none (archiv nevzniká), pending (PDF se vytváří), done (hotovo), failed (PDF se nepodařilo vytvořit, doklad je platný),
  • fileId: ID přílohy s archivním PDF, dokud není hotové, null,
  • pdfSha256: otisk SHA-256 archivního PDF,
  • error: důvod u stavu failed.

Archivní PDF stáhnete operací Archiv dokladu.

Odpověď a chyby

Odpověď má HTTP 200 i tehdy, když se některé doklady nezpracovaly. Ty najdete ve failedInvoices s pořadím v požadavku (index), hash, strojovým kódem code a popisem message:

Kód Význam
validation Chybí nebo je neplatné pole dokladu, neznámý kód měny nebo sazby DPH. Název pole je v message.
hash-required Chybí hash.
stock-not-allowed Sklad vystavení neexistuje, je smazaný, nebo do něj uživatel nemá přístup.
numbering-failed Sklad nemá tiskovou sestavu nebo číslo nejde přidělit.
variable-invalid Variabilní symbol nemá 1 až 10 číslic, nebo tisková sestava má nečíselný prefix.
customer-required Doklad nad 10 000 Kč včetně DPH bez odběratele.
contact-invalid Neplatné údaje odběratele, například IČ nebo e-mail.
cash-limit Hotovostní platba nad 270 000 Kč.
author-not-found, company-mismatch Neplatný autor dokladu (author.id). Pole neposílejte, autorem je uživatel tokenu.
internal Neočekávaná chyba. Doklad se nezapsal, můžete ho poslat znovu se stejným hash.

Data a časy v documents (issued, eet.registered) mají formát ISO 8601 s časovou zónou, například 2026-11-06T16:28:00+01:00.

Doklad odmítnutý ve failedInvoices se nezapíše. Po opravě ho můžete poslat znovu se stejným hash.

Autentizace a oprávnění

Vyžaduje API token: Bearer v hlavičce nebo URL token.

Parametry

Tělo požadavku

NázevTypPovinnýPopisPříklad
options.responseenum anoVždy documents. Bez této hodnoty běží interní režim pokladny, který tu nepopisujeme a který vrací jen potvrzení bez dat dokladu. documents
options.htmlboolean netrue vrátí u každého dokladu samostatný HTML dokument k tisku nebo převodu do PDF. Výchozí false. 1
invoicesarray anoDoklady k vystavení, nejvýše 100 v jednom požadavku. Každý se zpracuje samostatně. [{...}]
invoices[].hashstring anoVaše jedinečné ID dokladu, nejvýše 64 znaků, např. ID objednávky nebo UUID. Podle něj server pozná opakované odeslání. hyd-7f3c2a9e-1b4d-4c0a-9a51-2b7e0f6d1c11
invoices[].issuingStock.idinteger neSklad vystavení. Určuje tiskovou sestavu, číselnou řadu, bankovní účet, EET a uzávěrku. Uživatel tokenu musí mít do skladu přístup. Bez hodnoty platí aktivní sklad uživatele. 12
invoices[].typeenum anoTyp dokladu: cash (účtenka) nebo invoice (faktura). Další typy dokladů z pokladny server přijme, HTML pro ně ale nevrací. cash
invoices[].paymentenum anoZpůsob platby: cash (hotově), card (kartou nebo platební bránou), bank (převodem). card
invoices[].paidboolean neUhrazenost dokladu. Výchozí true pro cash a card, jinak false. 1
invoices[].issueddatetime neDatum a čas vystavení. Bez časové zóny se bere jako čas v Praze. Výchozí je okamžik přijetí. 2026-11-06 16:28:00
invoices[].taxabledate neDatum zdanitelného plnění (DUZP). Výchozí je den vystavení. 2026-11-06
invoices[].duedate neDatum splatnosti. Výchozí je den vystavení. 2026-11-20
invoices[].variablestring neVariabilní symbol, 1 až 10 číslic. Bez hodnoty se použije číslo dokladu. U QR platby pošlete variableSymbol z QR platby. 2026000042
invoices[].numberinteger neNeposílejte. Číslo přidělí server jako další v řadě skladu vystavení. null
invoices[].textstring nePoznámka na dokladu. Objednávka 2026-1187
invoices[].transactionInfoobject neÚdaje z platebního terminálu ve stejném tvaru jako z pokladny. Vytisknou se na účtence. {"card":{"type":"VISA","last4Digits":"4603"},"transactionCode":"AUTH42"}
invoices[].itemsarray anoPoložky dokladu, aspoň jedna. [{...}]
invoices[].items[].namestring anoNázev položky. U produktu z katalogu (items[].id) se může vynechat. Vstupné dospělý
invoices[].items[].codestring neVáš kód položky, nejvýše 500 znaků, např. kód vstupenky nebo voucheru. Vrací se v odpovědi u položky. TKT-8F2K-19QX
invoices[].items[].countnumber anoMnožství. 1
invoices[].items[].itemPriceExclVatnumber anoCena za kus bez DPH. 200.89
invoices[].items[].itemPriceInclVatnumber anoCena za kus s DPH. 225
invoices[].items[].vat.codestring anoKód sazby DPH z číselníku firmy (Nastavení → Sazby DPH). 12
invoices[].items[].discountnumber neSleva na položce v procentech, vytiskne se u položky. Ceny ani součty server podle ní nepřepočítává. Výchozí 0. 0
invoices[].items[].idinteger neID produktu z katalogu firmy. Bez hodnoty vznikne volná položka, která neodepisuje sklad. null
invoices[].items[].storableboolean neOdepsat položku ze skladu. Výchozí true u produktu z katalogu, false u volné položky.
invoices[].prices.currencystring anoKód měny z číselníku firmy (Nastavení → Měny), u koruny obvykle Kč. Kč
invoices[].prices.priceInclVatnumber anoCelková cena dokladu s DPH. 450
invoices[].prices.pricesarray anoRekapitulace podle sazeb DPH: code (kód sazby), priceExclVat (základ), priceInclVat (s DPH). [{"code":"12","priceExclVat":401.79,"priceInclVat":450}]
invoices[].contactobject neOdběratel. Buď {"id": ...} existujícího kontaktu, nebo údaje odběratele, podle kterých server kontakt v adresáři najde, nebo založí. Viz Odběratel. {"externalId":"c3a1f0e2-7d4b-4e55-9a0c-1f2e3d4c5b6a","companyName":"Ukázková škola","ic":"12345679"}

Příklad požadavku

curl

curl -X POST 'https://www.elpokladny.cz/api/v2/sync/invoices' \
  -H 'Authorization: Bearer elp_live_example.example_secret' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "options": {
    "response": "documents",
    "html": true
  },
  "invoices": [
    {
      "hash": "hyd-7f3c2a9e-1b4d-4c0a-9a51-2b7e0f6d1c11",
      "issuingStock": { "id": 12 },
      "type": "cash",
      "payment": "card",
      "issued": "2026-11-06 16:28:00",
      "items": [
        {
          "name": "Vstupné dospělý",
          "code": "TKT-8F2K-19QX",
          "count": 1,
          "itemPriceExclVat": 200.89,
          "itemPriceInclVat": 225,
          "vat": { "code": "12" }
        },
        {
          "name": "Vstupné dospělý",
          "code": "TKT-8F2K-19QY",
          "count": 1,
          "itemPriceExclVat": 200.89,
          "itemPriceInclVat": 225,
          "vat": { "code": "12" }
        }
      ],
      "prices": {
        "currency": "Kč",
        "priceInclVat": 450,
        "prices": [
          { "code": "12", "priceExclVat": 401.79, "priceInclVat": 450 }
        ]
      }
    }
  ]
}'

PHP

<?php
$ch = curl_init('https://www.elpokladny.cz/api/v2/sync/invoices');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => array (
  0 => 'Authorization: Bearer elp_live_example.example_secret',
  1 => 'Content-Type: application/json',
),
    CURLOPT_POSTFIELDS => '{
  "options": {
    "response": "documents",
    "html": true
  },
  "invoices": [
    {
      "hash": "hyd-7f3c2a9e-1b4d-4c0a-9a51-2b7e0f6d1c11",
      "issuingStock": { "id": 12 },
      "type": "cash",
      "payment": "card",
      "issued": "2026-11-06 16:28:00",
      "items": [
        {
          "name": "Vstupné dospělý",
          "code": "TKT-8F2K-19QX",
          "count": 1,
          "itemPriceExclVat": 200.89,
          "itemPriceInclVat": 225,
          "vat": { "code": "12" }
        },
        {
          "name": "Vstupné dospělý",
          "code": "TKT-8F2K-19QY",
          "count": 1,
          "itemPriceExclVat": 200.89,
          "itemPriceInclVat": 225,
          "vat": { "code": "12" }
        }
      ],
      "prices": {
        "currency": "Kč",
        "priceInclVat": 450,
        "prices": [
          { "code": "12", "priceExclVat": 401.79, "priceInclVat": 450 }
        ]
      }
    }
  ]
}',
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;

javascript

const response = await fetch("https://www.elpokladny.cz/api/v2/sync/invoices", {
    "method": "POST",
    "headers": {
        "Authorization": "Bearer elp_live_example.example_secret",
        "Content-Type": "application/json"
    },
    "body": "{\n  \"options\": {\n    \"response\": \"documents\",\n    \"html\": true\n  },\n  \"invoices\": [\n    {\n      \"hash\": \"hyd-7f3c2a9e-1b4d-4c0a-9a51-2b7e0f6d1c11\",\n      \"issuingStock\": { \"id\": 12 },\n      \"type\": \"cash\",\n      \"payment\": \"card\",\n      \"issued\": \"2026-11-06 16:28:00\",\n      \"items\": [\n        {\n          \"name\": \"Vstupné dospělý\",\n          \"code\": \"TKT-8F2K-19QX\",\n          \"count\": 1,\n          \"itemPriceExclVat\": 200.89,\n          \"itemPriceInclVat\": 225,\n          \"vat\": { \"code\": \"12\" }\n        },\n        {\n          \"name\": \"Vstupné dospělý\",\n          \"code\": \"TKT-8F2K-19QY\",\n          \"count\": 1,\n          \"itemPriceExclVat\": 200.89,\n          \"itemPriceInclVat\": 225,\n          \"vat\": { \"code\": \"12\" }\n        }\n      ],\n      \"prices\": {\n        \"currency\": \"Kč\",\n        \"priceInclVat\": 450,\n        \"prices\": [\n          { \"code\": \"12\", \"priceExclVat\": 401.79, \"priceInclVat\": 450 }\n        ]\n      }\n    }\n  ]\n}"
});
const data = await response.json();

Ukázkové odpovědi

Doklad vystaven (HTTP 200)

application/json

{
  "status": "success",
  "successInvoices": [
    {
      "number": 42,
      "type": "cash",
      "hash": "hyd-7f3c2a9e-1b4d-4c0a-9a51-2b7e0f6d1c11",
      "stocksInfo": []
    }
  ],
  "documents": [
    {
      "id": 18234,
      "hash": "hyd-7f3c2a9e-1b4d-4c0a-9a51-2b7e0f6d1c11",
      "duplicate": false,
      "stockId": 12,
      "type": "cash",
      "number": 42,
      "numberFormated": "2026000042",
      "variable": "2026000042",
      "issued": "2026-11-06T16:28:00+01:00",
      "taxable": "2026-11-06",
      "due": "2026-11-06",
      "payment": "card",
      "paid": true,
      "storno": false,
      "stornoId": null,
      "currency": "Kč",
      "priceExclVat": 401.79,
      "priceInclVat": 450,
      "vat": [
        { "code": "12", "rate": 12, "base": 401.79, "vat": 48.21, "total": 450 }
      ],
      "items": [
        {
          "id": 99101,
          "productId": null,
          "name": "Vstupné dospělý",
          "code": "TKT-8F2K-19QX",
          "count": 1,
          "itemPriceInclVat": 225,
          "priceInclVat": 225,
          "vatCode": "12"
        },
        {
          "id": 99102,
          "productId": null,
          "name": "Vstupné dospělý",
          "code": "TKT-8F2K-19QY",
          "count": 1,
          "itemPriceInclVat": 225,
          "priceInclVat": 225,
          "vatCode": "12"
        }
      ],
      "contactId": null,
      "contactAction": null,
      "eet": { "status": "registered", "pok": "...", "registered": "2026-11-06T16:28:01+01:00" },
      "html": "<!DOCTYPE html>\n<html lang=\"cs\">...</html>",
      "htmlTemplate": "58mm_invoice",
      "paperWidth": 80,
      "htmlSha256": "c1e79486b77cc5a03da65835bc82864bedffdc00f7e3029d8ba0bfab878bfb88",
      "htmlError": null,
      "archive": { "status": "none", "fileId": null }
    }
  ],
  "failedInvoices": []
}

Opakované odeslání stejného hash (HTTP 200)

application/json

{
  "status": "success",
  "successInvoices": [
    {
      "number": 42,
      "type": "cash",
      "hash": "hyd-7f3c2a9e-1b4d-4c0a-9a51-2b7e0f6d1c11",
      "stocksInfo": []
    }
  ],
  "documents": [
    {
      "id": 18234,
      "hash": "hyd-7f3c2a9e-1b4d-4c0a-9a51-2b7e0f6d1c11",
      "duplicate": true,
      "stockId": 12,
      "type": "cash",
      "number": 42,
      "numberFormated": "2026000042",
      "variable": "2026000042",
      "payment": "card",
      "paid": true,
      "priceInclVat": 450,
      "archive": { "status": "none", "fileId": null }
    }
  ],
  "failedInvoices": []
}

Odmítnuté doklady ve failedInvoices (HTTP 200)

application/json

{
  "status": "success",
  "successInvoices": [],
  "documents": [],
  "failedInvoices": [
    {
      "index": 0,
      "hash": "hyd-bad-vs",
      "number": null,
      "code": "variable-invalid",
      "message": "Variabilní symbol musí být 1 až 10 číslic."
    },
    {
      "index": 1,
      "hash": "hyd-big",
      "number": null,
      "code": "customer-required",
      "message": "Doklad nad 10 000 Kč vč. DPH musí mít odběratele."
    }
  ]
}

Neplatné options (HTTP 400)

application/json

{
  "status": "error",
  "code": "invalid-options",
  "message": "options.html musí být true / false."
}

Chybí platný API token (HTTP 401)

application/json

{
  "status": "error",
  "message": "Unauthorized"
}

Možné chyby

Chybové stavy

HTTPKdyPodoba
400Neplatné options (code invalid-options), chybějící nebo prázdné pole invoices (invoices-empty) nebo víc než 100 dokladů (batch-too-large). Nezpracuje se žádný doklad.
401Chybí nebo je neplatný API token. status-message
403API token se použil z IP adresy, která není u přístupu povolená, nebo je přístup odepřen. status-message

Související návody