API Reference - @weavix/tracker-plugin-sdk-core

hostApi (HostApi)

API for interacting with the Tracker application: plugin initialization, theme, language, slot context, window size, and readiness notification.

Exports the hostApi singleton. Usually used inside TrackerPluginProvider (react package); you can call it directly if needed.

init()

Initializes the plugin (reads parameters from the URL, establishes a connection with Tracker, and performs auto-resize if necessary). Call once before using other methods.

Parameters: options?: HostInitOptions — options (for example autoResize, defaults to true).

Throws: Error — if the URL lacks required parameters (slot, parentOrigin, id, elementId).

import { hostApi } from "@weavix/tracker-plugin-sdk-core";

hostApi.init({ autoResize: true });

getTheme()

Returns the current Tracker theme.

Returns: Promise<Theme>

const theme = await hostApi.getTheme(); // 'light' | 'light-hc' | 'dark' | 'dark-hc' | 'system'

getLanguage()

Returns the current Tracker language.

Returns: Promise<string> (for example 'ru', 'en').

const language = await hostApi.getLanguage();

getUserAvatars()

Gets user avatars in a single request through Tracker.

Parameters: users: Array<{ uid?: string; login?: string }> — 1–100 users. For each user, provide a non-empty string uid, login, or both.

Returns: Promise<Array<string | null>>. Results follow the input order. Each item is an absolute HTTP(S) avatar URL or null if the avatar is unavailable.

const [aliceAvatar, bobAvatar] = await hostApi.getUserAvatars([
    { login: "alice" },
    { uid: "123" },
]);

If the app does not support the method, the request may fail with METHOD_NOT_SUPPORTED. Show the user's initials if the URL is missing, the request fails, or the image cannot load.

The image domain must be allowed by the plugin's CSP img-src directive.

getContext()

Returns the context of the slot where the plugin is running. The level of returned data is determined by the contextLevel parameter specified for the slot in manifest.json (see Slot context levels).

Parameters: level: 'basic' | 'full' (required)

Returns:

  • For level: 'basic' — Promise<BasicContext>, where BasicContext = { entityId: string; entityMeta?: Record<string, string> }
  • For level: 'full' — Promise<SlotContextMap[TSlot]>
// Basic context (only entity identifier)
// Requires contextLevel: 'basic' in manifest.json for this slot
const basicContext = await hostApi.getContext("basic");
// basicContext.entityId — identifier of the current entity
// basicContext.entityMeta — additional metadata (optional)

// Full context (all entity data)
// Requires contextLevel: 'full' in manifest.json for this slot
const fullContext = await hostApi.getContext("full");

updateContentSize()

Sends a request to Tracker to change the plugin window size.

Parameters: payload: ContentSizeUpdateRequest (fields height and width — at least one must be present).

Returns: Promise<…>

await hostApi.updateContentSize({ height: 500 }); // sets the plugin window height
await hostApi.updateContentSize({ width: 800 }); // sets the plugin window width
await hostApi.updateContentSize({ height: 500, width: 800 }); // sets the plugin window height and width

The plugin window width is applied considering the embedding space constraints.

Scrolling inside a plugin

If the iframe expands to the full content height, it has no scrollable area. As a result, element.scrollIntoView() and window.scrollTo() don't scroll the plugin document.
To scroll programmatically inside a plugin, disable automatic resizing with hostApi.disableAutoResize(). Then use hostApi.updateContentSize() to set the iframe height below the content height.

notifyReady()

Notifies Tracker that the plugin is ready.

Returns: Promise<…>

await hostApi.notifyReady();

getSlot()

Returns the current slot. Call only after init().

Returns: TSlot (key from SlotContextMap).

const slot = hostApi.getSlot(); // for example 'issue.action'

disableAutoResize()

Disables automatic container resizing based on content.

hostApi.disableAutoResize();

close()

Closes the plugin if it's displayed in a popup window.

hostApi.close();

Data transfer

Some slots support processing data that will be passed as an argument to the close method.
See the documentation for specific integration points for exact types and functionality.

preventClose()

Protects the plugin from accidental closure by the user, for example, by pressing Esc or clicking the close button. If the preventClose: true flag is set, Tracker will block closure until the flag is cleared. Only works with plugins displayed in a modal window.

