[{"data":1,"prerenderedAt":38},["ShallowReactive",2],{"doc-hub":3},{"html":4,"headings":5},"\u003Cp>Three things that make a project's public side one product instead of a pile of\nembeds:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>The hub\u003C\u002Fstrong>, a page at \u003Ccode>\u002Fhub\u002F&lt;public key&gt;\u003C\u002Fcode> that gathers what the project\nalready publishes: the changelog, roadmap, feedback board, blog, legal\ndocuments and brand kit, a way to chat, and a few links of your own.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>The Home tab\u003C\u002Fstrong> of the chat widget: what's new, the top feedback and the\nonboarding flows, next to Messages.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>\u003Ccode>helpbites.js\u003C\u002Fcode>\u003C\u002Fstrong>, one \u003Ccode>&lt;script&gt;\u003C\u002Fcode> tag that adds whichever of the chat,\nfeedback board, changelog and onboarding your project has, so a feature you\nswitch on later needs no edit to your site.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>All three wear the project's look from its \u003Ca href=\"\u002Fdocs\u002Fbrand\">Brand kit\u003C\u002Fa>: its accent,\nlogo, typefaces and corner radius. Change the kit and they follow.\u003C\u002Fp>\n\u003Ch2 id=\"turn-it-on\">Turn it on\u003Ca class=\"heading-anchor\" href=\"#turn-it-on\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>\u003Cstrong>Project → Settings → Public hub.\u003C\u002Fstrong> Nothing is on until you switch it on.\u003C\u002Fp>\n\u003Cdiv class=\"table-wrap\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Setting\u003C\u002Fth>\n\u003Cth>Meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>enabled\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Turns the page at \u003Ccode>\u002Fhub\u002F&lt;pk&gt;\u003C\u002Fcode> on. Off, it answers \u003Ccode>404\u003C\u002Fcode>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>title\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The page's heading. Empty uses the project's name.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>tagline\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The line under it. Empty uses the Brand kit's tagline.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>sections\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Which sections the page lists, in order: \u003Ccode>about\u003C\u002Fcode>, \u003Ccode>changelog\u003C\u002Fcode>, \u003Ccode>roadmap\u003C\u002Fcode>, \u003Ccode>feedback\u003C\u002Fcode>, \u003Ccode>blog\u003C\u002Fcode>, \u003Ccode>legal\u003C\u002Fcode>, \u003Ccode>brand\u003C\u002Fcode>, \u003Ccode>contact\u003C\u002Fcode>. Default: all of them.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>links\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Up to 8 links of your own, \u003Ccode>{ label, url }\u003C\u002Fcode> (http or https), shown after the sections.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>widgetHome\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>{ enabled, sections }\u003C\u002Fcode>: the chat widget's Home tab, with any of \u003Ccode>changelog\u003C\u002Fcode>, \u003Ccode>feedback\u003C\u002Fcode>, \u003Ccode>onboarding\u003C\u002Fcode>. Default off. It works without the page being on.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>Over the API, it is part of the project (the same call the panel makes). Only the\nkeys you send change; \u003Ccode>sections\u003C\u002Fcode> and \u003Ccode>links\u003C\u002Fcode> are replaced whole.\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-bash\">\u003Ccode>\u003Cspan class=\"shj-syn-func\">curl\u003C\u002Fspan>\u003Cspan class=\"shj-syn-kwd\"> -X\u003C\u002Fspan> PATCH https:\u002F\u002Fhelp.example.com\u002Fv1\u002Fadmin\u002Fprojects\u002FPROJECT_ID \\\n \u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"Authorization: Bearer \u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">$HELPBITES_ADMIN_KEY\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"\u003C\u002Fspan> \\\n \u003Cspan class=\"shj-syn-kwd\"> -H\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">\"Content-Type: application\u002Fjson\"\u003C\u002Fspan> \\\n \u003Cspan class=\"shj-syn-kwd\"> -d\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'{\"hub\":{\"enabled\":true,\"tagline\":\"Everything we ship\",\"sections\":[\"changelog\",\"roadmap\",\"feedback\",\"contact\"],\"links\":[{\"label\":\"Docs\",\"url\":\"https:\u002F\u002Fdocs.example.com\"}],\"widgetHome\":{\"enabled\":true,\"sections\":[\"changelog\",\"feedback\"]}}}'\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Ch2 id=\"the-page\">The page\u003Ca class=\"heading-anchor\" href=\"#the-page\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>\u003Ccode>https:\u002F\u002FYOUR-SUPPORT-HOST\u002Fhub\u002FPROJECT_PUBLIC_KEY\u003C\u002Fcode> needs no sign-in and works\nwithout JavaScript. A section shows only when its feature has something public:\u003C\u002Fp>\n\u003Cdiv class=\"table-wrap\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Section\u003C\u002Fth>\n\u003Cth>Shows when\u003C\u002Fth>\n\u003Cth>What it lists\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>about\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The Brand kit has an About text\u003C\u002Ftd>\n\u003Ctd>That text.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>changelog\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The \u003Ca href=\"\u002Fdocs\u002Ffeedback\">public changelog\u003C\u002Fa> is on and has entries\u003C\u002Ftd>\n\u003Ctd>The five latest, linking to \u003Ccode>\u002Fchangelog\u002F&lt;pk&gt;\u003C\u002Fcode>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>roadmap\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The board has public items, or the feedback board has its roadmap on\u003C\u002Ftd>\n\u003Ctd>A link to \u003Ccode>\u002Froadmap\u002F&lt;pk&gt;\u003C\u002Fcode>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>feedback\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The feedback board is on\u003C\u002Ftd>\n\u003Ctd>The three top posts and the board.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>blog\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The blog is on and has posts\u003C\u002Ftd>\n\u003Ctd>The five latest, linking to \u003Ccode>\u002Fblog\u002F&lt;pk&gt;\u003C\u002Fcode>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>legal\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>At least one legal document is published\u003C\u002Ftd>\n\u003Ctd>Each document, once (translations are reached from the original).\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>brand\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The Brand kit's page is public\u003C\u002Ftd>\n\u003Ctd>A link to \u003Ccode>\u002Fbrand\u002F&lt;pk&gt;\u003C\u002Fcode>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>contact\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Always\u003C\u002Ftd>\n\u003Ctd>\u003Cstrong>Start a chat\u003C\u002Fstrong>, which opens the chat widget (the page loads \u003Ccode>helpbites.js\u003C\u002Fcode> for it).\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>The page is plain server-rendered HTML with a strict Content Security Policy:\nnothing from a user is shown as HTML, every link must be http(s), and the only\nscripts are one fixed click handler and \u003Ccode>helpbites.js\u003C\u002Fcode> from the same origin.\u003C\u002Fp>\n\u003Ch2 id=\"json-get-v1hubpk\">JSON: \u003Ccode>GET \u002Fv1\u002Fhub\u002F{pk}\u003C\u002Fcode>\u003Ca class=\"heading-anchor\" href=\"#json-get-v1hubpk\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>The same data, for the widget's Home tab, the snippets below, or your own UI.\nPublic, no sign-in, CORS open, rate limited per address, cached for a minute with\nan \u003Ccode>ETag\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-bash\">\u003Ccode>\u003Cspan class=\"shj-syn-func\">curl\u003C\u002Fspan> https:\u002F\u002Fhelp.example.com\u002Fv1\u002Fhub\u002Fpk_abc123\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-json\">\u003Ccode>{\n  \u003Cspan class=\"shj-syn-var\">\"project\"\u003C\u002Fspan>: { \u003Cspan class=\"shj-syn-var\">\"name\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Acme\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"publicKey\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"pk_abc123\"\u003C\u002Fspan> },\n  \u003Cspan class=\"shj-syn-var\">\"look\"\u003C\u002Fspan>: { \u003Cspan class=\"shj-syn-var\">\"accent\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"#16a34a\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"accentText\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"#ffffff\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"radiusPx\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">8\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"scheme\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"auto\"\u003C\u002Fspan>,\n            \u003Cspan class=\"shj-syn-var\">\"logoUrl\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002F…\u002Flogo.svg\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"fontFamily\"\u003C\u002Fspan>: { \u003Cspan class=\"shj-syn-var\">\"display\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"\\\"Fraunces\\\", …\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"body\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"…\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"mono\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"…\"\u003C\u002Fspan> },\n            \u003Cspan class=\"shj-syn-var\">\"fontCssUrls\"\u003C\u002Fspan>: [\u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002Ffonts.googleapis.com\u002Fcss2?family=Fraunces\"\u003C\u002Fspan>] },\n  \u003Cspan class=\"shj-syn-var\">\"hub\"\u003C\u002Fspan>: { \u003Cspan class=\"shj-syn-var\">\"enabled\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-bool\">true\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"title\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Acme\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"tagline\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Everything we ship\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"url\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002Fhelp.example.com\u002Fhub\u002Fpk_abc123\"\u003C\u002Fspan> },\n  \u003Cspan class=\"shj-syn-var\">\"sections\"\u003C\u002Fspan>: [\n    { \u003Cspan class=\"shj-syn-var\">\"key\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"changelog\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"title\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"What is new\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"url\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002Fhelp.example.com\u002Fchangelog\u002Fpk_abc123\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"text\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"action\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>,\n      \u003Cspan class=\"shj-syn-var\">\"items\"\u003C\u002Fspan>: [{ \u003Cspan class=\"shj-syn-var\">\"title\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Dark mode\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"url\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002Fhelp.example.com\u002Fchangelog\u002Fpk_abc123\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"meta\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Oct 1, 2026\"\u003C\u002Fspan> }] },\n    { \u003Cspan class=\"shj-syn-var\">\"key\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"contact\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"title\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Contact us\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"url\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"text\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"items\"\u003C\u002Fspan>: [], \u003Cspan class=\"shj-syn-var\">\"action\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"chat\"\u003C\u002Fspan> }\n  ],\n  \u003Cspan class=\"shj-syn-var\">\"links\"\u003C\u002Fspan>: [{ \u003Cspan class=\"shj-syn-var\">\"label\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"Docs\"\u003C\u002Fspan>, \u003Cspan class=\"shj-syn-var\">\"url\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002Fdocs.example.com\"\u003C\u002Fspan> }],\n  \u003Cspan class=\"shj-syn-var\">\"home\"\u003C\u002Fspan>: \u003Cspan class=\"shj-syn-num\">null\u003C\u002Fspan>\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cul>\n\u003Cli>\u003Ccode>sections\u003C\u002Fcode> and \u003Ccode>links\u003C\u002Fcode> are empty while the page is off (\u003Ccode>hub.enabled\u003C\u002Fcode> is\n\u003Ccode>false\u003C\u002Fcode>). \u003Ccode>action: &quot;chat&quot;\u003C\u002Fcode> means &quot;open the chat&quot; rather than &quot;follow a link&quot;.\u003C\u002Fli>\n\u003Cli>\u003Ccode>home\u003C\u002Fcode> is the Home tab's data while \u003Ccode>widgetHome\u003C\u002Fcode> is on, otherwise \u003Ccode>null\u003C\u002Fcode>:\n\u003Ccode>{ sections, changelog: { url, entries[] } | null, feedback: { url, posts[] } | null, onboarding: { flows: [{ key, name }] } | null }\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>\u003Ccode>look\u003C\u002Fcode> is the project's look. Draw with it to match; it is the same object the\nchat embed uses (\u003Ccode>GET \u002Fv1\u002Fprojects\u002F{pk}\u002Fpublic\u003C\u002Fcode>).\u003C\u002Fli>\n\u003Cli>\u003Ccode>404\u003C\u002Fcode> when neither the page nor the Home tab is on, or the project is unknown.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"the-chat-widgets-home-tab\">The chat widget's Home tab\u003Ca class=\"heading-anchor\" href=\"#the-chat-widgets-home-tab\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>With \u003Ccode>widgetHome\u003C\u002Fcode> on, the widget opens on \u003Cstrong>Home\u003C\u002Fstrong> and has two tabs at the\nbottom, \u003Cstrong>Home\u003C\u002Fstrong> and \u003Cstrong>Messages\u003C\u002Fstrong> (with the unread count). Home shows:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>What's new\u003C\u002Fstrong>: the three latest changelog entries and a link to the rest.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Feedback\u003C\u002Fstrong>: the top posts and \u003Cstrong>Share an idea\u003C\u002Fstrong>, which opens the board.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Getting started\u003C\u002Fstrong>: a button per published \u003Ca href=\"\u002Fdocs\u002Fonboarding\">onboarding\u003C\u002Fa> flow.\nIt runs the flow in your page: if \u003Ccode>onboarding.js\u003C\u002Fcode> is on the page that copy\nruns, otherwise the widget adds it for that flow. Turn this section off in\n\u003Ccode>widgetHome.sections\u003C\u002Fcode> if you do not want every published flow offered.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>A section with nothing to show is left out, and a project with the tab on but\nnothing to put in it gets the chat as before. The wide inline layout\n(\u003Ccode>data-mode=&quot;inline&quot;\u003C\u002Fcode> in a panel wide enough for two columns) keeps its list and\nthread side by side and has no Home tab. The unread badge and the host protocol\n(\u003Ccode>ready\u003C\u002Fcode>, \u003Ccode>token\u003C\u002Fcode>, \u003Ccode>unread\u003C\u002Fcode>, \u003Ccode>close\u003C\u002Fcode>) are unchanged.\u003C\u002Fp>\n\u003Ch2 id=\"one-tag-helpbitesjs\">One tag: \u003Ccode>helpbites.js\u003C\u002Fcode>\u003Ca class=\"heading-anchor\" href=\"#one-tag-helpbitesjs\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-html\">\u003Ccode>\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">script\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">src\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002FYOUR-SUPPORT-HOST\u002Fhelpbites.js\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">data-project\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"pk_…\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">async\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">script\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>It asks \u003Ccode>GET \u002Fv1\u002Fhub\u002F{pk}\u002Floader\u003C\u002Fcode> which embeds the project has, then adds only\nthose, as the individual scripts (\u003Ccode>widget.js\u003C\u002Fcode>, \u003Ccode>feedback.js\u003C\u002Fcode>, \u003Ccode>changelog.js\u003C\u002Fcode>,\n\u003Ccode>onboarding.js\u003C\u002Fcode>). It is MIT-licensed and has no dependencies. With nothing else\nit adds the chat; the others draw on your page, so you opt in:\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-html\">\u003Ccode>\u003Cspan class=\"shj-syn-cmnt\">&lt;!-- the chat and a floating feedback button --&gt;\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">script\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">src\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002FYOUR-SUPPORT-HOST\u002Fhelpbites.js\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">data-project\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"pk_…\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">data-features\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"chat,feedback\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">async\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">script\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-syn-cmnt\">&lt;!-- the chat, the changelog inline, and the welcome flow once --&gt;\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">div\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">id\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"changelog\"\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">div\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">script\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">src\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"https:\u002F\u002FYOUR-SUPPORT-HOST\u002Fhelpbites.js\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">data-project\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"pk_…\"\u003C\u002Fspan>\n        \u003Cspan class=\"shj-syn-class\">data-changelog-target\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"#changelog\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">data-flow\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan>\u003Cspan class=\"shj-syn-str\">\"welcome\"\u003C\u002Fspan> \u003Cspan class=\"shj-syn-class\">async\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&lt;\u002F\u003C\u002Fspan>\u003Cspan class=\"shj-syn-var\">script\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">&gt;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cdiv class=\"table-wrap\">\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Attribute\u003C\u002Fth>\n\u003Cth>Meaning\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>data-project\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The public key. Required.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>data-features\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Only these modules: \u003Ccode>chat\u003C\u002Fcode>, \u003Ccode>feedback\u003C\u002Fcode>, \u003Ccode>changelog\u003C\u002Fcode>, \u003Ccode>onboarding\u003C\u002Fcode>, comma separated. Without it: the chat, plus any module you gave its own setting below.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>data-changelog-target\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>A selector: the changelog draws inline there. The changelog is inline-only, so it needs this.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>data-feedback-target\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>A selector: the feedback board draws inline there. Without it the board is a floating button (on the left when the chat is on the right).\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>data-flow\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>An onboarding flow's key to show. With \u003Ccode>data-features=&quot;onboarding&quot;\u003C\u002Fcode> and no flow, the project's \u003Ccode>welcome\u003C\u002Fcode> (else its first).\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>data-accent\u003C\u002Fcode>, \u003Ccode>data-theme\u003C\u002Fcode>, \u003Ccode>data-position\u003C\u002Fcode>, \u003Ccode>data-locale\u003C\u002Fcode>, \u003Ccode>data-token\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Passed to every module that reads them. \u003Ccode>data-token\u003C\u002Fcode> is the person's identity token as a string; to fetch one when needed, call \u003Ccode>HelpBites.push(['init', { getToken }])\u003C\u002Fcode> as for the \u003Ca href=\"\u002Fdocs\u002Fconnect#3-show-the-chat\">chat\u003C\u002Fa>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>data-mode\u003C\u002Fcode>, \u003Ccode>data-target\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The chat's (\u003Ccode>inline\u003C\u002Fcode> and its element).\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>data-&lt;module&gt;-&lt;name&gt;\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Aims one attribute at one module: \u003Ccode>data-feedback-position=&quot;left&quot;\u003C\u002Fcode>, \u003Ccode>data-onboarding-show=&quot;update&quot;\u003C\u002Fcode>, \u003Ccode>data-chat-mode=&quot;inline&quot;\u003C\u002Fcode>.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>data-host\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Where HelpBites lives, when you serve \u003Ccode>helpbites.js\u003C\u002Fcode> from your own site.\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\u003C\u002Fdiv>\n\u003Cp>A module the project has not set up (a feedback board that is off, no published\nflows) is skipped, and a script already on the page is never added twice, so you\ncan move to this tag one module at a time. If HelpBites cannot be reached for the\nloader call, the modules you named still load.\u003C\u002Fp>\n\u003Ch3 id=\"calls\">Calls\u003Ca class=\"heading-anchor\" href=\"#calls\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cp>\u003Ccode>window.HelpBites.push\u003C\u002Fcode> keeps working before and after the scripts have loaded.\nThe chat's own calls go to the chat, and a module name in front sends a call\nthere:\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-js\">\u003Ccode>window\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-class\">HelpBites\u003C\u002Fspan> \u003Cspan class=\"shj-syn-oper\">=\u003C\u002Fspan> window\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-class\">HelpBites\u003C\u002Fspan> \u003Cspan class=\"shj-syn-oper\">||\u003C\u002Fspan> []\n\u003Cspan class=\"shj-syn-class\">HelpBites\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">push\u003C\u002Fspan>([\u003Cspan class=\"shj-syn-str\">'init'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> { getToken\u003Cspan class=\"shj-syn-oper\">:\u003C\u002Fspan> () \u003Cspan class=\"shj-syn-kwd\">=&gt;\u003C\u002Fspan> \u003Cspan class=\"shj-syn-func\">fetch\u003C\u002Fspan>(\u003Cspan class=\"shj-syn-str\">'\u002Fapi\u002Fsupport\u002Ftoken'\u003C\u002Fspan>)\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">then\u003C\u002Fspan>(r \u003Cspan class=\"shj-syn-kwd\">=&gt;\u003C\u002Fspan> r\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">json\u003C\u002Fspan>())\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">then\u003C\u002Fspan>(r \u003Cspan class=\"shj-syn-kwd\">=&gt;\u003C\u002Fspan> r\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>token) }])\n\u003Cspan class=\"shj-syn-class\">HelpBites\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">push\u003C\u002Fspan>([\u003Cspan class=\"shj-syn-str\">'open'\u003C\u002Fspan>])                    \u003Cspan class=\"shj-syn-cmnt\">\u002F\u002F the chat\n\u003C\u002Fspan>\u003Cspan class=\"shj-syn-class\">HelpBites\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">push\u003C\u002Fspan>([\u003Cspan class=\"shj-syn-str\">'feedback'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'open'\u003C\u002Fspan>])        \u003Cspan class=\"shj-syn-cmnt\">\u002F\u002F HelpBitesFeedback.push(['open'])\n\u003C\u002Fspan>\u003Cspan class=\"shj-syn-class\">HelpBites\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-syn-func\">push\u003C\u002Fspan>([\u003Cspan class=\"shj-syn-str\">'onboarding'\u003C\u002Fspan>\u003Cspan class=\"shj-syn-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-syn-str\">'open'\u003C\u002Fspan>])      \u003Cspan class=\"shj-syn-cmnt\">\u002F\u002F HelpBitesOnboarding.push(['open'])\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>If you do not call \u003Ccode>init\u003C\u002Fcode>, the loader starts the chat itself (with \u003Ccode>data-token\u003C\u002Fcode>\nwhen there is one). The \u003Ccode>helpbites:loaded\u003C\u002Fcode> event on \u003Ccode>window\u003C\u002Fcode> says which modules\nwere added (\u003Ccode>event.detail.modules\u003C\u002Fcode>).\u003C\u002Fp>\n\u003Ch3 id=\"what-it-reads-get-v1hubpkloader\">What it reads: \u003Ccode>GET \u002Fv1\u002Fhub\u002F{pk}\u002Floader\u003C\u002Fcode>\u003Ca class=\"heading-anchor\" href=\"#what-it-reads-get-v1hubpkloader\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh3>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-bash\">\u003Ccode>\u003Cspan class=\"shj-syn-func\">curl\u003C\u002Fspan> https:\u002F\u002Fhelp.example.com\u002Fv1\u002Fhub\u002Fpk_abc123\u002Floader\n\u003Cspan class=\"shj-syn-cmnt\"># { \"project\": { \"name\": \"Acme\", \"publicKey\": \"pk_abc123\" },\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-cmnt\">#   \"modules\": { \"chat\": { \"enabled\": true, \"home\": true }, \"feedback\": { \"enabled\": true },\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-cmnt\">#                \"changelog\": { \"enabled\": true }, \"onboarding\": { \"enabled\": true, \"flows\": [\"welcome\"] } },\u003C\u002Fspan>\n\u003Cspan class=\"shj-syn-cmnt\">#   \"hub\": { \"enabled\": true, \"url\": \"https:\u002F\u002Fhelp.example.com\u002Fhub\u002Fpk_abc123\" }, \"accent\": \"#16a34a\" }\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Ch2 id=\"in-a-swift-app\">In a Swift app\u003Ca class=\"heading-anchor\" href=\"#in-a-swift-app\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>Read the hub with \u003Ccode>URLSession\u003C\u002Fcode> and show what's new and a way to give feedback.\nColours, font and corner radius are parameters; leave them out to wear the\nproject's Brand kit.\u003C\u002Fp>\n\u003Cdiv class=\"code-block\">\u003Cbutton type=\"button\" class=\"copy-btn\" data-copy aria-label=\"Copy to clipboard\">Copy\u003C\u002Fbutton>\u003Cpre class=\"shj-lang-plain\">\u003Ccode>\u002F\u002F WhatsNew.swift. MIT. The changelog and a feedback button from a HelpBites hub.\nimport SwiftUI\n\nstruct WhatsNew: View {\n  let host: URL                  \u002F\u002F https:\u002F\u002Fsupport.example.com\n  let projectKey: String         \u002F\u002F pk_…\n  var accent: Color? = nil       \u002F\u002F nil: the project's accent\n  var font: Font = .body\n  var cornerRadius: CGFloat? = nil\n\n  struct Hub: Decodable {\n    struct Look: Decodable { let accent: String; let radiusPx: Double }\n    struct Item: Decodable { let title, url, meta: String }\n    struct Section: Decodable { let key, title, url: String; let items: [Item] }\n    let look: Look\n    let sections: [Section]\n    func section(_ key: String) -&gt; Section? { sections.first { $0.key == key } }\n  }\n\n  @State private var hub: Hub?\n  @Environment(\\.openURL) private var openURL\n\n  var body: some View {\n    let tint = accent ?? hub.map { Color(hex: $0.look.accent) } ?? .accentColor\n    let radius = cornerRadius ?? hub.map { CGFloat($0.look.radiusPx) } ?? 8\n    VStack(alignment: .leading, spacing: 12) {\n      if let news = hub?.section(\u003Cspan class=\"shj-syn-str\">\"changelog\"\u003C\u002Fspan>) {\n        Text(news.title).bold()\n        ForEach(news.items, id: \\.title) { item in\n          Button { open(item.url) } label: {\n            HStack { Text(item.title); Spacer(); Text(item.meta).foregroundStyle(.secondary) }\n          }\n          .buttonStyle(.plain)\n        }\n      }\n      if let feedback = hub?.section(\u003Cspan class=\"shj-syn-str\">\"feedback\"\u003C\u002Fspan>) {\n        Button(feedback.title) { open(feedback.url) }\n          .padding(.horizontal, 14).padding(.vertical, 8)\n          .background(tint, in: RoundedRectangle(cornerRadius: radius))\n          .foregroundStyle(.white)\n      }\n    }\n    .font(font)\n    .task { hub = try? await load() }\n  }\n\n  private func load() async throws -&gt; Hub {\n    let (data, _) = try await URLSession.shared.data(from: host.appending(path: \u003Cspan class=\"shj-syn-str\">\"v1\u002Fhub\u002F\\(projectKey)\"\u003C\u002Fspan>))\n    return try JSONDecoder().decode(Hub.self, from: data)\n  }\n\n  private func open(_ link: String) { if let url = URL(string: link) { openURL(url) } }\n}\n\nprivate extension Color {\n  init(hex: String) {\n    let value = UInt64(hex.dropFirst(), radix: 16) ?? 0x4f46e5\n    self.init(red: Double((value &gt;&gt; 16) &#38; 255) \u002F 255, green: Double((value &gt;&gt; 8) &#38; 255) \u002F 255, blue: Double(value &#38; 255) \u002F 255)\n  }\n}\u003C\u002Fcode>\u003C\u002Fpre>\u003C\u002Fdiv>\n\u003Cp>The sections come back only while the public page is on. Turn on \u003Cstrong>Public page\u003C\u002Fstrong>\nfor this snippet; the hub does not have to be linked from anywhere.\u003C\u002Fp>\n\u003Ch2 id=\"your-own-ui\">Your own UI\u003Ca class=\"heading-anchor\" href=\"#your-own-ui\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cp>\u003Ccode>GET \u002Fv1\u002Fhub\u002F{pk}\u003C\u002Fcode> is everything the page and the Home tab show. Draw it with your\ncomponents and the \u003Ccode>look\u003C\u002Fcode> object, and link to the pages it names. For one\nwidget on your site you do not need the API at all: the loader and the Home tab\nare the same data with the project's look applied.\u003C\u002Fp>\n\u003Ch2 id=\"rules\">Rules\u003Ca class=\"heading-anchor\" href=\"#rules\" aria-label=\"Link to this section\">#\u003C\u002Fa>\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>The page and \u003Ccode>GET \u002Fv1\u002Fhub\u002F{pk}\u003C\u002Fcode> answer \u003Ccode>404\u003C\u002Fcode> while the hub is off; the JSON\nalso answers when only the Home tab is on, with \u003Ccode>sections\u003C\u002Fcode> and \u003Ccode>links\u003C\u002Fcode> empty.\nThe loader answers for any known project.\u003C\u002Fli>\n\u003Cli>Reads are limited per address (1,200 a minute) and cached for a minute.\u003C\u002Fli>\n\u003Cli>A hub exposes only what each feature already makes public (published posts,\nentries and documents, the public brand page). Hidden posts, drafts and private\nboards never appear.\u003C\u002Fli>\n\u003Cli>Custom links must be http(s); at most 8, labels up to 60 characters.\u003C\u002Fli>\n\u003Cli>\u003Ccode>hub\u003C\u002Fcode>, \u003Ccode>company\u003C\u002Fcode> and the rest of the project are set with\n\u003Ccode>PATCH \u002Fv1\u002Fadmin\u002Fprojects\u002F{id}\u003C\u002Fcode> by an operator session or an \u003Ccode>ak_\u003C\u002Fcode> admin key.\u003C\u002Fli>\n\u003C\u002Ful>\n",[6,10,13,16,19,22,26,29,32,35],{"id":7,"text":8,"level":9},"turn-it-on","Turn it on",2,{"id":11,"text":12,"level":9},"the-page","The page",{"id":14,"text":15,"level":9},"json-get-v1hubpk","JSON: GET \u002Fv1\u002Fhub\u002F{pk}",{"id":17,"text":18,"level":9},"the-chat-widgets-home-tab","The chat widget's Home tab",{"id":20,"text":21,"level":9},"one-tag-helpbitesjs","One tag: helpbites.js",{"id":23,"text":24,"level":25},"calls","Calls",3,{"id":27,"text":28,"level":25},"what-it-reads-get-v1hubpkloader","What it reads: GET \u002Fv1\u002Fhub\u002F{pk}\u002Floader",{"id":30,"text":31,"level":9},"in-a-swift-app","In a Swift app",{"id":33,"text":34,"level":9},"your-own-ui","Your own UI",{"id":36,"text":37,"level":9},"rules","Rules",1792677543076]