InvoiceHub dokumentace

Doménové události se odpalují samy. Vytvoření dokladu, jeho odeslání e-mailem, úhrada, založení kontaktu i načtení platby z banky doručí webhook všem endpointům, které danou událost odebírají. Úplný seznam je v katalogu událostí níž.

Kromě toho lze doručení vyvolat i ručně:

Registrace endpointu

Všechna volání níže vyžadují hlavičku Authorization: Bearer <API klíč>. Základní adresa staging prostředí je https://invoicehub-api.zeabur.app/api/v1.

POST /api/v1/webhooks
Content-Type: application/json

{
  "name": "Zapier – zaplacené faktury",
  "url": "https://hooks.example.com/invoicehub",
  "events": ["document.sent", "document.paid"]
}
  • name – interní pojmenování endpointu.
  • url – absolutní HTTPS adresa, na kterou se posílá POST.
  • events – pole názvů událostí, které tento endpoint odebírá. Obvykle sem patří názvy z katalogu událostí. Server obsah neověřuje proti číselníku – přijme libovolné řetězce, takže si sem můžete zapsat i vlastní název odpalovaný akcí TRIGGER_WEBHOOK. Nezná-li server zapsaný název, prostě se pro něj nikdy nic nedoručí.

Pole description v této verzi neexistuje; pokud ho pošlete, nikde se neprojeví.

Secret dostanete jen jednou

Při vytvoření server vygeneruje podepisovací tajemství (32 náhodných bajtů v hex zápisu) a vrátí ho pouze v odpovědi na tento jeden request. Následné GET volání už secret nevrací a znovu ho nezobrazíte.

Uložte si secret hned – ideálně do trezoru tajemství nebo proměnné prostředí přijímající aplikace. Když ho ztratíte, jediná cesta zpět je smazat webhook a založit ho znovu (dostanete nový secret).

Správa a vypnutí

Operace Endpoint
Seznam webhooků GET /api/v1/webhooks
Detail webhooku GET /api/v1/webhooks/:id
Registrace POST /api/v1/webhooks
Úprava PUT /api/v1/webhooks/:id

Přes PUT lze měnit name, url, events a isActive. Dočasné vypnutí endpointu se dělá právě nastavením isActive na false:

PUT /api/v1/webhooks/:id
Content-Type: application/json

{ "isActive": false }

Formát doručení

Tělo požadavku je vždy JSON obálka se čtyřmi klíči. Vlastní data události jsou v data:

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "document.paid",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "…": "obsah podle události – viz katalog níž"
  }
}

Klíč se jmenuje event (nikoli type) a čas timestamp (nikoli created_at) – v ISO 8601. Tvar data pro každou událost najdete v katalogu událostí.

HTTP hlavičky

Hlavička Obsah
X-InvoiceHub-Signature sha256=<hex> – HMAC‑SHA256 podpis těla
X-InvoiceHub-Event název události, stejný jako event v těle
X-InvoiceHub-Delivery hodnota id z obálky – identifikátor doručení

Samostatná hlavička s časovým razítkem neexistuje a systém nemá žádnou ochranu proti replay útoku nad rámec toho, že timestamp je součástí podepsaných dat. Pokud replay ochranu potřebujete, vyhodnoťte si na své straně stáří timestamp a zahazujte již viděná id doručení.

Ověření podpisu

Podpis vzniká jako HMAC-SHA256 nad přesným JSON řetězcem obálky, se secretem daného webhooku jako klíčem, výsledek je hex. Proto musíte podpis počítat nad surovým (nezparsovaným) tělem požadavku – jakmile tělo zparsujete a znovu serializujete, pořadí klíčů či mezery se mohou lišit a podpis nebude sedět.

Oficiální SDK pro žádný jazyk zatím neexistuje; ověření je pár řádků nad standardní kryptografickou knihovnou. Příklad pro Node.js a Express:

const crypto = require('crypto');
const express = require('express');

const app = express();
const SECRET = process.env.INVOICEHUB_WEBHOOK_SECRET;

