Конверсії
Методи для журналу конверсій - усього, що прийшло постбеками від партнерок і з самого трафіку (встановлення, відкриття офера). Тут кожну подію видно окремим рядком: із виплатою, відвідувачем і статусом надсилання у Facebook. Що означають колонки й статуси в панелі, див. розділ «Конверсії».
| Метод | Адреса | Що робить |
|---|---|---|
| GET | /conversions | Список конверсій за період |
| GET | /conversions/{id} | Одна конверсія та всі візити її відвідувача |
| POST | /conversions/{id}/re-export | Надіслати конверсію у Facebook ще раз |
Замініть ВАШ_КЛЮЧ і panel.example.com на свої.
Список конверсій
GET/conversions
Конверсії ваших PWA за період, свіжі зверху.
| Параметр | Обов'язково | Що фільтрує |
|---|---|---|
date_from, date_to | так | Період за датою отримання події: РРРР-ММ-ДД, дні повністю за UTC, не довший за місяць - як у розділі «Статистика» |
event[] | ні | Тип події, можна кілька: install, open_offer, registration, deposit, repeat_deposit, page_view |
export_status | ні | Статус надсилання у Facebook: exported, failed, not_exported або open_offer |
pwa_id або pwa_ids[] | ні | Одне чи кілька PWA |
split_id або split_ids[] | ні | Один чи кілька сплітів - конверсії з їхніх потоків |
visitor_id | ні | Частина ідентифікатора відвідувача |
page, per_page | ні | Сторінка та її розмір: за замовчуванням 100, максимум 200 |
curl -G "https://panel.example.com/api/conversions" \
-H "Authorization: Bearer ВАШ_КЛЮЧ" \
-H "Accept: application/json" \
--data-urlencode "date_from=2026-10-01" \
--data-urlencode "date_to=2026-10-05" \
--data-urlencode "event[]=deposit" \
--data-urlencode "event[]=repeat_deposit"<?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,
]);
$page = 1;
do {
$response = $api->get('conversions', ['query' => [
'date_from' => '2026-10-01',
'date_to' => '2026-10-05',
'event' => ['deposit', 'repeat_deposit'],
'per_page' => 200,
'page' => $page,
]]);
$data = json_decode($response->getBody(), true)['data'];
foreach ($data['conversions'] as $conversion) {
echo "{$conversion['received_at']} {$conversion['pwa']['name']}: {$conversion['payout']} {$conversion['currency']}\n";
}
$page++;
} while ($data['meta']['current_page'] < $data['meta']['last_page']);# pip install requests
import requests
API = "https://panel.example.com/api"
HEADERS = {"Authorization": "Bearer ВАШ_КЛЮЧ", "Accept": "application/json"}
page = 1
while True:
response = requests.get(f"{API}/conversions", headers=HEADERS, params={
"date_from": "2026-10-01",
"date_to": "2026-10-05",
"event[]": ["deposit", "repeat_deposit"],
"per_page": 200,
"page": page,
}, timeout=30)
data = response.json()["data"]
for conversion in data["conversions"]:
print(conversion["received_at"], conversion["pwa"]["name"], conversion["payout"], conversion["currency"])
if data["meta"]["current_page"] >= data["meta"]["last_page"]:
break
page += 1// Node.js 18+, без залежностей; збережіть як script.mjs
const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer ВАШ_КЛЮЧ', Accept: 'application/json', 'Content-Type': 'application/json' };
for (let page = 1; ; page++) {
const params = new URLSearchParams({
date_from: '2026-10-01',
date_to: '2026-10-05',
per_page: 200,
page,
});
params.append('event[]', 'deposit');
params.append('event[]', 'repeat_deposit');
const response = await fetch(`${API}/conversions?${params}`, {
method: 'GET',
headers,
signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();
for (const conversion of data.conversions) {
console.log(conversion.received_at, conversion.pwa.name, conversion.payout, conversion.currency);
}
if (data.meta.current_page >= data.meta.last_page) break;
}Відповідь
{
"data": {
"meta": { "current_page": 1, "per_page": 200, "last_page": 1, "total": 1 },
"conversions": [
{
"id": "Rt5K",
"pwa": { "id": "WZAX", "name": "Promo EN", "icon_url": null },
"pwa_visitor_id": "7f3c2a9e-1b4d-4c8e-9a2f-5d6e7f8a9b0c",
"event": "deposit",
"raw_event": "ftd",
"payout": "45.00",
"currency": "USD",
"tid": "tx-55102",
"external_click_id": null,
"export_status": "failed",
"export_error": "[400] Malformed access token",
"exported_at": null,
"can_reexport": true,
"status": "scheduled",
"received_at": "05 Oct 2026 14:23",
"created_at": "05 Oct 2026 14:23",
"updated_at": "05 Oct 2026 14:23"
}
]
}
}| Поле | Що це |
|---|---|
pwa | PWA, якому зараховано конверсію; null, якщо PWA не визначилося (такі рядки бачить лише admin) |
pwa_visitor_id | Відвідувач, за яким конверсія прив'язалася до візиту |
event | Тип події (список - у таблиці параметрів вище). null - партнерка надіслала статус, який панель не розпізнала: така подія не рахується в статистиці й не йде у Facebook |
raw_event | Статус рівно так, як його надіслала партнерка (ftd, sale, reg…) |
payout, currency | Виплата з постбека - рядком, як прийшла |
tid | Ідентифікатор транзакції з постбека |
external_click_id | click_id з постбека, якщо партнерка його передала |
export_status | Надсилання у Facebook - див. нижче |
export_error | Відповідь Facebook, якщо надсилання не пройшло |
exported_at | Коли подія пішла у Facebook |
can_reexport | Чи можна надіслати ще раз: не можна в open_offer і в подій з event: null |
received_at | Коли подія прийшла в панель - за ним фільтрується період |
status | Службове поле, для скриптів значення не має |
export_status:
exported- Facebook прийняв подію.not_exported- подію ще не надсилали. Надсилання відбувається раз на хвилину, але подія так і лишитьсяnot_exported, якщо в PWA немає пікселя з токеном, події не призначено подію Facebook,eventдорівнюєnullабо подія старша за 3 дні.failed- Facebook відмовив, причина - вexport_error. Якщо при цьомуexported_atпорожній, помилка тимчасова (Facebook недоступний, ліміт) - панель сама повторить надсилання. Якщоexported_atзаповнений - відмова остаточна, потрібен повторний експорт після виправлення.open_offer- службова подія, у Facebook вона не надсилається взагалі.
Сума за період
Щоб порахувати виручку, складайте payout за кожною currency окремо - валюти в одну цифру не зводяться. Готові суми за валютами за період є в розділі «Статистика» (total_deposits.amounts).
Фільтр export_status=open_offer показує лише відкриття офера, параметр event[] за нього не враховується.
Помилки
| Код | message | Коли |
|---|---|---|
422 | The date from field is required. (and 1 more error) | Не передано період; решта помилок періоду - як у розділі «Статистика» |
422 | The selected event.0 is invalid. | Невідомий тип події в event[] |
422 | The selected export status is invalid. | Невідомий export_status |
422 | The per page field must not be greater than 200. | per_page більше 200 |
422 | Invalid pwa_id / Invalid split_id | Ідентифікатор PWA або спліта не розпізнано |
404 | Not found | PWA або спліт із фільтра чужий або не існує |
Одна конверсія
GET/conversions/{id}
Конверсія та до 100 останніх візитів її відвідувача: з якого домену та IP він приходив, із якими мітками й який візит приніс конверсію. Зручно, коли партнерка сперечається щодо конверсії або потрібно знайти креатив, що її приніс.
curl https://panel.example.com/api/conversions/Rt5K \
-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,
]);
$details = json_decode($api->get('conversions/Rt5K')->getBody(), true)['data'];
foreach ($details['visits'] as $visit) {
if ($visit['matched']) {
echo "Конверсію приніс візит {$visit['created_at']}, sub_1 = {$visit['subs']['sub_1']}\n";
}
}# pip install requests
import requests
API = "https://panel.example.com/api"
HEADERS = {"Authorization": "Bearer ВАШ_КЛЮЧ", "Accept": "application/json"}
details = requests.get(f"{API}/conversions/Rt5K", headers=HEADERS, timeout=30).json()["data"]
for visit in details["visits"]:
if visit["matched"]:
print("Конверсію приніс візит", visit["created_at"], "sub_1 =", (visit["subs"] or {}).get("sub_1"))// 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}/conversions/Rt5K`, {
method: 'GET',
headers,
signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();
for (const visit of data.visits) {
if (visit.matched) {
console.log('Конверсію приніс візит', visit.created_at, 'sub_1 =', visit.subs?.sub_1);
}
}Відповідь
{
"data": {
"conversion": {
"id": "Rt5K",
"pwa": { "id": "WZAX", "name": "Promo EN", "icon_url": null },
"event": "deposit",
"payout": "45.00",
"currency": "USD",
"export_status": "failed",
"received_at": "05 Oct 2026 14:23"
},
"visits_count": 1,
"visits": [
{
"created_at": "05 Oct 2026 13:20",
"ip_address": "203.0.113.7",
"from_domain": "fit-tracker.example",
"country": "US",
"user_agent": "Mozilla/5.0 (Linux; Android 14)",
"offer_visitor_id": "aff-91822",
"offer_redirect_url": "https://offer.example/?sub1=fb-ua-creo1",
"subs": { "sub_1": "fb-ua-creo1", "sub_2": "adset-7" },
"third_party_tokens": null,
"is_unique": true,
"matched": true
}
]
}
}conversion - той самий запис, що в списку (тут скорочений). visits_count - скільки всього візитів у відвідувача; у visits - не більше 100 останніх, свіжі зверху.
| Поле візиту | Що це |
|---|---|
from_domain | Домен, на який прийшов відвідувач |
offer_visitor_id, offer_redirect_url | Ідентифікатор відвідувача в офера й посилання, на яке його відправили |
subs | Заповнені мітки sub_1 … sub_20; null, якщо міток не було |
third_party_tokens | Решта параметрів із посилання: fbclid, gclid тощо |
is_unique | Перший візит цього відвідувача |
matched | Візит, який приніс конверсію: останній візит на той самий потік до отримання події |
Якщо жоден візит не позначено matched, пов'язаний візит не знайдено - найчастіше через втрачений pwa_visitor_id у постбеку.
Помилки
| Код | message | Коли |
|---|---|---|
404 | Not found | Конверсія чужа або не існує |
Повторний експорт
POST/conversions/{id}/re-export
Знімає позначку про надсилання й помилку, і найближче фонове надсилання (раз на хвилину) спробує передати подію у Facebook ще раз.
Знадобиться, коли Facebook відмовив через налаштування, яке ви вже виправили: наприклад, оновили токен пікселя. Спершу виправте причину - інакше повтор отримає ту саму помилку.
curl -X POST https://panel.example.com/api/conversions/Rt5K/re-export \
-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->post('conversions/Rt5K/re-export');
$conversion = json_decode($response->getBody(), true)['data']['conversion'];
echo "{$conversion['id']}: {$conversion['export_status']}" . PHP_EOL;# pip install requests
import requests
API = "https://panel.example.com/api"
HEADERS = {"Authorization": "Bearer ВАШ_КЛЮЧ", "Accept": "application/json"}
response = requests.post(f"{API}/conversions/Rt5K/re-export", headers=HEADERS, timeout=30)
conversion = response.json()["data"]["conversion"]
print(conversion["id"], conversion["export_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}/conversions/Rt5K/re-export`, {
method: 'POST',
headers,
signal: AbortSignal.timeout(30000),
});
const { data } = await response.json();
console.log(data.conversion.id, data.conversion.export_status);Відповідь - конверсія після скидання, export_status у неї тепер not_exported:
Відповідь
{
"data": {
"conversion": {
"id": "Rt5K",
"event": "deposit",
"export_status": "not_exported",
"export_error": null,
"exported_at": null,
"can_reexport": true
}
}
}Помилки
| Код | message | Коли |
|---|---|---|
422 | Event cannot be re-exported | can_reexport: false - відкриття офера або подія з event: null |
404 | Not found | Конверсія чужа або не існує |
Лише свіжі конверсії
Фонове надсилання бере події не старші за 3 дні з моменту отримання (received_at). Повторний експорт старішої конверсії скине її статус, але у Facebook вона вже не піде.
Щоб перенадіслати всі помилки разом, візьміть список з export_status=failed і викличте повторний експорт для кожного рядка - не частіше за ліміт запитів із «Вступу до API».