Skip to content

PWA ​

Методи для PWA-застосунків: знайти потрібні, створити нове, змінити налаштування, увімкнути або вимкнути, наклонувати й прибрати в архів. Що означають самі налаштування, див. розділ «PWA - створення (вкладка «Загальне»)» і сусідні сторінки довідника.

МетодАдресаЩо робить
GET/pwasСписок PWA
GET/pwas/{id}Одне PWA з усіма налаштуваннями
POST/pwasСтворити PWA
PUT/pwas/{id}Змінити, увімкнути або вимкнути
POST/pwas/{id}/cloneКлонувати
DELETE/pwas/{id}Прибрати в архів

Замініть ВАШ_КЛЮЧ і panel.example.com на свої.

Список PWA ​

GET/pwas

PWA ваших команд, нові й нещодавно змінені зверху. Архівні не показуються.

ПараметрЩо фільтрує
searchЧастина назви
domainЧастина домену, прив'язаного до PWA
statusactive - лише увімкнені, inactive - лише вимкнені
archived1 - лише архівні
team_idКоманда
offer_countryКраїна в посиланнях на пропозиції, дволітерний код (US, DE); PWA з посиланням під ANY теж потрапляють
group_idГрупа доступу
cloudflare_id, filter_account_idАкаунт Cloudflare або фільтрації
page, per_pageСторінка та її розмір (за замовчуванням 100)
bash
curl "https://panel.example.com/api/pwas?status=active&offer_country=US" \
  -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('pwas', ['query' => ['status' => 'active', 'offer_country' => 'US']]);
$pwas = json_decode($response->getBody(), true)['data']['pwas'];

foreach ($pwas as $pwa) {
    echo "{$pwa['id']} {$pwa['name']}: {$pwa['stat_installs']} встановлень" . 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}/pwas", headers=HEADERS, params={"status": "active", "offer_country": "US"}, timeout=30)
pwas = response.json()["data"]["pwas"]

for pwa in pwas:
    print(pwa["id"], pwa["name"], pwa["stat_installs"], "встановлень")
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?status=active&offer_country=US`, { headers, signal: AbortSignal.timeout(30000) });
const { data } = await response.json();

for (const pwa of data.pwas) {
  console.log(pwa.id, pwa.name, pwa.stat_installs, 'встановлень');
}
Відповідь
json
{
  "data": {
    "meta": { "current_page": 1, "per_page": 100, "last_page": 1, "total": 1 },
    "pwas": [
      {
        "id": "WZAX",
        "name": "Promo EN",
        "active": true,
        "archived": false,
        "filter_stream_id": null,
        "icon_url": "/api/pwas/WZAX/assets/icon-96.png",
        "stat_uniques": 1520,
        "stat_installs": 410,
        "stat_registrations": 96,
        "stat_deposits": 21,
        "stat_repeat_deposits": 7,
        "similar_count": 0,
        "team": { "id": "WQby", "name": "Team A" },
        "user": { "id": "WZAX", "name": "Buyer", "email": "[email protected]" },
        "domains": [ { "id": "Xk9P", "domain": "fit-tracker.example" } ],
        "groups": [],
        "created_at": "05 Oct 2026 14:03",
        "updated_at": "05 Oct 2026 14:03"
      }
    ]
  }
}

Лічильники stat_* - за весь час: унікальні відвідувачі, встановлення, реєстрації, депозити та повторні депозити. Статистику за період беріть із розділу «Статистика».

Помилки
КодmessageКоли
422The offer country field format is invalid.offer_country - не дві латинські літери

Одне PWA ​

GET/pwas/{id}

Усе про застосунок, включно з налаштуваннями в полі config.

bash
curl https://panel.example.com/api/pwas/WZAX \
  -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('pwas/WZAX');
$pwa = json_decode($response->getBody(), true)['data']['pwa'];

echo $pwa['name'] . ': ' . ($pwa['active'] ? 'увімкнено' : 'вимкнено') . 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}/pwas/WZAX", headers=HEADERS, timeout=30)
pwa = response.json()["data"]["pwa"]

print(pwa["name"], "увімкнено" if pwa["active"] else "вимкнено")
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/WZAX`, { headers, signal: AbortSignal.timeout(30000) });
const { data } = await response.json();