// pozor: express.raw(), ne express.json() – potřebujeme surové tělo
app.post('/invoicehub', express.raw({ type: 'application/json' }), (req, res) => {
  const header = req.get('X-InvoiceHub-Signature') || '';
  const received = header.startsWith('sha256=') ? header.slice(7) : '';

  const expected = crypto
    .createHmac('sha256', SECRET)
    .update(req.body) // Buffer se surovým tělem
    .digest('hex');

  const a = Buffer.from(received, 'hex');
  const b = Buffer.from(expected, 'hex');
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.status(401).send('invalid signature');
  }

  const payload = JSON.parse(req.body.toString('utf8'));
  console.log(payload.event, payload.id, payload.timestamp);

  res.status(200).send('ok');
});

A totéž v Pythonu – podstatné je opět surové tělo a porovnání v konstantním čase:

import hmac, hashlib

def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
    received = signature_header.removeprefix("sha256=")
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, received)

Nikdy neporovnávejte podpisy operátorem == nad řetězci – použijte porovnání v konstantním čase (crypto.timingSafeEqual, hmac.compare_digest). A na nepodepsané či nesedící požadavky odpovídejte 401, ne 200.

Opakování pokusů

Jedno doručení má nejvýše 3 pokusy a timeout jednoho pokusu je 10 sekund. Zpoždění mezi pokusy jsou 1 minuta, 5 minut a 30 minut a čeká se blokujícím způsobem – doručení neúspěšného webhooku se tak může protáhnout na desítky minut.

Každý pokus, včetně neúspěšného, se zapíše do historie doručení. Po vyčerpání všech pokusů se endpoint automaticky nedeaktivujeisActive zůstává true a odešle se pouze interní notifikace o selhání. Trvale nedostupný endpoint tedy musíte vypnout sami přes PUT.

Z pohledu příjemce z toho plyne: odpovězte rychle (do 10 s) stavovým kódem 2xx a těžkou práci si zařaďte do vlastní fronty. A počítejte s tím, že stejné doručení můžete dostat vícekrát – zpracování dělejte idempotentní podle id z obálky (hlavička X-InvoiceHub-Delivery).

Testovací doručení

POST /api/v1/webhooks/:id/test

Odešle jeden pokus bez opakování. Událost je vždy webhook.test a tělo vypadá takto:

{
  "id": "0c7b4f2a-6a1e-45f0-9f1c-3b8d5e2a7c10",
  "event": "webhook.test",
  "timestamp": "2026-08-19T09:14:22.481Z",
  "data": {
    "message": "This is a test delivery from InvoiceHub",
    "webhookId": "3d2a1b0c-…"
  }
}

Je to nejrychlejší způsob, jak si na svém endpointu ověřit dostupnost, TLS a hlavně správnost ověřování podpisu, ještě než postavíte zbytek integrace.

Historie a znovuodeslání

GET  /api/v1/webhooks/:id/deliveries
POST /api/v1/webhooks/:id/deliveries/:deliveryId/replay

První endpoint vrací stránkovaný seznam doručení včetně neúspěšných pokusů, druhý odešle konkrétní doručení znovu. Hodí se, když váš systém měl výpadek a chcete zameškaná doručení dohnat.

Pozor na rozpor s API reference: v OpenAPI specifikaci na / je tato operace zatím uvedená pod cestou …/deliveries/:deliveryId/resend a chybí tam …/test. Skutečná implementace používá replay – řiďte se touto stránkou, specifikace bude doplněna.

Katalog událostí

Server odpaluje níže uvedené události sám, jakmile k dané akci v aplikaci dojde. Endpoint dostane jen ty, které má zapsané v poli events. Stejný katalog vydává i API voláním GET /api/v1/webhooks/events – používá ho i nabídka v aplikaci (Nastavení → API a webhooky), takže co je v nabídce, to se i doručuje.

