Skip to content

Embedded Chat & SSO

Embedded Chat & SSO

This page covers the integration surface used by partners who embed Hutly on their own web properties, or who bridge Hutly identity into a partner application:

  • Embedded chat — mint short-lived, chat-scoped tokens so a widget on your own site can talk to a Hutly agent without ever exposing an API key to the browser.
  • SSO — exchange a Hutly session for a one-time token that logs the user into a partner app (VicForms, Platform Accounts, PropertyData, and others).
  • ABN / ACN lookup — resolve Australian Business / Company numbers against the ABR from your own onboarding or forms flows.

Base URL: https://api.intellia.com.au

All tokens minted by the endpoints on this page are assume-role tokens: they carry the fixed role "chat", are scoped to a single organization, and expire 2 hours after minting. They grant no admin, billing, or settings access.

Embedded Chat

Website Chat Token (anonymous widget)

POST /public/website-chat-token

Authentication: None (public endpoint). This is the token the public Hutly chat widget calls from an anonymous browser session before opening the agent. No API key is exposed to the client.

Mints a per-visitor, chat-scoped token against the Hutly GTM organization. The visitor identity is namespaced server-side as visitor:<visitorId>, so a caller-supplied value can never collide with a real user account.

Request Body:

{
  "visitorId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
}
  • visitorId (optional): A browser-generated identifier the widget persists in localStorage. Omit it on first visit — the server mints one and returns it so the widget can stash and reuse it (memory and conversation state persist across reloads for the same id). If supplied, it must be 1–64 characters matching [a-zA-Z0-9_-]+; anything else returns 400 Invalid visitorId.

Response:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC...",
  "expiresAt": "2026-07-13T12:00:00.000Z",
  "visitorId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "organizationId": "<hutly-gtm-org-id>"
}
  • token: The assume-role JWT to send as Authorization: Bearer <token> on subsequent chat calls.
  • expiresAt: ISO-8601 expiry, 2 hours from mint.
  • visitorId: The id the token is bound to (echoed back, or newly minted).
  • organizationId: Always the Hutly GTM org — the widget can only chat with the marketing agent in that org.
This endpoint is unauthenticated by design. Rate limiting is enforced at the API-gateway / WAF layer, not in the handler.

Assume-Role Token (authenticated mint for embedded apps)

POST /orgs/{organizationId}/assume-role

Authentication: Requires either a Hutly user session or an organization API key. This endpoint is not noAPIKey-gated — an API key can mint tokens, but only if the key carries the assume_role.write permission. When called with an API key that lacks that permission, the request returns 403 Unauthorized - API key does not have assume_role write permission. Capability required: org.assume_role.

Use this to mint an end-user chat token for an embedded application where you control the identity (for example, your own logged-in customers). If the target user does not already exist and you supply userEmail, a chat-role member is created in the organization.

Request Body:

{
  "userId": "user-123",
  "userEmail": "customer@example.com",
  "userName": "Customer Name",
  "permissions": []
}
  • userId (required): The user to mint the token for.
  • userEmail (optional): If the user does not exist, provide this to create a chat-role member. Without it, an unknown userId returns 404 User not found.
  • userName (optional): Display name for a newly created user (defaults to the local part of the email).
  • permissions (optional): Permission strings embedded in the token.

Response:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC...",
  "expiresAt": "2026-07-13T12:00:00.000Z",
  "userId": "user-123",
  "organizationId": "org-456",
  "role": "chat"
}

Verify Assume-Role Token

POST /orgs/{organizationId}/assume-role/verify

Authentication: None (skipAuth). Anyone can submit a token for verification against the organization in the path — no session or API key is needed, since verification is a signature check, not a privileged action.

Validates a token’s signature, expiry, and that its audience matches the {organizationId} in the path.

Request Body:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC..."
}

Response:

{
  "valid": true,
  "userId": "user-123",
  "organizationId": "org-456",
  "role": "chat",
  "permissions": [],
  "expiresAt": "2026-07-13T12:00:00.000Z"
}

When the token is malformed, expired, or scoped to a different organization, the endpoint returns 200 with { "valid": false, "error": "<reason>" } rather than an error status.

Legacy Public Token

GET /buddybee/public-token

Authentication: None (public endpoint).

Mints a chat-scoped token for a shared synthetic “unknown” user against the Hutly Internal organization. Retained for existing public-widget callers.

