Přeskočit na obsah

Dokumentace pro vývojáře

Poslední aktualizace 26. září 2026.

Vše, co Changeloop pro tebe publikuje, je obyčejný JSON přes HTTPS. Není potřeba instalovat žádné SDK, rotovat žádný API klíč ani projít krokem přihlášení: dva feedy níže jsou anonymní veřejná čtení klíčovaná ID tvého feedu. Nahraď YOUR_PUBLIC_ID svým v jakémkoliv příkladu na této stránce.

Jedna věc, kterou je dobré vědět předtím, než začneš: ID tvého veřejného feedu je přímo v aplikaci. Přihlas se, otevři Nastavení, a je přímo tam v sekci Veřejný feed, do které se dostaneš ve výchozím stavu, spolu s připravenými odkazy na changelog.json a roadmap.json, odkazem na tvou hostovanou stránku feedu a úryvkem kódu widgetu níže, každý s vlastním tlačítkem pro kopírování.

Začínáme

Pět kroků tě dovede od registrace k changelogu na tvém vlastním webu. Stránka „Get started“ v aplikaci tě jimi provede a každý krok odškrtne, jakmile ho dokončíš.

  1. Připoj zdroj: repozitář na GitHubu, projekt na GitLabu nebo repozitář na Bitbucketu.
  2. Vyber jazyk, ve kterém se budou psát tvoje záznamy.
  3. Volitelně si vytvoř tagy, aby čtenáři mohli filtrovat podle oblasti produktu.
  4. Zveřejni svůj první záznam. Sloučené změny přicházejí do schránky recenzí jako návrhy: jeden schval, nebo pro daný repozitář zapni automatické zveřejňování.
  5. Dej ho na svůj web: odkaž na hostovanou stránku, vlož widget nebo vykresli JSON feed na vlastní stránce.

Tvůj changelog v přibližně deseti řádcích React

Vlož tohle do komponenty a máš funkční changelog. Není třeba přidávat nic dalšího.

import { useEffect, useState } from 'react';

const FEED = 'https://api.changeloop.dev/v1/public/YOUR_PUBLIC_ID/changelog.json';

export function Changelog() {
  const [entries, setEntries] = useState([]);
  useEffect(() => {
    fetch(FEED).then((r) => r.json()).then((feed) => setEntries(feed.data));
  }, []);
  return <ul>{entries.map((e) => <li key={e.id}><b>{e.title}</b><p>{e.mdContent}</p></li>)}</ul>;
}

mdContent je markdown, který jsme sepsali, jako text. Pokud raději vykresluješ formátovaný výstup, použij místo toho htmlContent: je sestaven na serveru naším vlastním sanitizérem z pevného seznamu povolených tagů a atributů, a je to jediná hodnota v kterékoliv z těchto odpovědí určená k vložení jako markup. Vše ostatní je text a záznamy sepsané z veřejného repozitáře mohou být ovlivněny kýmkoli, kdo tam může otevřít pull request, takže se k nim podle toho chovej.

Feed changelogu

GET/v1/public/YOUR_PUBLIC_ID/changelog.json

Tvé publikované záznamy, od nejnovějšího, přičemž nejnovější ID rozhoduje shody u identických časových razítek.

Parametry dotazu

  • repos přijímá seznam plných názvů repozitářů oddělených čárkou, například acme/web,acme/api. Vrátí se pouze záznamy z těchto repozitářů. Nech prázdné a dostaneš je všechny.
  • limit je, kolik záznamů chceš na stránku. Výchozí je 20, cokoliv nad 50 je omezeno na 50, a cokoliv nedokážeme interpretovat jako kladné číslo se vrátí zpět na 20 místo selhání.
  • cursor je neprůhledný. Vezmi hodnotu nextCursor z předchozí odpovědi a vrať ji tak, jak je. Kurzor, který nedokážeme dekódovat, je zpracován, jako by žádný kurzor nebyl, takže dostaneš zpět první stránku místo chyby.

Odpověď

{
  "data": [
    {
      "id": "66b0c1f2e4a9d1c3b5a70011",
      "title": "Saved views on the inbox",
      "mdContent": "You can now pin a filter and come back to it.",
      "htmlContent": "<p>You can now pin a filter and come back to it.</p>",
      "repoFullName": "acme/web",
      "category": "feature",
      "tags": ["Inbox"],
      "learnMoreUrl": "https://acme.example/docs/saved-views",
      "publishedAt": "2026-08-06T09:12:44.000Z"
    }
  ],
  "nextCursor": null,
  "tagColors": { "Inbox": "#4f46e5" }
}

