Pushes
Methods for push notifications: create a push, change its texts and schedule, find out the audience size, send it right away, clone it and archive it. For how pushes, types, schedule and filter work, see the "Push notifications" section.
| Method | Address | What it does |
|---|---|---|
| GET | /pwa_pushes | List pushes |
| GET | /pwa_pushes/{id} | One push |
| POST | /pwa_pushes | Create a push |
| PUT | /pwa_pushes/{id} | Update, turn on, turn off, restore from archive |
| GET | /pwa_pushes/{id}/audience | How many subscribers get the push |
| POST | /pwa_pushes/{id}/send | Send now |
| POST | /pwa_pushes/{id}/clone | Clone |
| DELETE | /pwa_pushes/{id} | Archive |
| POST | /pwa_pushes/preview | Show how a text with variants reaches a subscriber |
| POST | /pwa_pushes/uniqueize | Rewrite a text into variants with AI |
Replace YOUR_KEY and panel.example.com with your own.
List pushes
GET/pwa_pushes
Pushes of your teams, recently changed first. Archived ones are not shown.
| Parameter | What it filters |
|---|---|
search | Part of the name |
type | manual, scheduled or triggered |
status | active or inactive |
team_id | Team |
pwa_id | Pushes that reach this PWA's subscribers |
archived | 1 - including archived |
page, per_page | Page and its size (100 by default) |
curl "https://panel.example.com/api/pwa_pushes?status=active&pwa_id=WZAX" \
-H "Authorization: Bearer YOUR_KEY" \
-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 YOUR_KEY', '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']}: sent {$push['sent_count']}, clicks {$push['clicked_count']}\n";
}# pip install requests
import requests
API = "https://panel.example.com/api"
HEADERS = {"Authorization": "Bearer YOUR_KEY", "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"], "sent", push["sent_count"], "clicks", push["clicked_count"])// Node.js 18+, no dependencies; save as script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer YOUR_KEY', 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, 'sent', push.sent_count, 'clicks', push.clicked_count);
}Response
{
"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"
}
]
}
}All-time counters: sent_count - delivered, failed_count - not delivered, clicked_count - clicks. last_run_at is when the push was last sent; unlike the other dates it comes in ISO 8601 format.
Errors
| Code | message | When |
|---|---|---|
422 | The selected type is invalid. | type is not one of manual, scheduled, triggered |
422 | The selected status is invalid. | status is neither active nor inactive |
One push
GET/pwa_pushes/{id}
The same object as in the list, in data.pwa_push.
curl https://panel.example.com/api/pwa_pushes/WZAX \
-H "Authorization: Bearer YOUR_KEY" \
-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 YOUR_KEY', '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 YOUR_KEY", "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+, no dependencies; save as script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer YOUR_KEY', 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);Errors
| Code | message | When |
|---|---|---|
404 | Not found | No push with this id |
403 | This action is unauthorized. | A push of another team or created by another user (for a customer) |
Creating a push
POST/pwa_pushes
| Field | Required | What it is |
|---|---|---|
name | yes | Push name in the panel |
team_id | yes | The push's team |
type | yes | manual - only via send, scheduled - on a schedule, triggered - some time after a subscriber's event |
default_lang | yes | The language whose text subscribers without their own translation get |
status | no | active - works on schedule and triggers. inactive by default |
config.messages | no | Texts by language: the key is a language code, inside title (required, up to 120 characters), body (up to 500), url, icon |
config.schedule.slots | no | Slots: days - weekdays from 1 (Mon) to 7 (Sun), time - time HH:MM in UTC. Without slots a scheduled push is saved but never sent |
config.schedule.delay_after | no | Delays after install, registration, deposit: 30m, 2h, 3d; null - the trigger is off. Without delays a triggered push is never sent |
config.filter | no | Who to send to: pwa_ids - PWAs, countries - two-letter country codes, statuses - installed, registered, deposited |
For a customer, team_id is filled in automatically - their own team.
An empty filter means "all subscribers of all the team's PWAs". pwa_ids may list only PWAs of the push's team that you have access to, otherwise 422. Subscribers of disabled and archived PWAs are not in the audience: their apps no longer open.
In title and body you can write text variants - {Hey|Hi} and the other constructs from the "Push notifications" section: each subscriber gets their own combination.
curl -X POST https://panel.example.com/api/pwa_pushes \
-H "Authorization: Bearer YOUR_KEY" \
-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 YOUR_KEY', '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 "Created push {$pushId}" . PHP_EOL;# pip install requests
import requests
API = "https://panel.example.com/api"
HEADERS = {"Authorization": "Bearer YOUR_KEY", "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("Created push", push_id)// Node.js 18+, no dependencies; save as script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer YOUR_KEY', 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('Created push', data.pwa_push.id);The response is the created push in data.pwa_push, the same as GET/pwa_pushes/{id}. A push with the active status starts sending at the nearest matching slot or on a trigger - no separate start is needed.
Errors
| Code | message | When |
|---|---|---|
422 | The name field is required. | A required field is missing - the same for team_id, type, default_lang |
422 | You do not have access to this team | team_id of a team you are not in |
422 | The selected type is invalid. | type is not one of manual, scheduled, triggered |
422 | Every message needs a title. | The text in some language has no title |
422 | The config.schedule.slots.0.time field must match the format H:i. | The slot time is not in HH:MM format |
422 | The config.schedule.slots.0.days.0 field must be between 1 and 7. | A weekday outside 1-7 |
422 | The delay must look like 30m, 2h or 3d. | A trigger delay in another format |
422 | The selected PWA does not exist. | A non-existent PWA in config.filter.pwa_ids |
422 | You do not have access to this resource | A PWA in config.filter.pwa_ids you have no access to |
422 | This resource belongs to another team | A PWA of another team in config.filter.pwa_ids |
422 | The config.filter.countries.0 field must be 2 characters. | A country not given as a two-letter code |
Updating, turning on and off
PUT/pwa_pushes/{id}
Changes only the fields passed, accepts the same fields as creation. To stop a push - "status": "inactive", to restore it from the archive - "archived": false.
curl -X PUT https://panel.example.com/api/pwa_pushes/WZAX \
-H "Authorization: Bearer YOUR_KEY" \
-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 YOUR_KEY', '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 YOUR_KEY", "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+, no dependencies; save as script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer YOUR_KEY', 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);The response is the push after the change in data.pwa_push.
config is replaced as a whole
If the request contains config, it replaces the texts, schedule and filter at once: whatever is missing from the request is erased. First get the push, change what you need in its config and send config as a whole.
Errors
| Code | message | When |
|---|---|---|
422 | The selected status is invalid. | status is neither active nor inactive |
422 | Every message needs a title. | The same config checks as on creation, including the PWAs in config.filter.pwa_ids |
404 | Not found | No push with this id |
403 | This action is unauthorized. | A push of another team or created by another user (for a customer) |
Audience size
GET/pwa_pushes/{id}/audience
How many subscribers match the push's filter right now, without subscribers of disabled and archived PWAs. Handy to check before sending.
curl https://panel.example.com/api/pwa_pushes/WZAX/audience \
-H "Authorization: Bearer YOUR_KEY" \
-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 YOUR_KEY', 'Accept' => 'application/json'],
'timeout' => 30,
]);
$count = json_decode($api->get('pwa_pushes/WZAX/audience')->getBody(), true)['data']['count'];
echo "Will receive the push: {$count}" . PHP_EOL;# pip install requests
import requests
API = "https://panel.example.com/api"
HEADERS = {"Authorization": "Bearer YOUR_KEY", "Accept": "application/json"}
count = requests.get(f"{API}/pwa_pushes/WZAX/audience", headers=HEADERS, timeout=30).json()["data"]["count"]
print("Will receive the push:", count)// Node.js 18+, no dependencies; save as script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer YOUR_KEY', 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('Will receive the push:', data.count);Response: {"data": {"count": 1250}}.
Errors
| Code | message | When |
|---|---|---|
404 | Not found | No push with this id |
403 | This action is unauthorized. | A push of another team or created by another user (for a customer) |
Send now
POST/pwa_pushes/{id}/send
Queues the push for sending to the whole audience of its filter right away.
This is a real mailing
The request sends notifications to real subscribers, and sending can't be cancelled. The method works with any push status and type, even a disabled one, and doesn't remember past sends: every call sends the push to everyone again, including those who already got it on the schedule or a trigger. An archived push is not sent (422). At most 10 sends per minute per user. Don't call it in a loop or when retrying after network errors - check audience and the counters first.
curl -X POST https://panel.example.com/api/pwa_pushes/WZAX/send \
-H "Authorization: Bearer YOUR_KEY" \
-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 YOUR_KEY', 'Accept' => 'application/json'],
'timeout' => 30,
]);
$queued = json_decode($api->post('pwa_pushes/WZAX/send')->getBody(), true)['data']['queued'];
echo "Queued for sending: {$queued}" . PHP_EOL;# pip install requests
import requests
API = "https://panel.example.com/api"
HEADERS = {"Authorization": "Bearer YOUR_KEY", "Accept": "application/json"}
queued = requests.post(f"{API}/pwa_pushes/WZAX/send", headers=HEADERS, timeout=30).json()["data"]["queued"]
print("Queued for sending:", queued)// Node.js 18+, no dependencies; save as script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer YOUR_KEY', 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('Queued for sending:', data.queued);Response: {"data": {"queued": 1250}} - how many subscribers were queued. The delivery itself runs in the background, the result shows up in sent_count and failed_count.
Errors
| Code | message | When |
|---|---|---|
422 | An archived push cannot be sent | The push is archived |
429 | Too many requests. Try again in a minute. | More than 10 sends in a minute |
404 | Not found | No push with this id |
403 | This action is unauthorized. | A push of another team or created by another user (for a customer) |
Cloning
POST/pwa_pushes/{id}/clone
Copies of a push, one per name in names. A copy gets the original's team, type, language and the whole config, and is created disabled with zero counters.
curl -X POST https://panel.example.com/api/pwa_pushes/WZAX/clone \
-H "Authorization: Bearer YOUR_KEY" \
-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 YOUR_KEY', '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 YOUR_KEY", "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+, no dependencies; save as script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer YOUR_KEY', 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);
}Response
{
"data": {
"clones": [
{ "id": "WQby", "name": "Evening reminder DE", "type": "scheduled", "status": "inactive", "default_lang": "en" }
]
}
}Errors
| Code | message | When |
|---|---|---|
422 | The names field is required. | names not passed |
404 | Not found | No push with this id |
403 | This action is unauthorized. | A push of another team or created by another user (for a customer) |
Archiving
DELETE/pwa_pushes/{id}
Archives the push: it is no longer sent on the schedule and triggers, the history and counters are kept. To restore it - PUT with "archived": false.
curl -X DELETE https://panel.example.com/api/pwa_pushes/WZAX \
-H "Authorization: Bearer YOUR_KEY" \
-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 YOUR_KEY', 'Accept' => 'application/json'],
'timeout' => 30,
]);
$response = $api->delete('pwa_pushes/WZAX');
echo 'Push archived, HTTP ' . $response->getStatusCode() . PHP_EOL;# pip install requests
import requests
API = "https://panel.example.com/api"
HEADERS = {"Authorization": "Bearer YOUR_KEY", "Accept": "application/json"}
response = requests.delete(f"{API}/pwa_pushes/WZAX", headers=HEADERS, timeout=30)
print("Push archived, HTTP", response.status_code)// Node.js 18+, no dependencies; save as script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer YOUR_KEY', Accept: 'application/json', 'Content-Type': 'application/json' };
const response = await fetch(`${API}/pwa_pushes/WZAX`, {
method: 'DELETE',
headers,
signal: AbortSignal.timeout(30000),
});
console.log('Push archived, HTTP', response.status);Response: {"data": true}.
Errors
| Code | message | When |
|---|---|---|
404 | Not found | No push with this id |
403 | This action is unauthorized. | A push of another team or created by another user (for a customer) |
Text preview
POST/pwa_pushes/preview
Builds one random combination from a text with variants, the way a subscriber will see it. The text field - up to 2000 characters. Each call gives a new combination.
The push title and text can be rendered in one call: instead of text, send title and body (up to 2000 characters each) - the answer is {"data": {"title": …, "body": …}}, an empty field comes back as an empty string.
curl -X POST https://panel.example.com/api/pwa_pushes/preview \
-H "Authorization: Bearer YOUR_KEY" \
-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 YOUR_KEY', '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 YOUR_KEY", "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+, no dependencies; save as script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer YOUR_KEY', 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);Response: {"data": {"text": "Hey, 7 new lessons"}}.
Errors
| Code | message | When |
|---|---|---|
422 | The text field is required when none of title / body are present. | Neither text nor title / body passed |
Uniqueize with AI
POST/pwa_pushes/uniqueize
Rewrites a plain phrase into a text with variants, like the Uniqueize with AI button in the push form. Fields: text - a phrase up to 2000 characters, lang - language code (optional).
Works through an AI provider
The method is available only if an administrator connected an AI provider in the panel settings, and every call uses up its limits. Without a provider you get 422 with AI uniqueizer is not configured, if the provider didn't answer - 422 with AI uniqueizer is unavailable.
curl -X POST https://panel.example.com/api/pwa_pushes/uniqueize \
-H "Authorization: Bearer YOUR_KEY" \
-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 YOUR_KEY', '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 YOUR_KEY", "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+, no dependencies; save as script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer YOUR_KEY', Accept: 'application/json', 'Content-Type': 'application/json' };
// AI answers slower than usual - 60-second timeout
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);Response: {"data": {"text": "{Your|The} plan {is ready|is waiting} {for you|}"}}.
Errors
| Code | message | When |
|---|---|---|
422 | AI uniqueizer is not configured | No AI provider connected in the panel |
422 | The text field is required. | text not passed |