Událost Kdy nastane
document.created Byl založen nový doklad (POST /documents) — včetně dokladů vzniklých z opakované série nebo ze schránky nákladů.
document.updated Doklad byl změněn přes PATCH /documents/:id — položky, částky, odběratel nebo štítky.
document.deleted Koncept byl smazán (DELETE /documents/:id). Payload nese poslední známý stav dokladu — po smazání už ho nelze dohledat.
document.sent Doklad byl úspěšně odeslán odběrateli e-mailem (POST /documents/:id/send-email) — včetně upomínky, poděkování za platbu a nabídky.
document.viewed Odběratel otevřel doklad přes veřejný odkaz. Posílá se při každém zobrazení, ne jen při prvním.
document.paid Doklad se dostal do stavu PAID — přechodem stavu, spárováním platby, nebo hned při založení jako uhrazený.
document.overdue Denní kontrola (8:00) našla neuhrazenou fakturu po splatnosti. Posílá se jednou za doklad, ne každý den — stejně jako odpovídající notifikace.
document.archived Doklad přešel do stavu ARCHIVED (POST /documents/:id/transition).
contact.created Byl založen nový kontakt (POST /contacts).
contact.updated Kontakt byl změněn přes PATCH /contacts/:id. Archivace ani rozarchivování sem nespadá — na to je contact.archived.
contact.archived Kontakt byl archivován (PATCH /contacts/:id s archived: true). Kontakty se nemažou, jen archivují.
product.created Byla založena nová položka ceníku (POST /products).
product.updated Položka ceníku byla změněna přes PATCH /products/:id.
product.archived Položka ceníku byla vyřazena (DELETE /products/:id) — jde o měkké smazání, záznam zůstává s active: false.
payment.imported Ze synchronizace s bankou nebo z ručního importu výpisu vznikla nová platba. Posílá se za každou nově založenou platbu.
payment.matched Platba byla spojena s dokladem — ručně (PUT /payments/:id/match), potvrzením návrhu, nebo automatickým párováním při importu.
payment.unmatched Platbě byla zrušena vazba na doklad (DELETE /payments/:id/match).
automation.started Automatizace navěšená na systémovou událost začala běžet. Vzniká i pro běh, který následně skončí přeskočením kvůli nesplněným podmínkám.
automation.finished Běh automatizace doběhl — buď provedl akce (COMPLETED), nebo se přeskočil, protože nesedly podmínky (SKIPPED).
automation.failed Běh automatizace skončil chybou — buď spadl celý (výjimka), nebo neprošla některá z akcí.
ai.completed Operace AI (OCR dokladu, chat, analýza dat firmy) doběhla úspěšně.
ai.failed Operace AI skončila chybou — model neodpověděl, nebo se nepodařilo zpracovat vstup.

Dokumenty

document.created

Byl založen nový doklad (POST /documents) — včetně dokladů vzniklých z opakované série nebo ze schránky nákladů.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "document.created",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0001qw3f7h2n5m1a",
    "number": "2026-0042",
    "type": "INVOICE",
    "status": "DRAFT",
    "currency": "CZK",
    "total": 12100,
    "paidAmount": 0,
    "contactId": "clx8k2p9c0002qw3f8j4k6l2b",
    "clientName": "Novák s.r.o.",
    "issuedAt": "2026-08-19T00:00:00.000Z",
    "dueAt": "2026-09-02T00:00:00.000Z"
  }
}

document.updated

Doklad byl změněn přes PATCH /documents/:id — položky, částky, odběratel nebo štítky.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "document.updated",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0001qw3f7h2n5m1a",
    "number": "2026-0042",
    "type": "INVOICE",
    "status": "ISSUED",
    "currency": "CZK",
    "total": 12100,
    "paidAmount": 0,
    "contactId": "clx8k2p9c0002qw3f8j4k6l2b",
    "clientName": "Novák s.r.o.",
    "issuedAt": "2026-08-19T00:00:00.000Z",
    "dueAt": "2026-09-02T00:00:00.000Z"
  }
}

document.deleted

Koncept byl smazán (DELETE /documents/:id). Payload nese poslední známý stav dokladu — po smazání už ho nelze dohledat.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "document.deleted",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0001qw3f7h2n5m1a",
    "number": "2026-0042",
    "type": "INVOICE",
    "status": "DRAFT",
    "currency": "CZK",
    "total": 12100,
    "paidAmount": 0,
    "contactId": "clx8k2p9c0002qw3f8j4k6l2b",
    "clientName": "Novák s.r.o.",
    "issuedAt": "2026-08-19T00:00:00.000Z",
    "dueAt": "2026-09-02T00:00:00.000Z"
  }
}

