---
title: "Webhookok | Posty dokumentáció"
description: "A Posty szól a rendszerednek, ha egy bejegyzés kiment vagy elbukott. Események, a törzs alakja és az aláírás ellenőrzése."
canonical: https://posty.hu/cs/dokumentace/automatizace/webhooky
source: https://posty.hu/cs/dokumentace/automatizace/webhooky.md
---

Automatizálás

# Webhookok

A Posty szól a rendszerednek, ha egy bejegyzés kiment vagy elbukott. Események, a törzs alakja és az aláírás ellenőrzése.

## K čemu slouží

Webhook funguje obráceně: Posty se nedotazujete, ozveme se my vašemu systému, když se něco stane. Vyšel příspěvek, selhalo publikování, odpojil se kanál.

Funkce je dostupná od tarifu Pro. Najdete ji v levém menu v části `Automatizace`, na kartě `Webhooky`. Tarif určuje, kolik webhooků můžete mít.

## Vytvoření webhooku

1. 1
   
   Přidat webhook
   
   Zadejte mu název a adresu koncového bodu, který bude požadavky přijímat. Musí to být adresa HTTPS.
2. 2
   
   Vyberte události
   
   Můžete vybrat několik, nebo seznam nechat prázdný. Prázdný seznam znamená všechno, včetně událostí přidaných později.
3. 3
   
   Vyberte kanály
   
   Webhook můžete omezit na konkrétní kanály, pokud vás zajímají jen ty.
4. 4
   
   Uložte ho a zapište si tajný klíč k podpisu
   
   Tajný klíč začíná předponou `whsec_`. V editoru webhooku ho můžete kdykoli zobrazit a znovu vygenerovat.

Prázdný seznam událostí znamená všechno

Když nevyberete žádnou událost, dostanete všechny, včetně těch, které přidáme později. Když vyberete šest, dostanete přesně těch šest. Sedmá, později přidaná událost na tento webhook nedorazí.

## Události

| Událost | Kdy |
| --- | --- |
| `post.published` | Příspěvek vyšel na kanál. |
| `post.failed` | Příspěvek skončil ve stavu chyby: platforma ho odmítla, token přestal platit, kanál byl offline nebo vypnutý, nebo to limit tarifu nedovolil. |
| `channel.disconnected` | Přístup skončil a kanál přešel do režimu offline. Fronta tohoto kanálu nic nepublikuje, dokud ho znovu nepřipojíte. |
| `channel.refresh_needed` | Obnovení tokenu se zaseklo v polovině. Kanál není offline, ale připojení musíte dokončit ručně. |
| `channel.disabled` | Kanál je vypnutý: vypnuli jste ho vy, nebo ho po změně tarifu vypnulo odsouhlasení fakturace. |
| `channel.enabled` | Pozastavený kanál se znovu zapnul. |

Událost `channel.connected` neexistuje: připojení probíhá v několika krocích a mezistavy nemá smysl hlásit.

Každé doručení nese i hlavičku `X-Posty-Event`. Řiďte se ale polem `event` v těle: hlavička v podpisu není, pole ano.

## Tělo požadavku

Tělo je **vždy JSON pole**, u každé události. Nepředpokládejte, že má vždy délku jedna.

### post.published

```
[
  {
    "id": "cm6tcts4f0005qcwit25cis26",
    "content": "Ez az első bejegyzés Instagramra",
    "publishDate": "2026-09-15T09:00:00.000Z",
    "releaseURL": "https://instagram.com/p/...",
    "state": "PUBLISHED",
    "integration": {
      "id": "cm6s4uyou0001i2r47pxix6z1",
      "name": "Posty",
      "providerIdentifier": "instagram",
      "picture": "https://uploads.posty.hu/...jpeg",
      "type": "social"
    },
    "event": "post.published"
  }
]
```

Kód másolása

`publishDate` je UTC, jako každé časové razítko v Posty.

### post.failed

Stejný objekt, navíc s polem `error`. Hodnota `state` je `ERROR` a `releaseURL` je `null`, protože k publikování nedošlo. `error` je vlastní věta platformy, pokud nějaká je, jinak `null`.

### Události channel