Response:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC...",
  "expiresAt": "2026-07-13T12:00:00.000Z",
  "userId": "<unknown-user-id>",
  "organizationId": "<hutly-internal-org-id>",
  "role": "chat"
}
For new anonymous embeds, prefer POST /public/website-chat-token, which namespaces each visitor and preserves per-visitor memory. The legacy public token maps every anonymous caller onto one shared user.

SSO

SSO Token Exchange

POST /orgs/{organizationId}/auth/sso/exchange

Authentication: Requires a Hutly user session. Capability required: auth.sso_exchange.

Exchanges a Hutly JWT for a single-use exchange token (valid 30 seconds) that a partner app can redeem to establish a logged-in session. The exchange token is stored server-side and auto-expires; the partner app validates and consumes it on redemption.

Request Body:

{
  "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC...",
  "targetDomain": "propertydata"
}
  • jwt (required): The Hutly session JWT to bridge.
  • targetDomain (required): One of buddybee, intellia, adl, propertydata, vicforms. Any other value returns 400 Invalid targetDomain.

Response:

{
  "exchangeToken": "3f2a...<64 hex chars>",
  "expiresAt": 1752403200
}
  • exchangeToken: The one-time token the partner app redeems.
  • expiresAt: Unix epoch seconds (30 seconds from mint).
When targetDomain is propertydata, the exchange is gated server-side: any unmet PDOL deeds for the user must be signed first, or the request is rejected. This mirrors the launcher UI’s signature prompt and prevents minting a token that would bypass the per-query deed checks inside the portal.

VicForms SSO

GET /orgs/{organizationId}/buddybee/vicforms/auth

Authentication: Requires a Hutly user session. Capability required: buddybee.use.

Returns a VicForms session token for the calling user, using the VicForms request token stored in the user’s organization-member metadata. Requires the caller to be a member of the organization and to have a request_token in their member metadata (otherwise 400).

Response:

{
  "token": "<vicforms-session-token>",
  "success": true
}

Platform Accounts SSO

GET /orgs/{organizationId}/buddybee/platform/auth

Authentication: Requires a Hutly user session. Capability required: buddybee.use.

Same shape as VicForms SSO, but returns a Platform Accounts session token. Also requires a request_token in the caller’s member metadata.

Response:

{
  "token": "<platform-accounts-session-token>",
  "success": true
}

ABN / ACN Lookup

Lookup by ABN or ACN

GET /buddybee/abn-lookup/{abn}

Authentication: Requires a Hutly user session or API key. Capability required: abn.lookup. Organization and subscription checks are bypassed, so this works from any authenticated context.

Resolves an Australian Business Number or Company Number against the ABR. The path segment is named abn for backwards compatibility, but the handler dispatches by digit count: an 11-digit value is treated as an ABN, a 9-digit value as an ACN. Whitespace is stripped. A value that is neither returns 400 Value must be a valid 11-digit ABN or 9-digit ACN.

Response:

{
  "entityName": "Example Pty Ltd",
  "acn": "123456789",
  "legalPostcode": "3000",
  "legalState": "VIC",
  "legalStreetName": "Collins Street",
  "legalStreetNumber": "1",
  "legalSuburb": "Melbourne",
  "legalUnitNumber": "",
  "entityStatus": "Active",
  "businessNames": ["Example Trading"],
  "isGstRegistered": true,
  "isAbnActive": true
}

Lookup Availability

GET /buddybee/abn-lookup-available

Authentication: Requires a Hutly user session or API key. Capability required: abn.lookup. Organization and subscription checks are bypassed.

Reports whether the ABR lookup service is currently configured and reachable (a valid ABR GUID and base URL are present). Use this to gate lookup UI before prompting for an ABN.

Response:

{
  "available": true
}

Deprecated Endpoints

The two flat-path user-metadata endpoints below are deprecated and scheduled for removal. They only existed for legacy clients that could not pass an organization id — the handler guesses the org by finding the caller’s VicForms organization. Migrate to the org-scoped replacements.
Deprecated Replacement
GET /buddybee/user/metadata GET /orgs/{organizationId}/buddybee/user/metadata
PUT /buddybee/user/metadata PUT /orgs/{organizationId}/buddybee/user/metadata

Both deprecated endpoints require a Hutly user session and resolve the target organization by locating the caller’s VicForms membership. New integrations must call the org-scoped paths, which take the organization id explicitly.