document.sent

Doklad byl úspěšně odeslán odběrateli e-mailem (POST /documents/:id/send-email) — včetně upomínky, poděkování za platbu a nabídky.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "document.sent",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0001qw3f7h2n5m1a",
    "number": "2026-0042",
    "type": "INVOICE",
    "status": "SENT",
    "currency": "CZK",
    "total": 12100,
    "paidAmount": 0,
    "contactId": "clx8k2p9c0002qw3f8j4k6l2b",
    "clientName": "Novák s.r.o.",
    "issuedAt": "2026-08-19T00:00:00.000Z",
    "dueAt": "2026-09-02T00:00:00.000Z",
    "sentTo": "fakturace@novak.cz",
    "subject": "Faktura 2026-0042",
    "emailType": "DOCUMENT"
  }
}

document.viewed

Odběratel otevřel doklad přes veřejný odkaz. Posílá se při každém zobrazení, ne jen při prvním.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "document.viewed",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0001qw3f7h2n5m1a",
    "number": "2026-0042",
    "type": "INVOICE",
    "status": "SENT",
    "currency": "CZK",
    "total": 12100,
    "paidAmount": 0,
    "contactId": "clx8k2p9c0002qw3f8j4k6l2b",
    "clientName": "Novák s.r.o.",
    "issuedAt": "2026-08-19T00:00:00.000Z",
    "dueAt": "2026-09-02T00:00:00.000Z",
    "viewedAt": "2026-08-20T10:12:45.221Z"
  }
}

document.paid

Doklad se dostal do stavu PAID — přechodem stavu, spárováním platby, nebo hned při založení jako uhrazený.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "document.paid",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0001qw3f7h2n5m1a",
    "number": "2026-0042",
    "type": "INVOICE",
    "status": "PAID",
    "currency": "CZK",
    "total": 12100,
    "paidAmount": 12100,
    "contactId": "clx8k2p9c0002qw3f8j4k6l2b",
    "clientName": "Novák s.r.o.",
    "issuedAt": "2026-08-19T00:00:00.000Z",
    "dueAt": "2026-09-02T00:00:00.000Z"
  }
}

document.overdue

Denní kontrola (8:00) našla neuhrazenou fakturu po splatnosti. Posílá se jednou za doklad, ne každý den — stejně jako odpovídající notifikace.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "document.overdue",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0001qw3f7h2n5m1a",
    "number": "2026-0042",
    "type": "INVOICE",
    "status": "SENT",
    "currency": "CZK",
    "total": 12100,
    "paidAmount": 0,
    "contactId": "clx8k2p9c0002qw3f8j4k6l2b",
    "clientName": "Novák s.r.o.",
    "issuedAt": "2026-08-19T00:00:00.000Z",
    "dueAt": "2026-09-02T00:00:00.000Z",
    "daysOverdue": 7,
    "remainingAmount": 12100
  }
}

document.archived

Doklad přešel do stavu ARCHIVED (POST /documents/:id/transition).

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "document.archived",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0001qw3f7h2n5m1a",
    "number": "2026-0042",
    "type": "INVOICE",
    "status": "ARCHIVED",
    "currency": "CZK",
    "total": 12100,
    "paidAmount": 0,
    "contactId": "clx8k2p9c0002qw3f8j4k6l2b",
    "clientName": "Novák s.r.o.",
    "issuedAt": "2026-08-19T00:00:00.000Z",
    "dueAt": "2026-09-02T00:00:00.000Z",
    "previousStatus": "PAID"
  }
}

Kontakty

contact.created

Byl založen nový kontakt (POST /contacts).

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "contact.created",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0002qw3f8j4k6l2b",
    "name": "Novák s.r.o.",
    "email": "fakturace@novak.cz",
    "phone": "+420 601 234 567",
    "type": "CLIENT",
    "taxId": "25596641",
    "vatId": "CZ25596641",
    "archived": false
  }
}

