Skip to content

Введение в API ​

API PWA Hub нужен для ваших скриптов: выгрузить статистику и конверсии, наклонировать PWA под новую кампанию, повесить домен, включить или выключить приложение - без ручной работы в панели.

Через API доступно то же, что вы делаете в панели, и с теми же правами: скрипт видит и меняет ровно те PWA, сплиты и прочие ресурсы, что и вы - team_lead ресурсы своих команд, customer свои, и те и другие - открытые им через группы доступа. Настройки, пользователи, аккаунты интеграций, пароль и сам ключ через API недоступны - только из панели.

Коллекция для Postman

Все методы API готовы к запуску без кода: скачайте коллекцию, импортируйте её в Postman и задайте переменные baseUrl (адрес вашей панели с /api) и apiKey.

Получение ключа ​

  1. Администратор включает вам Manage API Token (см. раздел «Пользователи»). Это нужно и самим администраторам: без переключателя ключ не выдаётся и не работает.
  2. Откройте Profile и в карточке API Key нажмите Generate Key (см. раздел «Профиль»).
  3. Скопируйте ключ и сохраните его в настройках скрипта.

Ключ - это пароль

С ключом можно делать всё, что можете вы сами. Не публикуйте его в репозиториях, чатах и коде, который выполняется в браузере. Если ключ утёк - перевыпустите его в профиле, старый перестанет работать сразу.

API работает, только если он входит в вашу лицензию, и только пока лицензия активна.

Запрос ​

Адрес API - домен вашей панели с /api на конце, например https://panel.example.com/api. Ключ передаётся в заголовке Authorization, тело запроса - JSON:

bash
curl https://panel.example.com/api/user/profile \
  -H "Authorization: Bearer ВАШ_КЛЮЧ" \
  -H "Accept: application/json"
php
<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';

$api = new GuzzleHttp\Client([
    'base_uri' => 'https://panel.example.com/api/',
    'headers' => ['Authorization' => 'Bearer ВАШ_КЛЮЧ', 'Accept' => 'application/json'],
    'timeout' => 30,
]);

$response = $api->get('user/profile');
$user = json_decode($response->getBody(), true)['data']['user'];

echo $user['email'] . PHP_EOL;
python
# pip install requests
import requests

API = "https://panel.example.com/api"
HEADERS = {"Authorization": "Bearer ВАШ_КЛЮЧ", "Accept": "application/json"}

response = requests.get(f"{API}/user/profile", headers=HEADERS, timeout=30)
user = response.json()["data"]["user"]

print(user["email"])
js
// Node.js 18+, без зависимостей; сохраните как script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer ВАШ_КЛЮЧ', Accept: 'application/json', 'Content-Type': 'application/json' };

const response = await fetch(`${API}/user/profile`, { headers, signal: AbortSignal.timeout(30000) });
const { data } = await response.json();

console.log(data.user.email);

Этот запрос - удобная проверка ключа: он возвращает пользователя, которому ключ принадлежит, и его команды.

Идентификаторы ​

У всех объектов короткие строковые идентификаторы вида WZAX - и в ответах, и в запросах (team_id, cloudflare_id и т.д.). Берите их из ответов API или из адресной строки панели.

Ответ ​

Данные всегда лежат в поле data:

json
{
  "data": {
    "pwa": { "id": "WZAX", "name": "Promo EN", "active": true }
  }
}

Списки приходят постранично: в data.meta - номер страницы и общее количество, рядом - сами записи под именем ресурса.

json
{
  "data": {
    "meta": { "current_page": 1, "per_page": 100, "last_page": 3, "total": 245 },
    "pwas": [ { "id": "WZAX", "name": "Promo EN" } ]
  }
}

Страница задаётся параметром page, её размер - per_page (по умолчанию 100). Чтобы забрать всё, идите по страницам, пока current_page не дойдёт до last_page.

Даты в ответах - в формате 05 Oct 2026 14:03, по UTC.

Ошибки ​

Ошибка - это HTTP-код и JSON с data: null и текстом в message:

json
{
  "data": null,
  "message": "The name field is required. (and 2 more errors)",
  "errors": {
    "name": ["The name field is required."],
    "cloudflare_id": ["The cloudflare id field is required."]
  }
}
КодКогдаЧто делать
401Unauthenticated - не передан заголовок Authorization; Invalid API key - ключ неверный, перевыпущен или у вас выключили Manage API Token; API key access is not enabled - API нет в лицензии; Account is not approved - аккаунт не подтверждёнПроверьте ключ в профиле, обратитесь к администратору
403Not available with an API key - этот метод доступен только из панели; This action is unauthorized. - нет прав на объект; или лицензия неактивна (тогда в ответе есть поле error)Проверьте, что объект в вашей команде
404Not found - объекта с таким идентификатором нетПроверьте идентификатор
422Ошибка в данных - в errors перечислены поля и что с ними не такИсправьте поля из errors
429Too many requests. Try again in a minute. или Too many invalid API key attempts. Try again in a minute. - превышен лимит, см. «Лимиты»Подождите минуту и повторите