Každý záznam nese stejných devět klíčů: id, title, mdContent, htmlContent, repoFullName, category, tags, learnMoreUrl a publishedAt. category je feature, fix nebo internal a je null, pokud ho ten, kdo sepsal záznam, nenastavil; publishedAt je řetězec ISO 8601 a htmlContent je prázdný řetězec u záznamu, který nikdy neprošel sepisovatelem. tags je pole názvů tvých vlastních produktových oblastí a je prázdné, pokud žádné nebyly přiřazeny, learnMoreUrl je null, pokud ho recenzent nepřidal, a barva pro vykreslení každého tagu pochází z mapy tagColors v odpovědi, ne ze záznamu, takže tag, který jsi odstranil ze svého slovníku, se jednoduše vykreslí bez barvy. nextCursor je null, když dosáhneš konce.

Neznámé ID feedu odpoví 404 s {"error":"not_found"}, stejně jako chybně zformované. Tyto dva případy jsou záměrně nerozlišitelné, takže tento endpoint nelze použít ke zjištění, jaká ID existují.

Feed roadmapy

GET/v1/public/YOUR_PUBLIC_ID/roadmap.json

Stejné tři sloupce, které tvůj tým už ručně udržuje.

{
  "columns": [
    { "column": "planned", "items": [], "hasMore": false },
    {
      "column": "building",
      "items": [
        {
          "id": "66b0c1f2e4a9d1c3b5a70042",
          "column": "building",
          "publicTitle": "Slack notifications",
          "publicDescription": "Post each published entry to a channel you pick.",
          "publishedAt": "2026-08-05T16:20:01.000Z"
        }
      ],
      "hasMore": false
    },
    { "column": "shipped", "items": [], "hasMore": false }
  ]
}

columns je pole, ne objekt indexovaný podle názvu sloupce, a jeho pořadí je součástí smlouvy: planned, pak building, pak shipped. Všechny tři jsou vždy přítomny, včetně prázdných, takže nikdy nemusíš rozlišovat „takový sloupec neexistuje“ od „ještě v něm nic není“. Vykresli je v pořadí, v jakém jsi je dostal, a budeš odpovídat každé jiné povrchové ploše, kterou stavíme.

Položka má přesně pět klíčů: id, column, publicTitle, publicDescription a publishedAt. publicDescription je vždy řetězec a může být prázdný, nikdy null. Nic o issue, ze kterého položka pochází, tu není odhaleno, ani repozitář, ani číslo issue, a to je záměrné, ne opomenutí, které později doplníme.

Tento endpoint nepřijímá žádné parametry dotazu vůbec. Není tu žádný kurzor, limit ani filtr repozitáře, protože roadmapa je malá tabule, kterou kurátoruje člověk, ne log, který nekonečně roste. Každý sloupec vrací až 50 položek a nastaví hasMore, pokud jich bylo víc. hasMore je informativní: neexistuje kurzor, kterým by ses jím řídil, takže kolem toho nebuduj stránkování.

publicTitle a publicDescription jsou obyčejný text sepsaný z názvů a obsahů issues, které ve veřejném repozitáři může ovlivnit kdokoli, kdo issue otevře. Nenesou žádnou záruku sanitizace HTML a nejsou výjimkou htmlContent. Vykresli je jako text.

Vložitelný widget

Pokud raději nic nestavíš, vlož tyto dva řádky. Widget je custom element vykreslující se do shadow rootu, takže nedědí tvé styly ani do nich neprosakuje.

<script src="https://api.changeloop.dev/widget.js" defer></script>
<changelogapp-widget
  data-public-id="YOUR_PUBLIC_ID"
  data-api="https://api.changeloop.dev"></changelogapp-widget>

Oba atributy jsou povinné. data-public-id je ID tvého feedu, data-api je origin, ze kterého widget načítá data. Pokud některý chybí, element zapíše chybu do konzole a nic nevykreslí, což je první věc, kterou zkontroluj, pokud vidíš prázdné místo tam, kde by měl widget být.

Přidej k elementu data-theme="dark" pro tmavé vykreslení; tvá stránka to může přepínat za běhu. Pro hlubší stylování widget nabízí CSS vlastní proměnné (--changelogapp-text, --changelogapp-bg, --changelogapp-accent a další) a názvy ::part(), které nastavíš ve vlastním stylu. Aplikace zobrazuje živý náhled obou motivů v Nastavení, sekce Veřejný feed.

