Agentic Workforce ME Developer PortalDocs 1.21 · Widget 0.5.0 · API —

Reference

JavaScript API & events

HiveChat.init handle methods, element events and programmatic control recipes.

Three objects matter: the global HiveChat API (the loader puts it on window; the ESM build exports it), the handle returned by HiveChat.init, and the <hive-chat> element itself, which dispatches DOM events.

HiveChat

MemberSignatureDescription
versionreadonly version: stringBuild version of the loaded bundle (the @hive/embed package version, currently 0.5.0); the URL path /embed/v1/ is the compatibility line.
initinit(opts: HiveChatOptions, container?: Element | null): HiveChatHandleCreates a <hive-chat> (launcher mode: appended to document.body; or into container). Calling it again with the same key — or, in bearer mode without a key, the same basePath + binding — reuses the existing widget and applies the new options.

HiveChatHandle

MemberSignatureDescription
elementreadonly element: HiveChatElementThe underlying custom element — add event listeners here.
openopen(): voidOpen the panel and focus the composer.
closeclose(): voidClose the panel; focus returns to the launcher.
toggletoggle(): voidOpen or close.
sendsend(text: string): Promise<void>Send a message as the end user and follow the run until it settles. Ignored while another turn is in flight.
resetreset(): voidForget the current thread and start fresh (also cancels a live stream).
updateupdate(opts: Partial<HiveChatOptions>): voidChange options in place — theme/locale/texts re-render without a new session; changing key, apiUrl, basePath, binding, user.token, storage or visitorId re-mints. A new authToken on an otherwise identical config is a token swap (same as setAuthToken()), not a new session.
setAuthTokensetAuthToken(token: string): voidBearer mode only: replace the pre-issued token after your host re-issued it. Takes effect on the next request, keeps the thread, and — if the widget had paused on a 401 (hive:auth-expired) — clears the error state and fires hive:auth-resumed. Empty strings and calls before the widget is configured are ignored; it never mints or refreshes a token by itself.
destroydestroy(): voidRemove the element and forget the handle.
TypeScript
const chat = HiveChat.init({ key: 'hive_pk_REPLACE_WITH_YOUR_PUBLISHABLE_KEY' });

chat.open();                       // show the panel
await chat.send('Where is my order?');   // send as the visitor, resolves when the run settles
chat.update({ locale: 'ar' });     // re-render in Arabic, same session
chat.reset();                      // new thread
chat.destroy();                    // remove the element

HiveChatElement

The element registered as hive-chat. Everything on the handle is a thin call into it. Useful when you create elements in markup (Vue, Angular, plain HTML):

MemberSignatureDescription
configureconfigure(opts: Partial<HiveChatOptions>): voidMerge options programmatically (what the loader and React wrapper use). Attributes still win over programmatic values.
openopen(): voidSame as the handle.
closeclose(): voidSame as the handle.
toggletoggle(): voidSame as the handle.
sendsend(text: string): Promise<void>Same as the handle.
resetreset(): voidSame as the handle.
setAuthTokensetAuthToken(token: string): voidSame as the handle (bearer mode). Rewriting the auth-token attribute has the same effect.
threadIdreadonly threadId: string | nullThe current thread id (null before the first message).
HTML
<!-- Drive the element directly (no loader) -->
<hive-chat id="support" key="hive_pk_REPLACE_WITH_YOUR_PUBLISHABLE_KEY" api-url="https://HIVE" mode="inline"
           style="display:block;height:600px"></hive-chat>
<script type="module">
  import 'https://HIVE/embed/v1/hive-embed.mjs';
  const el = document.getElementById('support');
  el.addEventListener('hive:ready', () => el.send('Hello!'));
  console.log(el.threadId);   // null until the first message is accepted
</script>

Events

All events are CustomEvents dispatched on the <hive-chat> host, bubbles: true and composed: true, so you can also listen on document. The React wrapper maps each to a prop.

