Skip to content

Export ​

Two methods return a ready CSV file for a period: every conversion or every visit of your PWAs. It is the same download as the Export button in the panel, only from a script - to reconcile with the affiliate network and the tracker, or to build a report in Google Sheets or Excel. You do not need them for the tables inside the panel itself: the paged conversions list is GET/conversions, the aggregated numbers are in the "Statistics" section.

MethodPathWhat it does
GET/export/conversionsConversions for a period as CSV
GET/export/visitsVisits for a period as CSV

Replace YOUR_KEY and panel.example.com with your own.

How the file is built ​

  • The response is a file, not JSON: Content-Type: text/csv; charset=UTF-8, the name is in Content-Disposition - conversions_2026-10-01_2026-10-07.csv or visits_2026-10-01_2026-10-07.csv.
  • ; as the separator, UTF-8 with a BOM, the first row holds the column names. Excel opens such a file into columns on a double-click, Google Sheets takes it via File → Import.
  • The data come from the analytics store: they run up to 5 minutes behind the panel, and the conversions file has no Facebook export status column - but you can filter by it (export_status).
  • The file holds only what you see in the panel: admin - everything, team_lead - their teams, customer - their own PWAs.
  • At most 10 downloads per minute per user, then 429.

Conversions to CSV ​

GET/export/conversions

Every conversion for the period, one row per event, in the order they were received.

ParameterRequiredWhat it filters
date_from, date_toyesPeriod by the event's received date: YYYY-MM-DD, whole days in UTC, no longer than a month
event[]noEvent type, several allowed: install, open_offer, registration, deposit, repeat_deposit
export_statusnoStatus of sending to Facebook: exported, failed, not_exported or open_offer - as in GET/conversions; open_offer keeps only offer opens and event[] is ignored then
pwa_id or pwa_ids[]noOne or several PWAs
split_id or split_ids[]noOne or several splits - conversions from their flows
bash
curl -G "https://panel.example.com/api/export/conversions" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Accept: application/json" \
  --data-urlencode "date_from=2026-10-01" \
  --data-urlencode "date_to=2026-10-07" \
  --data-urlencode "event[]=deposit" \
  -o conversions.csv
php
<?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' => 120,
]);

$api->get('export/conversions', [
    'query' => ['date_from' => '2026-10-01', 'date_to' => '2026-10-07', 'event' => ['deposit']],
    'sink' => 'conversions.csv',
]);

echo 'Saved: conversions.csv, ' . filesize('conversions.csv') . " bytes\n";
python
# pip install requests
import requests

API = "https://panel.example.com/api"
HEADERS = {"Authorization": "Bearer YOUR_KEY", "Accept": "application/json"}

response = requests.get(f"{API}/export/conversions", headers=HEADERS, params={
    "date_from": "2026-10-01",
    "date_to": "2026-10-07",
    "event[]": ["deposit"],
}, timeout=120)
response.raise_for_status()

with open("conversions.csv", "wb") as file:
    file.write(response.content)
print("Saved: conversions.csv,", len(response.content), "bytes")
js
// Node.js 18+, no dependencies; save as script.mjs
import { writeFileSync } from 'node:fs';

const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer YOUR_KEY', Accept: 'application/json' };

const params = new URLSearchParams({ date_from: '2026-10-01', date_to: '2026-10-07' });
params.append('event[]', 'deposit');

const response = await fetch(`${API}/export/conversions?${params}`, { headers, signal: AbortSignal.timeout(120000) });
if (!response.ok) throw new Error(`HTTP ${response.status}: ${(await response.json()).message}`);

writeFileSync('conversions.csv', Buffer.from(await response.arrayBuffer()));
console.log('Saved: conversions.csv');
Response
csv
date;pwa;split;event;raw_event;payout;currency;visitor_id;tid;click_id;country;device
2026-10-03 14:23:11;Promo EN;;deposit;ftd;45.00;USD;7f3c2a9e-1b4d-4c8e-9a2f-5d6e7f8a9b0c;tx-55102;;DE;Android
2026-10-04 09:02:47;Promo EN;Split A;install;install;;;0b1d8f2c-4e6a-4b7c-8d9e-1f2a3b4c5d6e;;;PL;iOS
ColumnWhat it is
dateWhen the event reached the panel, UTC - the period filters by this date
pwaName of the PWA the conversion was credited to
splitName of the split if the visitor came through its flow; otherwise empty
eventEvent type: install, open_offer, registration, deposit, repeat_deposit; empty when the network sent a status the panel did not recognise
raw_eventThe status exactly as the network sent it (ftd, sale, reg…)
payout, currencyThe payout from the postback, as received
visitor_idThe visitor the conversion was matched to - the same visitor_id as in the visits file
tidTransaction id from the postback
click_idclick_id from the postback, when the network passed it
country, deviceCountry and device of this visitor's latest visit
Errors
CodemessageWhen
422The date from field is required. (and 1 more error)No period passed
422The date to field must be a date before or equal to 2026-11-01.The period is longer than a month; the date in the text is date_from plus one month
422The date to field must be a date after or equal to date from.date_to is before date_from
422The selected event.0 is invalid.Unknown event type in event[]
422Invalid pwa_id / Invalid split_idThe PWA or split identifier isn't recognised
404Not foundA PWA or split from the filter belongs to someone else or doesn't exist
429Too many requests. Try again in a minute.More than 10 downloads per minute