```
[
  {
    "event": "channel.disconnected",
    "reason": "token_revoked",
    "detail": "— access was removed in the account's Meta settings",
    "integration": {
      "id": "cm6s4uyou0001i2r47pxix6z1",
      "name": "Posty",
      "providerIdentifier": "instagram",
      "picture": "https://uploads.posty.hu/...jpeg",
      "type": "social"
    }
  }
]
```

Kód másolása

`reason` je uzavřená sada: `token_revoked`, `refresh_failed`, `manual`, `plan_limit`. Podle ní větvete. `detail` je volný text anglicky, nebo `null`: čte ho člověk, ne váš kód.

## Ověření podpisu

Každé doručení je podepsané, v hlavičce `X-Posty-Signature`:

```
X-Posty-Signature: t=1770000000,v1=10bd17b41e83eee170010df01daeeaa0edf2f939afa6e97f41e1fa7bd27e6191
```

Kód másolása

- `t`: unixový čas v sekundách, UTC, v okamžiku podpisu.
- `v1`: hexadecimální hodnota malými písmeny `HMAC-SHA256(tajemství, "<t>.<surové tělo>")`.
- Klíčem je tajný klíč k podpisu daného webhooku, s předponou `whsec_`.

Je to záměrně stejný tvar jako u podpisu Stripe, takže existující ověřovací knihovny Stripe s ním fungují. Stačí změnit název hlavičky a tajný klíč.

Podepisujte surové tělo, ne znovu serializované

`JSON.stringify` není kanonický: pořadí klíčů, escapování unicode a formátování čísel se liší podle implementace. Přijímající systém, který tělo nejdřív zpracuje a pak ho znovu převede na řetězec, spočítá jiný hash a odmítne naprosto v pořádku doručení. Tělo načtěte surově, **před zpracováním**.

### Ověření krok za krokem

- Načtěte surové tělo a hlavičku X-Posty-Signature.
- Hlavičku rozdělte podle čárek a každou část podle prvního rovnítka. Tak získáte hodnoty t a v1.
- Odmítněte ho, pokud je rozdíl mezi t a aktuálním časem větší než tolerance. Počítáme s tolerancí 300 sekund. To je ochrana proti přehrání.
- Spočítejte HMAC-SHA256(tajemství, t + "." + surové tělo) jako hexadecimální hodnotu malými písmeny.
- Porovnejte výsledek s hodnotou v1 porovnáním v konstantním čase.

Node.js

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

function verify(secret, rawBody, header, toleranceSeconds = 300) {
  const parts = Object.fromEntries(
    header.split(',').map((p) => {
      const at = p.indexOf('=');
      return [p.slice(0, at).trim(), p.slice(at + 1).trim()];
    })
  );

  const t = Number(parts.t);
  if (!Number.isFinite(t)) return false;
  if (Math.abs(Math.floor(Date.now() / 1000) - t) > toleranceSeconds) return false;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${t}.${rawBody}`)
    .digest('hex');

  return (
    expected.length === parts.v1.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
  );
}
```

Kód másolása

Pro ruční ověření zachyceného doručení totéž ze shellu:

```
printf '%s' "$T.$RAW_BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex
```

Kód másolása

`v1` je verzovaný záměrně: kdyby se schéma někdy změnilo, doručení ponesou po přechodnou dobu starý i nový prvek. Berte prvek, jehož názvu rozumíte, a zbytek ignorujte. Nepředpokládejte, že hlavička má přesně dvě části.

## Co musí přijímající systém vědět

- Než cokoli čtete, řiďte se polem `event` v těle a neznámé události ignorujte: přibudou další.
- Jako klíč použijte pole `id` příspěvku, nebo dvojici `integration.id` a událost, a opakované doručení zpracujte idempotentně.
- Čekejte jedno doručení na kanál, ne jedno na skupinu příspěvků, a nepředpokládejte pořadí.
- Při špatném podpisu požadavek odmítněte a zapište ho do logu. Jen tak bude podvržené POST vidět.

Pokud se na události chcete dotazovat, ne je přijímat, koncový bod [Oznámení](https://posty.hu/cs/dokumentace/api/koncove-body/ertesitesek) vrací tytéž události jako seznam.

Stránky dokumentace

Něco vám na této stránce chybí? Napište na [norbert@posty.hu](mailto:norbert@posty.hu) nebo na stránce [Nápověda](https://posty.hu/cs/napoveda) vyplňte formulář.
