Skip to content

Пуши ​

Методы для пуш-уведомлений: завести пуш, поменять тексты и расписание, узнать размер аудитории, отправить сразу, наклонировать и убрать в архив. Как устроены пуши, типы, расписание и фильтр, см. раздел «Пуш-уведомления».

МетодАдресЧто делает
GET/pwa_pushesСписок пушей
GET/pwa_pushes/{id}Один пуш
POST/pwa_pushesСоздать пуш
PUT/pwa_pushes/{id}Изменить, включить, выключить, вернуть из архива
GET/pwa_pushes/{id}/audienceСколько подписчиков получит пуш
POST/pwa_pushes/{id}/sendОтправить сейчас
POST/pwa_pushes/{id}/cloneКлонировать
DELETE/pwa_pushes/{id}Убрать в архив
POST/pwa_pushes/previewПоказать, как текст с вариантами придёт подписчику
POST/pwa_pushes/uniqueizeПереписать текст в варианты с помощью AI

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

Список пушей ​

GET/pwa_pushes

Пуши ваших команд, недавно изменённые сверху. Архивные не показываются.

ПараметрЧто фильтрует
searchЧасть названия
typemanual, scheduled или triggered
statusactive или inactive
team_idКоманда
pwa_idПуши, которые дойдут до подписчиков этого PWA
archived1 - вместе с архивными
page, per_pageСтраница и её размер (по умолчанию 100)
bash
curl "https://panel.example.com/api/pwa_pushes?status=active&pwa_id=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('pwa_pushes', ['query' => ['status' => 'active', 'pwa_id' => 'WZAX']]);
$pushes = json_decode($response->getBody(), true)['data']['pwa_pushes'];

foreach ($pushes as $push) {
    echo "{$push['name']}: отправлено {$push['sent_count']}, кликов {$push['clicked_count']}\n";
}
python
# pip install requests
import requests

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

response = requests.get(f"{API}/pwa_pushes", headers=HEADERS, params={"status": "active", "pwa_id": "WZAX"}, timeout=30)
pushes = response.json()["data"]["pwa_pushes"]

for push in pushes:
    print(push["name"], "отправлено", push["sent_count"], "кликов", push["clicked_count"])
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 params = new URLSearchParams({ status: 'active', pwa_id: 'WZAX' });
const response = await fetch(`${API}/pwa_pushes?${params}`, {
  method: 'GET',
  headers,
  signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();

for (const push of data.pwa_pushes) {
  console.log(push.name, 'отправлено', push.sent_count, 'кликов', push.clicked_count);
}
Ответ
json
{
  "data": {
    "meta": { "current_page": 1, "per_page": 100, "last_page": 1, "total": 1 },
    "pwa_pushes": [
      {
        "id": "WZAX",
        "name": "Evening reminder",
        "type": "scheduled",
        "status": "active",
        "default_lang": "en",
        "config": {
          "messages": {
            "en": { "title": "{Hey|Hi}, your plan for today is ready", "body": "Just 15 minutes - start now", "url": null, "icon": null }
          },
          "schedule": { "slots": [ { "days": [1, 2, 3, 4, 5], "time": "19:00" } ] },
          "filter": { "pwa_ids": ["WZAX"], "countries": ["US"], "statuses": ["installed"] }
        },
        "sent_count": 1250,
        "failed_count": 14,
        "clicked_count": 96,
        "archived": false,
        "last_run_at": "2026-10-05T19:00:00.000000Z",
        "team": { "id": "WQby", "name": "Team A" },
        "created_at": "05 Oct 2026 14:23",
        "updated_at": "05 Oct 2026 14:23"
      }
    ]
  }
}

Счётчики за всё время: sent_count - доставлено, failed_count - не доставлено, clicked_count - кликов. last_run_at - когда пуш отправлялся последний раз; в отличие от остальных дат он приходит в формате ISO 8601.

Ошибки
КодmessageКогда
422The selected type is invalid.type не из manual, scheduled, triggered
422The selected status is invalid.status не active и не inactive

Один пуш ​

GET/pwa_pushes/{id}

Тот же объект, что в списке, в data.pwa_push.

bash
curl https://panel.example.com/api/pwa_pushes/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,
]);