Visits to CSV ​

GET/export/visits

Every visit for the period, one row per visit, in time order. This is the raw traffic data: it is what you reconcile clicks against the tracker with, by sub tags, and what you build lists of visitors who installed the PWA but never converted from.

ParameterRequiredWhat it filters
date_from, date_toyesPeriod by the visit time: YYYY-MM-DD, whole days in UTC, no longer than a month
pwa_id or pwa_ids[]noOne or several PWAs
split_id or split_ids[]noOne or several splits - visits through their flows
countrynoCountry, two-letter code (DE, PL)
bash
curl -G "https://panel.example.com/api/export/visits" \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Accept: application/json" \
  --data-urlencode "date_from=2026-10-01" \
  --data-urlencode "date_to=2026-10-07" \
  --data-urlencode "pwa_id=WZAX" \
  -o visits.csv
php
<?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' => 300,
]);

$api->get('export/visits', [
    'query' => ['date_from' => '2026-10-01', 'date_to' => '2026-10-07', 'pwa_id' => 'WZAX'],
    'sink' => 'visits.csv',
]);

echo 'Saved: visits.csv, ' . filesize('visits.csv') . " bytes\n";
python
# pip install requests
import requests

API = "https://panel.example.com/api"
HEADERS = {"Authorization": "Bearer YOUR_KEY", "Accept": "application/json"}

response = requests.get(f"{API}/export/visits", headers=HEADERS, params={
    "date_from": "2026-10-01",
    "date_to": "2026-10-07",
    "pwa_id": "WZAX",
}, timeout=300)
response.raise_for_status()

with open("visits.csv", "wb") as file:
    file.write(response.content)
print("Saved: visits.csv,", len(response.content), "bytes")
js
// Node.js 18+, no dependencies; save as script.mjs
import { writeFileSync } from 'node:fs';

const API = 'https://panel.example.com/api';
const headers = { Authorization: 'Bearer YOUR_KEY', Accept: 'application/json' };

const params = new URLSearchParams({ date_from: '2026-10-01', date_to: '2026-10-07', pwa_id: 'WZAX' });

const response = await fetch(`${API}/export/visits?${params}`, { headers, signal: AbortSignal.timeout(300000) });
if (!response.ok) throw new Error(`HTTP ${response.status}: ${(await response.json()).message}`);

writeFileSync('visits.csv', Buffer.from(await response.arrayBuffer()));
console.log('Saved: visits.csv');
Response
csv
date;pwa;split;visitor_id;country;lang;os;device;unique;flow_unique;white;from_domain;ip;sub_1;sub_2;sub_3;sub_4;sub_5;sub_6;sub_7;sub_8;sub_9;sub_10;sub_11;sub_12;sub_13;sub_14;sub_15;sub_16;sub_17;sub_18;sub_19;sub_20
2026-10-03 14:20:05;Promo EN;;7f3c2a9e-1b4d-4c8e-9a2f-5d6e7f8a9b0c;DE;de;Android;Android;1;1;0;fit-tracker.example;203.0.113.7;fb-de-01;creative-7;;;;;;;;;;;;;;;;;;
2026-10-03 14:21:40;Promo EN;Split A;0b1d8f2c-4e6a-4b7c-8d9e-1f2a3b4c5d6e;PL;pl;iOS;iOS;1;1;0;fit-tracker.example;198.51.100.23;fb-pl-02;;;;;;;;;;;;;;;;;;;
ColumnWhat it is
dateVisit time, UTC
pwaName of the PWA the visit landed on
splitName of the split if the visit came through its flow; otherwise empty
visitor_idVisitor identifier - the visit is linked to conversions by it
country, langCountry and browser language
os, deviceOperating system and device type: Android, iOS or Desktop
unique1 - this visitor's first visit in the panel, 0 - a repeat
flow_unique1 - the visitor's first visit on this flow (that is how uniques are counted in statistics)
white1 - the filter sent the visitor to the white page; such a visit is not in the funnel
from_domainThe domain the PWA was opened from
ipVisitor's IP address
sub_1 … sub_20Sub tags from the link, as received; empty when the tag was absent
Errors
CodemessageWhen
422The date from field is required. (and 1 more error)No period passed
422The date to field must be a date before or equal to 2026-11-01.The period is longer than a month; the date in the text is date_from plus one month
422The date to field must be a date after or equal to date from.date_to is before date_from
422The country field format is invalid.country is not two letters
422Invalid pwa_id / Invalid split_idThe PWA or split identifier isn't recognised
404Not foundA PWA or split from the filter belongs to someone else or doesn't exist
429Too many requests. Try again in a minute.More than 10 downloads per minute

A big file - narrow the selection

An active team has millions of visits a month, and the file runs to hundreds of megabytes. Export per PWA or per week: a few requests in a row are faster than one huge one, and the limit of 10 downloads a minute is sized for that.