Use this method to prevent the loss of unsaved changes.

import { hostApi } from "@weavix/tracker-plugin-sdk-core";

// Block closure if there are unsaved changes
hostApi.preventClose({ preventClose: true });

Parameters: { preventClose: boolean }

  • preventClose: true — blocks the plugin from being closed by the user
  • preventClose: false — removes the block

Example usage with React:

import { hostApi } from "@weavix/tracker-plugin-sdk-react";
import { useEffect, useState } from "react";

function MyEditor() {
    const [content, setContent] = useState("");
    const [saved, setSaved] = useState(true);

    const hasChanges = !saved;

    // Automatically set/remove the block when the state changes
    useEffect(() => {
        hostApi.preventClose({ preventClose: hasChanges });
    }, [hasChanges]);

    const handleSave = async () => {
        await saveContent(content);
        setSaved(true);
    };

    return (
        <div>
            <textarea
                value={content}
                onChange={(e) => {
                    setContent(e.target.value);
                    setSaved(false);
                }}
            />
            <button onClick={handleSave}>Save</button>
        </div>
    );
}

Important

  • Remember to remove the block (preventClose: false) after saving data, otherwise the user won't be able to close the plugin.
  • During forced closure (for example, navigating to another screen) Tracker may ignore the block.

uiApi

API for interacting with Tracker's user interface: showing notifications, displaying pop-ups, and more.

Toasts

Plugins can show toast notifications in the Tracker interface via uiApi.toaster. The API closely resembles useToaster from @gravity-ui/uikit.

Permission

The tracker:ui:toaster permission must be requested in manifest.json:

{
    "permissions": {
        "ui": ["toaster"]
    }
}
import { uiApi } from "@weavix/tracker-plugin-sdk-core";

// Simple toast
uiApi.toaster.add({
    title: "Saved",
    theme: "success",
});

// Toast with text content and custom display time
uiApi.toaster.add({
    title: "Error",
    theme: "danger",
    content: "Failed to load data",
    autoHiding: 10000,
});

// Toast with an action button
uiApi.toaster.add({
    title: "Item deleted",
    theme: "info",
    content: "QUEUE-123",
    actions: [
        {
            label: "Undo",
            onClick: () => {
                // handle click
            },
        },
    ],
});

Parameters

Parameter

Type

Default

Description

title

string

—

Toast title (required)

name

string

auto

Unique key for deduplication. Generated automatically if not provided

theme

'success' | 'danger' | 'warning' | 'info'

'info'

Theme (color and icon)

content

string

—

Text content below the title

autoHiding

number

5000

Display time in ms (from 1000 to 30000)

isClosable

boolean

true

Show close button

actions

ToastAction[]

—

Action buttons (max. 2)

ToastAction:

Parameter

Type

Description

label

string

Button text (max. 50 characters)

onClick

() => void

Callback on click

Returns: Promise<{ name: string }> — toast name (for identification).

Limitations:

  • title — max. 200 characters
  • content — max. 500 characters
  • actions — max. 2 buttons
  • Rate limit — 5 toasts per 10 seconds per plugin

Error handling

import {
    trackerApi,
    PluginActionError,
} from "@weavix/tracker-plugin-sdk-core";

try {
    await trackerApi.v3.get["/issues/{id}"]({ pathParams: { id: "BAD" } });
} catch (e) {
    if (e instanceof PluginActionError) {
        console.log(e.code, e.message, e.errorData);
    }
}

Confirm Dialog

A plugin can show a modal confirmation dialog. The dialog is rendered on the Tracker side (not inside the iframe), so it overlays the entire application and focuses the user on making a decision.

Permission

The tracker:ui:confirm permission must be requested in manifest.json:

{
    "permissions": {
        "ui": ["confirm"]
    }
}
import { uiApi } from "@weavix/tracker-plugin-sdk-core";

const { confirmed } = await uiApi.confirm.show({ message: "Are you sure?" });

Parameters

Parameter

Type

Limit

Default

Description

title

string

≤ 200

—

Dialog title

message

string

≤ 500

— (required)

Confirmation text

textButtonApply

string