$push = json_decode($api->get('pwa_pushes/WZAX')->getBody(), true)['data']['pwa_push'];

echo "{$push['name']}: {$push['type']}, {$push['status']}" . PHP_EOL;
python
# pip install requests
import requests

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

push = requests.get(f"{API}/pwa_pushes/WZAX", headers=HEADERS, timeout=30).json()["data"]["pwa_push"]

print(push["name"], push["type"], push["status"])
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}/pwa_pushes/WZAX`, {
  method: 'GET',
  headers,
  signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();

console.log(data.pwa_push.name, data.pwa_push.type, data.pwa_push.status);
Ошибки
КодmessageКогда
404Not foundПуша с таким id нет
403This action is unauthorized.Пуш чужой команды или создан другим пользователем (для customer)

Создание пуша ​

POST/pwa_pushes

ПолеОбязательноЧто это
nameдаНазвание пуша в панели
team_idдаКоманда пуша
typeдаmanual - только по send, scheduled - по расписанию, triggered - через время после события подписчика
default_langдаЯзык, текст которого получат подписчики без своего перевода
statusнетactive - работает по расписанию и триггерам. По умолчанию inactive
config.messagesнетТексты по языкам: ключ - код языка, внутри title (обязателен, до 120 символов), body (до 500), url, icon
config.schedule.slotsнетСлоты: days - дни недели от 1 (пн) до 7 (вс), time - время ЧЧ:ММ по UTC. Без слотов пуш scheduled сохранится, но не отправится ни разу
config.schedule.delay_afterнетЗадержки после install, registration, deposit: 30m, 2h, 3d; null - триггер выключен. Без задержек пуш triggered не отправится ни разу
config.filterнетКому отправлять: pwa_ids - PWA, countries - двухбуквенные коды стран, statuses - installed, registered, deposited

У customer team_id подставляется сам - его команда.

Пустой фильтр значит «все подписчики всех PWA команды». В pwa_ids можно указывать только PWA команды пуша, которые вам доступны, иначе 422. Подписчики выключенных и архивных PWA в аудиторию не попадают: их приложения не открываются.

В title и body можно писать варианты текста - {Hey|Hi} и другие конструкции из раздела «Пуш-уведомления»: каждый подписчик получит свою комбинацию.

bash
curl -X POST https://panel.example.com/api/pwa_pushes \
  -H "Authorization: Bearer ВАШ_КЛЮЧ" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Evening reminder",
    "team_id": "WQby",
    "type": "scheduled",
    "default_lang": "en",
    "status": "active",
    "config": {
      "messages": { "en": { "title": "{Hey|Hi}, your plan for today is ready", "body": "Just 15 minutes - start now" } },
      "schedule": { "slots": [ { "days": [1, 2, 3, 4, 5], "time": "19:00" } ] },
      "filter": { "pwa_ids": ["WZAX"], "countries": ["US"], "statuses": ["installed"] }
    }
  }'
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('pwa_pushes', ['json' => [
    'name' => 'Evening reminder',
    'team_id' => 'WQby',
    'type' => 'scheduled',
    'default_lang' => 'en',
    'status' => 'active',
    'config' => [
        'messages' => ['en' => ['title' => '{Hey|Hi}, your plan for today is ready', 'body' => 'Just 15 minutes - start now']],
        'schedule' => ['slots' => [['days' => [1, 2, 3, 4, 5], 'time' => '19:00']]],
        'filter' => ['pwa_ids' => ['WZAX'], 'countries' => ['US'], 'statuses' => ['installed']],
    ],
]]);
$pushId = json_decode($response->getBody(), true)['data']['pwa_push']['id'];

echo "Создан пуш {$pushId}" . 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}/pwa_pushes", headers=HEADERS, json={
    "name": "Evening reminder",
    "team_id": "WQby",
    "type": "scheduled",
    "default_lang": "en",
    "status": "active",
    "config": {
        "messages": {"en": {"title": "{Hey|Hi}, your plan for today is ready", "body": "Just 15 minutes - start now"}},
        "schedule": {"slots": [{"days": [1, 2, 3, 4, 5], "time": "19:00"}]},
        "filter": {"pwa_ids": ["WZAX"], "countries": ["US"], "statuses": ["installed"]},
    },
}, timeout=30)
push_id = response.json()["data"]["pwa_push"]["id"]

print("Создан пуш", push_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}/pwa_pushes`, {
  method: 'POST',
  headers,
  body: JSON.stringify({
    name: 'Evening reminder',
    team_id: 'WQby',
    type: 'scheduled',
    default_lang: 'en',
    status: 'active',
    config: {
      messages: { en: { title: '{Hey|Hi}, your plan for today is ready', body: 'Just 15 minutes - start now' } },
      schedule: { slots: [{ days: [1, 2, 3, 4, 5], time: '19:00' }] },
      filter: { pwa_ids: ['WZAX'], countries: ['US'], statuses: ['installed'] },
    },
  }),
  signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();

console.log('Создан пуш', data.pwa_push.id);

Ответ - созданный пуш в data.pwa_push, в том же виде, что и GET/pwa_pushes/{id}. Пуш со статусом active начнёт отправляться в ближайший подходящий слот или по триггеру - без отдельного запуска.

Ошибки
КодmessageКогда
422The name field is required.Не передано обязательное поле - так же для team_id, type, default_lang
422You do not have access to this teamteam_id команды, в которой вас нет
422The selected type is invalid.type не из manual, scheduled, triggered
422Every message needs a title.У текста на каком-то языке нет title
422The config.schedule.slots.0.time field must match the format H:i.Время слота не в формате ЧЧ:ММ
422The config.schedule.slots.0.days.0 field must be between 1 and 7.День недели вне 1-7
422The delay must look like 30m, 2h or 3d.Задержка триггера в другом формате
422The selected PWA does not exist.В config.filter.pwa_ids несуществующее PWA
422You do not have access to this resourceВ config.filter.pwa_ids PWA, к которому у вас нет доступа
422This resource belongs to another teamВ config.filter.pwa_ids PWA другой команды
422The config.filter.countries.0 field must be 2 characters.Страна не двухбуквенным кодом

Изменение, включение и выключение ​

PUT/pwa_pushes/{id}

Меняет только переданные поля, принимает те же поля, что и создание. Остановить пуш - "status": "inactive", вернуть из архива - "archived": false.

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

echo "{$push['name']}: {$push['status']}" . 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}/pwa_pushes/WZAX", headers=HEADERS, json={"status": "inactive"}, timeout=30)
push = response.json()["data"]["pwa_push"]