console.log(data.pwa.name, data.pwa.active ? 'увімкнено' : 'вимкнено');
Відповідь (скорочено)
json
{
  "data": {
    "pwa": {
      "id": "WZAX",
      "name": "Promo EN",
      "active": true,
      "cloudflare_id": "WZAX",
      "filter_account_id": null,
      "filter_stream_id": null,
      "domains": [ { "id": "Xk9P", "domain": "fit-tracker.example" } ],
      "config": {
        "general": { "name": "Fit Tracker", "language": "en", "templateAndroid": "google-v1" },
        "offerLinks": {
          "US": [ { "lang": "en", "link": "https://offer.example/?sub1={sub1}" } ]
        },
        "metrics": { "facebook": { "pixelId": null, "events": [] }, "google": { "tagId": null } },
        "comments": [],
        "translations": []
      },
      "similar": []
    }
  }
}

Поля config повторюють вкладки форми PWA: general - «Загальне», offerLinks - посилання на пропозиції за країнами, metrics - пікселі, comments - відгуки, translations - переклади.

У offerLinks країна ANY - запасна: її посилання отримує відвідувач, для якого не знайшлося посилання в його країні (країни немає в списку, вона не визначилась або в ній немає посилання під його мову); мова * - будь-яка. Зміна PWA з config потребує хоча б одного посилання, а за general.white.type = off - посилання під ANY.

Помилки
КодmessageКоли
403This action is unauthorized.Немає доступу до PWA: воно не з ваших команд (у customer - створене не ним) і не відкрите вам через групу доступу
404Not foundPWA з таким id немає

Створення PWA ​

POST/pwas

ПолеОбов'язковоЩо це
nameтакНазва PWA в панелі
cloudflare_idтакАкаунт Cloudflare, список - GET/cloudflares
team_idдля team_lead і adminКоманда: id з GET/teams (розділ «Довідники») або team.id будь-якого рядка GET/pwas; у customer підставляється його команда, передане значення не враховується
activeніtrue - одразу увімкнути. За замовчуванням PWA створюється вимкненим
filter_account_id, filter_stream_idніАкаунт фільтрації та потік у ньому
configніНалаштування, як у відповіді GET/pwas/{id}
bash
curl -X POST https://panel.example.com/api/pwas \
  -H "Authorization: Bearer ВАШ_КЛЮЧ" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Promo EN",
    "team_id": "WQby",
    "cloudflare_id": "WZAX",
    "config": {
      "general": { "name": "Fit Tracker", "language": "en", "templateAndroid": "google-v1" },
      "offerLinks": { "US": [ { "lang": "en", "link": "https://offer.example/?sub1={sub1}" } ] }
    }
  }'
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->post('pwas', ['json' => [
    'name' => 'Promo EN',
    'team_id' => 'WQby',
    'cloudflare_id' => 'WZAX',
    'config' => [
        'general' => ['name' => 'Fit Tracker', 'language' => 'en', 'templateAndroid' => 'google-v1'],
        'offerLinks' => ['US' => [['lang' => 'en', 'link' => 'https://offer.example/?sub1={sub1}']]],
    ],
]]);
$pwa = json_decode($response->getBody(), true)['data']['pwa'];

echo "Створено PWA {$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={
    "name": "Promo EN",
    "team_id": "WQby",
    "cloudflare_id": "WZAX",
    "config": {
        "general": {"name": "Fit Tracker", "language": "en", "templateAndroid": "google-v1"},
        "offerLinks": {"US": [{"lang": "en", "link": "https://offer.example/?sub1={sub1}"}]},
    },
}, timeout=30)
pwa = response.json()["data"]["pwa"]

