Skip to content

Конверсії ​

Методи для журналу конверсій - усього, що прийшло постбеками від партнерок і з самого трафіку (встановлення, відкриття офера). Тут кожну подію видно окремим рядком: із виплатою, відвідувачем і статусом надсилання у 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
bash
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
<?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']);
python
# 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
js
// 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;
}
Відповідь
json
{
  "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"
      }
    ]
  }
}
ПолеЩо це
pwaPWA, якому зараховано конверсію; null, якщо PWA не визначилося (такі рядки бачить лише admin)
pwa_visitor_idВідвідувач, за яким конверсія прив'язалася до візиту
eventТип події (список - у таблиці параметрів вище). null - партнерка надіслала статус, який панель не розпізнала: така подія не рахується в статистиці й не йде у Facebook
raw_eventСтатус рівно так, як його надіслала партнерка (ftd, sale, reg…)
payout, currencyВиплата з постбека - рядком, як прийшла
tidІдентифікатор транзакції з постбека
external_click_idclick_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Коли
422The date from field is required. (and 1 more error)Не передано період; решта помилок періоду - як у розділі «Статистика»
422The selected event.0 is invalid.Невідомий тип події в event[]
422The selected export status is invalid.Невідомий export_status
422The per page field must not be greater than 200.per_page більше 200
422Invalid pwa_id / Invalid split_idІдентифікатор PWA або спліта не розпізнано
404Not foundPWA або спліт із фільтра чужий або не існує

Одна конверсія ​

GET/conversions/{id}

Конверсія та до 100 останніх візитів її відвідувача: з якого домену та IP він приходив, із якими мітками й який візит приніс конверсію. Зручно, коли партнерка сперечається щодо конверсії або потрібно знайти креатив, що її приніс.

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

$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";
    }
}
python
# 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"))
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}/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);
  }
}
Відповідь
json
{
  "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Коли
404Not foundКонверсія чужа або не існує

Повторний експорт ​

POST/conversions/{id}/re-export

Знімає позначку про надсилання й помилку, і найближче фонове надсилання (раз на хвилину) спробує передати подію у Facebook ще раз.

Знадобиться, коли Facebook відмовив через налаштування, яке ви вже виправили: наприклад, оновили токен пікселя. Спершу виправте причину - інакше повтор отримає ту саму помилку.

bash
curl -X POST https://panel.example.com/api/conversions/Rt5K/re-export \
  -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->post('conversions/Rt5K/re-export');
$conversion = json_decode($response->getBody(), true)['data']['conversion'];

echo "{$conversion['id']}: {$conversion['export_status']}" . 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}/conversions/Rt5K/re-export", headers=HEADERS, timeout=30)
conversion = response.json()["data"]["conversion"]

print(conversion["id"], conversion["export_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}/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:

Відповідь
json
{
  "data": {
    "conversion": {
      "id": "Rt5K",
      "event": "deposit",
      "export_status": "not_exported",
      "export_error": null,
      "exported_at": null,
      "can_reexport": true
    }
  }
}
Помилки
КодmessageКоли
422Event cannot be re-exportedcan_reexport: false - відкриття офера або подія з event: null
404Not foundКонверсія чужа або не існує

Лише свіжі конверсії

Фонове надсилання бере події не старші за 3 дні з моменту отримання (received_at). Повторний експорт старішої конверсії скине її статус, але у Facebook вона вже не піде.

Щоб перенадіслати всі помилки разом, візьміть список з export_status=failed і викличте повторний експорт для кожного рядка - не частіше за ліміт запитів із «Вступу до API».