# Webhooky · Dokumentace DameDokladu

> Podepsané účetní události ve vašich systémech: adresy, obsah, podpis, opakování a záznam doručení.

Source: https://damedoklad.cz/docs/webhooks/

# Webhooky

Podepsané účetní události ve vašich systémech: adresy, obsah, podpis, opakování a záznam doručení.

Webhook je adresa ve vašem systému, kterou DameDoklad zavolá, když se něco stane: třeba když vystavíte fakturu nebo přijde platba. Nemusíte se tak pořád ptát API, co je nového.

Webhooky spravujete v **Nastavení > Webhooky** nebo přes API. K založení potřebujete tarif s webhooky, viz [ceník](/cenik/).

## Založení adresy

```bash
curl https://api.damedoklad.cz/v1/webhooks \
  -H "Authorization: Bearer $DAMEDOKLAD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/hooks/damedoklad", "events": ["invoice.issued", "received_invoice.*"] }'
```

Odpověď obsahuje podpisové tajemství `secret`, které začíná `whsec_`. Uvidíte ho jen jednou. Když ho ztratíte, vyměňte ho přes `POST /v1/webhooks/{id}/rotate-secret`; staré tajemství okamžitě přestane platit.

V `events` uveďte názvy událostí, předponu jako `invoice.*` nebo `*` pro všechno. Adresa musí být veřejná: soukromé a místní adresy DameDoklad odmítne a před každým doručením to ověřuje znovu.

## Co přijde

Každé doručení je `POST` s tělem v JSON:

```json
{
  "id": "evt_6f1c2a9b04d3e8f17a5c0b21",
  "type": "invoice.issued",
  "createdAt": "2026-10-30T09:12:44.120Z",
  "workspaceId": "wsp_…",
  "data": { "row": { "id": "inv_…", "number": "FV2026001", "status": "issued" }, "lines": [] }
}
```

| Pole | Význam |
| --- | --- |
| `id` | Označení události. Při opakovaném doručení zůstává stejné, takže podle něj poznáte opakování. |
| `type` | Název události. |
| `createdAt` | Kdy se událost stala. |
| `workspaceId` | Firma. |
| `data` | Co událost říká o objektu. Pole se liší podle události, a když potřebujete víc, načtěte aktuální stav přes API. |

Spolu s tím přijdou tyto hlavičky:

| Hlavička | Význam |
| --- | --- |
| `X-DameDoklad-Event` | Název události. |
| `X-DameDoklad-Delivery` | Označení tohoto doručení, stejné jako v záznamu doručení. |
| `X-DameDoklad-Signature` | Podpis, viz níže. |
| `User-Agent` | `DameDoklad-Webhooks/1.0` |

## Kontrola podpisu

Hlavička s podpisem vypadá jako `t=1793351564,v1=5f8a…`. `t` je čas odeslání v unixových sekundách a `v1` je šestnáctkové HMAC SHA-256 textu `{t}.{syrové tělo}` s vaším tajemstvím jako klíčem. Porovnávejte nad syrovými bajty těla, ještě před zpracováním JSON.

```js
import { createHmac, timingSafeEqual } from 'node:crypto';

export function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map((part) => part.split('=')));
  const expected = createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
  const same = expected.length === parts.v1.length && timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  return same && fresh;
}
```

```python
import hashlib, hmac, time

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(part.split("=", 1) for part in header.split(","))
    signed = parts["t"].encode() + b"." + raw_body
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts["v1"]) and abs(time.time() - int(parts["t"])) < 300
```

Pětiminutové okno je naše doporučení proti přehrání zprávy. DameDoklad podepisuje každý pokus s novým `t`.

## Opakování

Jakákoli odpověď `2xx` do 15 sekund znamená doručeno. Všechno ostatní se opakuje, celkem nejvýš osmkrát:

| Po pokusu | Další pokus za |
| --- | --- |
| 1 | 1 minutu |
| 2 | 5 minut |
| 3 | 30 minut |
| 4 | 2 hodiny |
| 5 | 6 hodin |
| 6 | 12 hodin |
| 7 | 24 hodin |