Обработка ошибок ​

Проверяйте код ответа, прежде чем читать data. При ошибке выведите message, а для 422 - ещё и поля из errors: там сказано, что именно исправить. Пример ниже нарочно создаёт PWA без названия и печатает, что ответил сервер.

bash
curl -X POST https://panel.example.com/api/pwas \
  -H "Authorization: Bearer ВАШ_КЛЮЧ" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{}' \
  -w "\nHTTP %{http_code}\n"
php
<?php
// composer require guzzlehttp/guzzle
require 'vendor/autoload.php';

$api = new GuzzleHttp\Client([
    'base_uri' => 'https://panel.example.com/api/',
    'headers' => ['Authorization' => 'Bearer ВАШ_КЛЮЧ', 'Accept' => 'application/json'],
    'timeout' => 30,
    'http_errors' => false, // не бросать исключение на 4xx/5xx, разбираем ответ сами
]);

$response = $api->post('pwas', ['json' => []]);
$body = json_decode($response->getBody(), true);

if ($response->getStatusCode() >= 400) {
    echo "Ошибка {$response->getStatusCode()}: {$body['message']}" . PHP_EOL;
    foreach ($body['errors'] ?? [] as $field => $messages) {
        echo "  {$field}: " . implode(' ', $messages) . PHP_EOL;
    }
    exit(1);
}

echo "Создано PWA {$body['data']['pwa']['id']}" . PHP_EOL;
python
# pip install requests
import requests

API = "https://panel.example.com/api"
HEADERS = {"Authorization": "Bearer ВАШ_КЛЮЧ", "Accept": "application/json"}

response = requests.post(f"{API}/pwas", headers=HEADERS, json={}, timeout=30)
body = response.json()

if not response.ok:
    print(f"Ошибка {response.status_code}: {body['message']}")
    for field, messages in body.get("errors", {}).items():
        print(f"  {field}: {' '.join(messages)}")
    raise SystemExit(1)

print("Создано PWA", body["data"]["pwa"]["id"])
js
// Node.js 18+, без зависимостей; сохраните как script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer ВАШ_КЛЮЧ', Accept: 'application/json', 'Content-Type': 'application/json' };

const response = await fetch(`${API}/pwas`, {
  method: 'POST',
  headers,
  body: JSON.stringify({}),
  signal: AbortSignal.timeout(30000),
});
const body = await response.json();

if (!response.ok) {
  console.log(`Ошибка ${response.status}: ${body.message}`);
  for (const [field, messages] of Object.entries(body.errors ?? {})) {
    console.log(`  ${field}: ${messages.join(' ')}`);
  }
  process.exit(1);
}

console.log('Создано PWA', body.data.pwa.id);

Вывод:

Ошибка 422: The name field is required. (and 2 more errors)
  name: The name field is required.
  team_id: The team id field is required.
  cloudflare_id: The cloudflare id field is required.

Не повторяйте 4xx в цикле

Ошибки 4xx, кроме 429, сами не пройдут: повтор того же запроса даст тот же ответ. Повторять имеет смысл только 429 (через минуту) и ошибки сети или 5xx.

Лимиты ​

  • 300 запросов в минуту на пользователя - на все методы вместе.
  • 10 отправок пушей в минуту на пользователя (POST/pwa_pushes/{id}/send) - каждая отправка - это настоящая рассылка.
  • 10 отказов 401 по ключу в минуту с одного IP - неверный ключ, неподтверждённый аккаунт или API не в лицензии. Дальше любой запрос с ключом с этого IP получает 429 до конца минуты, отсчитанной от первого отказа, - даже с правильным ключом. Если скрипт поймал 401 - остановите его, а не повторяйте запрос.

Что доступно ​

РазделЧто можно
PWAсписок, просмотр, создание, изменение, включение и выключение, клонирование, архивирование
Сплитысписок, просмотр, создание, изменение, включение и выключение, клонирование, архивирование
Потокисписок, просмотр, добавление PWA в сплит, изменение веса, удаление из сплита
Доменысписок, добавление к PWA или сплиту, включение и пересоздание DNS, удаление
Пушисписок, просмотр, создание, изменение, предпросмотр, аудитория, отправка, клонирование, архивирование
Лендингисписок
Пиксели и тегисписок, просмотр, добавление, изменение, архивирование
Статистикадашборд, воронка, статистика по саб-меткам
Конверсиисписок, просмотр, повторная отправка в Facebook
Экспортконверсии и визиты в CSV за период
Справочникикоманды, аккаунты Cloudflare, аккаунты фильтрации и их потоки