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».