EventdetailWhenReact prop
hive:ready{ key_id }Display config loaded (GET /v1/embed/config); the launcher/panel is rendered and usable. No session exists yet.onReady
hive:session{ visitor_id, identified }A session token was minted — on the first open (launcher mode), on mount (inline mode) or on the first send(), whichever comes first. identified is true when a valid identity JWT was presented.onSession
hive:openundefinedThe panel opened (launcher click, open(), or the open attribute).onOpen
hive:closeundefinedThe panel closed (close button, Escape, or close()).onClose
hive:message{ role: 'user' | 'agent', text }A user turn was sent, or an agent reply completed.onMessage
hive:attachments{ count, files: [{ name, mime }] }Selected documents were uploaded and attached to an accepted turn. It exposes safe metadata only, never file bytes.onAttachments
hive:error{ code, retry_after }Config fetch, session or run failure — an API problem code (e.g. EMBED_ORIGIN_DENIED, RATE_LIMITED), a run failure code relayed from the stream’s run.failed event (MODEL_ERROR, BUDGET_EXCEEDED, RETRIES_EXHAUSTED, TOOL_ERROR, … — since 0.2; 0.1 only showed these in the bubble), or a widget code (NETWORK, STREAM_LOST, HTTP_<status>). retry_after (seconds, since 0.2.1) is set only when the API problem carried it — today 429 RATE_LIMITED — and is undefined otherwise; use it for a real "try again in Ns" instead of a fixed number. The widget itself never shows the code to the visitor: its error row is part="error" with the code in data-code (hive-chat::part(error) { display: none } hides it when your page owns the copy).onError
hive:auth-expired{ code }Bearer mode only (authToken): the pre-issued token was refused with a 401 — code is the problem code. The widget shows the error state and ignores send() until setAuthToken() (or a rewritten auth-token attribute) supplies a new token; it never refreshes one itself.onAuthExpired
hive:auth-resumedundefinedBearer mode only: a replacement token reached a widget paused on hive:auth-expired; the error state clears and the same thread continues (not a re-mint).onAuthResumed
hive:status{ status: 'idle' | 'sending' | 'streaming' | 'waiting' | 'error' | 'listening' | 'thinking' | 'speaking' }Emitted on every conversation-state transition; the first value after hive:ready is idle. idle — no run in flight (composer enabled); sending — the message was accepted, no visible text yet; streaming — the reply is being rendered (first delta, or the final text when deltas are buffered); waiting — run.waiting received (an approval is open on this thread); error — hive:error fired for the current turn (back to idle on the next send or reset()). While a voice session is live (voice option) the status reads listening, thinking or speaking instead and returns to the conversation status when the session ends. Lets a host composer disable itself while a turn is in flight instead of hitting 409 EMBED_RUN_IN_FLIGHT.onStatus
hive:voice{ state: 'idle' | 'connecting' | 'listening' | 'thinking' | 'speaking' | 'muted' | 'error' | 'ended', transcript? }Voice sessions (voice option): every state change of the mic row — connecting while the microphone and socket open, listening / thinking / speaking through a turn, muted, error (a fatal problem; the code arrives on hive:error), ended. transcript is the visitor’s final transcript for the turn in flight once the server has it (also emitted, with the current state, when it arrives). Completed spoken turns additionally fire hive:message for the user and the agent like typed turns.onVoice
hive:block{ lang, source, index, message_id }With blocks.render set to host or both: one event per processed fence of a FINAL agent message (run.completed), in document order. In both mode, a validated full-message chart JSON also emits a synthetic lang: chart event. Never fired for a restored thread. source is untrusted model text: parse and validate it on your page; never inject it as HTML.onBlock

hive:auth-expired and hive:auth-resumed only fire in bearer mode (authToken); a widget using a publishable key never dispatches them.

JavaScript
const chat = HiveChat.init({ key: 'hive_pk_REPLACE_WITH_YOUR_PUBLISHABLE_KEY' });
const el = chat.element;

el.addEventListener('hive:ready', (e) => {
  console.log('config loaded for key', e.detail.key_id);   // no session yet
});
el.addEventListener('hive:session', (e) => {
  const { visitor_id, identified } = e.detail;   // minted on first open / first send
  analytics.identify(visitor_id);
});
el.addEventListener('hive:message', (e) => {
  const { role, text } = e.detail;      // 'user' | 'agent'
  analytics.track('chat_message', { role, length: text.length });
});
el.addEventListener('hive:error', (e) => {
  console.warn('hive-chat error', e.detail.code);   // e.g. 'RATE_LIMITED'
});
el.addEventListener('hive:open', () => document.body.classList.add('chat-open'));
el.addEventListener('hive:close', () => document.body.classList.remove('chat-open'));
TypeScript
// TypeScript: the events are plain CustomEvents — type the detail yourself
import type { HiveChatElement } from '@hive/embed';

type HiveEvents = {
  'hive:ready': { key_id: string };
  'hive:session': { visitor_id: string; identified: boolean };
  'hive:message': { role: 'user' | 'agent'; text: string };
  'hive:error': { code: string };
};

function on<K extends keyof HiveEvents>(
  el: HiveChatElement, name: K, fn: (detail: HiveEvents[K]) => void,
) {
  el.addEventListener(name, (e) => fn((e as CustomEvent<HiveEvents[K]>).detail));
}

Error codes in hive:error

detail.code is either a platform problem code (see the REST reference — EMBED_ORIGIN_DENIED, EMBED_KEY_DISABLED, RATE_LIMITED, AGENT_NOT_PUBLISHED…) or one of the widget’s own:

CodeMeaning
EMBED_THREAD_REQUIRED_FOR_ATTACHMENTDocuments were selected before the conversation had an accepted first turn and therefore no owned thread existed for a safe upload.
CONFIGInvalid init options (bad key format, or apiUrl could not be inferred). Logged as a [hive-embed] console warning and the panel shows the offline notice; this one is internal — no hive:error event is dispatched.
NETWORKThe fetch itself failed (offline, DNS, CSP connect-src block, mixed content).
STREAM_LOSTThe SSE stream dropped and three reconnect attempts (with ?since) failed.
HTTP_<status>The API answered with a non-JSON error body (e.g. a proxy 502).

A run that ends with the SSE event run.failed renders an error bubble with the run’s failure code and a Retry action; it is a run outcome, not a transport failure, so it does not dispatch hive:error.

Recipes

Open on a button click

HTML
<button id="help">Need help?</button>
<script async src="https://HIVE/embed/v1/hive-embed.js" data-key="hive_pk_REPLACE_WITH_YOUR_PUBLISHABLE_KEY"></script>
<script>
  // The script is async: a click can land before it has loaded, when
  // window.HiveChat is still the stub below and has no init(). The loader
  // drains the queue (q: [[options, container?]]) as soon as it runs.
  window.HiveChat = window.HiveChat || { q: [] };
  document.getElementById('help').addEventListener('click', () => {
    if (typeof window.HiveChat.init === 'function') {
      // Loaded: init() is idempotent per key and returns the auto-initialized handle.
      window.HiveChat.init({ key: 'hive_pk_REPLACE_WITH_YOUR_PUBLISHABLE_KEY' }).open();
    } else {
      // Not yet: queue an init that opens the panel once the bundle arrives.
      window.HiveChat.q.push([{ key: 'hive_pk_REPLACE_WITH_YOUR_PUBLISHABLE_KEY', open: true }]);
    }
  });
</script>

Prefill from page context

JavaScript
// Open with a context-aware first message (sent as the visitor).
const chat = HiveChat.init({ key: 'hive_pk_REPLACE_WITH_YOUR_PUBLISHABLE_KEY' });

document.querySelector('#ask-about-product').addEventListener('click', async () => {
  chat.open();
  await chat.send(`I have a question about ${document.title} (${location.pathname})`);
});

Pass page URL / user metadata

JavaScript
// Pass page URL and user metadata — the safe way.
//
// The widget sends no free-form metadata from the browser (it is untrusted).
// Page context therefore travels either as part of the message text (visible
// to the visitor, above) or — for attributes you vouch for — inside the
// identity JWT your backend signs:
//
//   { sub: user.id, name: user.name, meta: { plan: 'pro', region: 'ae', page: '/pricing' } }
//
// meta lands on the contact record (end_users.attributes.embed) and is visible
// to operators in the console; it is not injected into the prompt.
const { token } = await fetch('/api/hive-identity?page=' + encodeURIComponent(location.pathname))
  .then((r) => r.json());
HiveChat.init({ key: 'hive_pk_REPLACE_WITH_YOUR_PUBLISHABLE_KEY', user: { token } });

Single-page apps, login and logout

JavaScript
// Single-page apps: create once, update on route change, destroy on logout.
let chat;

export function mountChat(user) {
  chat = HiveChat.init({
    key: 'hive_pk_REPLACE_WITH_YOUR_PUBLISHABLE_KEY',
    locale: document.documentElement.lang.startsWith('ar') ? 'ar' : 'en',
    user: user ? { token: user.hiveToken } : undefined,
  });
}

router.afterEach((to) => {
  // e.g. hide the launcher on checkout
  chat?.element.toggleAttribute('hidden', to.path.startsWith('/checkout'));
});

export function onLogout() {
  chat?.reset();                       // drop the identified thread
  chat?.update({ user: undefined });   // continue as anonymous …
  // … or chat?.destroy() to remove it entirely
}

ESM exports

Beyond HiveChat, the ESM build (@hive/embed / /embed/v1/hive-embed.mjs) exports the building blocks, so you can reuse the API client, the Markdown renderer or the SSE parser in a custom UI:

HiveChat, HiveChatElement, TAG, defineHiveChat, setDefaultApiUrl, VERSION, EmbedClient, EmbedApiError, HiveChatConfigError, resolveOptions, resolveBlocks, resolveStrings, sanitizeTheme, mergeTheme, themeToCssVars, resolveLocale, dirFor, STRINGS, renderMarkdown, liftFences, escapeHtml, createSseParser, reduce, initialState

Types: HiveChatOptions, HiveChatHandle, HiveChatApi, EmbedTheme, EmbedDisplayConfig, EmbedPublicConfig, EmbedSession, EmbedEvent, HistoryMessage, ProblemDocument, ChatState, ChatMessage, Strings, SseFrame.