# Embeds and public endpoints

These work from a visitor's browser, so they need no token. Each is created inside KLCT and identified by a slug you copy from its settings page.

## Support chat widget

Create a widget under **Support, Widgets**, list your site under its allowed origins, and paste the loader on every page:

```html
<script src="https://app.klctai.com/support/YOUR-WIDGET-SLUG/embed.js" async></script>
```

The loader adds a chat bubble. Control it from your page with `window.klctSupport`:

```js
klctSupport('open');                       // open the chat
klctSupport('close');
klctSupport('toggle');
klctSupport('sendMessage', 'I need help with my order');
klctSupport('book');                       // open the booking window, if the widget has one
klctSupport('dismissible');                // add a small hide cross to the bubble
klctSupport('on', { event: 'open', cb: () => console.log('chat opened') });  // also: close, dismiss, booking:open, booking:close
klctSupport('logout');                     // call on sign-out so a shared computer forgets the visitor
```

### Tell the widget who is signed in

Call `identify` after your user signs in. Extra keys become visitor attributes the team sees next to the conversation.

```js
klctSupport('identify', {
  external_id: 'user_8841',
  signature: 'HEX_HMAC_FROM_YOUR_SERVER',
  name: 'Dana Cole',
  email: 'dana@acme.example',
  plan: 'pro',
});
```

On its own `external_id` is only a label, because page code can claim anything. To make it a proven identity (so the same person is recognized across devices), compute the signature on **your server** and pass it down with the page:

```php
$signature = hash_hmac('sha256', (string) $user->id, $widgetIdentitySecret);
```

```js
const signature = createHmac('sha256', process.env.KLCT_IDENTITY_SECRET).update(String(user.id)).digest('hex');
```

The identity secret is on the widget's settings page. Never ship it to the browser. Turn on **Require verified identity** on the widget to refuse unsigned claims.

### Standalone ticket form

A separate page for customers who prefer a form to a chat:

```html
<script src="https://app.klctai.com/support/YOUR-WIDGET-SLUG/form.js" async></script>
```

Or link to `https://app.klctai.com/support/YOUR-WIDGET-SLUG/form`.

## Forms

Build a form under **Forms**. It is available at:

- `https://app.klctai.com/forms/YOUR-FORM-SLUG` as a hosted page,
- `https://app.klctai.com/forms/YOUR-FORM-SLUG/embed.js` as a script that adds it to your page.

Submissions create or update a contact, run the form's automations and carry ad and UTM attribution. To post a submission from your own server instead of the embed, send `POST https://app.klctai.com/forms/YOUR-FORM-SLUG/submit` with the `X-Form-Key` header from the form's settings.

## Booking

Meeting types are bookable at `https://app.klctai.com/book/YOUR-HANDLE/EVENT-SLUG`, and each page has an `embed.js` at `https://app.klctai.com/book/YOUR-HANDLE/EVENT-SLUG/embed.js`. Your handle and event slugs are on the Booking pages. Visitors can cancel or reschedule from the links in their confirmation email.

## Landing pages

Pages built in the page builder are served at `https://app.klctai.com/go/YOUR-PAGE-SLUG`, or on your own domain when you connect one.

## Customer portal

The changelog, feedback board and roadmap you manage under **Portal** are public pages for your customers. To read or write the same data from code, use the [changelog](reference#changelog) and [feedback](reference#feedback-and-roadmap) endpoints.
