# hiy.ai docs, in full Every page of https://hiy.ai/docs in sidebar order. The index is https://hiy.ai/llms.txt. --- title: "Getting started" description: "Make an agent in about a minute, then test it, publish it and share it." source: https://hiy.ai/docs/getting-started --- # Getting started Make an agent in about a minute: paste one address, pick where it answers, and press **Create**. It reads your pages and trains itself. After this guide you'll have an agent that answers from your pages, shows its sources, and says so when it doesn't know. ## The six steps to a working agent 1. **Paste one address** — Paste your site, docs or channel and press **Find its pages**: it lists what is under the address and reads none of it, and what you leave ticked is what gets read. Next to the name, **Change** picks the kind of agent: a Support Agent for a product, a Team Agent for the colleagues you invite, or an Expert Twin that answers as you. This is step 1 of [the setup](/docs/setup#1-your-site). ![Setup, step 1: the address field with Find its pages, and Continue without a site beneath it](https://hiy.ai/docs-shots/getting-started/site.webp) *Setup › Your site* 2. **Pick where it answers, then Create** — Choose where it will answer, then press **Create** on the Connect step. Nothing exists before that press. After it, your agent reads your pages, writes its introduction and trains. Once it starts reading your pages, the rest runs on our servers, so you can close the tab. See [A new agent trains itself](/docs/training#a-new-agent-trains-itself). 3. **Ask it a question** — Press **Test** in the agent's header and ask what a visitor would. Only you can see your agent until you publish, and testing never counts toward your allowance. See [Testing your agent](/docs/testing). ![The Test dock beside an agent's page, with starting questions and the line Testing never counts](https://hiy.ai/docs-shots/testing/dock.webp) *Agent › Test* 4. **Teach it something it missed** — When it can't answer, **Teach it** opens Knowledge with the question filled in. Add a source or a correction: a few things you actually wrote are worth more than a pile of generic filler. 5. **Publish** — Nothing is public until you publish. Open the state menu in the agent's header, which reads **Draft**, and choose **Live**. Turning it **Off** again is instant. 6. **Share or embed it** — Share your link or [embed your agent](/docs/embed) on your own site. The checklist stays until your agent is out in the world. ![Settings › Channels › Share: each suggested question with its sharing buttons](https://hiy.ai/docs-shots/sharing/share.webp) *Settings › Channels › Share* The agent's Overview counts these six stages under **Set up** and ticks each as it really happens, in any order. ## Give it your voice For an Expert Twin, the **personality interview** on the agent's **Profile › Personality** is a short set of questions about how you phrase things. It's the biggest upgrade to how much it sounds like you, and it lands at the next [train](/docs/training). ## Awaiting review Publishing doesn't always make your page answer at once. Because [you may only speak for yourself or something you own](/docs/acceptable-use), an agent whose name we can't match to your account waits for a person to confirm it's you. For an Expert Twin, we match its name to the name on your Google sign-in or to your email address, never to a name typed into hiy, and its knowledge must mention that name. The state menu reads **In review** and the agent's Overview says **Awaiting review**, usually within one business day. The decision shows on the agent's Overview — don't wait on your inbox: it turns Live when it clears. You can keep testing and adding material the whole time. If a review is declined, the Overview says **This agent wasn’t approved**, with the reviewer's reason and what to send us. Your content and settings are untouched. ## Get set up Owners and admins see a **Get set up** list on **Home**, folded to one row, and as a card at the foot of an agent's pages (on a phone, under the agent's name in the menu). It has four steps: add knowledge, test your agent, connect a channel, and invite a teammate. In a workspace of only Team Agents or Expert Twins, the third step is **Go live**, and it ticks once one of them is live. Each step ticks by itself when it's true, and the next step's button opens a short guide beside the page. **Just me for now** skips the invite, and **Hide this list** puts it away until you bring it back with **Show again** at the top of **Guides** › **All guides**. ## Getting help **Help** is at the foot of the left column, and in the menu on a phone. It opens **Ask hiy's Support Agent**, **Guides for** the page you're on and **All guides** (these open the docs) and **Talk to our team** at hello@hiy.ai. **Book a setup call** appears when one is offered. On a page that has a guide, **Guides** in the top bar lists up to three of them, which open beside the page, then **All guides** and **Read the docs**. Press **⌘K** (**Ctrl K** on Windows) to jump to an agent, a page or a setting. **Good to know:** - An Expert Twin or a Team Agent lives at **hiy.ai/your-name**. Typing a name on the home page doesn't hold it; it's yours once you've made an account. - Files, an assistant export or a list aren't one address. Add them from **Knowledge** once the agent is built. - After the first train, new material waits for the next one: **Update agent**, or tonight if **Train overnight** is on. - **Forgot password?** on the sign-in screen emails you a link to set a new one. See [Signing in and out](/docs/signing-in). - Nothing blocks you: every step has a default or a skip, and the address can be left blank. ## Related - [How hiy is set up](/docs/setup) — The six steps of making an agent, and how to change your mind. - [Testing your agent](/docs/testing) — The private sandbox that doesn't count against anything. - [Sharing your Expert Twin](/docs/sharing) — Your link, deep links, and where to put them. --- title: "The three kinds of agent" description: "Support Agents, Team Agents and your Expert Twin — what each is for, and who can reach it." source: https://hiy.ai/docs/your-twins --- # The three kinds of agent One engine, three audiences. A Support Agent answers your customers inside your product, a Team Agent answers colleagues you invite, and an Expert Twin answers anyone. All three share the same grounding and the same honest "I don't know". An Expert Twin keeps where its answers come from, and your contact details, out of its answers unless you turn them on. What differs is who they answer and who is allowed to reach them. ![The Agents page with a block for Support Agents, Team Agents and Expert Twins, each ending in a New row](https://hiy.ai/docs-shots/overview/agents-list.webp) *Agents, in the sidebar* ## Support Agents An agent for a product you own. It answers your customers from your product's material, in a neutral voice: it represents the product, not a person. It has no public page. It answers inside your own site or app, and what it can't answer goes to your Inbox with the visitor's email attached, so a stuck customer never dead-ends. See [Support Agents](/docs/support-agents). ## Team Agents You, answering your colleagues from internal notes. Only people you invite can open it. Everyone else, search engines included, gets a page that says it doesn't exist. It reports what you wrote and never decides for anyone, and no screen shows who asked it what. See [Team Agents](/docs/team-agents). ## Your Expert Twin You, answering your audience at `hiy.ai/yourname`, from what you've actually made: writing, talks, notes, a CV. It's the one you share and embed. An Expert Twin may only be of yourself or something you own (see [Acceptable use](/docs/acceptable-use)). A name that doesn't match the name on your Google sign-in or your email address waits for a person to confirm it, and the agent reads **Awaiting review** until then. See [Getting started](/docs/getting-started#awaiting-review). A cleared Expert Twin carries a **Verified** badge beside its AI label. The badge belongs to the name that was checked. Rename the twin and the badge comes off while it stays live; renaming back restores it with no second review. ## Switching between them Open **Agents** in the sidebar to see every agent, grouped by kind. **New Support Agent**, **New Team Agent** and **New Expert Twin** start the next one, and **All agents** brings you back to the list from inside any agent. Each keeps its own knowledge, audience and rules, so adding material to one never changes another. ## How many you can have You get one Expert Twin, and it uses no agent slot. Support and Team Agents share the slots: up to 3 Support and Team Agents per workspace, counted together. [Early Access](/docs/early-access) allows 4 agents in all, at most 3 of them Support or Team Agents. Ask for one more and you're told before anything is made. It's a limit we hold for now. Talk to us if you need more. ### An unfinished agent still holds a slot A slot is spent the moment an agent exists, not when it goes live, so an unfinished agent still holds a slot. An agent you started and left, still a draft with no sources yet, counts exactly like a live one. That count reads one thing: whether the agent has any [sources](/docs/sources). It doesn't look at your [Lists](/docs/records), so an agent you've only given rows to still reads as unfinished, and every row is still there when you open it. Nothing is swept up for you, because a draft you unpublished on purpose looks the same as one you walked away from. Open the agent from your agents list and delete it to free its slot. See [Deleting an agent](/docs/deleting-an-agent). **Good to know:** - Only the account that created an agent can delete it. If a colleague's abandoned draft holds the last slot, the refusal names it and says that account has to free it. - Every public page carries a Report link, and no plan removes it. ## Related - [Support Agents](/docs/support-agents) — An agent for your product, inside your own site, with Inbox handover. - [Team Agents](/docs/team-agents) — You, answering colleagues from internal notes — invite-only. --- title: "How hiy is set up" description: "The six steps of making an agent, and how to change your mind." source: https://hiy.ai/docs/setup --- # How hiy is set up Setup makes an agent in six steps, five for an Expert Twin. Nothing is created until you press Create on step 3. ## The steps Each step has a default or a skip, and you land on Home at the end. It works on a phone as well as a desktop. ### 1. Your site Paste an address and press **Find its pages**, or press **Continue without a site**. It lists the pages and reads none of them until Create. When it finds your pages, a pop-up shows the ones it picked: help, FAQ, pricing, policies, about and contact first, up to 50 and your plan's room. Tick what you need, untick the rest, and press **Use**. **Review** opens it again. The page you paste is always read first, so a plan that reads fewer pages than your site has keeps it. If you claimed a hiy.ai name before signing up, it opens on your twin. The step's label follows the kind: "Your site", "Your docs" or "Your material". ![Step 1, Your site, while it finds pages: the address, a checklist with Found your name and logo ticked, the suggested product name and the kind](https://hiy.ai/docs-shots/setup/site.webp) *Step 1, while it finds your pages* ![The page review: Found 24 pages, the picked pages ticked, and Use 12 pages](https://hiy.ai/docs-shots/setup/pages.webp) *Step 1's page review* The pop-up counts pages against the room left on your plan, after what your workspace already holds, as "18 of 60 on your plan". Tick more and it says "2 over your plan": reading stops at that limit, in the order shown. Nothing is unticked for you. **Kind** shows what you're making, and **Change** opens the choice. For a Support or Team Agent, **More options** holds the address; for an Expert Twin, it holds the expertise line. ### 2. Where it answers Pick any of **Chat widget**, **Chat bar**, **Inside your product**, **Your page on hiy.ai** or **Your colleagues**, as the kind allows. Nothing goes live here. A Support Agent gets its line to paste on the last step. Press **Skip** to leave it for later. ![Step 2, Where should it answer: Chat widget, Chat bar and Inside your product, then Soon chips for WhatsApp, Slack, Email and Phone](https://hiy.ai/docs-shots/setup/reach.webp) *Step 2, where it answers* ### 3. Connect A Support Agent can pick the helpdesk a handover opens a ticket in. **Zendesk** and **Intercom** are tagged **Connect next**: you connect one while it builds. The rest are **Soon** chips. The button reads **Create Support Agent**, **Create Team Agent** or **Create Expert Twin**. It is the one press that makes something. ![Step 3, Connect your helpdesk: Zendesk and Intercom tagged Connect next, Soon chips, other material and the Create Support Agent button](https://hiy.ai/docs-shots/setup/connect.webp) *Step 3, with the Create button* ### 4. Build While it finds your pages, stay on the page. Once it starts reading them, the rest runs on our servers, so you can leave and it carries on. Its introduction is a proposal: edit it and press **Looks right**, or press **Keep the preset** (**Skip** when there's no preset). **Go to Home** leaves without stopping anything. On a Support Agent, one row reads **Checking 8 questions** while your agent is asked what customers usually ask. ### 5. Try it Ask what a visitor would. It answers from your pages and shows its sources. **Testing never counts**: it isn't charged to your plan or counted in Insights. On an Expert Twin, **Personality interview** opens the interview on its **Profile**. On a Support Agent the line over the chat reads **Answered 7 of 8 · 1 needs you**. Press **Teach it** on a question it couldn't answer, type the answer, and it learns it at once. **Should decline** counts it apart, and **Remove** drops it. Until the check lands, three common questions are the chips. See [the ready check](/docs/testing#ready-check). ### 6. Team Type a colleague's email and press **Invite**. A row still marked **Invited** wasn't emailed, so press **Copy invite** and send it yourself. Someone already on your team is marked **Added**: they open this agent too and keep the others. **Go to Home** finishes setup. An Expert Twin has no Team step. For a Support Agent this step is **Go live**: press **Publish**, check your site under **Allowed websites**, choose **Anyone on your sites**, then press **Copy snippet** under **Your line to paste**. Open stays off until you choose it. ## What a preset sets Choosing a Support Agent preset on step 1 is a starting point, not a mode. It writes four things and then gets out of the way: a few list categories to fill in later, what the agent says it covers and how firmly it declines the rest, an opening line you can edit on step 4, and the sentence it says while handing over. It never writes suggested questions. See [Support Agents](/docs/support-agents#four-presets-one-agent). ## How Settings is arranged Everything you can change afterwards is on the agent's **Settings** page, one tab each: **Details**, **Rules**, **Handover**, **Channels**, **Follow-ups**, **Notifications** and **Automations**, for the kinds they apply to. **Search settings** looks in every tab. Its **Profile** is a page of its own. ## Answers you can still give Under **Settings › Rules › How hiy is set up** you can change the agent's main job, where your material lives, who talks to it and whether there's a team. Each saves on its own and applies the next time the page loads. It isn't a retrain, and noting where your material lives starts no import. **Good to know:** - A reload keeps your answers and reopens step 1. Closing the tab forgets them. - The **✕** asks before it leaves if you typed anything. **Discard** keeps nothing. - The address is fixed by Create and can't be renamed afterwards. Set it on step 1 (an agent keeps it under **More options**). - **Soon** chips are noted with your agent, not wired. - A Support Agent made here lists the site from step 1 as an allowed website, unless step 2 picked **Inside your product**. ## Related - [Getting started](/docs/getting-started) — Make an agent in about a minute, then test it, publish it and share it. - [Support Agents](/docs/support-agents) — An agent for your product, inside your own site, with Inbox handover. --- title: "Support Agents" description: "An agent for your product, inside your own site, with Inbox handover." source: https://hiy.ai/docs/support-agents --- # Support Agents A Support Agent answers your customers inside your own site or app, from your docs. When it can't answer, it says so and hands the question to your Inbox. ![A Support Agent's chat widget, open on its greeting and a starting question](https://hiy.ai/docs-shots/embed/bubble.webp) *The chat widget, as a visitor sees it* ## Set one up 1. **Start a Support Agent** — In **Agents**, press **New Support Agent**, paste your help centre or docs site, and press **Find its pages**. See [How hiy is set up](/docs/setup). 2. **Pick what it handles** — Next to **Kind**, press **Change** and choose a preset under **What it handles**. ![The four presets and Start from scratch under What it handles](https://hiy.ai/docs-shots/support-agents/presets.webp) 3. **Try it** — Press **Test** in the agent's header and ask what a customer would. Testing never counts toward your allowance. 4. **Publish it** — Open the state menu at the top of the agent, which reads **Draft**, and choose **Live**. Unless its name matches your account's, or your workspace joined [Early Access](/docs/early-access) by invitation, a person checks it first, usually within one business day, and the menu reads **In review**. The decision shows on the agent's Overview — don't wait on your inbox. ### Four presets, one agent Choose **SaaS product support**, **Orders & billing**, **Docs/developer assistant** or **Careers/HR**. Each preset is a starting point you can change later: it adds [lists](/docs/records), sets [what it answers](/docs/what-it-answers), and drafts a [greeting](/docs/first-impression) and a [handover sentence](/docs/handover). **Start from scratch** sets none of it. **Start from a preset** on the Agents page shows what each preset sets before you make the agent. ## Put it on your site There are two ways, both on **Channels › Chat widget › Install**, under **Who can open it**, and a Support Agent can also have a [Support page](/docs/support-page). ### One line, no server For a help centre, docs site or blog, where visitors don't sign in. 1. **Add your site and save** — In **Channels**, open **Chat widget** and press **Install** on your agent's row. Under **Allowed websites**, press **Add a website**, type your site, such as `yoursite.com`, then press **Add** and **Save**. 2. **Choose Anyone on your sites** — Under **Who can open it**, choose **Anyone on your sites**. It asks you once before it opens. 3. **Copy the line and paste it** — Under **Your snippet**, press **Copy snippet**. Paste it on the pages it should help on, just before ``. **Warning:** Anyone, even a script, can ask an open agent, so treat what it knows as public. See [Open on your site](/docs/embed#open-on-your-site). ### Signed in by your server For apps whose users sign in: your server signs a short-lived token for each visitor. 1. **Copy your signing secret** — In **Channels › Chat widget › Install**, open **Signed-in users**: step 1 is **Your signing secret**. 2. **Mint a token on your server** — The code is in the same **Signed-in users** steps and in [The chat API](/docs/developers#tokens-for-restricted-agents). 3. **Add the widget snippet** — Paste it where the agent should appear. ### The signing secret Your signing secret is in **Install › Signed-in users** and under **Workspace › Developers › Sites & install**. It signs your visitors' tokens, so keep it on your server, never in a browser or a code repository. ![The hidden signing secret with reveal, copy and Rotate buttons](https://hiy.ai/docs-shots/support-agents/signing-secret.webp) **Rotate** makes a new secret at once and old tokens stop working, so update your server straight away. If the secret can't be read, **Your signing secret** says so and offers **Retry**, and publishing, who can read the Inbox and what your site tells this agent all keep working. ### The widget The snippet in **Signed-in users** is the whole install: one ` ``` `data-mode` picks how it looks: - `bubble`: a chat button, bottom right, that opens a panel. Not on the Free plan. - `bar`: a slim message box along the bottom of the page. - `page`: a [Support page](/docs/support-page), the help page where you paste it. - Left out: a chat block where you pasted it (**In the page** on **Chat bar › Install**). The loader adds only the chat and, for the bubble, a small stylesheet for the button. Copy yours from **Install**: it carries your form's `data-door`. ### Put your agent on your site 1. **Make your agent live** — Open the state menu in the agent's header and choose **Live**. ![The state menu open in the agent header](https://hiy.ai/docs-shots/sharing/state-menu.webp) *Your agent's header* 2. **Open it on your site** — Support Agents only: list your website and choose **Anyone on your sites** under **Who can open it**. 3. **Copy the snippet** — In **Channels**, open **Chat widget**, press **Install** on your agent's row, then **Copy snippet**. Or press **Copy prompt** and paste it into your coding agent. ![A Chat widget's Install tab with Copy snippet](https://hiy.ai/docs-shots/channels/install-snippet.webp) *Channels › Chat widget › Install* 4. **Paste it on your site** — Paste it on the pages it should help on, just before ``. **Where to paste** under the snippet has the steps for your site builder. 5. **Add another place it answers** — A chat bar or a block (see [The snippet](#the-snippet)), or your product for visitors your server signs in (see [Restricted agents need a token](#restricted-agents-need-a-token)). ### Restricted agents need a token A Support Agent or a Team Agent only answers visitors your server vouches for, unless the Support Agent is [open on your site](#open-on-your-site). Add `data-token-url="/api/hiy-token"`: the loader asks that address on your site for a visitor token before it opens, and again when it expires. To write the token into the page instead, use `data-token="…"`. **Warning:** The token is readable by the visitor, and it rides in a URL: the chat's web address, which reaches browser history and logs. Put nothing in it they may not see about themselves. See [attested attributes](/docs/developers#attested-attributes). Ready-made token code for Next.js, Node.js, WordPress and static hosts is in [Recipes for the inline embed](/docs/developers#recipes-for-the-inline-embed). ### Writing the iframe yourself `/embed/your-name` is a real page you can frame: ```html ``` Give it at least 500px of height. A restricted agent takes its token as `?token=…` in the address. The script's inline block is 520px tall and up to 680px wide, so write the iframe for another size. ## What visitors see The chat follows each visitor's own light or dark setting and uses your agent's accent colour. It keeps the citations, the honest "I don't know" and the AI label. Where your agent can't answer (it isn't live, or [Open on your site](#open-on-your-site) doesn't cover that page), the bar and an inline block hide themselves, and the bubble shows *This agent isn’t available right now* when opened, then hides. That includes `localhost` and previews. ### The floating bubble ![The chat panel open above the round chat button](https://hiy.ai/docs-shots/embed/bubble.webp) *Channels › Chat widget, preview* Nothing loads until a visitor points at, taps or tabs to the button. On a phone it opens full screen above the keyboard, and the page behind stays still; **Esc** or the button closes it. You set its look in [Channels](/docs/channels). ### Launcher colour The bubble's snippet also carries `data-color` (your accent colour, or `ink`), `data-name` (your agent's name), for the bottom-left corner `data-side="left"`, and `data-theme="light"` or `"dark"` when you fix Light or dark in Style. They work only with `data-color`: ```html ``` **After you change the colour, name, corner or Light or dark, copy the snippet again.** A snippet without `data-color` keeps the standard launcher. ### The embedded chat bar ![The chat bar at the bottom of a page, with a card above it](https://hiy.ai/docs-shots/embed/bar.webp) *Channels › Chat bar, preview* A small message box sits at the bottom of the page. A visitor's first keystroke opens a card above it with your greeting and the conversation. **Esc** puts it away. See [What a visitor sees](/docs/bar#what-a-visitor-sees). To open the bar from your own button, set its behaviour to **Your button** in Channels, then add `data-hiy-open` to any element, or call `window.hiy.open()`: ```html ``` ### Languages The widget's own words follow the visitor's browser language: English, Spanish, French, German, Portuguese, Italian or Dutch, and English otherwise. You can fix one language in [Style](/docs/style#language). Your own greeting and starting questions are never translated. Answers follow whatever language the visitor writes in. ## Allowed websites List the sites that may show your agent under **Allowed websites** on **Chat widget › Install**. `yoursite.com` also covers other subdomains, such as `www.yoursite.com`; a listed `www.yoursite.com` covers only that host. Anywhere else, the chat shows *This agent isn't enabled for this website*. An agent [open on your site](#open-on-your-site) hides itself there instead. With the list empty, any site can show it. The list decides where the chat appears, not who can ask. To keep answers private, make the agent restricted and use tokens. If a listed site shows *This agent needs a valid visitor token*, the token's `aud` doesn't match the page: set it to exactly `location.origin`. While you build on your own computer, add `localhost`. An agent [open on your site](#open-on-your-site) never answers there: test it on your live site. ## Open on your site A Support Agent can answer on your listed websites with no server and no token code. It suits a help centre, a docs site or a blog. 1. **Add your website and save** — Setup lists the site you gave it. Add any other and save, on **Chat widget › Install**. 2. **Choose Anyone on your sites** — It stays off until a website is saved, and asks you once. 3. **Paste the line it shows** — It's the plain snippet, with no token address: ```html ``` hiy signs visitors in itself, only on `https:` pages of sites on your list. It never does so for `localhost`, hiy's own pages, or a host many sites share, such as `vercel.app` or `github.io`: list `yours.vercel.app` instead. **Good to know:** - Anyone on your sites can ask, and so can a script. Treat what the agent knows, and its instructions, as public. Visitors are anonymous: only [look-ups that need no key](/docs/actions#open-on-your-site) run. - Each day it answers up to a fifth of your allowance, each visitor a tenth of that, then stops until midnight UTC and emails you once. Each month it stops at 80% and never charges overage. - Visitors can hand over once per conversation: 3 a day each, 20 a day per agent. - Turning it off takes effect on the next message. Tokens from your own server keep working. ## What your site needs Paste the snippet as it is, once per page, as a classic script (not a module). After you change the colour, name or corner, copy it again. Don't serve `embed.js` from your own domain: visitors must get the current version. If your site sends these headers, add to the policy you already send: | Header | Line | | --- | --- | | Content-Security-Policy | `script-src https://hiy.ai` | | Content-Security-Policy | `frame-src https://hiy.ai` | | Permissions-Policy, for calls | `microphone=(self "https://hiy.ai")` | - With `'strict-dynamic'` in `script-src`, put the page's nonce on the tag too. Don't add `'unsafe-inline'`. - With no `frame-src`, add one with your `default-src` sources plus `https://hiy.ai`. - For the chat widget, `style-src` needs `'unsafe-inline'` with no nonce or hash, or your script nonce. Otherwise the button may draw wrongly. - A Permissions-Policy that names `microphone` must include `"https://hiy.ai"`: `microphone=()` and `microphone=(self)` both block calls. - Nothing else. ### Single-page apps - Add it once per page load: `next/script` in a layout that stays mounted, or an effect that first checks it isn't there. - It stays until a full page load. To hide it on some pages or over a phone menu, use `[data-hiy-part] { display: none !important; }`. Coding agent? Give it [hiy.ai/install.md](https://hiy.ai/install.md), the same steps as the `hiy-install` skill. The chat shows "Powered by hiy" unless your plan removes it. See [The hiy.ai credit](/docs/attribution). ## Related - [Support Agents](/docs/support-agents) — An agent for your product, with Inbox handover. - [Channels](/docs/channels) — Every place your agents answer. - [The chat API](/docs/developers) — Call your agent from your own code. - [The hiy.ai credit](/docs/attribution) — What the “Powered by hiy.ai” line is. --- title: "The chat API" description: "Call your agent from your own code: the chat endpoint, visitor tokens, limits and errors." source: https://hiy.ai/docs/developers --- # The chat API Call your agent from your own code: one endpoint, `POST /api/chat`, streams the answer and its sources. If you only want the chat on your site, the [embed snippet](/docs/embed) already does all of this. **Note:** This is the endpoint hiy's own pages use. It isn't versioned yet: there's no SDK, and we'll tell you before we change it. Building something that needs it stable? Tell us at [hello@hiy.ai](mailto:hello@hiy.ai). ## POST /api/chat Send `content-type: application/json`, from your server. A browser on another site is refused, and a proxy that forwards the browser's `Origin` header must drop it. ```json { "slug": "your-agent", "message": "Does the export include attachments?", "sessionId": "0f0e3b3e-6a0a-4f4b-9a1e-3f0a1b2c3d4e", "history": [], "preview": false } ``` - **slug** (`string`, required) — The agent's address, 1–64 characters. - **message** (`string`, required) — The visitor's question, 1–2000 characters. - **sessionId** (`string (uuid)`, optional) — A UUID from a previous reply's `x-session-id`. Ignored unless it belongs to this agent. - **history** (`array`, optional) — Up to 20 turns of `role` + `content` (4000 characters each). Advisory — see below. - **preview** (`boolean`, optional) — The owner's own sandbox. Anyone who isn't the owner gets a 403. - **wire** (`2`, optional) — Asks for [progress records](#progress-records-opt-in-wire-2) ahead of the answer. Only `2` is accepted. Where they are off, the response is exactly what it would be without this field. Anything that fails validation gets a `400` with `"Invalid request."`, whatever the reason. `history` and `sessionId` are hints, not state. The server rebuilds the conversation from its own stored messages and discards assistant turns you send, so a forged earlier answer can't steer the agent. Keep sending `sessionId`: it threads the conversation in the owner's dashboard. ### The response A `200` streams `text/plain; charset=utf-8` with `cache-control: no-store`, and the conversation's id in an `x-session-id` header. The text is the answer. After the last word comes one NUL byte (`U+0000`), then one line of JSON with the answer's sources. Split on the *first* NUL: before it is the answer, after it is this frame: ```json { "citations": [{ "title": "Refund policy", "snippet": "…", "origin": "source", "url": "https://…" }], "searches": ["refund window", "returns after 30 days"], "searchCount": 2, "records": [{ "id": "…", "type": "services", "title": "Migration review", "url": "https://…", "cta": "Book a time" }], "lookups": ["services"] } ``` Every field is optional and may be empty. `citations` is what the answer was built from. `searchCount` and `lookups` count searches even when the owner hides their wording. `cta` is a button label that comes with a `url`: show it, never branch on it. More NUL-separated frames may follow: read the first and ignore the rest. If something fails mid-stream, the stream errors instead of closing cleanly. Treat an aborted read as a failed message, unless the metadata frame had arrived. ### Errors - **400** `"Invalid request."`: the body failed validation. - **403** `"Not allowed from this site."`: sent from a browser on another site. - **403** `"Not authorized to preview this twin."`: `preview: true` from someone who isn't the owner. - **404** `"Twin not found."`: no such agent, **or** it's restricted and your token didn't check out. - **429**: a rate limit or the monthly allowance; see [Rate limits](#rate-limits). - **503** `"Chat isn't configured yet (no LLM key on the server)."`: the server has no AI model configured. Plan for the `404`: a restricted agent gives the same "not found" for a wrong address and for any bad, expired or misdirected token, so nobody can probe whether it exists. Check your token's expiry before sending. ### Progress records (opt-in, wire 2) Send `"wire": 2` and the stream may start with progress records saying what the agent is doing. Until they are on for your workspace, the response is unchanged, so it is safe to send now. A record is the byte `U+001E` (written `\u001E` below), one line of JSON, then a newline: ```text \u001E{"t":"checking"} \u001E{"t":"sources","titles":["Refund policy","Shipping times"]} Our refund window is 30 days from delivery… ``` `t` is `checking` (a search started), `sources` (up to 3 page titles it found; a later one replaces the earlier) or `error` (the turn failed before any text). Ignore any other `t`. Read records only when the response has the header `x-hiy-wire: 2`, and only before the first byte of answer text. A `sources` title means a page was checked, not used: `citations` stays the only claim of use. Refusals, limit and safety replies carry no records. ## Rate limits Four limits, all answered with `429`: 1. **Per IP, all agents:** 20 requests a minute. Body: `"Slow down a little."` with `code: "slow_down"`. 2. **Per caller, per agent:** 100 messages a day. 3. **Per account, every agent:** the plan's monthly allowance. 4. **Per agent:** a public agent stops at a fifth of the allowance a day. One [open on your site](/docs/embed#open-on-your-site) also stops at a tenth of that per caller and 80% of the month. The last three are **deliberately indistinguishable**, so nobody can work out a stranger's plan from them. Each answers `"This agent has reached its monthly message limit."` plus a reset date: *"Its allowance resets on 1 September."*, always the first of next month (UTC). You may be let back in much sooner, so back off and retry. If hiy can't check these limits for a moment, it answers `503` with `code: "unavailable"` and a `Retry-After` header; retry then. Slack and the Zapier [Ask the Agent](/docs/zapier) action share these limits, counted per Slack user or per API key. ### Every limit - `message`: 1–2000 characters. - `slug`: 1–64 characters. - `history`: 20 turns, 4000 characters each. - Requests per IP: 20 a minute. - Messages per caller, per agent: 100 a day. - Messages per public agent: a fifth of the monthly allowance a day. - Monthly allowance, per account: 300 messages on Free, 2,000 on Starter ([Plans & billing](/docs/plans-and-billing)). - Token lifetime: one hour at most; 60 seconds of clock skew allowed. - Attested facts in a token: 6 keys, 200 characters per value. - Citations per answer: 3, each up to 1,200 characters (260 when the owner hides receipts). hiy publishes no speed or accuracy numbers, because it doesn't measure them. ## Tokens for restricted agents Support Agents and Team Agents have no public link. A visitor gets in with a **signed token your own server mints**, so your users need no hiy account. Send it as a bearer token on every request: ``` Authorization: Bearer v1.eyJ0d2luIjoi… ``` ### The format `v1.` + base64url of the payload + `.` + base64url of the signature. Always set `aud`, the origin of the site that embeds the agent: hiy refuses a token whose `aud` doesn't match the page. ```json { "twin": "the agent's id", "sub": "your own user id", "aud": "https://yoursite.com", "iat": 1755000000, "exp": 1755000900 } ``` The signature is **HMAC-SHA256** over `v1.` with your signing secret. It is deliberately **not a JWT**: there is one algorithm, no algorithm field to confuse and no key discovery. ### The rules we enforce - **Audience-bound.** `twin` must name the agent being asked; a token never opens another agent. - **One hour, maximum.** A token whose `exp` is more than an hour after its `iat` is refused. Fifteen minutes is a good default; clocks may differ by 60 seconds. - **Server-side only.** In a browser, the secret would let any visitor mint tokens for any of your users. ### Minting one Your signing secret is on the agent's **Install** screen (**Signed-in users › Your signing secret**) and on **Workspace › Developers › Sites & install**, with the snippet and the token route. Put the secret in your server's environment and mint a token per page view: ```js // Node.js — run on YOUR server, never in the browser: const crypto = require("crypto"); function mintTwinToken(secret, twinId, userId, siteOrigin) { const now = Math.floor(Date.now() / 1000); // aud: the origin of the page that embeds the agent — hiy refuses it on any other site it can see. const payload = Buffer.from(JSON.stringify({ twin: twinId, sub: String(userId), aud: siteOrigin, iat: now, exp: now + 900, // 15 minutes; 1 hour is the maximum we accept })).toString("base64url"); const body = "v1." + payload; const sig = crypto.createHmac("sha256", secret).update(body).digest("base64url"); return body + "." + sig; } ``` This is the exact code step 2 of **Signed-in users** gives you. Pass the result to the embed as `?token=…`, or send it as the bearer header above. ### Attested attributes A token can carry a few facts about the person, so an action needn't ask what your site already knows. Put them under `att`: ```js // The same payload as above, with one key added. const payload = Buffer.from(JSON.stringify({ twin: twinId, sub: String(userId), att: { order_id: "A-4471", plan: "Pro", }, iat: now, exp: now + 900, })).toString("base64url"); ``` - **You declare the keys, your server fills in the values.** Name up to six keys under **What your site tells this agent**, in **Channels › Chat widget › Install › Signed-in users**. A key you didn't declare is dropped before anything reads it, and nothing tells the model it was there. - **A malformed `att` fails the whole token.** It must be a flat object of at most six keys matching `/^[a-z][a-z0-9_]{0,38}$/` (`order_id`, not `orderId`), each with a string value of at most 200 characters. A restricted agent answers `404`; a public one drops all the facts. Neither says which key broke. - **The token is readable by the visitor, and it rides in a URL** (`?token=`), reaching history and logs. Put nothing in `att` the person may not see, and prefer the `Authorization` header for tokens with facts. - **The visitor is told which keys arrived**, by name, never by value. - **Attested values are readable by an action for the duration of one answer and are never written to the session row, the leads table, or anything joined to them.** What your endpoint sends back is kept with the conversation. ### Tokens hiy mints itself An agent [open on your site](/docs/embed#open-on-your-site) gets tokens from hiy, only for `https:` pages on its allowed websites. They carry no attested facts and stop working when you switch the agent off. Your own server's tokens still work beside them. ### Rotating your secret **Rotate** next to **Your signing secret** (**Channels › Chat widget › Install › Signed-in users**, or **Workspace › Developers › Sites & install**) makes a new secret at once. Every token signed with the old one stops working, so update your server straight away; visitors see *This session has expired* until you do. ## Recipes for the inline embed The same mint on four kinds of host, each wired to the **inline** embed from [Embedding](/docs/embed) rather than the floating bubble, because the inline embed works on every plan. Each signs with **HMAC-SHA256** where a browser can't reach, and only the token leaves your server. ### Next.js Mint inside a Server Component. With no `"use client"` in the file, Next.js keeps it out of every browser bundle. ```tsx // app/support/page.tsx — a Server Component; this file never ships to the browser import { createHmac } from "node:crypto"; import { headers } from "next/headers"; function mintTwinToken(secret: string, twinId: string, userId: string, siteOrigin: string): string { const now = Math.floor(Date.now() / 1000); const payload = Buffer.from(JSON.stringify({ twin: twinId, sub: String(userId), aud: siteOrigin, // this page's own origin — hiy refuses the token on any other site it can see iat: now, exp: now + 900, // 15 minutes; 1 hour is the maximum we accept })).toString("base64url"); const body = "v1." + payload; const sig = createHmac("sha256", secret).update(body).digest("base64url"); return body + "." + sig; } export default async function SupportPage() { const userId = await currentUserId(); // however your app already knows who's signed in const h = await headers(); const origin = `${h.get("x-forwarded-proto") ?? "https"}://${h.get("host")}`; const token = mintTwinToken( process.env.HIY_SIGNING_SECRET!, // read on the server, never returned to the client process.env.HIY_TWIN_ID!, userId, origin ); return (