---
metadata:
  - name: generator
    content: Diplodoc Platform v5.66.1
  - property: og:type
    content: article
  - property: article:section
    content: Платформа плагинов
  - property: og:title
    content: Внешние API
  - property: article:tag
    content: Техническая инструкция
alternate:
  - https://yandex.ru/support/tracker/en/plugins/externalApi.md
  - https://yandex.ru/support/tracker/ru/plugins/externalApi.md
  - href: https://yandex.ru/support/tracker/ru/plugins/externalApi.md
    type: text/markdown
    title: Markdown version
  - href: https://yandex.ru/support/tracker/ru/llms.txt?revision=r22057024
    rel: describedby
---
> **Documentation Index:** Fetch the complete configuration index at https://yandex.ru/support/tracker/ru/llms.txt?revision=r22057024


# Внешние API

Плагин может обращаться к внешним HTTP API двумя способами:

- **[Запросы через платформу](#proxy)** — плагин вызывает `hostApi.externalApiCall()`, а прокси платформы выполняет запрос со своего бекенда. Это основной способ: платформа авторизует запрос, ведет аудит, ограничивает частоту запросов и блокирует небезопасные направления.
- **[Прямые запросы](#direct-access)** — плагин отправляет запрос из браузера с помощью `fetch` или `XMLHttpRequest`. Платформа в таких запросах не участвует, поэтому они не поддерживают авторизацию и не рекомендуются к использованию.

Способ доступа к каждому домену задается в манифесте.

## Разрешение в манифесте {#manifest}

Добавьте в `manifest.json` секцию `permissions.external` с перечнем разрешенных доменов и способов доступа к ним:

```json
{
    "permissions": {
        "external": [
            {
                "domain": "api.example.com",
                "access": ["proxy"],
                "authorization": {
                    "type": "oauth",
                    "scopes": ["read", "write"],
                    "contextTypes": ["user"]
                },
                "instructions": {
                    "ru": "Создайте токен с правами read и write в настройках Example API",
                    "en": "Create a token with the read and write permissions in Example API settings"
                }
            }
        ]
    }
}
```

В поле `domain` укажите имя хоста без протокола, пути и порта. Каждый домен объявляйте один раз.

Поле `access` задает способ доступа к домену:

- `proxy` — [запросы через платформу](#proxy) с помощью `hostApi.externalApiCall()`;
- `direct` — [прямые запросы](#direct-access) из браузера. Платформа добавляет домен в директиву `connect-src` политики CSP плагина.

Если поле `access` не указано, разрешены оба способа. Указывайте `access` явно и разрешайте только тот способ, который использует плагин, — как правило, `["proxy"]`. Домен с `access: ["proxy"]` не добавляется в CSP, поэтому прямой запрос к нему браузер заблокирует.

Поле `authorization` опционально — его можно опустить для доменов без авторизации.

### Авторизация прокси {#proxy-auth}

Поле `authorization` описывает, какой токен нужен для домена и как его подставить в запрос, но **не содержит сам токен**:

- `type` — `oauth` для OAuth-токена или `token` для API-ключа и других не-OAuth токенов;
- `scopes` — минимальные права токена, которые нужны плагину. Поле только декларирует права и не выдает их токену;
- `contextTypes` — контекст хранения токена. Всегда указывайте `["user"]`: поддерживаются только личные токены пользователя.

В поле `instructions` укажите для пользователя, где получить токен и какие права ему выдать, на русском и английском языках.

Авторизация проходит на стороне Трекера:

1. Плагин вызывает `hostApi.externalApiAuthCheckAndRequest()` с контекстом `user`.
1. Если у пользователя еще нет токена для домена, Трекер показывает диалог ввода токена с инструкцией из манифеста.
1. Трекер сохраняет токен для текущего пользователя и домена. Плагин получает только результат `{ success: boolean }` — сам токен в плагин не попадает.
1. При вызове `hostApi.externalApiCall()` платформа подставляет токен в запрос и выполняет его со своего бекенда.

Если токен перестал работать, например, истек, пользователю нужно ввести новый токен.

## Запросы через платформу {#proxy}

Основной способ обращения к внешним API. Плагин передает параметры запроса — URL, метод, заголовки и тело — в `hostApi.externalApiCall()`, а платформа выполняет запрос со своего бекенда и возвращает результат. При этом платформа:

- подставляет в запрос токен, если для домена настроено поле `authorization`. Токен не передается в iframe плагина;
- блокирует запросы к небезопасным направлениям: приватным сетям, `localhost` и неразрешенным редиректам;
- ведет аудит запросов;
- ограничивает частоту запросов по плагину и организации.

Чтобы отправлять запросы к домену через платформу, укажите для него в манифесте `access: ["proxy"]`.


### Базовое использование {#basic-usage}

**Типичный сценарий** — проверить авторизацию, при необходимости запросить ее у пользователя, затем вызвать API:

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

async function fetchItems() {
    // Проверить авторизацию и показать диалог, если нужно
    const { success } = await hostApi.externalApiAuthCheckAndRequest({
        domains: ["api.example.com"],
        contextType: "user",
    });
    if (!success) {
        // Пользователь закрыл диалог или истек таймаут
        return;
    }

    // Вызвать внешний API через прокси платформы
    const { status, body } = await hostApi.externalApiCall({
        url: "https://api.example.com/v1/items",
        method: "GET",
        contextType: "user",
    });
    // status — HTTP-статус ответа
    // body   — тело ответа (Record<string, unknown>)
}
```

**POST с телом и таймаутом:**

```tsx
const { status, body } = 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,
});
```

### Обработка ошибок {#errors}

При сетевой ошибке или ответе с ошибочным статусом платформа возвращает `PluginActionError` с кодом `EXTERNAL_API_CALL_ERROR` (`1013`). Детали — в `e.errorData`:

```tsx
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);
    }
}
```

### Управление авторизацией {#auth}

**Быстрый путь** — `externalApiAuthCheckAndRequest` проверяет авторизацию и при необходимости показывает диалог в одном вызове, см. пример выше.

**Ручное управление.** Если нужен более тонкий контроль — используйте отдельные методы:

```tsx
// Проверить статус по доменам
const { domains } = await hostApi.externalApiAuthGetStatus({
    domains: ["api.example.com"],
    contextType: "user",
});
const isAuthed = domains.every((d) => d.authenticated);

