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.
| Method | Path | What it does |
|---|---|---|
| GET | /export/conversions | Conversions for a period as CSV |
| GET | /export/visits | Visits 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 inContent-Disposition-conversions_2026-10-01_2026-10-07.csvorvisits_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.
| Parameter | Required | What it filters |
|---|---|---|
date_from, date_to | yes | Period by the event's received date: YYYY-MM-DD, whole days in UTC, no longer than a month |
event[] | no | Event type, several allowed: install, open_offer, registration, deposit, repeat_deposit |
export_status | no | Status 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[] | no | One or several PWAs |
split_id or split_ids[] | no | One or several splits - conversions from their flows |
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
// 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";# 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")// 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
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| Column | What it is |
|---|---|
date | When the event reached the panel, UTC - the period filters by this date |
pwa | Name of the PWA the conversion was credited to |
split | Name of the split if the visitor came through its flow; otherwise empty |
event | Event type: install, open_offer, registration, deposit, repeat_deposit; empty when the network sent a status the panel did not recognise |
raw_event | The status exactly as the network sent it (ftd, sale, reg…) |
payout, currency | The payout from the postback, as received |
visitor_id | The visitor the conversion was matched to - the same visitor_id as in the visits file |
tid | Transaction id from the postback |
click_id | click_id from the postback, when the network passed it |
country, device | Country and device of this visitor's latest visit |
Errors
| Code | message | When |
|---|---|---|
422 | The date from field is required. (and 1 more error) | No period passed |
422 | The 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 |
422 | The date to field must be a date after or equal to date from. | date_to is before date_from |
422 | The selected event.0 is invalid. | Unknown event type in event[] |
422 | Invalid pwa_id / Invalid split_id | The PWA or split identifier isn't recognised |
404 | Not found | A PWA or split from the filter belongs to someone else or doesn't exist |
429 | Too 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.
| Parameter | Required | What it filters |
|---|---|---|
date_from, date_to | yes | Period by the visit time: YYYY-MM-DD, whole days in UTC, no longer than a month |
pwa_id or pwa_ids[] | no | One or several PWAs |
split_id or split_ids[] | no | One or several splits - visits through their flows |
country | no | Country, two-letter code (DE, PL) |
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
// 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";# 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")// 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
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;;;;;;;;;;;;;;;;;;;| Column | What it is |
|---|---|
date | Visit time, UTC |
pwa | Name of the PWA the visit landed on |
split | Name of the split if the visit came through its flow; otherwise empty |
visitor_id | Visitor identifier - the visit is linked to conversions by it |
country, lang | Country and browser language |
os, device | Operating system and device type: Android, iOS or Desktop |
unique | 1 - this visitor's first visit in the panel, 0 - a repeat |
flow_unique | 1 - the visitor's first visit on this flow (that is how uniques are counted in statistics) |
white | 1 - the filter sent the visitor to the white page; such a visit is not in the funnel |
from_domain | The domain the PWA was opened from |
ip | Visitor's IP address |
sub_1 … sub_20 | Sub tags from the link, as received; empty when the tag was absent |
Errors
| Code | message | When |
|---|---|---|
422 | The date from field is required. (and 1 more error) | No period passed |
422 | The 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 |
422 | The date to field must be a date after or equal to date from. | date_to is before date_from |
422 | The country field format is invalid. | country is not two letters |
422 | Invalid pwa_id / Invalid split_id | The PWA or split identifier isn't recognised |
404 | Not found | A PWA or split from the filter belongs to someone else or doesn't exist |
429 | Too 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.