β ΠΠ°Π·Π°Π΄import 'dotenv/config';
const API_KEY = process.env.POPADS_API_KEY;
const BASE_V1 = 'https://www.popads.net/api';
const BASE_V2 = 'https://www.popads.net/apiv2';
if (!API_KEY) {
console.error('β POPADS_API_KEY not set in .env');
process.exit(1);
}
// βββ API v1 ββββββββββββββββββββββββββββββββββββββββββββ
const v1 = async (action, params = {}, method = 'GET') => {
const url = new URL(`${BASE_V1}/${action}`);
url.searchParams.set('key', API_KEY);
const opts = { method, headers: { Accept: 'application/json' } };
if (method === 'POST') {
Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
} else {
Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
}
const res = await fetch(url, opts);
if (!res.ok && res.status !== 406) {
const text = await res.text();
throw new Error(`PopAds v1 ${res.status}: ${text}`);
}
return res.json();
};
// βββ API v2 ββββββββββββββββββββββββββββββββββββββββββββ
const v2 = async (method, path, body = null) => {
const url = `${BASE_V2}${path}?key=${API_KEY}`;
const opts = {
method,
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
};
if (body) opts.body = JSON.stringify(body);
const res = await fetch(url, opts);
const data = await res.json();
return data;
};
// βββ v1 Commands βββββββββββββββββββββββββββββββββββββββ
const userStatus = () => v1('user_status');
const campaignList = () => v1('campaign_list');
const campaignStart = (id) => v1('campaign_start', { campaign_id: id }, 'POST');
const campaignPause = (id) => v1('campaign_pause', { campaign_id: id }, 'POST');
const campaignTopUp = (id, amount) => v1('campaign_top_up', { campaign_id: id, amount }, 'POST');
const campaignEmptyBudget = (id, amount) => v1('campaign_empty_budget', { campaign_id: id, amount }, 'POST');
const campaignRunout = () => v1('campaign_runout');
const websiteDetails = (id) => v1(`website_details/${id}`);
const reportAdvertiser = (params = {}) => {
const defaults = {
zone: 'America/Vancouver',
quick: 'today',
groups: 'campaigns',
};
return v1('report_advertiser', { ...defaults, ...params }, 'POST');
};
// βββ v2 Commands βββββββββββββββββββββββββββββββββββββββ
const getCampaignDetails = (id) => v2('GET', `/campaign/details/${id}`);
const createCampaign = (config) => v2('POST', '/campaign/add', config);
const updateCampaign = (id, config) => v2('PUT', `/campaign/update/${id}`, config);
const patchCampaign = (id, config) => v2('PATCH', `/campaign/update/${id}`, config);
const getOptions = (name, country = null) => {
const path = country ? `/options/${name}/${country}` : `/options/${name}`;
return v2('GET', path);
};
// βββ CLI βββββββββββββββββββββββββββββββββββββββββββββββ
const [cmd, ...args] = process.argv.slice(2);
const commands = {
async status() {
console.log('\nπ€ PopAds Account\n');
const data = await userStatus();
console.log(JSON.stringify(data, null, 2));
},
async campaigns() {
console.log('\nπ’ Campaigns\n');
const data = await campaignList();
if (Array.isArray(data)) {
data.forEach((c) => {
console.log(` β’ [${c.id}] ${c.name} β ${c.status} | budget: $${c.budget || '?'} | bid: $${c.max_bid || '?'}`);
});
} else {
console.log(JSON.stringify(data, null, 2));
}
},
async start() {
const [id] = args;
if (!id) { console.log('Usage: node popads.js start <campaign_id>'); return; }
const r = await campaignStart(id);
console.log('β
Started:', JSON.stringify(r));
},
async pause() {
const [id] = args;
if (!id) { console.log('Usage: node popads.js pause <campaign_id>'); return; }
const r = await campaignPause(id);
console.log('βΈοΈ Paused:', JSON.stringify(r));
},
async topup() {
const [id, amount] = args;
if (!id || !amount) { console.log('Usage: node popads.js topup <campaign_id> <amount>'); return; }
const r = await campaignTopUp(id, amount);
console.log('π° Topped up:', JSON.stringify(r));
},
async report() {
const [quick, group] = args;
console.log(`\nπ Report (${quick || 'today'}, group: ${group || 'campaigns'})\n`);
const data = await reportAdvertiser({
quick: quick || 'today',
groups: group || 'campaigns',
});
console.log(JSON.stringify(data, null, 2));
},
async details() {
const [id] = args;
if (!id) { console.log('Usage: node popads.js details <campaign_id>'); return; }
const data = await getCampaignDetails(id);
console.log(JSON.stringify(data, null, 2));
},
async options() {
const [name, country] = args;
if (!name) {
console.log(`
Options: ad-block-values, advertise-type, browsers, categories,
connection-speeds, connection-types, countries, devices,
form-factors, frequency-cap-days, languages, operating-systems,
quality, resolutions, timezones, regions/{country}`);
return;
}
const data = await getOptions(name, country);
console.log(JSON.stringify(data, null, 2));
},
async create() {
console.log('β οΈ Use node popads.js create-cpi or create-mainstream');
},
// Quick campaign creator β CPI SmartLink via BeMob
async 'create-cpi'() {
const [geo, budget, bid] = args;
if (!geo) { console.log('Usage: node popads.js create-cpi <GEO> [budget] [bid]'); return; }
const BEMOB_CPI_URL = 'https://27zff.bemobtrcks.com/go/06b83d41-b52e-443d-a1a3-c52adf4bb40c';
console.log(`Creating CPI campaign for ${geo.toUpperCase()}...`);
const r = await createCampaign(buildCampaignConfig(
`CPI Direct - ${geo.toUpperCase()}`, BEMOB_CPI_URL, geo, budget, bid
));
console.log(JSON.stringify(r, null, 2));
},
// Quick campaign creator β Mainstream SmartLink via BeMob
async 'create-mainstream'() {
const [geo, budget, bid] = args;
if (!geo) { console.log('Usage: node popads.js create-mainstream <GEO> [budget] [bid]'); return; }
const BEMOB_MS_URL = 'https://27zff.bemobtrcks.com/go/8fb53f2a-e310-4aa3-b573-9ba53a7664a8';
console.log(`Creating Mainstream campaign for ${geo.toUpperCase()}...`);
const r = await createCampaign(buildCampaignConfig(
`Mainstream Direct - ${geo.toUpperCase()}`, BEMOB_MS_URL, geo, budget, bid
));
console.log(JSON.stringify(r, null, 2));
},
async help() {
console.log(`
π§ PopAds CLI
ΠΠΊΠΊΠ°ΡΠ½Ρ:
node popads.js status β ΠΠ°Π»Π°Π½Ρ, ΠΈΠ½ΡΠΎ
node popads.js campaigns β Π‘ΠΏΠΈΡΠΎΠΊ ΠΊΠ°ΠΌΠΏΠ°Π½ΠΈΠΉ
Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅:
node popads.js start <id> β ΠΠ°ΠΏΡΡΡΠΈΡΡ ΠΊΠ°ΠΌΠΏΠ°Π½ΠΈΡ
node popads.js pause <id> β ΠΠΎΡΡΠ°Π²ΠΈΡΡ Π½Π° ΠΏΠ°ΡΠ·Ρ
node popads.js topup <id> <amount> β ΠΠΎΠΏΠΎΠ»Π½ΠΈΡΡ ΠΊΠ°ΠΌΠΏΠ°Π½ΠΈΡ
node popads.js details <id> β ΠΠ΅ΡΠ°Π»ΠΈ ΠΊΠ°ΠΌΠΏΠ°Π½ΠΈΠΈ (v2)
Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅:
node popads.js create-cpi <GEO> [budget] [bid]
node popads.js create-mainstream <GEO> [budget] [bid]
ΠΡΠΈΠΌΠ΅Ρ: node popads.js create-cpi PH 10 0.001
ΠΡΡΡΡΡ:
node popads.js report [quick] [group]
quick: today, yesterday, last7days, last30days, thismonth
group: campaigns, websites, countries, hours
Π‘ΠΏΡΠ°Π²ΠΎΡΠ½ΠΈΠΊΠΈ:
node popads.js options β Π‘ΠΏΠΈΡΠΎΠΊ ΡΠΏΡΠ°Π²ΠΎΡΠ½ΠΈΠΊΠΎΠ²
node popads.js options countries β Π‘ΡΡΠ°Π½Ρ
node popads.js options operating-systems β ΠΠ‘
`);
},
};
const run = commands[cmd] || commands.help;
run().catch((err) => {
console.error(`β ${err.message}`);
process.exit(1);
});
export {
userStatus, campaignList, campaignStart, campaignPause, campaignTopUp,
reportAdvertiser, getCampaignDetails, createCampaign, updateCampaign,
patchCampaign, getOptions,
};