print(push["name"], push["status"])
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}/pwa_pushes/WZAX`, {
  method: 'PUT',
  headers,
  body: JSON.stringify({ status: 'inactive' }),
  signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();

console.log(data.pwa_push.name, data.pwa_push.status);

Ответ - пуш после изменения в data.pwa_push.

config заменяется целиком

Если в запросе есть config, он заменяет тексты, расписание и фильтр разом: чего нет в запросе, то сотрётся. Сначала получите пуш, поменяйте в его config нужное и отправьте config целиком.

Ошибки
КодmessageКогда
422The selected status is invalid.status не active и не inactive
422Every message needs a title.Те же проверки config, что при создании, включая PWA в config.filter.pwa_ids
404Not foundПуша с таким id нет
403This action is unauthorized.Пуш чужой команды или создан другим пользователем (для customer)

Размер аудитории ​

GET/pwa_pushes/{id}/audience

Сколько подписчиков подходит под фильтр пуша прямо сейчас, без подписчиков выключенных и архивных PWA. Удобно проверить перед отправкой.

bash
curl https://panel.example.com/api/pwa_pushes/WZAX/audience \
  -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,
]);

$count = json_decode($api->get('pwa_pushes/WZAX/audience')->getBody(), true)['data']['count'];

echo "Получат пуш: {$count}" . PHP_EOL;
python
# pip install requests
import requests

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

count = requests.get(f"{API}/pwa_pushes/WZAX/audience", headers=HEADERS, timeout=30).json()["data"]["count"]

print("Получат пуш:", count)
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}/pwa_pushes/WZAX/audience`, {
  method: 'GET',
  headers,
  signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();

console.log('Получат пуш:', data.count);

Ответ: {"data": {"count": 1250}}.

Ошибки
КодmessageКогда
404Not foundПуша с таким id нет
403This action is unauthorized.Пуш чужой команды или создан другим пользователем (для customer)

Отправить сейчас ​

POST/pwa_pushes/{id}/send

Сразу ставит пуш в отправку всей аудитории из его фильтра.

Это настоящая рассылка

Запрос отправляет уведомления реальным подписчикам, и отменить отправку нельзя. Метод срабатывает при любом статусе и типе пуша, даже у выключенного, и не помнит прошлых отправок: каждый вызов шлёт пуш всем заново, включая тех, кто уже получил его по расписанию или триггеру. Архивный пуш не отправляется (422). Не больше 10 отправок в минуту на пользователя. Не вызывайте метод в цикле и при повторах после ошибок сети - сначала проверьте audience и счётчики.

bash
curl -X POST https://panel.example.com/api/pwa_pushes/WZAX/send \
  -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,
]);