contact.updated

Kontakt byl změněn přes PATCH /contacts/:id. Archivace ani rozarchivování sem nespadá — na to je contact.archived.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "contact.updated",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0002qw3f8j4k6l2b",
    "name": "Novák s.r.o.",
    "email": "fakturace@novak.cz",
    "phone": "+420 601 234 567",
    "type": "CLIENT",
    "taxId": "25596641",
    "vatId": "CZ25596641",
    "archived": false
  }
}

contact.archived

Kontakt byl archivován (PATCH /contacts/:id s archived: true). Kontakty se nemažou, jen archivují.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "contact.archived",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0002qw3f8j4k6l2b",
    "name": "Novák s.r.o.",
    "email": "fakturace@novak.cz",
    "phone": "+420 601 234 567",
    "type": "CLIENT",
    "taxId": "25596641",
    "vatId": "CZ25596641",
    "archived": true
  }
}

Produkty

product.created

Byla založena nová položka ceníku (POST /products).

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "product.created",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0003qw3f9m5n7o3c",
    "name": "Konzultace",
    "sku": "KONZ-01",
    "unit": "hod",
    "price": 1500,
    "vatRate": 21,
    "active": true
  }
}

product.updated

Položka ceníku byla změněna přes PATCH /products/:id.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "product.updated",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0003qw3f9m5n7o3c",
    "name": "Konzultace",
    "sku": "KONZ-01",
    "unit": "hod",
    "price": 1500,
    "vatRate": 21,
    "active": true
  }
}

product.archived

Položka ceníku byla vyřazena (DELETE /products/:id) — jde o měkké smazání, záznam zůstává s active: false.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "product.archived",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0003qw3f9m5n7o3c",
    "name": "Konzultace",
    "sku": "KONZ-01",
    "unit": "hod",
    "price": 1500,
    "vatRate": 21,
    "active": false
  }
}

Platby

payment.imported

Ze synchronizace s bankou nebo z ručního importu výpisu vznikla nová platba. Posílá se za každou nově založenou platbu.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "payment.imported",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0004qw3f0n6o8p4d",
    "amount": 12100,
    "currency": "CZK",
    "direction": "IN",
    "receivedAt": "2026-08-25T00:00:00.000Z",
    "variableSymbol": "20260042",
    "counterAccount": "123456789/0800",
    "matchStatus": "AUTO_MATCHED",
    "documentId": "clx8k2p9c0001qw3f7h2n5m1a",
    "bankAccountId": "clx8k2p9c0005qw3f1o7p9q5e",
    "source": "BANK_SYNC"
  }
}

payment.matched

Platba byla spojena s dokladem — ručně (PUT /payments/:id/match), potvrzením návrhu, nebo automatickým párováním při importu.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "payment.matched",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0004qw3f0n6o8p4d",
    "amount": 12100,
    "currency": "CZK",
    "direction": "IN",
    "receivedAt": "2026-08-25T00:00:00.000Z",
    "variableSymbol": "20260042",
    "counterAccount": "123456789/0800",
    "matchStatus": "MANUAL_MATCHED",
    "documentId": "clx8k2p9c0001qw3f7h2n5m1a",
    "bankAccountId": "clx8k2p9c0005qw3f1o7p9q5e",
    "documentNumber": "2026-0042",
    "matchedBy": "clx8k2p9c0006qw3f2p8q0r6f"
  }
}

payment.unmatched

Platbě byla zrušena vazba na doklad (DELETE /payments/:id/match).

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "payment.unmatched",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "id": "clx8k2p9c0004qw3f0n6o8p4d",
    "amount": 12100,
    "currency": "CZK",
    "direction": "IN",
    "receivedAt": "2026-08-25T00:00:00.000Z",
    "variableSymbol": "20260042",
    "counterAccount": "123456789/0800",
    "matchStatus": "UNMATCHED",
    "documentId": null,
    "bankAccountId": "clx8k2p9c0005qw3f1o7p9q5e",
    "previousDocumentId": "clx8k2p9c0001qw3f7h2n5m1a"
  }
}