≤ 50

"OK"

Confirm button text

textButtonCancel

string

≤ 50

"Cancel"

Cancel button text

theme

'normal' | 'danger'

—

'normal'

Theme for the apply button

Limits and errors

  • 1 active confirm per plugin. Attempting to open a second dialog while the first is active rejects the promise with CONFIRM_ALREADY_OPEN.
  • Maximum 5 simultaneous dialogs in the shared queue (from all plugins). If the queue overflows — QUEUE_OVERFLOW.
  • 5-minute timeout. If the user doesn't respond, the promise is rejected with Request timeout.
  • Closing the plugin iframe (removing it from the screen) automatically resolves all pending confirm dialogs for that plugin as { confirmed: false }.
  • Esc / clicking the close button — { confirmed: false }.

Programmatically open links

uiApi.navigate({
    path: `/path`,
    params: { a: "testParam" },
    options: { newTab: true },
});
type NavigateRequest = {
    path: string;
    params?: QueryParams;
    options?: {
        newTab?: boolean;
    };
};

Handling link clicks

  1. Relative links and links to the plugin domain => open in the plugin

  2. External links => are passed to Tracker via uiApi.navigate =>

    links to Tracker => open in the current tab or a new tab depending on target="_blank"
    external links => always open in a new tab

trackerApi (TrackerApi)

A class for calling the Tracker Public API via the platform (contract api.tracker.call). Access to endpoints is through the typed v3 API.

For method descriptions and response formats, see: Common format.

Exports the trackerApi singleton.

v3

An object with HTTP methods: get, post, put, patch, delete. Keys are endpoint paths from OpenAPI (@weavix/tracker-api-types); when accessing a path, the IDE shows hints and JSDoc.

Examples:

import { trackerApi } from "@weavix/tracker-plugin-sdk-core";

// GET
const data = await trackerApi.v3.get["/issues/{id}"]({
    pathParams: { id: "QUEUE-123" },
    queryParams: { expand: ["COMMENTS"] },
});

// POST
await trackerApi.v3.post["/v2/issues"]({
    bodyParams: { queue: { key: "TASK" }, summary: "New issue" },
});

//POST with file
await trackerApi.v3.post["/attachments"]({
    bodyParams: { filename },
    file,
});
  • v3.get[path](payload) — GET; payload: pathParams, optionally queryParams.
  • v3.post[path](payload) / put / patch — payload includes bodyParams (and if necessary pathParams, queryParams).
  • v3.delete[path](payload) — DELETE; payload: pathParams, optionally queryParams.

All requests via trackerApi.v3 send version: 'v3' in the contract.


storageApi

Platform JSON storage at the organization level — storageApi.orgShared.get / storageApi.orgShared.patch. A full description of the methods, patch merge semantics, versioning, and error codes is in the Data storage section.

import { storageApi } from "@weavix/tracker-plugin-sdk-core";

const record = await storageApi.orgShared.get("settings");
await storageApi.orgShared.patch({
    bucket: "settings",
    data: { theme: "dark" },
});

hostApi.externalApi*

Methods for calling external (non-Tracker) HTTP APIs through the platform's proxy with OAuth authorization support.

Direct requests

Call external APIs through hostApi.externalApiCall(). Direct HTTP requests from the plugin (fetch, XMLHttpRequest) are only possible to domains with access: ["direct"], but they don't support authorization and aren't recommended. For more information, see External APIs.

Add the permissions.external section to manifest.json with a list of allowed domains. For requests through the platform, set the access field to proxy:

{
    "permissions": {
        "external": [
            {
                "domain": "api.example.com",
                "access": ["proxy"],
                "authorization": {
                    "type": "oauth",
                    "scopes": ["read", "write"],
                    "contextTypes": ["user"]
                }
            },
            {
                "domain": "cdn.example.com",
                "access": ["proxy"]
            }
        ]
    }
}

The authorization field is optional — you can omit it for domains that don't require authorization (for example, public CDNs). The "token" type is used for API keys and other non-OAuth tokens.

Only the user's personal tokens are supported: specify "user" in the manifest contextTypes and in the contextType parameter of the methods. The "organization" value exists in the SDK types, but the platform doesn't support it. For more information about authorization, see Proxy authorization.