$queued = json_decode($api->post('pwa_pushes/WZAX/send')->getBody(), true)['data']['queued'];

echo "Поставлено в отправку: {$queued}" . PHP_EOL;
python
# pip install requests
import requests

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

queued = requests.post(f"{API}/pwa_pushes/WZAX/send", headers=HEADERS, timeout=30).json()["data"]["queued"]

print("Поставлено в отправку:", queued)
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}/pwa_pushes/WZAX/send`, {
  method: 'POST',
  headers,
  signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();

console.log('Поставлено в отправку:', data.queued);

Ответ: {"data": {"queued": 1250}} - сколько подписчиков поставлено в отправку. Сама доставка идёт в фоне, результат появится в sent_count и failed_count.

Ошибки
КодmessageКогда
422An archived push cannot be sentПуш в архиве
429Too many requests. Try again in a minute.Больше 10 отправок за минуту
404Not foundПуша с таким id нет
403This action is unauthorized.Пуш чужой команды или создан другим пользователем (для customer)

Клонирование ​

POST/pwa_pushes/{id}/clone

Копии пуша, по одной на каждое название в names. Копия получает команду, тип, язык и весь config оригинала, а создаётся выключенной и с нулевыми счётчиками.

bash
curl -X POST https://panel.example.com/api/pwa_pushes/WZAX/clone \
  -H "Authorization: Bearer ВАШ_КЛЮЧ" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"names": ["Evening reminder DE"]}'
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('pwa_pushes/WZAX/clone', ['json' => ['names' => ['Evening reminder DE']]]);
$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}/pwa_pushes/WZAX/clone", headers=HEADERS, json={"names": ["Evening reminder DE"]}, 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}/pwa_pushes/WZAX/clone`, {
  method: 'POST',
  headers,
  body: JSON.stringify({ names: ['Evening reminder DE'] }),
  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": "Evening reminder DE", "type": "scheduled", "status": "inactive", "default_lang": "en" }
    ]
  }
}
Ошибки
КодmessageКогда
422The names field is required.Не передан names
404Not foundПуша с таким id нет
403This action is unauthorized.Пуш чужой команды или создан другим пользователем (для customer)

Архивирование ​

DELETE/pwa_pushes/{id}

Убирает пуш в архив: он больше не отправляется по расписанию и триггерам, история и счётчики сохраняются. Вернуть - PUT с "archived": false.

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

