# Chatbot API

New to chatbots? [General](/docs/ai/chatbots/general.md) gives an overview. This
page covers chatbots in code: rendering one from PHP, adding markup to it,
controlling it from JavaScript, and managing saved chatbots over REST.

## Render a chatbot from PHP

`sleekAi_render_chatbot()` prints a chatbot widget built from an array instead
of a chatbot saved in the editor. Call it where your theme prints markup, for
example on `wp_footer`:

```php
add_action('wp_footer', function () {
    if (!function_exists('sleekAi_render_chatbot') || !is_singular('product')) {
        return;
    }

    $productId = get_queried_object_id();

    sleekAi_render_chatbot([
        'model' => [
            'model' => 'openai-gpt-4.1-mini',
        ],
        'data' => [
            'instruction' => 'You answer questions about the product {title}. '
                . 'Its description is: {description}',
            'variables' => [
                'title' => get_the_title($productId),
                'description' => wp_strip_all_tags(get_post_field('post_content', $productId)),
            ],
        ],
        'widget' => [
            'button' => [
                'text' => 'Ask about this product',
            ],
        ],
    ]);
});
```

- `model.model` is required. It takes the same provider-and-model identifiers
  as the [Developer API](/docs/ai/api.md#model).
- Each key in `data.variables` replaces the matching `{key}` in
  `data.instruction`. Values must be strings, and only a variable with exactly
  that key replaces a placeholder.
- SleekAI wraps the instruction in the same fixed guidelines as every chatbot.
- Nothing renders while no API key is stored.

Chat requests do not receive the array from the page. SleekAI stores it in a
transient for a week, renewed at most daily when rendered, named
`sleek-ai_chatbot_data_` followed by the `key` you pass or, without a `key`, by
an MD5 hash of the array. Requests read it from there. With a fixed `key`, the
stored array stays the same until its next daily renewal. Use a key only for
data shared by every visitor, and include a content revision when the data
changes. The server-side lifetime must exceed the lifetime of cached pages
that carry its key.

## Cacheable public context

Inline chatbots can set `'visitorContext' => 'anonymous'`. This opts just that
render into public context: its bootstrap has no login nonce, its signed user
scope is zero, and completion and polling requests omit browser credentials.
Anonymous and logged-in visitors receive identical widget markup. The default
remains the current user's context. Each widget carries its own bootstrap, so
public and personalized widgets can coexist without sharing authentication.

For a saved chatbot, use `visitor_context="anonymous"` on its shortcode. Its
published status and display conditions still apply. Automatic widgets can
select context per render through `sleekAi/chatbot/visitorContext`, whose second
argument is that widget's chatbot settings. Returning `anonymous` changes no
stored bot or global WordPress user. Signed completion authorization remains
unchanged; public context does not grant access to private chatbot posts.

## Options

The array follows the shape of a saved chatbot. These are the keys a chatbot
rendered from PHP reads, with the values SleekAI uses when a key is missing:

```php
sleekAi_render_chatbot([
    // Optional. Names the transient and the key markup filter.
    'key' => 'support',
    'model' => [
        // Required. Provider and model identifier.
        'model' => 'openai-gpt-4.1-mini',
    ],
    'data' => [
        'instruction' => '',
        // Strings keyed by variable name.
        'variables' => [],
    ],
    'widget' => [
        'general' => [
            // Shows a button that switches the chat to fullscreen.
            'fullscreen' => false,
        ],
        'position' => [
            'alignment' => 'right', // 'left' or 'right'
            'distance' => '16px',
        ],
        'button' => [
            'type' => 'button', // 'button' or 'logo'
            'text' => 'Chat with AI',
            'color' => '#000000',
            'backgroundColor' => '#FFFFFF',
            'borderColor' => '#E4E4E7',
            'borderRadius' => '8px',
            'fontSize' => '0.875rem',
            'logo' => [
                // Image shown on the button when type is 'logo'.
                'url' => null,
            ],
        ],
        'chat' => [
            'initialMessage' => null,
            'inputText' => 'Send a message',
            'nameAi' => 'SleekAI',
            'theme' => 'light', // 'light', 'dark' or 'dark-wordpress'
            'presets' => [
                'label' => '',
                // Strings, or arrays with a 'value' key.
                'items' => [],
            ],
        ],
        'logo' => [
            // Image shown in the chat window's header.
            'url' => null,
        ],
        'storage' => [
            'type' => 'none', // 'none', 'sessionStorage' or 'indexeddb'
        ],
        'messages' => [
            'menu' => [
                'chatFromHere' => false, // needs 'indexeddb' storage
                'regenerate' => false,
                'delete' => false,
            ],
        ],
    ],
]);
```

The [Widget](/docs/ai/chatbots/widget.md) page describes what each setting does,
and the button options set the CSS custom properties described in
[Styling](/docs/ai/chatbots/styling.md).

The public renderer represents an
absent button logo, header logo or welcome message as `null`; the widget treats
those three values as empty strings while retaining the other saved settings.
Numbers, objects and other malformed string values still fail validation.

The configured `widget.chat.theme` applies to both the chatbot and its frame.
`light` stays light regardless of the visitor's system preference; `dark` and
`dark-wordpress` use dark mode.

## Add markup to a chatbot

SleekAI has no filter that changes a chatbot's settings before it renders.
Change saved chatbots in the editor, and build chatbots that differ per page
with `sleekAi_render_chatbot()`. Three filters add markup, usually a `<style>`
element, which SleekAI inserts into the chatbot's frame:

- `sleekAi/chatbot/markup` for every chatbot.
- `sleekAi/chatbot/key={key}/markup` for a chatbot rendered from PHP, where
  the key is `sleek-ai_chatbot_data_` followed by its `key`.
- `sleekAi/chatbot/id={id}/markup` for a chatbot saved in the editor, by its
  post ID.

They run in that order, each with the markup so far and the chatbot's array:

```php
add_filter('sleekAi/chatbot/key=sleek-ai_chatbot_data_support/markup', function ($markup, $chatbot) {
    return $markup . '<style>:root { --sleek-ai--chatbot-button--padding: 10px 14px; }</style>';
}, 10, 2);
```

The [hooks reference](/docs/ai/reference/hooks.md) lists their arguments.

## JavaScript API

The script that SleekAI prints with the first chatbot on a page defines
`window.SleekAI.chatbot`:

```js
// Open the first chatbot on the page, or open it in fullscreen.
SleekAI.chatbot.open()
SleekAI.chatbot.open({ fullscreen: true })

// Close it again.
SleekAI.chatbot.close()

// Hide the widget and its button, for example while another modal is open,
// and show it again.
SleekAI.chatbot.hide()
SleekAI.chatbot.show()

// Every method takes the chatbot's position on the page.
SleekAI.chatbot.hide({ index: 2 })
```

`index` is not the chatbot's ID. It counts every chatbot on the page, embedded
chats included, in the order SleekAI renders them, starting at 1. Shortcodes in
the page content render before the saved widget chatbots, which SleekAI adds
in the footer. `hide()` and `show()` act on floating widgets only.

### When chatbots load

A visitor who never uses a chatbot downloads only its button and settings.
A floating chatbot loads its frame when a pointer moves onto its button, the
button takes focus or a finger touches it, so it is usually ready by the time
the visitor clicks. A click that arrives sooner shows the button busy and
opens the chat as soon as it has loaded. The framed button then replaces the
page's button in place and keeps its focus. An embedded chat loads when it
comes within 400 pixels of the viewport, in browsers without
`IntersectionObserver` at once. `SleekAI.chatbot.open()` loads a chatbot that
has not loaded yet and opens it once it has; `close()` acts on loaded chatbots
only.

## REST management

Administrators can manage saved chatbots through SleekAI's REST operations,
with normal WordPress REST authentication such as a REST nonce or an
application password:

- `Chatbot_list` lists every chatbot.
- `Chatbot_create` creates a chatbot. Every call creates another one.
- `Chatbot_read` returns one chatbot.
- `Chatbot_update` replaces a chatbot's saved definition.
- `Chatbot_remove` deletes a chatbot and its synchronized files.

The [REST reference](/docs/ai/reference/rest.md) gives their methods and paths,
under `sleek-ai/v1/chatbot`. Every one requires the `manage_options`
capability.

`Chatbot_update` replaces, it does not merge. Always send the full chatbot
returned by `Chatbot_read`; omitted sections are removed and the editor shows
their defaults. `wp sleek ai chatbot create` and `wp sleek ai chatbot update`
do the same from the command line, from a JSON file.