Po osmém neúspěchu zůstane doručení v záznamu jako `failed` a můžete ho poslat znovu přes `POST /v1/webhook-deliveries/{id}/retry`. Záznam najdete přes `GET /v1/webhooks/{id}/deliveries`.

`POST /v1/webhooks/{id}/test` hned pošle podepsanou událost `webhook.test` a vrátí výsledek. Testovací události se neopakují.

## Příjem událostí

-   **Odpovídejte rychle.** Událost si uložte a zpracujte ji až potom.
-   **Počítejte s opakováním.** Stejná událost může přijít víckrát, proto si evidujte `id`.
-   **Nespoléhejte na pořadí.** V případě pochybností si načtěte aktuální stav objektu přes API.
-   **Událost odchází až po potvrzení transakce**, takže stornovaná operace se nikdy neohlásí.

## Události

| Událost | Kdy nastane |
| --- | --- |
| `invoice.issued` | Faktura byla vystavena. |
| `invoice.storno` | Faktura byla stornována. |
| `invoice.payment_added` | K faktuře přibyla úhrada. |
| `invoice.payment_removed` | Úhrada faktury byla odebrána. |
| `received_invoice.recorded` | Přijatá faktura byla zaevidována. |
| `received_invoice.storno` | Přijatá faktura byla stornována. |
| `received_invoice.settled` | Přijatá faktura byla uhrazena. |
| `credit_note.issued` | Dobropis byl vystaven. |
| `credit_note.storno` | Dobropis byl stornován. |
| `credit_note.payment_added` | K dobropisu přibyla úhrada. |
| `proforma.issued` | Zálohová faktura byla vystavena. |
| `proforma.payment_added` | K zálohové faktuře přibyla úhrada. |
| `delivery_note.issued` | Dodací list byl vystaven. |
| `member.invited` | Někdo dostal pozvánku do firmy. |
| `member.joined` | Někdo přijal pozvánku. |
| `member.role_changed` | Změnila se role člena. |
| `member.removed` | Člen byl odebrán. |
| `company.updated` | Změnily se údaje firmy. |
| `inbox.document_received` | Doklad dorazil do K vyřízení. |
| `inbox.document_finished` | Doklad v K vyřízení byl dokončen. |

## Správa přes API

Webhooky spravujete těmito operacemi:

-   [Ask the shop to send a notification here when an order is created or changes, so an order arrives within a minute and not at the next 15-minute read. Turn it on with webhooksEnabled](/docs/api-reference/connections/#registerShopWebhooks) `POST /v1/shop-connections/{id}/register-webhooks`
-   [Send a failed delivery again](/docs/api-reference/platform/#retryWebhookDelivery) `POST /v1/webhook-deliveries/{id}/retry`
-   [List the event types a webhook can subscribe to. Payloads are in the \`webhooks\` section of /openapi.json](/docs/api-reference/platform/#listWebhookEvents) `GET /v1/webhook-events`
-   [List webhook endpoints](/docs/api-reference/platform/#listWebhookEndpoints) `GET /v1/webhooks`
-   [Create a webhook endpoint. The signing secret is returned once.](/docs/api-reference/platform/#createWebhookEndpoint) `POST /v1/webhooks`
-   [Get a webhook endpoint](/docs/api-reference/platform/#getWebhookEndpoint) `GET /v1/webhooks/{id}`
-   [Update a webhook endpoint: URL, events, or pause it](/docs/api-reference/platform/#updateWebhookEndpoint) `PATCH /v1/webhooks/{id}`
-   [Delete a webhook endpoint and its delivery log](/docs/api-reference/platform/#deleteWebhookEndpoint) `DELETE /v1/webhooks/{id}`
-   [List delivery attempts of a webhook endpoint, newest first](/docs/api-reference/platform/#listWebhookDeliveries) `GET /v1/webhooks/{id}/deliveries`
-   [Replace the signing secret. The new secret is returned once; the old one stops working immediately.](/docs/api-reference/platform/#rotateWebhookSecret) `POST /v1/webhooks/{id}/rotate-secret`
-   [Send a signed test event to this endpoint now and return the result. Test events are not retried.](/docs/api-reference/platform/#testWebhookEndpoint) `POST /v1/webhooks/{id}/test`