Automatizace

automation.started

Automatizace navěšená na systémovou událost začala běžet. Vzniká i pro běh, který následně skončí přeskočením kvůli nesplněným podmínkám.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "automation.started",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "automationId": "clx8k2p9c0007qw3f3q9r1s7g",
    "runId": "clx8k2p9c0008qw3f4r0s2t8h",
    "name": "Upomínka po splatnosti",
    "triggerEvent": "document.created",
    "documentId": "clx8k2p9c0001qw3f7h2n5m1a"
  }
}

automation.finished

Běh automatizace doběhl — buď provedl akce (COMPLETED), nebo se přeskočil, protože nesedly podmínky (SKIPPED).

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "automation.finished",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "automationId": "clx8k2p9c0007qw3f3q9r1s7g",
    "runId": "clx8k2p9c0008qw3f4r0s2t8h",
    "name": "Upomínka po splatnosti",
    "triggerEvent": "document.created",
    "documentId": "clx8k2p9c0001qw3f7h2n5m1a",
    "status": "COMPLETED",
    "actionsRun": 2,
    "actionsFailed": 0
  }
}

automation.failed

Běh automatizace skončil chybou — buď spadl celý (výjimka), nebo neprošla některá z akcí.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "automation.failed",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "automationId": "clx8k2p9c0007qw3f3q9r1s7g",
    "runId": "clx8k2p9c0008qw3f4r0s2t8h",
    "name": "Upomínka po splatnosti",
    "triggerEvent": "document.created",
    "documentId": "clx8k2p9c0001qw3f7h2n5m1a",
    "status": "FAILED",
    "errorMessage": "SMTP connection timed out"
  }
}

AI

ai.completed

Operace AI (OCR dokladu, chat, analýza dat firmy) doběhla úspěšně.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "ai.completed",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "operation": "ocr",
    "model": "claude-opus-4-6",
    "inputSummary": "Soubor: faktura.pdf, 214KB",
    "outputSummary": "Dodavatel: Novák s.r.o., Částka: 12100"
  }
}

ai.failed

Operace AI skončila chybou — model neodpověděl, nebo se nepodařilo zpracovat vstup.

{
  "id": "8f1c9a2e-4d3b-4a17-9a51-2c9f0b3d7e64",
  "event": "ai.failed",
  "timestamp": "2026-08-19T06:00:04.812Z",
  "data": {
    "operation": "chat",
    "model": "claude-opus-4-6",
    "errorMessage": "Request timed out"
  }
}

Vlastní názvy událostí

Pole events se neověřuje proti katalogu – server přijme libovolný řetězec. To je záměr: kromě událostí z katalogu si můžete posílat i vlastní, které si odpálíte akcí TRIGGER_WEBHOOK v automatizaci.

  1. Zvolte si název ve tvaru oblast.akce, například reminder.due nebo invoice.recurring.due. Vyhněte se názvům z katalogu výš, ať se vám vlastní doručení nemíchají se systémovými.
  2. Zapište ho do events při registraci webhooku.
  3. Stejný název použijte v parametru akce TRIGGER_WEBHOOK v automatizaci.
  4. Na své straně větvěte zpracování podle hlavičky X-InvoiceHub-Event.

Obsah data u vlastní události není payload z katalogu: akce TRIGGER_WEBHOOK posílá kontext automatizace (mimo jiné documentId, organizationId, documentType, amount, status, tags). Nespoléhejte tedy u vlastních názvů na tvar popsaný výš.

Checklist příjemce

  • Endpoint na veřejné HTTPS adrese, odpověď 2xx do 10 sekund.
  • Podpis ověřený nad surovým tělem, porovnání v konstantním čase.
  • Neplatný podpis → 401, žádné zpracování.
  • Idempotence podle X-InvoiceHub-Delivery – doručení může dorazit opakovaně.
  • Vlastní kontrola stáří timestamp, chcete‑li replay ochranu.
  • Monitoring vaší strany – InvoiceHub vám vypnutí mrtvého endpointu neudělá.