Пуши
Методы для пуш-уведомлений: завести пуш, поменять тексты и расписание, узнать размер аудитории, отправить сразу, наклонировать и убрать в архив. Как устроены пуши, типы, расписание и фильтр, см. раздел «Пуш-уведомления».
| Метод | Адрес | Что делает |
|---|---|---|
| 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 | Часть названия |
type | manual, scheduled или triggered |
status | active или inactive |
team_id | Команда |
pwa_id | Пуши, которые дойдут до подписчиков этого PWA |
archived | 1 - вместе с архивными |
page, per_page | Страница и её размер (по умолчанию 100) |
curl "https://panel.example.com/api/pwa_pushes?status=active&pwa_id=WZAX" \
-H "Authorization: Bearer ВАШ_КЛЮЧ" \
-H "Accept: application/json"<?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";
}# 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"])// 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);
}Ответ
{
"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 | Когда |
|---|---|---|
422 | The selected type is invalid. | type не из manual, scheduled, triggered |
422 | The selected status is invalid. | status не active и не inactive |
Один пуш
GET/pwa_pushes/{id}
Тот же объект, что в списке, в data.pwa_push.
curl https://panel.example.com/api/pwa_pushes/WZAX \
-H "Authorization: Bearer ВАШ_КЛЮЧ" \
-H "Accept: application/json"<?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;# 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"])// 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 | Когда |
|---|---|---|
404 | Not found | Пуша с таким id нет |
403 | This 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} и другие конструкции из раздела «Пуш-уведомления»: каждый подписчик получит свою комбинацию.
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
// 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;# 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)// 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 | Когда |
|---|---|---|
422 | The name field is required. | Не передано обязательное поле - так же для team_id, type, default_lang |
422 | You do not have access to this team | team_id команды, в которой вас нет |
422 | The selected type is invalid. | type не из manual, scheduled, triggered |
422 | Every message needs a title. | У текста на каком-то языке нет title |
422 | The config.schedule.slots.0.time field must match the format H:i. | Время слота не в формате ЧЧ:ММ |
422 | The config.schedule.slots.0.days.0 field must be between 1 and 7. | День недели вне 1-7 |
422 | The delay must look like 30m, 2h or 3d. | Задержка триггера в другом формате |
422 | The selected PWA does not exist. | В config.filter.pwa_ids несуществующее PWA |
422 | You do not have access to this resource | В config.filter.pwa_ids PWA, к которому у вас нет доступа |
422 | This resource belongs to another team | В config.filter.pwa_ids PWA другой команды |
422 | The config.filter.countries.0 field must be 2 characters. | Страна не двухбуквенным кодом |
Изменение, включение и выключение
PUT/pwa_pushes/{id}
Меняет только переданные поля, принимает те же поля, что и создание. Остановить пуш - "status": "inactive", вернуть из архива - "archived": false.
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
// 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;# 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"])// 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 | Когда |
|---|---|---|
422 | The selected status is invalid. | status не active и не inactive |
422 | Every message needs a title. | Те же проверки config, что при создании, включая PWA в config.filter.pwa_ids |
404 | Not found | Пуша с таким id нет |
403 | This action is unauthorized. | Пуш чужой команды или создан другим пользователем (для customer) |
Размер аудитории
GET/pwa_pushes/{id}/audience
Сколько подписчиков подходит под фильтр пуша прямо сейчас, без подписчиков выключенных и архивных PWA. Удобно проверить перед отправкой.
curl https://panel.example.com/api/pwa_pushes/WZAX/audience \
-H "Authorization: Bearer ВАШ_КЛЮЧ" \
-H "Accept: application/json"<?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;# 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)// 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 | Когда |
|---|---|---|
404 | Not found | Пуша с таким id нет |
403 | This action is unauthorized. | Пуш чужой команды или создан другим пользователем (для customer) |
Отправить сейчас
POST/pwa_pushes/{id}/send
Сразу ставит пуш в отправку всей аудитории из его фильтра.
Это настоящая рассылка
Запрос отправляет уведомления реальным подписчикам, и отменить отправку нельзя. Метод срабатывает при любом статусе и типе пуша, даже у выключенного, и не помнит прошлых отправок: каждый вызов шлёт пуш всем заново, включая тех, кто уже получил его по расписанию или триггеру. Архивный пуш не отправляется (422). Не больше 10 отправок в минуту на пользователя. Не вызывайте метод в цикле и при повторах после ошибок сети - сначала проверьте audience и счётчики.
curl -X POST https://panel.example.com/api/pwa_pushes/WZAX/send \
-H "Authorization: Bearer ВАШ_КЛЮЧ" \
-H "Accept: application/json"<?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;# 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)// 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 | Когда |
|---|---|---|
422 | An archived push cannot be sent | Пуш в архиве |
429 | Too many requests. Try again in a minute. | Больше 10 отправок за минуту |
404 | Not found | Пуша с таким id нет |
403 | This action is unauthorized. | Пуш чужой команды или создан другим пользователем (для customer) |
Клонирование
POST/pwa_pushes/{id}/clone
Копии пуша, по одной на каждое название в names. Копия получает команду, тип, язык и весь config оригинала, а создаётся выключенной и с нулевыми счётчиками.
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
// 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;
}# 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"])// 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);
}Ответ
{
"data": {
"clones": [
{ "id": "WQby", "name": "Evening reminder DE", "type": "scheduled", "status": "inactive", "default_lang": "en" }
]
}
}Ошибки
| Код | message | Когда |
|---|---|---|
422 | The names field is required. | Не передан names |
404 | Not found | Пуша с таким id нет |
403 | This action is unauthorized. | Пуш чужой команды или создан другим пользователем (для customer) |
Архивирование
DELETE/pwa_pushes/{id}
Убирает пуш в архив: он больше не отправляется по расписанию и триггерам, история и счётчики сохраняются. Вернуть - PUT с "archived": false.
curl -X DELETE https://panel.example.com/api/pwa_pushes/WZAX \
-H "Authorization: Bearer ВАШ_КЛЮЧ" \
-H "Accept: application/json"<?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;# 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)// 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 | Когда |
|---|---|---|
404 | Not found | Пуша с таким id нет |
403 | This action is unauthorized. | Пуш чужой команды или создан другим пользователем (для customer) |
Предпросмотр текста
POST/pwa_pushes/preview
Собирает из текста с вариантами одну случайную комбинацию, как её увидит подписчик. Поле text - до 2000 символов. Каждый вызов даёт новую комбинацию.
Заголовок и текст пуша можно собрать одним вызовом: вместо text передайте title и body (каждое до 2000 символов) - ответ придёт как {"data": {"title": …, "body": …}}, пустое поле вернётся пустой строкой.
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
// 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;# 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"])// 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 | Когда |
|---|---|---|
422 | The 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.
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
// 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;# 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)// 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 | Когда |
|---|---|---|
422 | AI uniqueizer is not configured | В панели не подключён AI-провайдер |
422 | The text field is required. | Не передан text |