print("Створено PWA", 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({
    name: 'Promo EN',
    team_id: 'WQby',
    cloudflare_id: 'WZAX',
    config: {
      general: { name: 'Fit Tracker', language: 'en', templateAndroid: 'google-v1' },
      offerLinks: { US: [{ lang: 'en', link: 'https://offer.example/?sub1={sub1}' }] },
    },
  }),
  signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();

console.log('Створено PWA', data.pwa.id);

Відповідь - створене PWA в data.pwa, з active, archived, team, user і порожнім domains. Домен до PWA прив'язується окремо, див. розділ «Домени».

Помилки
КодmessageКоли
422The name field is required. (and 2 more errors)Немає name, cloudflare_id або team_id - у errors вказано, яких саме
422You do not have access to this teamteam_id - команда, у якій вас немає
422The cloudflare id field must be an integer.cloudflare_id не знайдено - передано неправильний id
422The offer links country "USA" must be a two-letter code or ANY.Країна в config.offerLinks - не дволітерний код і не ANY
422The link field format is invalid.Посилання на пропозицію не починається з http:// або https://
422The selected template android is invalid.Невідомий шаблон у config.general.templateAndroid / templateIos

Простіше клонувати

Налаштувань у PWA багато, і збирати config з нуля довго. Зазвичай зручніше налаштувати одне PWA в панелі, а нові робити його клонами.

Зміна, увімкнення та вимкнення ​

PUT/pwas/{id}

Змінює лише передані поля. Приймає ті самі поля, що й створення.

team_id під час зміни не обов'язковий: без нього PWA лишається у своїй команді, а передати його потрібно лише щоб перенести PWA в іншу команду (team_lead - в одну зі своїх). customer змінює лише свої PWA та відкриті йому через групу доступу.

Увімкнути PWA:

bash
curl -X PUT https://panel.example.com/api/pwas/WZAX \
  -H "Authorization: Bearer ВАШ_КЛЮЧ" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"active": true}'
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->put('pwas/WZAX', ['json' => ['active' => true]]);
$pwa = json_decode($response->getBody(), true)['data']['pwa'];

echo $pwa['name'] . ': ' . ($pwa['active'] ? 'увімкнено' : 'вимкнено') . PHP_EOL;
python
# pip install requests
import requests

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

response = requests.put(f"{API}/pwas/WZAX", headers=HEADERS, json={"active": True}, timeout=30)
pwa = response.json()["data"]["pwa"]