externalApiCall()

Executes an HTTP request to an external API through the platform proxy. The URL must belong to a domain allowed in permissions.external; the platform adds authorization headers.

Parameters:

Parameter

Type

Default

Description

url

string

—

Full request URL (required)

method

'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'

—

HTTP method (required)

headers

Record<string, string>

—

Additional headers

body

Record<string, unknown>

—

Request body

timeoutMs

number

—

Request timeout in milliseconds

contextType

'user' | 'organization'

—

Credential context for the proxy

Returns: Promise<{ status: number; headers?: Record<string, string>; body?: Record<string, unknown> }>

If the proxy request fails, throws PluginActionError with code EXTERNAL_API_CALL_ERROR (1013); details are in e.errorData.

import {
    hostApi,
    PluginActionError,
    EXTERNAL_API_CALL_ERROR,
} from "@weavix/tracker-plugin-sdk-core";

// GET
const { status, body } = await hostApi.externalApiCall({
    url: "https://api.example.com/v1/items",
    method: "GET",
    contextType: "user",
});

// POST with body and timeout
const result = await hostApi.externalApiCall({
    url: "https://api.example.com/v1/items",
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: { name: "New item", value: 42 },
    contextType: "user",
    timeoutMs: 10000,
});

// Error handling
try {
    await hostApi.externalApiCall({
        url: "https://api.example.com/data",
        method: "GET",
    });
} catch (e) {
    if (e instanceof PluginActionError && e.code === EXTERNAL_API_CALL_ERROR) {
        console.error("Proxy error:", e.errorData);
    }
}

externalApiAuthCheckAndRequest()

Combines checking the authorization status and requesting credentials only for unauthenticated domains. If all domains are already authenticated — immediately returns { success: true } without a dialog.

Parameters:

Parameter

Type

Default

Description

domains

string[]

all plugin domains

Domains to check

contextType

'user' | 'organization'

—

Credential context type

Returns: Promise<{ success: boolean }> — false if the user closed the dialog or the timeout expired (~5 minutes).

const { success } = await hostApi.externalApiAuthCheckAndRequest({
    domains: ["api.example.com"],
    contextType: "user",
});
if (!success) return;

externalApiAuthGetStatus()

Returns the authorization status for domains.

Parameters:

Parameter

Type

Default

Description

domains

string[]

all plugin domains

Domains to check

contextType

'user' | 'organization'

—

Credential context type

Returns: Promise<{domains: Array<{domain: string; contextType: AuthContextType; authenticated: boolean}>}>

const { domains } = await hostApi.externalApiAuthGetStatus({
    domains: ["api.example.com"],
    contextType: "user",
});
const isAuthed = domains.every((d) => d.authenticated);

externalApiAuthRequest()

Shows the user a dialog for entering credentials for the specified domains. If confirmed successfully, the platform saves the credentials.

Parameters:

Parameter

Type

Default

Description

domains

ExternalApiDomainInfo[]

—

Domains (required, at least one)

ExternalApiDomainInfo:

Field

Type

Description

domain

string

Domain from the manifest

instructions

string \| { en?: string; ru?: string }

Hint in the dialog (optional)

Returns: Promise<{ success: boolean }> — false if the user closed the dialog.

await hostApi.externalApiAuthRequest({
    domains: [
        {
            domain: "api.example.com",
            instructions: { ru: "Войдите в Example", en: "Sign in to Example" },
        },
    ],
});

externalApiAuthRevoke()

Revokes the saved authorization for the specified domains.

Parameters:

Parameter

Type

Default

Description

domains

string[]

—

Domains to revoke (required, at least one)

contextType

'user' | 'organization'

—

Credential context type

Returns: Promise<{ success: boolean }>

await hostApi.externalApiAuthRevoke({
    domains: ["api.example.com"],
    contextType: "user",
});

Types

TrackerApiInitOptions

Options for creating a TrackerApi instance (if not using the singleton). Currently, only trackerApi is exported from core, and no options are passed.

interface TrackerApiInitOptions {
    apiVersion?: string;
}

TrackerApiCallOptions

Parameters for calling a v3 endpoint: pathParams, queryParams, bodyParams.