Přidejte data-repos, pokud chcete zobrazit jen některé repozitáře, například changelog jednoho produktu na webu tohoto produktu, když jeden účet sdílí více produktů. Hodnota je seznam plných názvů owner/repo oddělených čárkou; samotný název bez vlastníka nic neodpovídá a vykreslí prázdný kanál bez chyby. Zohlední se nejvýše deset repozitářů. Takto omezený widget zobrazuje jen záložky Updates a Feedback, protože roadmapa nemá pohled podle repozitáře, a zpětná vazba se stále zakládá tam, kam míří cíl zpětné vazby vašeho týmu. V Nastavení, Veřejný kanál je výběr, který atribut napíše za vás.

Vykresluje tři karty v tomto pořadí: Updates, Roadmap a Feedback. První dvě čtou feedy výše. Třetí odesílá na endpoint níže a uchovává ID každého odeslání v localStorage, takže se návštěvník může vrátit a zjistit, co se stalo s tím, co odeslal.

Skript je poskytován verzovaně. /widget.js vždy poskytuje nejnovější build a je uložen v mezipaměti na hodinu, takže vydání se dostane k tvým návštěvníkům bez toho, aniž bys čeho ses dotkl. /widget-vN.js připíná jeden build: jakmile bylo číslo verze poskytnuto, jeho byty se už nikdy nezmění, a je uložen v mezipaměti na rok. Připni ho, pokud raději přijímáš změny záměrně.

Načti přesně jeden skript widgetu na stránku

Dvě URL jsou alternativy, ne vrstvy. Obě registrují stejný název custom elementu a prohlížeč umožňuje zaregistrovat název pouze jednou na dokument: který skript se spustí jako první, ten vyhraje po dobu životnosti stránky, a druhý se stane neaktivním. Takže stránka nesoucí jak /widget.js, tak /widget-v5.js vykresluje ten, který prohlížeč spustil jako první, což není něco, co ovládáš, a přidání /widget-v5.js vedle existujícího /widget.js pro připnutí verze nedělá nic.

Když se to stane, widget zapíše varování do konzole s uvedením obou buildů, takže nezůstaneš hádat. Nemůže udělat víc než varovat: než se spustí druhá kopie, první si už nárokovala název. Oprava je vždy nahradit tag skriptu místo přidání dalšího, a totéž platí, pokud ho za tebe vloží správce tagů nebo fragment. Chceš-li přejít z průběžného buildu na připnutý, změň src.

Hostovaná stránka feedu

https://feed.changeloop.dev/feed/YOUR_PUBLIC_ID

Na této adrese hostujeme i obyčejnou stránku: tvůj changelog a tvou tabuli roadmapy, vykreslené ze stejných dvou feedů výše. Nevyžaduje přihlášení ani nic nastaveného na tvé straně. Je to také místo, kam posíláme lidi zpět, jakmile se smyčka uzavře: komentář Shipped, který zanecháváme na issue na GitHubu, odkazuje sem, stejně jako shippedEntry.link z vyhledání odeslání výše, oba přistávají na doručeném záznamu s vlastní kotvou #entry-ID, která záznam najde, i když se mezitím přesunul na pozdější stránku.

Zacházej s ní jako se záložním řešením, ne integrací. Feed changelogu a widget zůstávají způsobem, jak to umístit na tvůj vlastní web, aby to vypadalo jako tvůj produkt, ne náš; tato stránka je pro případ, kdy jsi to ještě neudělal, a pro odkazy uzavírající smyčku, které sem míří bez ohledu na to, co jiného jsi postavil.

Vlastní doména

