> For the complete documentation index, see [llms.txt](https://anonym-team.gitbook.io/anonym-browser-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://anonym-team.gitbook.io/anonym-browser-docs/uk/app/local-api.md).

# Локальний API

Через локальний API можна керувати Anonym Browser зі своїх скриптів: отримувати список профілів, запускати й зупиняти їх, підключати Puppeteer або Playwright до запущеного профілю, створювати проксі, закладки та сценарії. Усе, що можна зробити вручну в застосунку, можна зробити запитом.

Сторінка для тих, хто пише код. Якщо ви хочете керувати профілями через ШІ-асистента (Claude, Cursor), дивіться [MCP-сервер для ШІ-агентів](/anonym-browser-docs/uk/app/mcp.md).

{% file src="/files/SeSF1rIDz3PfKjy2NPDs" %}
Повний опис усіх методів у форматі OpenAPI 3 — відкрийте в Postman, Insomnia або Swagger Editor
{% endfile %}

## Як це працює

* API працює, поки запущено застосунок і виконано вхід в обліковий запис. Окремо вмикати його не потрібно.
* Адреса за замовчуванням — `http://127.0.0.1:32771`. Підключитися можна лише з цього самого комп’ютера.
* Ключів і токенів немає: запит від будь-якої програми на вашому комп’ютері виконується від імені облікового запису, у який ви ввійшли.
* Запити з вебсторінок і розширень браузера відхиляються. Викликайте API зі скриптів: curl, Python, Node.js, PowerShell.

## Дізнатися порт

1. У лівому меню натисніть **API** — відкриється вікно **Налаштування** на блоці **API-порт**.
2. Перегляньте рядок **Фактичний активний порт**. Якщо порт `32771` зайнятий іншою програмою, застосунок вибере вільний — у скриптах використовуйте саме фактичний.

Свій порт можна вказати в полі **API-порт** (від 1024 до 65535) і натиснути **Зберегти**. Сервер перезапуститься на новому порту.

Перевірте підключення:

```bash
curl http://127.0.0.1:32771/health
```

```json
{ "ok": true, "service": "anonym-browser-local-api", "version": "1.6.0" }
```

## Основні правила

* **Майже всі запити прив’язані до оточення.** Спершу отримайте `id` оточення через `GET /v1/environments`, потім використовуйте його в шляху: `/v1/environments/{environmentId}/profiles`.
* **Ідентифікатори — рядки**, навіть якщо схожі на числа: `"9007199254740993"`.
* **Тіло запиту — JSON** із заголовком `Content-Type: application/json`. Для `POST`-запитів без параметрів (наприклад, запуск профілю) передавайте порожній об’єкт `{}`.
* **Списки посторінкові**: параметри `page` і `limit` (до 100), у відповіді — `items` і `pagination`.
* **Запуск і зупинка профілю асинхронні**: відповідь `202` містить операцію. Дочекайтеся її завершення запитом `GET /v1/operations/{id}?waitMs=25000` — він сам чекає до 25 секунд, опитувати щосекунди не потрібно.

## Приклади

### Отримати оточення і профілі

```bash
curl http://127.0.0.1:32771/v1/environments
curl "http://127.0.0.1:32771/v1/environments/42/profiles?limit=50&search=shop"
```

У PowerShell:

```powershell
Invoke-RestMethod http://127.0.0.1:32771/v1/environments
```

Відповідь зі списком профілів (скорочено):

```json
{
  "items": [
    {
      "id": "9007199254740993",
      "name": "Shop 1",
      "runtime": { "state": "stopped" }
    }
  ],
  "pagination": { "page": 1, "limit": 50, "total": 1 }
}
```

### Запустити профіль і підключити Playwright або Puppeteer

Сценарій: запустити профіль, відкрити в ньому сайт своїм кодом і зупинити профіль. Адресу для підключення повертає `GET …/profiles/{profileId}/automation` у полі `wsEndpoint`.

{% tabs %}
{% tab title="Python + Playwright" %}

```python
import requests
from playwright.sync_api import sync_playwright

BASE = "http://127.0.0.1:32771"
ENV_ID = "42"                     # id оточення
PROFILE_ID = "9007199254740993"   # id профілю


def api(method, path, **kwargs):
    response = requests.request(method, BASE + path, timeout=60, **kwargs)
    data = response.json()
    if not response.ok:
        error = data["error"]
        raise RuntimeError(f"{response.status_code} {error['code']}: {error['message']}")
    return data


def wait(operation):
    while operation["status"] in ("queued", "running"):
        operation = api("GET", f"/v1/operations/{operation['id']}", params={"waitMs": 25000})
    if operation["status"] != "succeeded":
        raise RuntimeError(operation["error"])
    return operation


profile_path = f"/v1/environments/{ENV_ID}/profiles/{PROFILE_ID}"

wait(api("POST", f"{profile_path}/start", json={}))
ws_endpoint = api("GET", f"{profile_path}/automation")["wsEndpoint"]

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(ws_endpoint)
    context = browser.contexts[0]  # контекст профілю: його cookies і розширення
    page = context.new_page()
    page.goto("https://example.com")
    print(page.title())
    page.close()

# Зупиняйте профіль через API, а не з Playwright: так дані профілю збережуться
wait(api("POST", f"{profile_path}/stop", json={}))
```

{% endtab %}

{% tab title="Node.js + Puppeteer" %}

```javascript
import puppeteer from "puppeteer-core";

const BASE = "http://127.0.0.1:32771";
const envId = "42";
const profileId = "9007199254740993";
const profilePath = `/v1/environments/${envId}/profiles/${profileId}`;

async function api(path, { method = "GET", body } = {}) {
  const response = await fetch(BASE + path, {
    method,
    headers: body ? { "Content-Type": "application/json" } : {},
    body: body ? JSON.stringify(body) : undefined,
  });
  const data = await response.json();
  if (!response.ok) throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
  return data;
}

async function wait(operation) {
  while (["queued", "running"].includes(operation.status)) {
    operation = await api(`/v1/operations/${operation.id}?waitMs=25000`);
  }
  if (operation.status !== "succeeded") throw new Error(operation.error?.message);
  return operation;
}

await wait(await api(`${profilePath}/start`, { method: "POST", body: {} }));
const { wsEndpoint } = await api(`${profilePath}/automation`);

const browser = await puppeteer.connect({ browserWSEndpoint: wsEndpoint, defaultViewport: null });
const page = await browser.newPage();
await page.goto("https://example.com");
console.log(await page.title());
await browser.disconnect(); // не browser.close(): профіль зупиняємо через API

await wait(await api(`${profilePath}/stop`, { method: "POST", body: {} }));
```

{% endtab %}
{% endtabs %}

### Запустити кілька профілів одним запитом

Масові запити заощаджують ліміт: один запит замість десятків. За раз можна запустити або зупинити до 100 профілів.

```bash
curl -X POST http://127.0.0.1:32771/v1/environments/42/profiles/start \
  -H "Content-Type: application/json" \
  -d '{"profileIds": ["9007199254740993", "9007199254740994"]}'
```

У відповіді для кожного профілю буде `operationId` (запуск почався) або `error` (чому не запустився).

### Додати проксі

```bash
curl -X POST http://127.0.0.1:32771/v1/environments/42/proxies \
  -H "Content-Type: application/json" \
  -d '{"proxies": [{"name": "DE Berlin", "protocol": "socks5", "host": "203.0.113.10", "port": 1080, "login": "user123", "password": "pass123"}]}'
```

## Що можна робити через API

| Розділ                 | Що доступно                                                                                                                                                    |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Оточення               | Список, створення, перейменування, видалення командного оточення або вихід із нього, ліміти тарифу                                                             |
| Профілі                | Створення (зокрема з пресета), зміна будь-яких налаштувань, новий відбиток, клонування, перенесення в інше оточення, теги, статуси та області видимості, кошик |
| Запуск                 | Запуск і зупинка одного або до 100 профілів, адреса для Puppeteer і Playwright, повторна синхронізація                                                         |
| Cookies                | Читання cookies профілів та імпорт cookies у профіль                                                                                                           |
| Пресети профілів       | Створення, зміна, копіювання, імпорт і експорт                                                                                                                 |
| Проксі                 | Додавання, імпорт рядками, перевірка, зміна IP, експорт, копіювання в інше оточення                                                                            |
| Закладки та розширення | Додавання, зміна, видалення, копіювання в інше оточення; пошук розширень у Chrome Web Store                                                                    |
| Команда                | Учасники, пресети прав, запрошення, доступ учасників до профілів                                                                                               |
| Сценарії               | Створення, імпорт і експорт, тестовий запуск, запуск на профілях, скасування, Cookie-робот                                                                     |
| Журнал                 | Записи журналу дій із фільтрами                                                                                                                                |

Точні параметри кожного запиту — у файлі OpenAPI на початку сторінки.

## Ліміт запитів

Усі скрипти й ШІ-агенти на комп’ютері витрачають один спільний ліміт запитів на хвилину. Він залежить від тарифу оточення.

* Поточний ліміт показує `GET /v1/app` у полі `rateLimit.requestsPerMinute` (`null` — без обмеження).
* У кожній відповіді є заголовки `X-RateLimit-Limit` і `X-RateLimit-Remaining`.
* У разі перевищення надходить `429` і заголовок `Retry-After` — зачекайте вказану кількість секунд і повторіть.

Щоб не впиратися в ліміт, використовуйте масові запити й `waitMs` замість частого опитування.

## Помилки

Помилка надходить в єдиному форматі:

```json
{
  "error": {
    "code": "PROFILE_NOT_RUNNING",
    "message": "The profile is not running",
    "requestId": "req_7f3c2a91"
  }
}
```

| Код                                    | Що означає                                                                                | Що зробити                                                            |
| -------------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `401 APP_NOT_AUTHENTICATED`            | У застосунку не виконано вхід                                                             | Увійдіть в обліковий запис у застосунку                               |
| `403 FREE_PLAN_FEATURE_UNAVAILABLE`    | Функція недоступна на тарифі оточення, наприклад створення кількох профілів одним запитом | Створюйте по одному або використовуйте оточення з відповідним тарифом |
| `409 PROFILE_NOT_RUNNING`              | Профіль не запущено на цьому комп’ютері                                                   | Спершу запустіть профіль і дочекайтеся завершення операції            |
| `409 PROFILE_BUSY`                     | Профілем зараз керує сценарій або ШІ-агент                                                | Дочекайтеся завершення або зупиніть сценарій                          |
| `415 LOCAL_API_UNSUPPORTED_MEDIA_TYPE` | Немає заголовка `Content-Type: application/json`                                          | Додайте заголовок і JSON-тіло                                         |
| `429 LOCAL_API_RATE_LIMIT`             | Перевищено ліміт запитів                                                                  | Зачекайте `Retry-After` секунд                                        |
| `503 LOCAL_API_LIMITS_UNAVAILABLE`     | Застосунок ще не отримав ліміти із сервера                                                | Перевірте інтернет і повторіть за хвилину                             |
| `LOCAL_API_ORIGIN_FORBIDDEN`           | Запит надіслано з вебсторінки або розширення                                              | Викликайте API зі скрипта, а не з браузера                            |