echo 'Пуш в архиве, HTTP ' . $response->getStatusCode() . 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}/pwa_pushes/WZAX", headers=HEADERS, timeout=30)

print("Пуш в архиве, HTTP", response.status_code)
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}/pwa_pushes/WZAX`, {
  method: 'DELETE',
  headers,
  signal: AbortSignal.timeout(30000),
});

console.log('Пуш в архиве, HTTP', response.status);

Ответ: {"data": true}.

Ошибки
КодmessageКогда
404Not foundПуша с таким id нет
403This action is unauthorized.Пуш чужой команды или создан другим пользователем (для customer)

Предпросмотр текста ​

POST/pwa_pushes/preview

Собирает из текста с вариантами одну случайную комбинацию, как её увидит подписчик. Поле text - до 2000 символов. Каждый вызов даёт новую комбинацию.

Заголовок и текст пуша можно собрать одним вызовом: вместо text передайте title и body (каждое до 2000 символов) - ответ придёт как {"data": {"title": …, "body": …}}, пустое поле вернётся пустой строкой.

bash
curl -X POST https://panel.example.com/api/pwa_pushes/preview \
  -H "Authorization: Bearer ВАШ_КЛЮЧ" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"text": "{Hey|Hi}, {%RINT=(3,9)} new lessons"}'
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('pwa_pushes/preview', ['json' => ['text' => '{Hey|Hi}, {%RINT=(3,9)} new lessons']]);

echo json_decode($response->getBody(), true)['data']['text'] . 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}/pwa_pushes/preview", headers=HEADERS, json={"text": "{Hey|Hi}, {%RINT=(3,9)} new lessons"}, timeout=30)
print(response.json()["data"]["text"])
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}/pwa_pushes/preview`, {
  method: 'POST',
  headers,
  body: JSON.stringify({ text: '{Hey|Hi}, {%RINT=(3,9)} new lessons' }),
  signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();

console.log(data.text);

Ответ: {"data": {"text": "Hey, 7 new lessons"}}.

Ошибки
КодmessageКогда
422The text field is required when none of title / body are present.Не передан ни text, ни title / body

Уникализация с AI ​

POST/pwa_pushes/uniqueize

Переписывает обычную фразу в текст с вариантами, как кнопка Uniqueize with AI в форме пуша. Поля: text - фраза до 2000 символов, lang - код языка (необязательно).

Работает через AI-провайдера

Метод доступен, только если администратор подключил AI-провайдера в настройках панели, и каждый вызов расходует его лимиты. Без провайдера придёт 422 с AI uniqueizer is not configured, если провайдер не ответил - 422 с AI uniqueizer is unavailable.

bash
curl -X POST https://panel.example.com/api/pwa_pushes/uniqueize \
  -H "Authorization: Bearer ВАШ_КЛЮЧ" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"text": "Your plan is ready", "lang": "en"}'
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' => 60,
]);

$response = $api->post('pwa_pushes/uniqueize', ['json' => ['text' => 'Your plan is ready', 'lang' => 'en']]);
$template = json_decode($response->getBody(), true)['data']['text'];

echo $template . 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}/pwa_pushes/uniqueize", headers=HEADERS, json={"text": "Your plan is ready", "lang": "en"}, timeout=60)
template = response.json()["data"]["text"]

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

// AI отвечает дольше обычного - таймаут 60 секунд
const response = await fetch(`${API}/pwa_pushes/uniqueize`, {
  method: 'POST',
  headers,
  body: JSON.stringify({ text: 'Your plan is ready', lang: 'en' }),
  signal: AbortSignal.timeout(60000),
});
const { data } = await response.json();

console.log(data.text);

Ответ: {"data": {"text": "{Your|The} plan {is ready|is waiting} {for you|}"}}.

Ошибки
КодmessageКогда
422AI uniqueizer is not configuredВ панели не подключён AI-провайдер
422The text field is required.Не передан text