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


# External APIs

A plugin can call external HTTP APIs in two ways:

- **[Requests through the platform](#proxy)** — the plugin calls `hostApi.externalApiCall()`, and the platform proxy executes the request from its backend. This is the primary method: the platform authorizes the request, runs audits, applies rate limits, and blocks unsafe destinations.
- **[Direct requests](#direct-access)** — the plugin sends the request from the browser using `fetch` or `XMLHttpRequest`. The platform isn't involved in such requests, so they don't support authorization and aren't recommended.

The access method for each domain is set in the manifest.

## Manifest permission {#manifest}

Add the `permissions.external` section to `manifest.json` with a list of allowed domains and the access methods for them:

```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"
                }
            }
        ]
    }
}
```

In the `domain` field, specify the hostname without the protocol, path, or port. Declare each domain only once.

The `access` field sets the access method for the domain:

- `proxy` — [requests through the platform](#proxy) using `hostApi.externalApiCall()`;
- `direct` — [direct requests](#direct-access) from the browser. The platform adds the domain to the `connect-src` directive of the plugin's CSP.

If the `access` field isn't specified, both methods are allowed. Specify `access` explicitly and allow only the method the plugin uses — usually `["proxy"]`. A domain with `access: ["proxy"]` isn't added to the CSP, so the browser will block direct requests to it.

The `authorization` field is optional — you can omit it for domains that don't require authorization.

### Proxy authorization {#proxy-auth}

The `authorization` field describes which token a domain requires and how to insert it into the request, but **does not contain the token itself**:

- `type` — `oauth` for an OAuth token or `token` for an API key and other non-OAuth tokens;
- `scopes` — the minimum token permissions the plugin needs. The field only declares the permissions and doesn't grant them to the token;
- `contextTypes` — the token storage context. Always specify `["user"]`: only the user's personal tokens are supported.

In the `instructions` field, tell the user where to get a token and which permissions to grant it, in Russian and English.

Authorization takes place on the Tracker side:

1. The plugin calls `hostApi.externalApiAuthCheckAndRequest()` with the `user` context.
1. If the user doesn't have a token for the domain yet, Tracker shows a token entry dialog with the instructions from the manifest.
1. Tracker saves the token for the current user and domain. The plugin only receives the `{ success: boolean }` result — the token itself never reaches the plugin.
1. When `hostApi.externalApiCall()` is called, the platform inserts the token into the request and executes it from its backend.

If the token stops working, for example, expires, the user needs to enter a new token.

## Requests through the platform {#proxy}

This is the primary way to call external APIs. The plugin passes the request parameters — URL, method, headers, and body — to `hostApi.externalApiCall()`, and the platform executes the request from its backend and returns the result. The platform:

- Inserts a token into the request if the `authorization` field is configured for the domain. The token isn't passed to the plugin's iframe.
- Blocks requests to unsafe destinations: private networks, `localhost`, and unauthorized redirects.
- Runs request audits.
- Applies rate limits per plugin and organization.

To send requests to a domain through the platform, specify `access: ["proxy"]` for it in the manifest.


### Basic usage {#basic-usage}

**A typical scenario** — check authorization, request it from the user if needed, then call the API:

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

async function fetchItems() {
    // Check authorization and show the dialog if needed
    const { success } = await hostApi.externalApiAuthCheckAndRequest({
        domains: ["api.example.com"],
        contextType: "user",
    });
    if (!success) {
        // The user closed the dialog or the timeout expired
        return;
    }

    // Call the external API through the host's proxy
    const { status, body } = await hostApi.externalApiCall({
        url: "https://api.example.com/v1/items",
        method: "GET",
        contextType: "user",
    });
    // status — HTTP response status
    // body   — response body (Record<string, unknown>)
}
```

**POST with a body and timeout:**

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

### Error handling {#errors}

On a network error or an error response status, the host throws a `PluginActionError` with the code `EXTERNAL_API_CALL_ERROR` (`1013`). Details are in `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);
    }
}
```

### Managing authorization {#auth}

**The quick way** — `externalApiAuthCheckAndRequest` checks authorization and, if needed, shows the dialog in a single call; see the example above.

**Manual control.** If you need finer-grained control, use the individual methods:

```tsx
// Check the status for domains
const { domains } = await hostApi.externalApiAuthGetStatus({
    domains: ["api.example.com"],
    contextType: "user",
});
const isAuthed = domains.every((d) => d.authenticated);

// Show the authorization dialog with a hint
if (!isAuthed) {
    await hostApi.externalApiAuthRequest({
        domains: [
            {
                domain: "api.example.com",
                instructions: {
                    ru: "Войдите в Example",
                    en: "Sign in to Example",
                },
            },
        ],
    });
}

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

For more details on the methods, see [hostApi.externalApi\*](https://yandex.ru/support/tracker/en/plugins/tools/sdk/core.md#externalApi).

## Direct requests {#direct-access}

{% note warning %}

Direct requests don't support authorization and aren't recommended. Use [requests through the platform](#proxy) instead.

{% endnote %}

If the domain's `access` field includes `direct`, the plugin can send requests to it from the browser using `fetch` or `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();
```

The platform only adds the domain to the `connect-src` directive of the plugin's CSP and isn't involved in the request:

- It doesn't insert tokens: you can't specify the `authorization` field for such a domain.
- It doesn't block unsafe destinations, run audits, or apply rate limits.

The external service must support [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) for the plugin's origin. The `direct` method only extends the `connect-src` directive: loading images, scripts, and styles from the domain is still blocked.