interface TrackerApiCallOptions {
    pathParams?: Record<string, string>;
    queryParams?: Record<string, unknown>;
    bodyParams?: Record<string, unknown>;
}

TrackerApiV3

Type of the trackerApi.v3 object: get/post/put/patch/delete methods with typed paths (from @weavix/tracker-api-types).


Theme

Tracker theme type.

type Theme = "light" | "light-hc" | "dark" | "dark-hc" | "system";

SlotContextMap

Mapping of slot names to full context types (level: 'full'). For example, the issue.action slot provides a context of type Issue. Context types (Issue, etc.) are defined by the @weavix/tracker-api-types package.

When level: 'basic', instead of the full entity object, BasicContext is returned:

type BasicContext = {
    /** Identifier of the current entity */
    entityId: string;
    /** Additional basic information.
     *  For example, for a comment, it contains the parent ticket identifier. */
    entityMeta?: Record<string, string>;
};

// Basic context: only entityId and entityMeta
const basicContext = await hostApi.getContext("basic");
// basicContext.entityId — entity identifier

// Full context: for the 'issue.action' slot, returns Issue
// Requires contextLevel: 'full' in manifest.json
const fullContext = await hostApi.getContext("full");

ContentSizeUpdateRequest

Request to change the plugin content size.

type ContentSizeUpdateRequest = { height?: number };

HostInitOptions

Options for initializing interaction with Tracker (passed to hostApi.init()).

interface HostInitOptions {
    /** Auto-resize based on content, defaults to true */
    autoResize?: boolean;
}

API error codes

When calling methods, the platform may return an error with a code. Constants are exported from the package:

import {
    EXTERNAL_API_CALL_ERROR,
    METHOD_NOT_SUPPORTED,
    MISSING_REQUIRED_SCOPE,
    PLUGIN_ID_IS_NOT_CORRECT,
    PLUGIN_ID_OR_SLOT_NOT_PROVIDED,
    UNKNOWN_ERROR,
    VALIDATION_ERROR,
} from "@weavix/tracker-plugin-sdk-core";

Constant

Code

Description

PLUGIN_ID_OR_SLOT_NOT_PROVIDED

1000

Required plugin initialization parameters are missing.

PLUGIN_ID_IS_NOT_CORRECT

1001

Incorrect or mismatched pluginId.

VALIDATION_ERROR

1002

Request validation error.

METHOD_NOT_SUPPORTED

1003

Method is not supported.

MISSING_REQUIRED_SCOPE

1004

Insufficient permissions (scope).

EXTERNAL_API_CALL_ERROR

1013

Error occurred while executing an HTTP request via hostApi.externalApiCall().

UNKNOWN_ERROR

6666

Unknown error.


Utils

getLocalizedString()

Returns a localized string based on the language code. The LocalizedString type is exported from @weavix/tracker-api-types and re-exported from core.

function getLocalizedString(
    value: LocalizedString,
    language: string,
    fallbackLanguage?: string,
): string;

getField()

Extracts a value from an object using a dot notation path.

function getField<T = unknown>(
    obj: Record<string, unknown>,
    path: string,
    defaultValue?: T,
): T | undefined;

Handlers

getHandler, setHandler, types HandlerFunction, Handlers, HttpMethod are exported — for registering request handlers from the Tracker side (see the contract and slots).


Complete Example

import {
    hostApi,
    trackerApi,
    getField,
    type Theme,
} from "@weavix/tracker-plugin-sdk-core";

// Initialization is typically done in TrackerPluginProvider (react)
hostApi.init({ autoResize: true });

const theme: Theme = await hostApi.getTheme();
const language = await hostApi.getLanguage();
const context = await hostApi.getContext();

// Calling Tracker API v3 (version: 'v3' is sent in the payload)
const issue = await trackerApi.v3.get["/issues/{id}"]({
    pathParams: { id: "KEY-1" },
    queryParams: { expand: ["COMMENTS"] },
});

const summary = getField<string>(issue, "summary", "No summary");

await hostApi.notifyReady();

Request/response types for endpoints (Issue, types for creating issues, queues, etc.) are defined by the @weavix/tracker-api-types package.

Previous