print(pwa["name"], "увімкнено" if pwa["active"] else "вимкнено")
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/WZAX`, {
  method: 'PUT',
  headers,
  body: JSON.stringify({ active: true }),
  signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();

console.log(data.pwa.name, data.pwa.active ? 'увімкнено' : 'вимкнено');

Вимкнути - те саме з "active": false. Учасники команди отримають сповіщення, що PWA зупинено.

config замінюється повністю

Якщо в запиті є config, він замінює всі налаштування PWA, а не доповнює їх: усе, чого немає в запиті, зітреться. Тому спершу отримайте поточний config, змініть у ньому потрібне й надішліть назад повністю.

Змінити посилання на пропозицію для США:

bash
# 1. Збережіть поточне PWA
curl https://panel.example.com/api/pwas/WZAX \
  -H "Authorization: Bearer ВАШ_КЛЮЧ" -H "Accept: application/json" > pwa.json

# 2. Змініть посилання й надішліть config повністю (потрібен jq)
jq '{config: (.data.pwa.config
     | .offerLinks.US = [{"lang": "en", "link": "https://new-offer.example/?sub1={sub1}"}])}' pwa.json \
| curl -X PUT https://panel.example.com/api/pwas/WZAX \
    -H "Authorization: Bearer ВАШ_КЛЮЧ" -H "Accept: application/json" \
    -H "Content-Type: application/json" -d @-
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,
]);

// 1. Поточне PWA
$pwa = json_decode($api->get('pwas/WZAX')->getBody(), true)['data']['pwa'];

// 2. Змінюємо посилання для США, решта config лишається як була
$config = $pwa['config'];
$config['offerLinks']['US'] = [['lang' => 'en', 'link' => 'https://new-offer.example/?sub1={sub1}']];

// 3. Надсилаємо config повністю
$response = $api->put('pwas/WZAX', ['json' => ['config' => $config]]);
$updated = json_decode($response->getBody(), true)['data']['pwa'];

echo $updated['config']['offerLinks']['US'][0]['link'] . PHP_EOL;
python
# pip install requests
import requests

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

# 1. Поточне PWA
pwa = requests.get(f"{API}/pwas/WZAX", headers=HEADERS, timeout=30).json()["data"]["pwa"]

# 2. Змінюємо посилання для США, решта config лишається як була
config = pwa["config"]
config["offerLinks"]["US"] = [{"lang": "en", "link": "https://new-offer.example/?sub1={sub1}"}]

# 3. Надсилаємо config повністю
response = requests.put(f"{API}/pwas/WZAX", headers=HEADERS, json={"config": config}, timeout=30)
updated = response.json()["data"]["pwa"]

print(updated["config"]["offerLinks"]["US"][0]["link"])
js
// Node.js 18+, без залежностей; збережіть як script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer ВАШ_КЛЮЧ', Accept: 'application/json', 'Content-Type': 'application/json' };

// 1. Поточне PWA
const current = await fetch(`${API}/pwas/WZAX`, { headers, signal: AbortSignal.timeout(30000) });
const { pwa } = (await current.json()).data;

// 2. Змінюємо посилання для США, решта config лишається як була
const config = pwa.config;
config.offerLinks.US = [{ lang: 'en', link: 'https://new-offer.example/?sub1={sub1}' }];

// 3. Надсилаємо config повністю
const response = await fetch(`${API}/pwas/WZAX`, {
  method: 'PUT',
  headers,
  body: JSON.stringify({ config }),
  signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();

console.log(data.pwa.config.offerLinks.US[0].link);

Відповідь - PWA після зміни в data.pwa.

Помилки
КодmessageКоли
422You do not have access to this teamteam_id - команда, у якій вас немає
422At least one offer link is required.У config.offerLinks немає жодного посилання
422The white page is off - at least one offer link with country ANY is required.general.white.type = off, а посилання під ANY немає
403This action is unauthorized.Немає доступу до PWA: воно не з ваших команд (у customer - створене не ним) і не відкрите вам через групу доступу

Помилки в config - ті самі, що під час створення.

Клонування ​

POST/pwas/{id}/clone

Робить копії PWA, по одній на кожну назву в names.

Копія отримує налаштування, зображення, акаунти Cloudflare і фільтрації та групи оригіналу. Не копіюються домени й потік фільтрації, а сама копія створюється вимкненою: прив'яжіть домен, задайте потік і увімкніть її.

bash
curl -X POST https://panel.example.com/api/pwas/WZAX/clone \
  -H "Authorization: Bearer ВАШ_КЛЮЧ" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"names": ["Promo EN 2", "Promo EN 3"]}'
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->post('pwas/WZAX/clone', ['json' => ['names' => ['Promo EN 2', 'Promo EN 3']]]);
$clones = json_decode($response->getBody(), true)['data']['clones'];

foreach ($clones as $clone) {
    echo "{$clone['id']} {$clone['name']}" . 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/WZAX/clone", headers=HEADERS, json={"names": ["Promo EN 2", "Promo EN 3"]}, timeout=30)
clones = response.json()["data"]["clones"]

for clone in clones:
    print(clone["id"], clone["name"])
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/WZAX/clone`, {
  method: 'POST',
  headers,
  body: JSON.stringify({ names: ['Promo EN 2', 'Promo EN 3'] }),
  signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();

for (const clone of data.clones) {
  console.log(clone.id, clone.name);
}
Відповідь
json
{
  "data": {
    "clones": [
      { "id": "WQby", "name": "Promo EN 2", "domains": [] },
      { "id": "Lm3T", "name": "Promo EN 3", "domains": [] }
    ]
  }
}
Помилки
КодmessageКоли
422The names field is required.Немає names або це порожній список
403This action is unauthorized.Немає доступу до PWA: воно не з ваших команд (у customer - створене не ним) і не відкрите вам через групу доступу

Архівування ​

DELETE/pwas/{id}

Прибирає PWA в архів разом із його потоками: застосунок перестає відкриватися, але статистика зберігається. Архівні PWA видно в списку з archived=1.

bash
curl -X DELETE https://panel.example.com/api/pwas/WZAX \
  -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->delete('pwas/WZAX');

echo $response->getStatusCode() === 200 ? 'PWA в архіві' . PHP_EOL : 'Помилка' . PHP_EOL;
python
# pip install requests
import requests

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

response = requests.delete(f"{API}/pwas/WZAX", headers=HEADERS, timeout=30)

print("PWA в архіві" if response.ok else "Помилка")
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/WZAX`, { method: 'DELETE', headers, signal: AbortSignal.timeout(30000) });

console.log(response.ok ? 'PWA в архіві' : 'Помилка');

Відповідь: {"data": true}.

Помилки
КодmessageКоли
403This action is unauthorized.Немає доступу до PWA: воно не з ваших команд (у customer - створене не ним) і не відкрите вам через групу доступу