// Показать диалог авторизации с подсказкой
if (!isAuthed) {
    await hostApi.externalApiAuthRequest({
        domains: [
            {
                domain: "api.example.com",
                instructions: {
                    ru: "Войдите в Example",
                    en: "Sign in to Example",
                },
            },
        ],
    });
}

// Отозвать сохраненные учетные данные
await hostApi.externalApiAuthRevoke({
    domains: ["api.example.com"],
    contextType: "user",
});
```

Подробнее о методах — в разделе [hostApi.externalApi\*](https://yandex.ru/support/tracker/ru/plugins/tools/sdk/core.md#externalApi).

## Прямые запросы {#direct-access}

{% note warning %}

Прямые запросы не поддерживают авторизацию и не рекомендуются к использованию. Используйте [запросы через платформу](#proxy).

{% endnote %}

Если в `access` домена указано значение `direct`, плагин может отправлять запросы к нему из браузера с помощью `fetch` или `XMLHttpRequest`:

```json
{
    "permissions": {
        "external": [
            {
                "domain": "cdn.example.com",
                "access": ["direct"]
            }
        ]
    }
}
```

```tsx
const response = await fetch("https://cdn.example.com/data.json");
const data = await response.json();
```

Платформа только добавляет домен в директиву `connect-src` политики CSP плагина и в запросе не участвует:

- не подставляет токены — поле `authorization` для такого домена указать нельзя;
- не блокирует небезопасные направления, не ведет аудит и не ограничивает частоту запросов.

Внешний сервис должен поддерживать [CORS](https://developer.mozilla.org/ru/docs/Web/HTTP/CORS) для источника (origin) плагина. Способ `direct` расширяет только директиву `connect-src`: загрузка изображений, скриптов и стилей с домена по-прежнему заблокирована.