Hostovanou stránku můžeš servírovat z vlastní adresy bez změn DNS nebo certifikátů. V Nastavení, sekce Vlastní doména, vlož veřejnou adresu, kterou uvidí tví čtenáři (například https://example.com/changelog), a pak nasměruj tuto cestu na svém webu na tam zobrazený cíl proxy: jedno pravidlo pokryje stránku, její assety, data i feedy. Zkontrolovat doménu načte tvou adresu z naší strany a řekne ti, zda je proxy správně, a pokud ne, co změnit.

MCP server

POSThttps://api.changeloop.dev/mcp

Pokud pracuješ v Claude Code, ChatGPT nebo jiném agentovi, který mluví Model Context Protocol, můžeš ho připojit přímo ke svému changelogu. Agent pak vidí, co čeká na recenzi, může upravit text a publikovat, aniž bys opustil editor. Je to stejná brána recenze jako webová aplikace: nic se nestane veřejným, dokud to něco neschválí.

Připojení Claude Code

Nejprve vytvoř API klíč (Nastavení, API klíče), pak přidej server se svým klíčem v hlavičce:

claude mcp add --transport http changeloop \
  https://api.changeloop.dev/mcp \
  --header "Authorization: Bearer clapi_YOUR_KEY"

Pro klienta, který místo toho čte konfiguraci JSON, vypadá totéž takto:

{
  "mcpServers": {
    "changeloop": {
      "type": "http",
      "url": "https://api.changeloop.dev/mcp",
      "headers": { "Authorization": "Bearer clapi_YOUR_KEY" }
    }
  }
}

Zatím neexistuje tok OAuth. Autentizace je API klíč v hlavičce, což dělají oba příkazy výše. Zrušení tohoto klíče v Nastavení odpojí agenta při jeho dalším požadavku.

Co agent dokáže

Sedm nástrojů, a seznam je záměrně krátký. Cokoliv jiného, co tento produkt dokáže, je dosažitelné přes REST API se stejným klíčem; každý nástroj vystavený agentovi je další věc, ke které může být přesvědčen, aby ho zavolal.

  • list_pending_entries, list_published_entries, get_entry - čtou tvé záznamy. Čekající nejsou veřejné.
  • update_entry - mění název nebo markdown obsah záznamu. HTML, který feed poskytuje, je znovu vykreslen z tvého markdownu naším sanitizérem; agent nemůže poskytnout HTML.
  • approve_entry - publikuje. Toto je veřejné a okamžité a upozorní jakoukoliv propojenou zpětnou vazbu na GitHubu. Schválit lze pouze čekající záznam.
  • discard_entry - udrží záznam mimo changelog. Vratné z webové aplikace.
  • get_changelog_info - ID tvého feedu a adresy, ze kterých je tvůj changelog poskytován.

Co nedokáže

Každý nástroj je omezen na tým, kterému klíč patří, a žádný z nich nepřijímá tým jako argument, takže neexistuje nic, čím by bylo možné mířit na jiný tým, i kdyby se o to něco pokusilo. Server nepřijímá relaci prohlížeče, pouze klíč: požadavek musí záměrně připojit přihlašovací údaje. A klíč nemůže spravovat klíče ani stáhnout export tvých dat, takže agent připojený tímto způsobem si nemůže vyrobit druhé přihlašovací údaje ani vytáhnout tvá data jedním voláním.

API klíče

Vše výše je anonymní a nevyžaduje žádné přihlašovací údaje. Autentizované API - tvá nastavení, tvá schránka recenzí - je jiná plocha a přijímá buď přihlášenou relaci prohlížeče, nebo API klíč. Klíče jsou pro skripty a agenty: cokoliv, co potřebuje dosáhnout na tvůj changelog bez člověka u klávesnice.

Authorization: Bearer clapi_YOUR_KEY

Vytvoř ho v aplikaci pod Nastavení, na kartě API klíče. Klíč se zobrazí jednou, ve chvíli, kdy ho vytvoříš, a nikdy víc: ukládáme pouze jeho hash, takže neexistuje žádná obrazovka, která by ti ho mohla ukázat podruhé. Pokud ho ztratíš, zruš ho a vytvoř další.

Co klíč dokáže a nedokáže

Klíč nese stejný přístup jako přihlášení, omezený na jediný tým, ve kterém byl vytvořen, se dvěma záměrnými výjimkami. Nemůže spravovat API klíče a nemůže stáhnout export tvých dat. Obojí vyžaduje skutečné přihlášení, aby si uniklý klíč nemohl vytvořit náhrady sám za sebe, nemohl zrušit klíče, které bys použil k jeho zablokování, a nemohl vytáhnout data tvého týmu jedním požadavkem.

Zrušení

Zrušení nabývá účinnosti při dalším požadavku. Zrušený klíč odpovídá 401 přesně jako neznámý, a nadále odpovídá 401 i z prohlížeče, který stále drží platnou relaci, protože požadavek nesoucí hlavičku Authorization se nikdy tiše nezkusí znovu jako požadavek s cookie. Zrušený klíč zůstává uveden se seznamem, kdy byl zrušen, a datem posledního použití, což je přesně to, co chceš při zjišťování, kam se uniklý klíč dostal.

Plány a limity

Bezplatný plán sepíše 20 sloučených změn měsíčně a omezuje denní počet prohlédnutých sloučení, roztříděné zpětné vazby, navržených karet roadmapy a alternativních verzí na 50 každý; týmový plán nemá pevné limity. Nastavení, sekce Plán a využití, ukazuje každý rozpočet tak, jak ho produkt sám počítá, včetně okamžiku, kdy se obnovuje, ještě než se cokoli odmítne. Práce, která dorazí nad limit, se pozdrží, neztratí: záznam nad kvótou čeká v inboxu a odmítnutý návrh roadmapy lze zopakovat, jakmile se okno obnoví.

GitLab a Bitbucket

Projekt GitLab nebo repozitář Bitbucket může krmit tvůj changelog stejným způsobem jako repozitář GitHub: připoj ho pod Nastavení, pak GitLab, nebo Nastavení, pak Bitbucket, přidej webhook, který ti dáme (nebo ho na bitbucket.org nech přidat přes Connect with Bitbucket, pokud stránka Bitbucket to tlačítko nabízí), a každá změna sloučená do větve, kterou jmenuješ, se stane návrhem záznamu ve tvé schránce recenzí, napsaným stejným způsobem a podléhajícím stejné lidské recenzi. Záznamy vznikají ze sloučených pull requestů nebo merge requestů, nebo, na GitHubu a Bitbucketu, z pushů, pokud zvolíš režim push v Nastavení, pak What creates drafts. Projekty z GitLabu vytvářejí návrhy pouze z merge requestů.

Připojení projektu

Projekty z GitLabu se připojují pod Nastavení, pak GitLab, repozitáře z Bitbucketu pod Nastavení, pak Bitbucket. Zadej cestu (na GitLabu skupinu a projekt, jako acme/web, na Bitbucketu workspace a repozitář, jako acme/app) a my ti vrátíme adresu webhooku a tajemství. Vlož oba do nastavení webhooku na jejich straně: na GitLabu zaškrtni Merge request events, na Bitbucketu zaškrtni spouštěče Merged pull request a Push repository. Samostatně hostované instance fungují, přes https. Tajemství se zobrazí jednou, v ten okamžik. Pokud ho ztratíš, odstraň projekt a připoj znovu. Na bitbucket.org, pokud ti stránka Bitbucket zobrazuje tlačítko Connect with Bitbucket, můžeš vkládání přeskočit: klikni na něj, jednou povol přístup a my přečteme hlavní větev repozitáře a webhook přidáme za tebe. Musíš mít v repozitáři práva správce. U samostatně hostovaného Bitbucketu, nebo když chceš raději vkládat, zvol Set it up by hand a dostaneš adresu a tajemství jako výše. Když repozitář z Bitbucketu odstraníš a připojíš znovu, smaž na Bitbucketu i jeho starý webhook, v Repository settings, pak Webhooks. Jakmile je projekt připojený, můžeš v jeho řádku změnit větev a zapnout automatickou publikaci, a pokud bylo nějaké doručení ignorováno, řádek uvede proč.

Proč Bitbucket žádá o větev a GitLab ne

GitLab nám řekne, kterou větev tvůj projekt považuje za výchozí, takže můžeš nechat pole prázdné a myslet tím právě to. Bitbucket vůbec neposílá výchozí větev, takže kdybychom tě nechali nechat pole prázdné, neměli bychom s čím porovnávat a tvůj webhook by tam vypadal dokonale nainstalovaný, aniž by kdy vyprodukoval jediný záznam. Raději položíme jednu otázku, než abychom to nechali stát se. S Connect with Bitbucket se na hlavní větev zeptáme přímo Bitbucketu, když povolíš přístup, takže ji nemusíš psát.

Co zatím nepokrývají

Záznamy changelogu a nic víc. Widget zpětné vazby, který za tebe otevře issue, odpověď zveřejněná zpět na tomto issue, když je oprava doručena, veřejná roadmapa řízená štítky issues a náhled zdroje ve schránce recenzí jsou dnes všechny výhradně pro GitHub.

Důvod je jeden, který raději uvedeme, než abychom ho zamlžovali. Každé z toho potřebuje přístupový token s právem zápisu do tvého projektu, uchovávaný námi. Záznamy changelogu žádný nepotřebují, protože vše, z čeho jsou napsány, přichází přímo ve webhooku, takže připojení GitLab nebo Bitbucket přes webhook nám nedává žádné přihlašovací údaje ani žádné čtení tvého kódu. Connect with Bitbucket je jediná výjimka. Bitbucket nám na jediný požadavek půjčí token, který smí číst repozitář a jeho pull requesty a spravovat jeho webhooky. Použijeme ho jen k přečtení hlavní větve a přidání webhooku a pak ho zahodíme. Nic se neukládá. Raději doručíme část, která tě nic nestojí, než abychom žádali o token, aby se doplnil seznam funkcí.

Další verze záznamu

Jedna změna obvykle musí být vysvětlena víc než jednou: zákazníkům v changelogu, tomu, kdo odpovídá na dotazy o ní, a v kanálu, kde nikdo nečte čtyři odstavce. Ze schránky recenzí můžeš sepsat jednu ze dvou dalších verzí záznamu předtím, než ho schválíš.

Verze oznámení je jeden nebo dva řádky, a to je to, co se zveřejní na Slacku, když schválíš záznam, místo celého textu. Poznámka pro podporu je interní brífink: co se změnilo, co si zákazníci všimnou, a věta, kterou by agent podpory mohl říct téměř doslovně. Obě jsou návrhy, které můžeš přepsat před použitím, a kteroukoliv lze odstranit.

Žádná z nich se nepublikuje

Tyto verze se nikdy neobjeví na tvé stránce changelogu, v žádném feedu, ve widgetu ani v API, které je poskytuje. Poznámka pro podporu je zejména napsána pro lidi uvnitř tvé společnosti a může být přímější než samotný záznam. Jediná místa, kde existuje, jsou tvá schránka recenzí a, pokud je používáš, tvá vlastní kopie.

Z čeho jsou napsány

Vždy ze záznamu, nikdy z pull requestu. To je záměrné: záznam už prošel pravidlem, které udržuje bezpečnostní opravy vágní, a tvou vlastní recenzí. Verze přepsaná z něj nemůže znovu zavést detail, který jsi odstranil, protože ten detail není v tom, co dostal model.

Oznamování na Slacku

Schval záznam, a může být zveřejněn v kanálu Slacku ve stejném okamžiku, kdy se stane veřejným. Připoj ho pod Nastavení, na kartě Slack: vytvoř příchozí webhook ve svém vlastním workspace, vyber kanál a vlož URL. Na tvé straně se nic neinstaluje kromě tohoto webhooku a nežádáme o žádný přístup k tvému workspace.

Zpráva nese název záznamu, text tak, jak jsi ho schválil, jeho kategorii a tagy, a odkaz zpět na záznam v tvém changelogu. Markdown je přeložen do toho, co Slack skutečně vykresluje, takže záznam nepřijde s vlastními hvězdičkami.

URL webhooku jsou přihlašovací údaje

Kdokoliv vlastní toto URL, může publikovat do kanálu, takže s ním zacházíme jako s heslem: je uloženo, a poté ho žádná obrazovka a žádná odpověď API znovu nezobrazí, včetně tvého vlastního exportu dat. To, co vidíš potom, je maska, dostačující k rozlišení dvou webhooků, a k ničemu pro kohokoliv jiného. Přijímáme pouze adresu hooks.slack.com, takže špatně zadané nebo nahrazené URL je odmítnuto místo načtení.

Když přestane fungovat

Pokud odstraníš aplikaci na Slacku nebo archivuješ kanál, webhook trvale přestane fungovat. Všimneme si toho při první odmítnuté zprávě, vypneme oznámení a uvedeme to na kartě Slack s důvodem a datem. Je záměrné, že to nezkoušíme dál tiše opakovat: changelog, který nikdo neoznámil, vypadá přesně jako ten, který nikdo nečetl, a to je rozdíl, o kterém stojí za to informovat.

Pozastavení

Pauza zastaví oznámení a zachová webhook, takže obnovení je jedno stisknutí místo dalšího kola přes Slack. Odpojení URL zcela odstraní. Tak jako tak samotné publikování není ovlivněno: Slack je kanál, do kterého tvůj changelog publikuje, nikdy brána, na kterou čeká. Pokud je Slack nedostupný, když něco schválíš, záznam se přesto publikuje a oznámení se zkusí znovu samo.

RSS a JSON Feed

GEThttps://api.changeloop.dev/v1/public/YOUR_PUBLIC_ID/rss.xmlGEThttps://api.changeloop.dev/v1/public/YOUR_PUBLIC_ID/feed.json

Stejné publikované záznamy jako feed k odběru, ve dvou formátech, kterým čtenáři rozumí: RSS 2.0 a JSON Feed 1.1. Oba přijímají stejné filtry repos, category a tag jako feed changelogu a nesou stejný Cache-Control a ETag. Žádný nestránkuje: čtenář dotazuje začátek feedu, takže tyto vracejí pouze nejnovější záznamy, bez kurzoru.

Text záznamu je sanitizovaný HTML, obalený v CDATA pro RSS a jako content_html pro JSON Feed. JSON Feed navíc nese barvy tvých tagů pod rozšířením s jmenným prostorem _changelogapp; RSS ne, protože žádný čtenář by je nevymaloval.

Hostovaná stránka oznamuje oba jako odkazy rel="alternate", takže prohlížeč nebo čtenář, který na ni přistane, se může přihlásit k odběru, aniž by mu byly řečeny cesty.

Jeden záznam samostatně

GEThttps://api.changeloop.dev/v1/public/YOUR_PUBLIC_ID/entries/ENTRY_ID

Vrací jeden publikovaný záznam, stejný objekt, který feed changelogu nese ve svém poli data. Sem míří trvalé odkazy ve feedech, a je to užitečné, když máš ID a nechceš procházet feed stránkováním, abys ho našel. Neznámé ID nebo ID patřící nepublikovanému záznamu vrací 404 se stejným tělem jako jakékoli jiné neznámé ID.

Feed markdown

GEThttps://api.changeloop.dev/v1/public/YOUR_PUBLIC_ID/changelog.md

Stejné publikované záznamy jako obyčejný markdown, poskytovaný jako text/markdown. Existuje pro čtenáře, kteří nejsou prohlížeči: LLM nebo agent odpovídající na „co se v tomto produktu nedávno změnilo“ dostane text bez parsování RSS nebo procházení JSON. Přijímá stejné filtry repos, category a tag jako feed changelogu, nese stejný Cache-Control a ETag a odpovídá 304 na podmíněný požadavek přesně jako oba ostatní.

Každý záznam je sekce: název jako nadpis, pak jeden řádek nesoucí datum, kategorii a jakékoliv tagy, pak text záznamu tak, jak byl napsán, pak odkaz Learn more, pokud ho záznam má, pak jeho trvalý odkaz. Dokument se otevírá názvem a popisem tvého feedu a vede zpět na hostovanou stránku. Když ještě nic nebylo publikováno, řekne to jednou větou místo vrácení prázdného těla, takže čtenář to dokáže odlišit od neúspěšného načtení.

Hostovaná stránka ho oznamuje jako odkaz rel="alternate" s type text/markdown, vedle odkazů RSS a JSON Feed, takže agent, který načetl HTML, ho může najít, aniž by mu byla řečena cesta.

To, co poskytuje, je markdown, který jsme sepsali a tys schválil, ne sanitizovaný HTML. To je bezpečné jako markdown, který je inertní, a proto tato odpověď nikdy není text/html. Pokud ho vykresluješ sám, escapuj ho stejně, jako bys escapoval jakýkoliv jiný nedůvěryhodný markdown: záznamy sepsané z veřejného repozitáře mohou být ovlivněny kýmkoli, kdo tam může otevřít pull request.

Sbírání zpětné vazby z tvého vlastního webu

Přidej své origins předtím, než to otestuješ

Toto je jediný endpoint v produktu, který zapisuje, takže nepřijímá požadavky odkudkoliv. Porovnává hlavičku Origin prohlížeče se seznamem povolení pro každý tým, a tento seznam začíná prázdný. Prázdný znamená odmítnout vše, ne povolit vše. Dokud nepřidáš origin, do kterého vkládáš, každé odeslání se vrátí s 403 a {"error":"origin_not_allowed"}, a nic se nedostane do tvé schránky. Pokud tvůj formulář vypadá správně a přesto selhává, téměř vždy je to tento důvod. Nastav seznam autentizovaným PATCH na /v1/settings/feed nesoucím {"allowedOrigins": ["https://your-site.example"]}, a přečti si ho zpátky pomocí GET na stejnou cestu, která odpoví tvým publicId, tvým allowedOrigins a feedTitle a feedDescription, které tvoji odběratelé vidí ve čtečce feedů. Ukládáme každý origin přesně v podobě, v jaké ho posílá prohlížeč, takže koncové lomítko nebo explicitní výchozí port v tom, co posíláš, není problém.

POST/v1/public/YOUR_PUBLIC_ID/feedback
POST https://api.changeloop.dev/v1/public/YOUR_PUBLIC_ID/feedback
Content-Type: application/json
Origin: https://your-site.example

{ "email": "someone@example.com", "message": "Dark mode, please." }

202 Accepted
{ "publicSubmissionId": "0ZbQ8yqk3n7T1sVJ4mWpLd2rXfEuGh6A" }

email musí vypadat jako e-mailová adresa a mít 254 znaků nebo méně. message musí být neprázdný a mít 2KB nebo méně, měřeno v bajtech UTF-8, ne znacích. Tělo JSON jako celek je omezeno na 8KB. Existuje ještě jedno pole, website: je to past na roboty, takže ho vynech, nebo ho pošli prázdné, pokud ho vykresluješ jako skryté pole tak, jak to dělá náš widget.

Stojí za to porozumět pasti na roboty, než pomocí ní budeš cokoliv ladit. Pokud website přijde s něčím napsaným, odpovídáme 202 s naprosto normálně vypadajícím ID odeslání a pak neuděláme nic, protože robot, který zjistí, že byl chycen, to prostě zkusí znovu jinak. To je správná odpověď pro robota a matoucí pro tebe, takže pokud tvůj vlastní formulář má pole s názvem website, které by prohlížeč mohl automaticky vyplnit, přejmenuj ho nebo ho odstraň. Odeslání, které vypadá přijaté a nikdy se neobjeví, je téměř vždy tento případ.

Odeslání, které přijmeme, vrátí 202 s publicSubmissionId. Vrať to zpět osobě, která to poslala, a ulož si to, pokud můžeš: je to jediný způsob, jak zjistí, co se stalo dál.

Módy selhání jsou 400 s invalid_email nebo invalid_message pro špatný tvar, 413 s email_too_large nebo message_too_large pro správný tvar, ale příliš velký, 429 s rate_limited nad 5 odeslání za minutu nebo 30 za hodinu z jedné adresy do jednoho feedu, 403 s origin_not_allowed a 404 s not_found pro ID feedu, které nerozpoznáme.

Existuje také denní limit pro každý tým na to, kolik navazující práce mohou odeslání spustit. Nad ním stále přijímáme a ukládáme vše, co přijde, prostě to čeká, až se na to podívá někdo z tvého týmu, místo aby to samo něco otevřelo.

Kontrola jednoho odeslání

GET/v1/public/YOUR_PUBLIC_ID/feedback/PUBLIC_SUBMISSION_ID

Odpovídá stavem, plus githubIssueUrl, jakmile pro toto odeslání existuje issue, plus shippedEntry nesoucí název a odkaz, jakmile je práce hotová. E-mailová adresa odesílatele není nikdy čtena z naší databáze pro tuto trasu, natož vrácena, což dělá odpověď bezpečnou pro vykreslení na stránce, kterou může vidět kdokoliv. ID je celý přihlašovací údaj, zacházej s ním tak. Je omezeno na 20 požadavků za minutu a 200 za hodinu na adresu a feed.

Mezipaměť, CORS a podmíněné požadavky

Oba feedy odesílají Cache-Control: public, max-age=60, stale-while-revalidate=300 spolu se silným ETagem. Pošli tento ETag zpět jako If-None-Match a nezměněný feed odpoví 304 bez těla. Žádné pole odpovědi nenese hodnotu nástěnných hodin, takže ETag zůstává stabilní, když znovu vykreslujeme data, která se nezměnila, což dělá tato 304 hodná spolehnutí.

Oba feedy a vyhledání odeslání jsou anonymní čtení a odpovídají s Access-Control-Allow-Origin: *, takže je můžeš volat z jakéhokoliv originu, z curlu nebo z kroku buildu. POST zpětné vazby je výjimka: odpovídá tvým vlastním povoleným originem a Vary: Origin, nikdy se zástupným znakem. Prohlížeče na něm dělají preflight, a preflight vždy odpoví 204 bez ohledu na to, zda je origin povolen, takže ho nelze použít k sondování tvého nastavení.